CTF - glibc高版本gdb调试问题

admin 2023年6月1日08:28:271 186 views字数 5205阅读17分21秒阅读模式

前言

由于高版本glibc的调试符号格式有变,导致gdb不能直接加载符号表,需要手动导入高版本的符号表,这里有几种方案。

glibc多版本配置方案

手动编译(不推荐)

glibc的编译需要特定版本的gcc和cri.o,版本不匹配大概率会编译失败各个发行版对应的版本:
2.23 ubuntu16.04
2.27 ubuntu18.04
2.31 ubuntu20.04
2.35 ubuntu22.04

正常情况下这几个版本的glibc能覆盖大部分的攻击手段了。
2.23版本的编译需要额外的patch,否则报错。patch可以在github上找到。(这个patch已经被apply了,但是Ubuntu官方并没有)

编译过程:

从github gnu等地方下载glibc源码,然后使用git checkout到你想要的版本。

创建额外的 build 目录,直接在 glibc 目录下创建了 build 目录mkdir build && cd build,使用下面的命令进行编译,

CFLAGS="-static -g -g3 -ggdb -gdwarf-4 -Og" CXXFLAGS="-static -g -g3 -ggdb -gdwarf-4 -Og" ../source/configure --prefix=/glibc/2.27/build --disable-werror
CFLAGS makefile 编译选项
-g:包含调试信息是 OS native format
-ggdb: 供 gdb 使用的调试信息
-g3: 产生额外的 debug 信息
-gdwarf-4: 产生 dwarf 格式的 debug info,产生 .debug_info段
-Og 启用不影响调试的编译优化--prefix 安装路径,只能是绝对路径
--disable-sanity-checks 关闭适应性检查。可能与 GNU/Linux 行为不一致

使用glibc-all-in-one(推荐)

我使用的是glibc-all-in-one,可以下载一些编译好的大版本的debs,包括glibc和他的符号表,然后解压到自己的目录使用。目前此项目好久没更新对新版的glibc调试符号没有兼容,我执行修改了下,实现了自动下载解压个版本libc到指定目录,而更新了extrct使其兼容高版本glibc符号表的解压。

修改过的版本:git clone [email protected]:1094093288/glibc-all-in-one.git

.
├── build   #不推荐使用
├── cp-libc-root.py # root用户使用此脚本将libc拷贝到用户目录
├── cp-libc-user.py # root用户使用此脚本将libc拷贝到用户目录
├── debs # 下载的deb存放路径
├── down-all.py # 下载list中所有的版本,存放libs下
├── download # 下载单个版本
├── download_old # 下载老版本
├── extract # 解压脚本,支持高版本符号表解压
├── libs # deb解压后的存放路径
├── list # 版本libc
├── old_list # 老版本glibc
├── README.md
└── update_list # 更新list

直接下载编译好的glibc(推荐)

下面是两个Ubuntu的地址(使用速度快的镜像站)
https://mirror.tuna.tsinghua.edu.cn/ubuntu/pool/main/g/glibc/
http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/

需要注意要下载libc6-{version}-{version}ubuntu{arch}.deb和libc6-dbg{version}-{version}ubuntu1.5_{arch}.deb

不要去下载libc-x64或者libc-amd64这两种包,这些包是给编译器交叉编译用的,没有调试符号和源码。不建议作为runtime。

  • libc6-dev-amd64_2.23-0ubuntu11.3_i386.deb这个包是32位系统交叉编译64位的包,不要下载这个。

  • libc6-amd64_2.23-0ubuntu11.3_i386.deb 这个包太奇怪了,也不要下,是32位系统下64位程序的C runtime。

源码:https://mirror.tuna.tsinghua.edu.cn/ubuntu/pool/universe/g/glibc/

下载后使用dpkg -X  xxx.deb path或者使用下面脚本一键部署到当前目录

set -aux
if [ -z $1 ]
then
   echo "no libc version specified"
   exit
fi

current_path=`readlink -f "$0"`
current_path=`dirname $current_path`
for i in `ls $current_path/*$1*.deb`
do
  dpkg -X $i $current_path
done

