この大会は2019/9/28 20:30(JST)~2019/9/29 20:30(JST)の予定で
開催されましたが、スコアサーバのスペックが悪く、
途中全くつながらくあきらめていました。
ただ12時間以上遅れて接続できるようになり、
開催時間は2019/9/30 13:30(JST)までに延長となりました。
実質自分一人でしたが、一応今回もチームで参戦。
結果は1364点で214チーム中47位でした。
自分で解けた問題をWriteupとして書いておきます。
Sanity Check (Misc)
freenodeで#bi0s-ctfチャネルに入る。
13:52 *R3x topic : Bsides CTF 2019 is live | CTF ends at Sep 30 - 10:00 am IST | Sorry for the initial glitches | Hosted by team bi0s | flag for sanity check - bsides_delhi{Welcome_to_BSides_Delhi}
bsides_delhi{Welcome_to_BSides_Delhi}
Business Planning Group (Forensics)
PNGの後ろにBPGが結合している。BPGファイルとして保存して開く。
画像にはBase64文字列らしきものが書いてある。
YnNpZGVzX2RlbGhpe0JQR19pNV9iM3R0M3JfN2g0bl9KUEd9Cg==
$ echo YnNpZGVzX2RlbGhpe0JQR19pNV9iM3R0M3JfN2g0bl9KUEd9Cg== | base64 -d bsides_delhi{BPG_i5_b3tt3r_7h4n_JPG}
bsides_delhi{BPG_i5_b3tt3r_7h4n_JPG}
SecureMAC (Crypto)
$ nc 35.188.170.152 1337 Are you sure you can break this?? n: 76472690532697166311269021454388689177337819643898942045648649751867098781025415467064983001826060648346992859933469733190992062552395519434685758658645859158524388939443193604668303015205778680402868870148158899016610276865820550344580001676405530950799291096238491161167924019305657802321745641587719633477 c: 5060590115074907654157443115269670455121700680545650614494579684796385803395442389488861108153558630937635714769114387689782977672747430779513838275172557831752831951447443618690425918742977709246496433951771110941509826730106825295859667024423110580931497154133833035641682463733419604392926160060406026250 enc_key: 7733309070852195143193103111258144016916408733264353946637309551910328067745900310261254365736406633900851633670377795196341452584950259992008214772252578322739868793109441848870933117722212871194379223725084763257441154198893337036520889792871193187008232406741375995946784104058637357478778159030583979776 Message 1: 1234567890abcdef1234567890abcdef Message 2: 1234567890abcdef1234567890abcdee Tags don't match
サーバ処理の概要は以下の通り。
・p, q: 512bit素数 ・n = p * q ・e = 65537 ・enc_key: keyをRSA暗号化 ・c1 = pow(bytes_to_long("fake_flag"),e,p) ・c2 = (pow(bytes_to_long("fake_flag"),e,q) ^ 1337)%q ・qinv = inverse(q,p) ・h = (qinv * (c1 - c2)) % p ・c = c2 + h*q ・n, c, enc_keyを表示 ・msg1, msg2: 16進数で入力 ・msg1とmsg2は異なるが、signの結果が同じものを指定できていれば、フラグを表示 さらにsignは以下のような処理。 ・tag: 最初のブロック(16バイト)をAES-ECB暗号化 ・2ブロック目以降、tagとのxorをAES-ECB暗号化し、tagとする。 ・最後のブロックで生成されたtagがsignの結果となる。
AESの鍵がわからないとどうしようもないと考え、まずはRSA CRT Fault Attackでnを素因数分解し、keyを復号する。
またsignの仕組みはこうなっている。
pt0 --[ECB]--> ct0 -> tag pt1 ^ ct0 --[ECB]--> ct1 -> tag
keyがわかっていれば、ct0を算出できる。
pt1 ^ ct0 が pt0 と同じであれば、pt0とpt0+pt1は同じタグになる。
以上のことからスクリプトを作成し、実行する。
import socket from Crypto.Cipher import AES from Crypto.Util.strxor import strxor from binascii import hexlify, unhexlify from Crypto.Util.number import * def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('35.188.170.152', 1337)) data = recvuntil(s, '1: \n').rstrip() print data #### decrypt key #### e = 65537 n = int(data.split('\n')[1].split(': ')[1]) c2 = int(data.split('\n')[2].split(': ')[1]) enc_key = int(data.split('\n')[3].split(': ')[1]) c1 = pow(bytes_to_long('fake_flag'), e, n) p = GCD(pow(c2 - c1, e, n), n) q = n / p assert p != 1 assert q != 1 assert p * q == n phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(enc_key, d, n) key = long_to_bytes(m) #### get two messages of same tag #### message1 = '1234567890abcdef' ECB = AES.new(key, AES.MODE_ECB) ct0 = ECB.encrypt(message1) pt1 = strxor(ct0, message1) message2 = message1 + pt1 print hexlify(message1) s.sendall(hexlify(message1) + '\n') data = recvuntil(s, '2: \n').rstrip() print data print hexlify(message2) s.sendall(hexlify(message2) + '\n') data = recvuntil(s, '\n').rstrip() print data
実行結果は以下の通り。
Are you sure you can break this?? n: 96838342337680682267171353265971032237294032508607201668491854263806820935507257020201554846768513785404162079515501788400272077902712859497750615959372529710074478533346415132895418900920925481934023577162607998710600750844042283691554771890081265167715533011289202032266831085194379168012745303876230348851 c: 82762930788866114361331566298418425441585658626734423801814167222017604637666030995313339402634457996150039514884707129717640360539671058514618015163522150561065740292930025759757930922296543751118585326474171749561856217047797331536806343472353171750630801533548282910733579338095878235075315491055574613409 enc_key: 14743966201402632176241257754478447951884458275889406290398299871117647370111201648871152565564132669215895939963962458134242560765314666733237935548142137268658802877923637914124409873842520516723143875066036678122285678465889900193241891892818857332242153876041392988564040068011322655396344645399722254759 Message 1: 31323334353637383930616263646566 Message 2: 313233343536373839306162636465665c2d32312074d2f6f28f5db87f022318 Congrats!! Here's your flag: bsides_delhi{F4ult'n'F0rg3_1s_@_b4d_c0mb1n4ti0n}
bsides_delhi{F4ult'n'F0rg3_1s_@_b4d_c0mb1n4ti0n}
Feedback(?) (Misc)
※正確な問題タイトルは自信がありませんが、こんな感じの名前だったかと...。スマホでアンケートの問題に答えたのですが、記録するのを忘れていました。
アンケートに答えたら、フラグが表示された。
bsides_delhi{Thanks_f0r_PlaYing_th1s_CTF_!!}}