花式技巧1——patchelf重链接
参考博客:https://www.freebuf.com/sectool/366854.html
https://www.cnblogs.com/9man/p/17581934.html
- 很多情况下题目附件除了给可执行程序以外还会给.so文件,.so文件有很多版本。但是.so文件里面的字串有显示其具体版本,这样我们就可以找相应的.dl文件和.so文件在本地进行重链接,这样就可以在本地模拟靶机上的环境,有利于gdb动态调试和查看内存地址
前提准备
安装glibc-all-in-one
1 2 3 4
| git clone https://github.com/matrix1001/glibc-all-in-one.git cd glibc-all-in-one chmod a+x build download extract sudo python3 update_list # 需要Python3 安装requests库 pip3 install requests
|

安装patch
sudo apt install -y patchelf chrpath
- 下载完成后再检查patch能否使用:出现以下就代表可以使用了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| iyheart@iyheart-virtual-machine ~/pwn_learn> patchelf -h syntax: patchelf [--set-interpreter FILENAME] [--page-size SIZE] [--print-interpreter] [--print-soname] Prints 'DT_SONAME' entry of .dynamic section. Raises an error if DT_SONAME doesn't exist [--set-soname SONAME] Sets 'DT_SONAME' entry to SONAME. [--set-rpath RPATH] [--add-rpath RPATH] [--remove-rpath] [--shrink-rpath] [--allowed-rpath-prefixes PREFIXES] With '--shrink-rpath', reject rpath entries not starting with the allowed prefix [--make-rpath-relative ROOTDIR] [--no-standard-lib-dirs] [--relative-to-file] [--print-rpath] [--force-rpath] [--add-needed LIBRARY] [--remove-needed LIBRARY] [--replace-needed LIBRARY NEW_LIBRARY] [--print-needed] [--no-default-lib] [--clear-symbol-version SYMBOL] [--output FILE] [--debug] [--version] FILENAME...
|
确定patch的库
方法一
- 在有题目所给libc.so.6的目录下直接输入
strings libc.so.6 |grep Ubuntu

1
| GNU C Library (Ubuntu GLIBC 2.35-0ubuntu3.6) stable release version 2.35.
|
方法二
- 确定偏移量,然后前往在线libc库搜索去搜索到对应的库
下载库
- 进入到glibc-all-in-one文件夹中,cat list查看对应的库**(Ubuntu GLIBC 2.35-0ubuntu3.6)**

1
| ./download 2.35-0ubuntu3.6_amd64
|

- 报错信息表示没有相应的工具解压
.zst
文件,下载相应软件,再重新 ./download 2.35-0ubuntu3.6_amd64
,没有报错,成功
1 2
| sudo apt update sudo apt install zstd
|

patch
- 找到题目所在
.ld
文件和.so.6
文件所在的位置

- 在patch之前先给
.ld
文件和 .so
文件添加可执行权限(下图仅做加权限的例子)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| # 设置新文件的ld路径 patchelf --set-interpreter 新ld路径 要patch的elf路径
patchelf --set-interpreter /home/myheart/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-linux-x 86-64.so.2 ./Palu
# 设置新的libc路径 patchelf --replace-needed libc.so.6 新libc路径 要patch的elf路径
patchelf --replace-needed libc.so.6 /home/myheart/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/l ibc-2.23.so ./Palu
# 如果是一个多线程依赖库那么就需要添加libc库,而不是替换libc库 patchelf --add-needed 你的文件目录/libc.so.6 ./pwn patchelf --add-needed 你的目录/libpthread.so.0 ./pwn (如果提示没有libpthread.so.0的话) #该命令我还不太了解 patchelf --set-rpath 你的文件目录/ld-linux-x86-64.so.2 ./pwn patchelf --set-rpath /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ./vuln
|

- 在重链接后使用
ldd
指令查看一下文件的链接路径是否成功,之后就是运行一下文件,看一下是不是patch
成功了。

花式技巧2——nop!
花式技巧3——glibc源码附加调试
效果
- 刚学堆的时候,可能不太理解
ptmalloc2
的运行机制。而且一开始对于glibc
大量的源码看着就很头痛,对初学者非常不友好。这时我们就可以进行调试。但是我们调试的时候是不会出现glibc
相关源代码的。也就是像下图所示一样。
- 我们在进入到
glibc
相关的库函数时,这边只有汇编代码,没有汇编代码对应的源代码,这就导致我们没办法一行代码对应着调试
,并不是很好理解源码。之后到调试io
相关的函数时也一样。所以我们这个小技巧就是glibc
附加源码调试。

- 如果附加源码调试后,我们调试窗口就会如下图所示,就会出现每一个汇编片段所对应的程序。效果如下图所示(图片引用于别人的博客)。


介绍
- 在附加源码调试的时候我们一定要注意程序动态链接的libc版本与libc附加源码的版本一致。
- 不同版本编译出来的可执行文件,这里存在一个不兼容性,这就导致有时候我们整理环境的时候非常困难。不兼容包括以下几点:
ubuntu
高版本编译器编译出来的程序,无法在ubuntu
低版本中运行(patchelf后有没法运行)(一定与编译器版本有关
可能和ubuntu版本有关
),而低版本编译出来的可执行文件,高版本可以直接运行(有向下兼容)
ubuntu
不同版本的glibc
源码不一样,所以我们一定要找到对应的glibc
版本。
- 为了解决以上问题,我使用
3
种方式混合使用。分别是:ubuntu各个版本的Docker镜像
、glibc-all-in-one
项目、patchelf
ubuntu各个版本的docker镜像
:可以编译相应glibc
版本的程序,这样就可以解决高版本ubuntu
编译后的可执行文件,如果patchelf低版本的libc文件会执行不了。
glibc-all-in-one
:这边有对应的版本glibc
能提供给我们,让我们对patchelf
可执行文件后还可以运行。并且我们patchelf
后,可以只下载当前glibc
版本中的一份源码(就不用下载glibc补丁前或补丁后的源码。)
环境
- 我们使用
glibc-all-in-one
默认使用打过最多补丁的glibc版本。这样出现的检查和保护机制会更多,而且也是比较新的。

1 2 3 4 5 6 7
| ./download 2.23-0ubuntu11.3_amd64 ./download 2.27-3ubuntu1.6_amd64 ./download 2.31-0ubuntu9_amd64 ./download 2.35-0ubuntu3_amd64 ./download 2.37-0ubuntu2_amd64 ./download 2.38-1ubuntu6_amd64 ./download 2.39-0ubuntu8_amd64
|
- 接下来我们去到这个网址,让后往下划我们就可以看到对应的
glibc
源码的包
1
| https://launchpad.net/ubuntu/+source/glibc/
|

- 然后根据我们之前下载的
glibc-all-in-one
对应版本,选择对应的glibc
源码


- 下载下来,然后放在一个文件夹中,然后进行解压,解压后我们就可以看到对应的源码了

附加源码


1
| dir /home/myheart/glibc_debug/glibc-2.23/libio
|
- 这时我们在
ubuntu16.04
的docker容器
中编译如下代码:
1 2 3 4 5 6
| #include<stdio.h> int main(){ FILE*fp=fopen("./flag","r"); fclose(fp); return 0; }
|
- 将编译好的文件复制到我们的宿主机来,再使用
patchelf
将ld
和libc
文件都patchelf
为glibc-all-in-one中glibc2.23的ld和libc文件

- 这时我们再进行
gdb
调试,调试的时候就发现能看到源码了。