mkdir $current_path/lib/x86_64-linux-gnu/.debug
cp -R $current_path/usr/lib/debug/lib/x86_64-linux-gnu/* $current_path/lib/x86_64-linux-gnu/.debug

# extract source
tar -C $current_path/usr/src/glibc -xvf   $current_path/usr/src/glibc/glibc-$1.tar.xz

加载指定版本的libc

  1. 可以使用LD_PRELOAD和强制加载libc.so,使用对应的ld.so启动目标程序:

    LD_PRLOAD=libc.so.6  ld.so xxx.elf2.30后可以使用ld.so --preload libc.so.6 xxx.elf注意elf要使用相对路径时要加./

  2. 使用pwntools启动,原理同1方法

 #. /libc/lib/x86_64-linux-gnu/ld-2.23.so --library-path ./libc/lib/x86_64-linux-gnu/ ./elf_name
p=process(ld_path+' --library-path '+"/".join(libc_path.split('/')[:-1])+" ./" +elf_name,shell=True)
p=process([ld_path,"--library-path","/".join(libc_path.split('/')[:-1]),"./"+elf_name])
p=process([ld_path,"./"+elf_name],env={'LD_PRELOAD':libc_path})
都可以正常启动,但是通过ld或者sh启动的elf文件,gdb中认不出LD_PRELOAD的libc,导致没有符号和源码。
通过info share来查看gdb是否加载了libc的符号,(*)代表未加载符号。

CTF - glibc高版本gdb调试问题

  1. 使用patchelf工具加载

    推荐使用这种方法

    下载地址:https://github.com/NixOS/patchelf

patchelf --set-interpreter <ld_path> <elf_path> 
patchelf --replace-needed <libc_path> <elf_path>

elf文件的<libc_path> 通过ldd命令可以查看。

patchelf有个bug,如果这两条命令执行过快的话(写脚本)可能会因为条件竞争导致elf被写坏。patch直接启动即可,需要注意的是elf和libc路径不能随意变动,除非上面patchelf的参数是绝对路径。


加载libc符号

如果直接使用下载的libc,符号可能没有自动加载(特别是高版本glibc)。使用下面的脚本载入符号。要先在gdb中使用source命令载入脚本。这个脚本看起来只能加载libc的符号。

add_separate_debug_file这个api没有在gdb中找到对应命令,只能写脚本。

低版本符号文件在usr/lib/debug/lib/{arch}/libc-{version}.so

高版本符号文件在usr/lib/debug/.build_id/{build_id[:2]}/build_id.debug

高版本应找到与libc的build_id一致的debug文件

import gdb


class loadsym(gdb.Command):
   """
  load symbol file to glibc
  Usage: loadsym {symbol file}
  Example:
      (gdb) loadsym '/path/to/usr/lib/debug/lib/x86_64-linux-gnu/libc-2.27.so'
  """

   def __init__(self):
       '''
      register command in constructer function
      '''

       super(self.__class__, self).__init__("loadsym", gdb.COMMAND_USER)

   def invoke(self, args, from_tty):
       '''
      in invoke method, we add command's features
      '''

       # using string_to_argv to convert args to list
       argv = gdb.string_to_argv(args)
       if len(argv) != 1:
           raise gdb.GdbError(
               'Fail to execute command, use "help loadsym" for help')
       print('[*] symbol file path: {}'.format(argv[0]))

       # traverse objfiles to find libc
       for i in gdb.objfiles():
           if 'libc' in i.filename[-12:]:  # load libc sym
               self.add_debug_file(i, argv[0])
               return
       print('[-] fail to find libc!')

   def add_debug_file(self, objfile, debugfile_path):
       '''
      add debug file and check debug file's status
      '''

       objfile.add_separate_debug_file(debugfile_path)
       # check symbol file is loading
       if gdb.lookup_symbol('main_arena') == None:
           print('[-] load debug file fail!')
           return False
       else:
           print('[+] load debug file success!')
           return True

if __name__ == "__main__":
   loadsym()
源码加载使用dir命令。
gdb_script: 可以写入/tmp目录,gdb中使用source就全部加载了。
gdb_script='''
attach {pid}
source loadsym.py
loadsym {libc_symbol_path}
dir {libc_source_path}
dir {libc_source_path}/libio
'''
gdb_script = '''
source /home/user/loadsym.py
loadsym /home/user/glibc-all-in-one/libs/2.36-0ubuntu4_amd64/.debug/d1/704d25fbbb72fa95d517b883131828c0883fe9.debug
'''

def ddebug():
   gdb.attach(io,gdb_script)
   pause()

Libc库

根据函数偏移来查找libc版本。不过大部分使用的都是Ubuntu下的libclibc databases:
  1. https://libc.blukat.me/   相对好些

  2. https://libc.rip/


参考

https://www.feishu.cn/docs/doccn74LPQrpSGDkqEjb2NihsRh


原文始发于微信公众号(Powehi Sec):CTF - glibc高版本gdb调试问题

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年6月1日08:28:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CTF - glibc高版本gdb调试问题http://cn-sec.com/archives/1779841.html
评论  1  访客  1
    • xxs 0

      修改过的glibc-all-in-one克隆不了 :?:

    发表评论

    匿名网友 填写信息