美文网首页CTF Re&&Pwn工具链
同时使用多种版本的libc && 编译libc

同时使用多种版本的libc && 编译libc

作者: pu1p | 来源:发表于2019-04-30 23:20 被阅读2次

    参考: https://bbs.pediy.com/thread-225849.htm

    做pwn题的时候经常会遇到不同的libc, 最简单的解决方法就是LD_PRELOAD了, 不过这个方法有一个局限. 就是如果libc的版本差太多的话就没办法使用了. 毕竟LD_PRELOAD只是告诉ld.so该去哪儿加载libc, 可是ld.so也没有办法去加载不同版本的ld.so
    于是我就只能傻乎乎地配了三个ubuntu的pwn环境, 虽然有docker可以用, 可是感觉在虚拟机里面又装一层docker实在有点蠢.... 总之既浪费时间又浪费空间
    通过上面的帖子我才发现其实是可以在一个ubuntu中使用多个版本的libc的, 只要修改程序使得其使用对应版本的ld.so即可

    elf文件有个段 PT_INTERP, 其中存储了程序使用的ld.so的路径, 默认是这样


    image.png

    我们通过上面链接里面给出的脚本可以修改程序的这个段的内容, 使得其启动的时候使用我们提供的ld.so, 然后我们就可以修改其为特定版本的ld.so从而达到使用不同版本libc的目的了
    下面就是修改为2.24版本的ld.so其使用 libc2.24


    image.png

    我发现如果使用自己编译的libc的话即使不使用LD_PRELOAD它也会找到对应的libc, 而不是默认的 /lib/x86_64-linux-gnu/libc.so.6, 应该是在ld.so里面记录了libc的路径.


    image.png

    而且我们还可以下载libc 2.24的源码从而实现源码级调试的目的. (具体操作参考 https://stackoverflow.com/questions/29955609/include-source-code-of-malloc-c-in-gdb )

    image.png

    贴一下我自己的脚本, 相比原帖修改了2点:

    1. 将修改后的文件就放在当前文件夹而不是/tmp/pwn/下
    2. 修改后的文件添加一个后缀, 表示使用的是哪个版本的ld.so, 因为现在经常有些题目不给libc.... 可能得试好几个
    #coding:utf-8
    from pwn import *
    import os
    def change_ld(binary, ld):
        if not os.access(ld, os.R_OK): 
          log.failure("Invalid path {} to ld".format(ld))
          return None
        if not os.access(binary, os.R_OK): 
          log.failure("Invalid path {} to binary".format(binary))
          return None
        binary = ELF(binary)
        path = './{}_{}'.format(os.path.basename(binary.path), ld.split('/')[-1])
        if os.access(path, os.F_OK):
          os.remove(path)
          print("remove exist file.....")
          return ELF(path)
        for segment in binary.segments:
          if segment.header['p_type'] == 'PT_INTERP':
            size = segment.header['p_memsz']
            addr = segment.header['p_paddr']
            data = segment.data()
            if size <= len(ld):
              log.failure("Failed to change PT_INTERP from {} to {}".
                format(data, ld))
              return None
            binary.write(addr, ld.ljust(size, '\x00'))
            break
        binary.save(path)    
        os.chmod(path, 0b111000000) #rwx------
        success("PT_INTERP has changed from {} to {}. Using temp file {}".format(data, ld, path)) 
        return ELF(path)
    

    建议还是使用自己编译的libc, 一个版本也就20分钟不到就编译好了.

    下面大概简单说了一下我编译libc的过程. 大家可以参考一下

    Appendix: 编译libc

    官方编译教程
    注意:
    本教程没有考虑到编译过程中可能需要某些诸如gcc之类软件依赖的情况.
    环境:

    Ubuntu 16.04 server版

    1. 下载glibc:
      我选择的是glibc_*.tar.gz版本
      1. 官网
      2. 教育网可以选择清华的镜像站
    2. 解压
      尽量不要再虚拟机的共享文件夹下解压, 可能会出现莫名其妙的问题, 速度可能也会很慢
      a. tar -xvf glibc_*.tar.gz
      b. 可以看到一个新的文件夹, 然后我们再新建两个文件夹用来存储编译结果:


      image.png

    第一文件夹是解压得到的, 后两个是新建的

    1. 配置编译参数
      a. 进入 *_build文件夹, 执行
    ../glibc-2.24/configure  '--prefix=/home/pu1p/glibcs/glibc-2.24_out'
    

    这儿解释一下, glibc编译的时候需要在一个新的文件夹下编译, 不允许在源代码的目录中编译.
    编译完成后还会产生一些诸如ldd等二进制文件,最好使用--prefix声明一个文件夹来存储这些产生的文件, 否则如果存储到默认路径/usr/local可能会影响系统的正常运行

    1. make:
      a. make (大概10min)
      b. make install (大概2min)
    2. 寻找libc.so 和 ld.so
      a. libc.so 就在glibc-2.24_build目录下
      b. ld.so 就在glibc-2.24_build/elf 目录下

    相关文章

      网友评论

        本文标题:同时使用多种版本的libc && 编译libc

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