この大会は2016/2/20 20:00(JST)~2016/2/22 8:00(JST)に開催されました。
今回はチームで参戦。結果は1350点で1492チーム中112位でした。
自分で解けた問題をWriteupとして書いておきます。
Quick Run (misc 60)
与えられたREADME.txtにはBASE64エンコードと思われるデータがたくさん入っている。
以下のスクリプトでそれぞれBASE64デコードしてファイル保存する。
import base64 i = 0 enc = '' for line_lf in open('README.txt').readlines(): line = line_lf.replace('\n', '') if len(line) == 76: enc += line else: enc += line with open('data' + str(i) + '.txt', 'wb') as f: f.write(enc.decode('base64').replace('\n', '\r\n')) enc = '' i = i + 1
これで24個のファイルが作成され、QRコードのようなものが書かれている。
よく見るとQRコードとしては白黒逆なので、ドラッグで反転させて、QRコードリーダで読み取っていく。
最初のデータは「F」。あとは順番に読み取っていくと、「Flagis:IW{QR_C0DES_RUL3}」となる。
IW{QR_C0DES_RUL3}
Oh Bob! (crypto 60)
3つの公開鍵ファイルと暗号ファイルが与えられている。暗号ファイルの中にはBASE64文字列が3行入っている。3つあるが、RSA暗号の復号問題と踏んで進める。まず公開鍵ファイルを見てみる。
# openssl rsa -pubin -text < bob.pub Public-Key: (228 bit) Modulus: 0d:56:4b:97:8f:9d:23:35:04:95:8e:ed:8b:74:43: 73:28:1e:d1:41:8b:29:f1:ec:fa:80:93:d8:cf Exponent: 65537 (0x10001) writing RSA key -----BEGIN PUBLIC KEY----- MDgwDQYJKoZIhvcNAQEBBQADJwAwJAIdDVZLl4+dIzUElY7ti3RDcyge0UGLKfHs +oCT2M8CAwEAAQ== -----END PUBLIC KEY----- # openssl rsa -pubin -text < bob2.pub Public-Key: (228 bit) Modulus: 0a:23:37:0e:7d:0f:b0:02:32:16:4a:c6:d6:42:84: 0f:c5:4e:92:02:43:3f:92:7a:60:eb:5a:db:d9 Exponent: 65537 (0x10001) writing RSA key -----BEGIN PUBLIC KEY----- MDgwDQYJKoZIhvcNAQEBBQADJwAwJAIdCiM3Dn0PsAIyFkrG1kKED8VOkgJDP5J6 YOta29kCAwEAAQ== -----END PUBLIC KEY----- # openssl rsa -pubin -text < bob3.pub Public-Key: (228 bit) Modulus: 0c:5b:69:e1:97:9e:54:1f:85:da:cd:e2:aa:14:d2: 72:2a:84:6f:41:b3:db:83:e6:67:e3:b3:d1:1d Exponent: 65537 (0x10001) writing RSA key -----BEGIN PUBLIC KEY----- MDgwDQYJKoZIhvcNAQEBBQADJwAwJAIdDFtp4ZeeVB+F2s3iqhTSciqEb0Gz24Pm Z+Oz0R0CAwEAAQ== -----END PUBLIC KEY-----
それぞれ合成数がわかったので、素因数分解する。
sage: factor(0x0d564b978f9d233504958eed8b744373281ed1418b29f1ecfa8093d8cf) 17963604736595708916714953362445519 * 20016431322579245244930631426505729 sage: factor(0x0a23370e7d0fb00232164ac6d642840fc54e9202433f927a60eb5adbd9) 16514150337068782027309734859141427 * 16549930833331357120312254608496323 sage: factor(0x0c5b69e1979e541f85dacde2aa14d2722a846f41b3db83e667e3b3d11d) 17357677172158834256725194757225793 * 19193025210159847056853811703017693
# rsatool.py -f PEM -o bob.sec -p 17963604736595708916714953362445519 -q 20016431322579245244930631426505729 Using (p, q) to initialise RSA instance : Saving PEM as bob.sec # rsatool.py -f PEM -o bob2.sec -p 16514150337068782027309734859141427 -q 16549930833331357120312254608496323 Using (p, q) to initialise RSA instance : Saving PEM as bob2.sec # rsatool.py -f PEM -o bob3.sec -p 17357677172158834256725194757225793 -q 19193025210159847056853811703017693 Using (p, q) to initialise RSA instance : Saving PEM as bob3.sec
secret.encの中の3つの文字列をBASE64デコードして、それぞれファイル保存する。
import base64 msg1 = 'DK9dt2MTybMqRz/N2RUMq2qauvqFIOnQ89mLjXY=' msg2 = 'AK/WPYsK5ECFsupuW98bCFKYUApgrQ6LTcm3KxY=' msg3 = 'CiLSeTUCCKkyNf8NVnifGKKS2FJ7VnWKnEdygXY=' with open('sec1', 'wb') as f: f.write(msg1.decode('base64')) with open('sec2', 'wb') as f: f.write(msg2.decode('base64')) with open('sec3', 'wb') as f: f.write(msg3.decode('base64'))
秘密鍵で復号する。
# openssl rsautl -decrypt -inkey bob.sec < sec1 IW{WEAK_R # openssl rsautl -decrypt -inkey bob3.sec < sec2 3_SO_BAD!} # openssl rsautl -decrypt -inkey bob2.sec < sec3 SA_K3YS_4R
フラグの形式に並び替える。
IW{WEAK_RSA_K3YS_4R3_SO_BAD!}
A numbers game (code 50)
ncで接続すると、このような表示。
# nc 188.166.133.53 11027 Hi, I heard that you're good in math. Prove it! Level 1.: x + 17 = 37
何回もこのxを答える必要がある。ただxは必ず左端で、四則演算しかなさそうだったので、以下のようなスクリプトで解く。
#!/usr/bin/env python import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('188.166.133.53', 11027)) for i in range(1, 10000): data = s.recv(256) print data data = s.recv(256) print data formula = data.split(': ') elem = formula[1].split(' ') if elem[1] == '+': ans = str(int(elem[4]) - int(elem[2])) elif elem[1] == '-': ans = str(int(elem[4]) + int(elem[2])) elif elem[1] == '*': ans = str(int(elem[4]) / int(elem[2])) elif elem[1] == '/': ans = str(int(elem[4]) * int(elem[2])) print ans s.sendall(ans)
100回正解すると、フラグが表示された。
IW{M4TH_1S_34SY}
It's Prime Time! (code 60)
ncで接続すると、このような表示。
# nc 188.166.133.53 11059 Hi, you know that prime numbers are important, don't you? Help me calculating the next prime! Level 1.: Find the next prime number after 4:
このafterの後の数字より大きい最小の素数を答える必要がある。素数判定のプログラムを探し、それを利用したスクリプトで解く。
#!/usr/bin/env python import socket def prime_check(d): if d < 2: return 0 if d == 2: return 1 if d % 2 == 0: return 0 a = 3 while a ** 2 <= d: if d % a == 0: return 0 a = a + 2 return 1 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('188.166.133.53', 11059)) for i in range(1, 10000): data = s.recv(256) print data data = s.recv(256) print data formula = data.split(':') elem = formula[1].split(' ') base = elem[7] try_digit = int(base) + 1 while True: if prime_check(try_digit) == 1: ans = str(try_digit) break try_digit = try_digit + 1 print ans s.sendall(ans)
100回正解すると、フラグが表示された。
IW{Pr1m3s_4r3_!mp0rt4nt}
A numbers game II (code 70)
ncで接続すると、このような表示。
# nc 188.166.133.53 11071
Hi, I like math and cryptography. Can you talk to me?!
Level 1.: 4.4.5.3.3.3.3.3.3.3.5.6.3.3.3.3.3.4.3.5.3.4.3.3.3.3.3.3.3.4.6.4.3.3.3.3.3.4.3.5.3.4.3.5
暗号のスクリプトが付いているので、それを読み解く。処理の概要は以下の通り。
1文字ずつASCIIコードを32とのXORをとる。 2進数8桁で0パディングする。 パディングした2進数を2桁ずつ区切って、51を足し、ASCII変換で文字表記にし、ドット(.)で区切る。
これをベースに復号すると、code 50と同様の計算式になる。さらに答える際には暗号が必要ということがわかり、それを踏まえてスクリプトで解く。
#!/usr/bin/env python import socket def decode(enc): l_enc = enc.split('.') dec = '' dec_tmp = '' for i in range(len(l_enc)): dec_tmp += format(ord(l_enc[i]) - 51, '02b') if i % 4 == 3: dec += chr(int(dec_tmp, 2) ^ 32) dec_tmp = '' return dec def encode(eq): out = [] for c in eq: q = bin(ord(c) ^ 32).lstrip('0b') q = "0" * (8 - len(q)) + q out.append(q) b = ''.join(out) pr = [] for x in range(0, len(b), 2): c = chr(int(b[x:x + 2], 2) + 51) pr.append(c) s = '.'.join(pr) return s s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('188.166.133.53', 11071)) for i in range(1, 10000): data = s.recv(256) print data data = s.recv(256) print data enc_line = data.split(': ') enc = enc_line[1].replace('\n', '') elem = decode(enc).split(' ') if elem[1] == '+': calc = str(int(elem[4]) - int(elem[2])) elif elem[1] == '-': calc = str(int(elem[4]) + int(elem[2])) elif elem[1] == '*': calc = str(int(elem[4]) / int(elem[2])) elif elem[1] == '/': calc = str(int(elem[4]) * int(elem[2])) ans = encode(calc) print ans s.sendall(ans)
100回正解すると、フラグが表示された。
IW{Crypt0_c0d3}