拖了快半年了, 终于来把这个坑给填上.
SROP SROP全称Sigreturn Oriented Programming, 指利用Linux系统调用rt_sigreturn来进行ROP攻击的技术. 这种技术利用了sigreturn系统调用的特性, 允许攻击者通过构造特定的栈帧来控制寄存器的值, 从而实现任意代码执行.
虽说SROP被归类为高级ROP的一种, 但其实它的原理并不复杂. 主要是利用了sigreturn系统调用的机制, 在执行该系统调用时, 内核会从用户空间的栈中恢复寄存器的状态, 即将当前$rsp指向的一块区域视为所谓的Signal Frame, 然后将其中的内容加载到相应的寄存器中. 通过精心构造这个Signal Frame, 攻击者可以将所有寄存器设置为任意值。
对于Signal Frame来说,会因为架构的不同而有所区别,这里给出分别给出x86以及x64的sigcontext:
x86 sigcontext struct sigcontext { unsigned short gs, __gsh; unsigned short fs, __fsh; unsigned short es, __esh; unsigned short ds, __dsh; unsigned long edi; unsigned long esi; unsigned long ebp; unsigned long esp; unsigned long ebx; unsigned long edx; unsigned long ecx; unsigned long eax; unsigned long trapno; unsigned long err; unsigned long eip; unsigned short cs, __csh; unsigned long eflags; unsigned long esp_at_signal; unsigned short ss, __ssh; struct _fpstate * fpstate ; unsigned long oldmask; unsigned long cr2; };
x64 sigcontext struct _fpstate { __uint16_t cwd; __uint16_t swd; __uint16_t ftw; __uint16_t fop; __uint64_t rip; __uint64_t rdp; __uint32_t mxcsr; __uint32_t mxcr_mask; struct _fpxreg _st [8]; struct _xmmreg _xmm [16]; __uint32_t padding[24 ]; }; struct sigcontext { __uint64_t r8; __uint64_t r9; __uint64_t r10; __uint64_t r11; __uint64_t r12; __uint64_t r13; __uint64_t r14; __uint64_t r15; __uint64_t rdi; __uint64_t rsi; __uint64_t rbp; __uint64_t rbx; __uint64_t rdx; __uint64_t rax; __uint64_t rcx; __uint64_t rsp; __uint64_t rip; __uint64_t eflags; unsigned short cs; unsigned short gs; unsigned short fs; unsigned short __pad0; __uint64_t err; __uint64_t trapno; __uint64_t oldmask; __uint64_t cr2; __extension__ union { struct _fpstate * fpstate ; __uint64_t __fpstate_word; }; __uint64_t __reserved1 [8 ]; };
实际在利用中也不需要那么麻烦手动构造, pwntools中的SigreturnFrame类已经帮我们封装好了:
from pwn import *context.arch = 'amd64' sigframe = SigreturnFrame() sigframe.rip = 0xdeadbeef sigframe.rsp = 0xdeadbeef sigframe.rbp = 0xdeadbeef ... payload = bytes (sigframe)
通常我们会结合syscall指令来触发sigreturn系统调用. 在x86-64架构中, syscall指令的系统调用号为15, 一般需要先设法将rax寄存器设置为15(如利用read函数返回值), 然后rop到syscall指令执行, 栈后面紧跟着构造好的Signal Frame, 这样在syscall结束时内核就会将寄存器设置为我们指定的值.
SROP chain 通过SROP技术, 我们还可以构造SROP chain, 也就是一系列的Signal Frame, 其中每个Signal Frame的$rsp都指向下一个Signal Frame. 这样在执行完第一个sigreturn后, 内核会将$rsp设置为下一个Signal Frame, 然后再次执行sigreturn, 以此类推.
最后, 需要注意的是, SROP的Signal Frame结构体需要的空间较大(在x64上需要0xf8字节, 加上触发syscall的gadget恰好为0x100字节), 因此在利用时需要确保有足够的空间来存放这些数据.