前情提要: 由于国赛在即, 而本人已经做了一个多月的dev没有碰过pwn, 所以打算复健一下, 结果第一个上午用着wsl就碰上了一个离谱bug
Bug
一个归档文件中, 包含了一个名为libc.so.6
的libc同名文件, 然后tar -xf
一下, 奇迹出现了, shell内除了buildin的工具全部失效了, 显示以下报错
ls: libc.so.6: version `GLIBC_2.28' not found (required by ls)
ls: libc.so.6: version `GLIBC_2.33' not found (required by ls)
ls: libc.so.6: version `GLIBC_2.34' not found (required by ls)
ls: libc.so.6: version `GLIBC_2.33' not found (required by /lib/x86_64-linux-gnu/libselinux.so.1)
ls: libc.so.6: version `GLIBC_2.30' not found (required by /lib/x86_64-linux-gnu/libselinux.so.1)
ls: libc.so.6: version `GLIBC_2.34' not found (required by /lib/x86_64-linux-gnu/libselinux.so.1)
然而, 当使用cd离开这个目录之后, 一切又恢复正常, 而且vscode中提供的文件操作也可以使用
笔者又从zsh切换到bash, 然后是sh, 发现问题不变,
找原因和Debug
综上所述, 问题的根源应该是非shell buildin的工具寻址里libc.so.6时出现了问题, 在工作目录中没有名为libc.so.6
的文件时, 会正常寻址, 有的时候则会尝试链接当前的工作目录下的文件
证据如下
# libc.so.6 版本过低
ls: libc.so.6: version `GLIBC_2.28' not found (required by ls)
ls: libc.so.6: version `GLIBC_2.33' not found (required by ls)
ls: libc.so.6: version `GLIBC_2.34' not found (required by ls)
ls: libc.so.6: version `GLIBC_2.33' not found (required by /lib/x86_64-linux-gnu/libselinux.so.1)
ls: libc.so.6: version `GLIBC_2.30' not found (required by /lib/x86_64-linux-gnu/libselinux.so.1)
ls: libc.so.6: version `GLIBC_2.34' not found (required by /lib/x86_64-linux-gnu/libselinux.so.1)
# libc.so.6 空的, 或者是一个文本文件
ls: error while loading shared libraries: libc.so.6: file too short
# libc.so.6 格式不对
ls: error while loading shared libraries: libc.so.6: cannot dynamically load position-independent executable
显然问题和库文件的搜索有关, 笔者想起来前段时间安装cuda时更改过.bashrc
中的搜索路径的环境变量
当时在.bashrc
的结尾加上了, 作为nvcc
的库文件搜索路径
#config cuda
export CUDA_HOME=/usr/local/cuda-12.3
export PATH=$PATH:$CUDA_HOME/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CUDA_HOME/lib64
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CUDA_HOME/extras/CUPTI/lib64
由于.bashrc
中默认没有LD_LIBRARY_PATH
的配置(至少我的没有), 所以上述的工具在CUDA的库文件中肯定找不到libc.so.6, 所以理论上将libc.so.6重新加到搜索路径中即可
export LD_LIBRARY_PATH=/lib/x86_64-linux-gnu
#config cuda
export CUDA_HOME=/usr/local/cuda-12.3
export PATH=$PATH:$CUDA_HOME/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CUDA_HOME/lib64
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CUDA_HOME/extras/CUPTI/lib64
大概就是这样, 完成之后再source .bashrc
, 即可
╭─ /home/pwn/testtable/works ▓▒░ ░▒▓ ✔ root@PainTech 10:48:21 ─╮
╰─ ls ─╯
libc libc.so.6 pwn
在此之后
即使成功解决了bug, 有几个问题没有存在疑惑
1. .bashrc
在LD_LIBRARY_PATH没有被填写的情况下, 为何正常链接
2. 为何工作目录下没有libc.so.6可以正常链接
这里主要和LD_LIBRARY_PATH的工作有关,
动态链接的文件会按照LD_LIBRARY_PATH所列出的顺序, 依次查找, 路径之间使用 ‘:’ 分割
╭─ ~ ▓▒░ ░▒▓ ✔ root@PainTech 11:09:01 ─╮
╰─ echo $LD_LIBRARY_PATH ─╯
/lib/x86_64-linux-gnu:/usr/local/cuda-12.3/lib64:/usr/local/cuda-12.3/extras/CUPTI/lib64
所以当添加好libc的目录之后, 链接就不再会出问题
但是仅仅这样无法解释, 之前没有/lib/x86_64-linux-gnu
时如何正常工作, 以及为什么有上面的bug出现
linux一个可执行文件寻找自己的链接的动态库有5种方式, 绝对路径 相对路径 -rpath LD_LIBRARY_PATH /etc/ld.so.conf(这样写应该会比较具体), 但是网上的资料(至少是中文资料)大多不全, 或者是没有明确的执行顺序的排列
举个例子, 下面是一个ELF的Header, Interpreter为绝对路径, ld一般都是绝对路径, 因为需要ld来执行库的查找
Needed Library比较有说头, 像这里的’libc.so.6’, 首先一般情况下它应该被设计为某个文件夹中的一个文件名, 但是实际上, 也可以被看作一个相对路径,
作为对比, 如果是 ‘./libc.so.6’ 就是一个单纯的相对路径
猜测是ls等非shell buildin 的工具, 在链接时把 ‘libc.so.6’ 当成了相对路径, 这里的相对是相对于使用命令的工作目录
LOAD:0000000000000000 ; Format : ELF64 for x86-64 (Shared object)
LOAD:0000000000000000 ; Interpreter '/lib64/ld-linux-x86-64.so.2'
LOAD:0000000000000000 ; Needed Library 'libc.so.6'
-rpath, 检查-rpath指定的路径, -rpath是编译器编译时的一个可选项, 下面是未使用和使用了-rpath参数的对比
LOAD:0000000000000000 ; Format : ELF64 for x86-64 (Shared object)
LOAD:0000000000000000 ; Interpreter '/lib64/ld-linux-x86-64.so.2'
LOAD:0000000000000000 ; Needed Library 'libc.so.6'
LOAD:0000000000000000 ; Format : ELF64 for x86-64 (Shared object)
LOAD:0000000000000000 ; Interpreter '/lib64/ld-linux-x86-64.so.2'
LOAD:0000000000000000 ; Needed Library 'libstdc++.so.6'
LOAD:0000000000000000 ; Needed Library 'libc.so.6'
LOAD:0000000000000000 ; Library runpath '/lib/x86_64-linux-gnu' # <------
意思就是 Needed Library
需要在 Library runpath
中找
ls执行文件的header信息, 可以看到是没有指定-rpath的, 没有-rpath相当于第一步直接放弃掉了
LOAD:0000000000000000 ; Format : ELF64 for x86-64 (Shared object)
LOAD:0000000000000000 ; Interpreter '/lib64/ld-linux-x86-64.so.2'
LOAD:0000000000000000 ; Needed Library 'libselinux.so.1'
LOAD:0000000000000000 ; Needed Library 'libc.so.6'
检查LD_LIBRARY_PATH, 流程不再赘述了. 注意的是, LD_LIBRARY_PATH是由Bash等交互提供的, 默认情况下应该是空的, 但是实际上包含了/usr/lib
以及/lib
文件夹
搜索/etc/ld.so.conf
,
╭─ ~ ▓▒░ ░▒▓ ✔ root@PainTech 13:24:04 ─╮
╰─ cat /etc/ld.so.conf ─╯
include /etc/ld.so.conf.d/*.conf
ld.so.conf应该是没有动过的
╭─ /etc/ld.so.conf.d ▓▒░ ░▒▓ ✔ root@PainTech 13:25:10 ─╮
╰─ ls ─╯
000_cuda.conf fakeroot-x86_64-linux-gnu.conf i386-linux-gnu.conf libc.conf zz_i386-biarch-compat.conf
988_cuda-12.conf gds-12-3.conf
这里主要关注x86和libc的conf文件
╭─ /etc/ld.so.conf.d ▓▒░ ░▒▓ ✔ root@PainTech 13:25:52 ─╮
╰─ cat x86_64-linux-gnu.conf ─╯
# Multiarch support
/usr/local/lib/x86_64-linux-gnu
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
╭─ /etc/ld.so.conf.d ▓▒░ ░▒▓ ✔ root@PainTech 13:25:56 ─╮
╰─ cat libc.conf ─╯
# libc default configuration
/usr/local/lib