<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    切換glibc版本

    看到這題目就知道現在說的是個困擾pwn選手多年的問題,這里提供兩種強行解決的方案

    方法1

    TODO:
    1. 自行下載glibc 2.23/2.24/2.25/2.26 源碼并編譯
    2. 將所需要使用到版本的ld.so放在pwn題目錄下
    3. 跑這個代碼
    引用自看雪論壇 https://bbs.pediy.com/thread-225849.htm

    def change_ld(binary, ld):
        """
        Force to use assigned new ld.so by changing the binary
        """
        if not os.access(ld, os.R_OK): 
            log.failure("Invalid path {} to ld".format(ld))
            return None
    
    
        if not isinstance(binary, ELF):
            if not os.access(binary, os.R_OK): 
                log.failure("Invalid path {} to binary".format(binary))
                return None
            binary = ELF(binary)
    
    
        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, '\0'))
                if not os.access('/tmp/pwn', os.F_OK): os.mkdir('/tmp/pwn')
                path = '/tmp/pwn/{}_debug'.format(os.path.basename(binary.path))
                if os.access(path, os.F_OK): 
                    os.remove(path)
                    info("Removing exist file {}".format(path))
                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)
    #example
    elf = change_ld('./pwn', './ld.so')
    p = elf.process(env={'LD_PRELOAD':'./libc.so.6'})

    用法很簡單,參數第一個可以是ELF,可以是路徑,第二個必須是ld.so的路徑(最好放在當前文件夾,原因后面講)。返回值我自己方便用所以是ELF,不喜歡的自己改成path,這個不會改變你原來的文件,只是建立一個修改的副本放在/tmp/pwn里面
    4. 不用LD_PRELOAD則加載 源碼級 libc(調libc=調源碼? 存在的) 或者 使用LD_PRELOAD加載給定的libc

    原理:
    PT_INTERP這是個神秘的東西,這個是編譯的時候就硬編碼好的東西,值是’/lib/ld-linux.so.2’ ,其實這個就是萬惡的ld了,程序加載的時候,首先進去的不是_start處的代碼,而是先加載執行PT_INTERP指向的程序,ld在加載后會給程序加載libc,最后再執行程序的代碼。
    但是在改的時候,是有長度限制的,代碼已經寫好了,所以將ld.so放當前文件夾就不會出錯。
    所以說,利用LD_PRELOAD直接加載不同版本的libc,會由于libc和ld匹配不上而出錯。

    改進

    轉載自簡書的韋師傅。https://www.jianshu.com/p/ee1ad4044ef7
    做pwn題的時候經常會遇到不同的libc, 最簡單的解決方法就是LD_PRELOAD了, 不過這個方法有一個局限. 就是如果libc的版本差太多的話就沒辦法使用了. 畢竟LD_PRELOAD只是告訴ld.so該去哪兒加載libc, 可是ld.so也沒有辦法去加載不同版本的libc
    于是我就只能傻乎乎地配了三個ubuntu的pwn環境, 雖然有docker可以用, 可是感覺在虛擬機里面又裝一層docker實在有點蠢…. 總之既浪費時間又浪費空間
    通過上面的帖子我才發現其實是可以在一個ubuntu中使用多個版本的libc的, 只要修改程序使得其使用對應版本的ld.so即可

    elf文件有個段 PT_INTERP, 其中存儲了程序使用的ld.so的路徑, 默認是這樣

    切換glibc版本

    默認使用 /lib64/ld-linux-x86-64.so.2

    我們通過上面鏈接里面給出的腳本可以修改程序的這個段的內容, 使得其啟動的時候使用我們提供的ld.so, 然后我們就可以修改其為特定版本的ld.so從而達到使用不同版本libc的目的了
    下面就是修改為2.24版本的ld.so其使用 libc2.24
    我們通過上面鏈接里面給出的腳本可以修改程序的這個段的內容, 使得其啟動的時候使用我們提供的ld.so, 然后我們就可以修改其為特定版本的ld.so從而達到使用不同版本libc的目的了
    下面就是修改為2.24版本的ld.so其使用 libc2.24

    切換glibc版本

    我發現如果使用自己編譯的libc的話即使不使用LD_PRELOAD它也會找到對應的libc, 而不是默認的 /lib/x86_64-linux-gnu/libc.so.6, 應該是在ld.so里面記錄了libc的路徑.

    切換glibc版本

    而且我們還可以下載libc 2.24的源碼從而實現源碼級調試的目的. (具體操作參考這個SO)

    切換glibc版本

    貼一下我自己的腳本, 相比原帖修改了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('.')[-2])
        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.so和ld.so

    不過我還是建議自己編譯libc, 一個版本也就20分鐘不到就編譯好了. 之后調試的時候會很方便

    這里提供一些安裝博客,里面提到的問題絕大多數情況大家都會遇到。
    編譯 Libc 2.23
    在 Arch Linux 下使用 glibc 2.23 調試程序&使用 pwndbg
    Pwn題目本地調試加載libc版本
    編譯帶debug_info的glibc
    Using a non-system glibc

    使用工具

    另一種方案是使用patchelf工具的–set-interpreter和–set-rpath命令替換ld.so和libc.so

    要是實在弄不好,就直接多安一個虛擬機,或者用docker,省的在這自閉好幾天都沒進展

    本文章首發在 網安wangan.com 網站上。

    上一篇 下一篇
    討論數量: 0
    只看當前版本


    暫無話題~
    亚洲 欧美 自拍 唯美 另类