前言
glibc多版本配置方案
手动编译(不推荐)
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
-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(推荐)
修改过的版本: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(推荐)
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
-
可以使用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要使用相对路径时要加./
-
使用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})
info share
来查看gdb是否加载了libc的符号,(*)
代表未加载符号。-
使用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符号
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='''
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库
-
https://libc.blukat.me/ 相对好些
-
https://libc.rip/
参考
https://www.feishu.cn/docs/doccn74LPQrpSGDkqEjb2NihsRh
原文始发于微信公众号(Powehi Sec):CTF - glibc高版本gdb调试问题
- 我的微信
- 微信扫一扫
-
- 我的微信公众号
- 微信扫一扫
-
评论