PWN花式技巧
花式技巧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
plaintext
1 | git clone https://github.com/matrix1001/glibc-all-in-one.git |
安装patch
- 先下载patch
sudo apt install -y patchelf chrpath
- 下载完成后再检查patch能否使用:出现以下就代表可以使用了
plaintext
1 | iyheart@iyheart-virtual-machine ~/pwn_learn> patchelf -h |
确定patch的库
方法一
- 在有题目所给libc.so.6的目录下直接输入
strings libc.so.6 |grep Ubuntu
plaintext
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)**
- 在glibc-all-in-one文件夹中输入
plaintext
1 | ./download 2.35-0ubuntu3.6_amd64 |
- 报错信息表示没有相应的工具解压
.zst
文件,下载相应软件,再重新./download 2.35-0ubuntu3.6_amd64
,没有报错,成功
plaintext
1 | sudo apt update |
patch
- 找到题目所在
.ld
文件和.so.6
文件所在的位置
- 在patch之前先给
.ld
文件和.so
文件添加可执行权限(下图仅做加权限的例子)
plaintext
1 | # 设置新文件的ld路径 |
- 在重链接后使用
ldd
指令查看一下文件的链接路径是否成功,之后就是运行一下文件,看一下是不是patch
成功了。
花式技巧2——nop!
花式技巧3——glibc源码附加调试
效果
- 刚学堆的时候,可能不太理解
ptmalloc2
的运行机制。而且一开始对于glibc
大量的源码看着就很头痛,对初学者非常不友好。这时我们就可以进行调试。但是我们调试的时候是不会出现glibc
相关源代码的。也就是像下图所示一样。 - 我们在进入到
glibc
相关的库函数时,这边只有汇编代码,没有汇编代码对应的源代码,这就导致我们没办法一行代码对应着调试
,并不是很好理解源码。之后到调试io
相关的函数时也一样。所以我们这个小技巧就是glibc
附加源码调试。
- 如果附加源码调试后,我们调试窗口就会如下图所示,就会出现每一个汇编片段所对应的程序。效果如下图所示(图片引用于别人的博客)。
- 这是我进行附加源码调试后的效果。
- 接下来就具体操作一番。参考博客:关于gdb源码调试环境搭建 - ZikH26 - 博客园
介绍
- 在附加源码调试的时候我们一定要注意程序动态链接的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版本。这样出现的检查和保护机制会更多,而且也是比较新的。
-
我们就要将对应的
glibc
版本拉下来(注意glibc-all-in-one
项目拉下来的其实都是编译过后的可执行文件,并没有带源码,这时给我们patchelf使用的glibc
) -
接下来输入如下命令,直接开始下载。前面两个好像可以下载,后面几个可能需要手动下载,这里图方便就下载了旧版的了。下载到最后三个的时候还会出现错误,那就之后再下载吧,前面四个版本够用了。
bash
1 | ./download 2.23-0ubuntu11.3_amd64 |
- 接下来我们去到这个网址,让后往下划我们就可以看到对应的
glibc
源码的包
plaintext
1 | https://launchpad.net/ubuntu/+source/glibc/ |
- 然后根据我们之前下载的
glibc-all-in-one
对应版本,选择对应的glibc
源码
- 然后往下滑找到这个,最大的
tar
包
- 下载下来,然后放在一个文件夹中,然后进行解压,解压后我们就可以看到对应的源码了
附加源码
- 我们现在就以调试
fopen
为例子。我们先去到这个网站Explore C, C++, Rust & Dart code on the web - 点击红色框这边
- 然后搜索
fopen
,会看到fopen
在这个目录下
- 这时我们对
~/.gdbinit
进行编辑,添加
bash
1 | dir /home/myheart/glibc_debug/glibc-2.23/libio |
- 这时我们在
ubuntu16.04
的docker容器
中编译如下代码:
c
1 |
|
- 将编译好的文件复制到我们的宿主机来,再使用
patchelf
将ld
和libc
文件都patchelf
为glibc-all-in-one中glibc2.23的ld和libc文件
- 这时我们再进行
gdb
调试,调试的时候就发现能看到源码了。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 iyheart的博客!