[水贴]记一次离谱报错

2024-12-01
前情提要: 由于国赛在即, 而本人已经做了一个多月的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

如何导致bug的发生

   希腊奶.
   只知道是由于可执行文件的中Needed Library 中的 libc.so.6字段在链接过程中产生了歧义, 一方面可以指的是环境变量路径中的libc.so.6, 一方面也可以指工作目录下的libc(即./libc.so.6), 由于种种原因, 导致越过了LD_LIBRARY和ld.conf.d的配置, 直接在当前文件夹中尝试链接
   但是更具体的, LD_LIBRARY和ld.conf.d的配置为什么被越过, 以及正常情况下, 它们的查找顺序是如何的仍然不太清晰