花式技巧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

image-20240404095652976

安装patch

  • 先下载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

image-20240404100047408

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)**

image-20240404100537753

  • 在glibc-all-in-one文件夹中输入
1
./download 2.35-0ubuntu3.6_amd64

image-20240404100641446

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

image-20240404101427279

patch

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

image-20240404101726686

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

image-20240428145545779

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

image-20240428201355463

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

image-20240428201520205

花式技巧2——nop!

花式技巧3——glibc源码附加调试

效果

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

image-20250328151131291

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

image-20220415171511841

  • 这是我进行附加源码调试后的效果。

image-20250328153204574

介绍

  • 在附加源码调试的时候我们一定要注意程序动态链接的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版本。这样出现的检查和保护机制会更多,而且也是比较新的。

image-20250328154649478

  • 我们就要将对应的glibc版本拉下来(注意glibc-all-in-one项目拉下来的其实都是编译过后的可执行文件,并没有带源码,这时给我们patchelf使用的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/

image-20250328165109514

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

image-20250328165203459

  • 然后往下滑找到这个,最大的tar

image-20250328165232064

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

image-20250328165358000

附加源码

image-20250328165526121

  • 然后搜索fopen,会看到fopen在这个目录下

image-20250328165610987

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

image-20250328170007840

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

image-20250328170142286