劫持__mlloc_hook和__free_hook

参考资料:PWN入门(3-14-1)-劫持__malloc_hook和__free_hook (yuque.com)

附件下载:

链接:https://pan.baidu.com/s/1-o9N0IPi3bpB-6mUIGjH6w
提取码:ti3t
–来自百度网盘超级会员V3的分享

若修改__malloc_hook和__free_hook的内容,就会在malloc或free的时候执行其中的内容(函数)。

实验环境

image-20230812111742538

Ubuntu版本为16.04.4,libc版本为2.23。

Demo1–__free_hook

首先看一下glibcc中__free_hook源码(libc版本为2.23):

1
2
void weak_variable (*__free_hook) (void *__ptr,
const void *) = NULL;

这就是__free_hook的定义。也可以看出当__free_hook中的内容不为空时,就会去执行里面的地址。

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// gcc -g -fno-stack-protector -z execstack -no-pie -z norelro __free_hook.c -o __free_hook

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

extern void (*__free_hook) (void *__ptr,const void *);

int main()
{
char *str = malloc(160);
strcpy(str,"/bin/sh");
printf("/bin/sh的地址为:0x%016X\n",str);
printf("__free_hook的地址为:0x%016X\n",&__free_hook);
printf("system函数的地址为:0x%016X\n",&system);
// 劫持__free_hook
__free_hook = system;

free(str);
return 0;
}

pwngdb调试

在第16行下断点,运行程序,观察输出信息:

image-20230812113311236

1
2
3
/bin/sh的地址为:0x0000000000601010
__free_hook的地址为:0x0000000000600AF0
system函数的地址为:0x00000000004004C0

分别查看内存情况:

1
2
3
4
5
6
7
8
9
pwndbg> x/16gx 0x601000
0x601000: 0x0000000000000000 0x00000000000000b1 #malloc_chunk
0x601010: 0x0068732f6e69622f 0x0000000000000000
#hs/nib/
0x601020: 0x0000000000000000 0x0000000000000000
0x601030: 0x0000000000000000 0x0000000000000000
0x601040: 0x0000000000000000 0x0000000000000000
0x601050: 0x0000000000000000 0x0000000000000000
0x601060: 0x0000000000000000 0x0000000000000000

/bin/sh已经写入到堆空间了。

此时发__free_hook为空:

1
2
3
4
5
6
7
8
9
pwndbg> x/16gx 0x0000000000600AF0
0x600af0 <__free_hook@@GLIBC_2.2.5>: 0x0000000000000000 0x0000000000000000
0x600b00: 0x0000000000000000 0x0000000000000000
0x600b10: 0x0000000000000000 0x0000000000000000
0x600b20: 0x0000000000000000 0x0000000000000000
0x600b30: 0x0000000000000000 0x0000000000000000
0x600b40: 0x0000000000000000 0x0000000000000000
0x600b50: 0x0000000000000000 0x0000000000000000
0x600b60: 0x0000000000000000 0x0000000000000000

单步继续执行 __free_hook = system;

再观察__free_hook处内存情况:

1
2
3
4
5
6
7
8
9
10
11
pwndbg> x/16gx 0x0000000000600AF0
0x600af0 <__free_hook@@GLIBC_2.2.5>: 0x00000000004004c0 0x0000000000000000
#system函数地址
0x600b00: 0x0000000000000000 0x0000000000000000
0x600b10: 0x0000000000000000 0x0000000000000000
0x600b20: 0x0000000000000000 0x0000000000000000
0x600b30: 0x0000000000000000 0x0000000000000000
0x600b40: 0x0000000000000000 0x0000000000000000
0x600b50: 0x0000000000000000 0x0000000000000000
0x600b60: 0x0000000000000000 0x0000000000000000

此时__free_hook处存放着system函数地址。

我们再回顾一下__free_hook函数的定义:

1
2
void weak_variable (*__free_hook) (void *__ptr,
const void *) = NULL;
  • 第一个参数void* __ptr指向堆中的”/bin/sh”
  • 第二个参数const void *指向“system函数地址”

这两个参数准备好,当再次free任意的内容时就会触发__free_hook中的system函数,从而getshell。

Demo2–__malloc_hook

和Demo1原理相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// gcc -g -fno-stack-protector -z execstack -no-pie -z norelro __malloc_hook.c -o __malloc_hook

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

extern void (*__malloc_hook) (size_t __size, const void *);

int main()
{
char *str = malloc(160);
strcpy(str,"/bin/sh");
printf("/bin/sh的地址为:0x%016X\n",str);
printf("__malloc_hook的地址为:0x%016X\n",&__malloc_hook);
printf("system函数的地址为:0x%016X\n",&system);
// 劫持__malloc_hook
__malloc_hook = system;

malloc(str);
return 0;
}

编译运行就能getshell。

疑难-程序的内存分布

假若没有关闭ALSR,正常运行程序就会出现下面的情况:

1
2
3
4
5
6
7
8
9
10
root@ubuntu:~/CTF-PWN/__free_hook# ./__free_hook
/bin/sh的地址为:0x0000000000BF1010
__free_hook的地址为:0x0000000000600AF0
system函数的地址为:0x00000000004004C0

root@ubuntu:~/CTF-PWN/__free_hook# ./__free_hook
/bin/sh的地址为:0x0000000001A72010
__free_hook的地址为:0x0000000000600AF0
system函数的地址为:0x00000000004004C0

从上图可以看出:“/bin/sh”所在的堆地址是随机的。

image-20230812121347199

从上面可以看出,编译完成的两个文件是关闭PIE保护的。

使用gdb调试看一下内存分布,第一次调试:

image-20230812121601003

第二次调试:

image-20230812121627292

可以看见两次调试时,程序的堆地址并没有发生变化。

我们关闭ALSR试试

image-20230812121907374

1
2
3
查看ALSR:sysctl kernel.randomize_va_space
关闭:echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
启用:echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

再次运行程序:

1
2
3
4
5
6
7
8
9
root@ubuntu:~/CTF-PWN/__free_hook# ./__free_hook
/bin/sh的地址为:0x0000000000601010
__free_hook的地址为:0x0000000000600AF0
system函数的地址为:0x00000000004004C0
# exit
root@ubuntu:~/CTF-PWN/__free_hook# ./__free_hook
/bin/sh的地址为:0x0000000000601010
__free_hook的地址为:0x0000000000600AF0
system函数的地址为:0x00000000004004C0

关闭ASLR之后堆地址不在随机。

得出结论

当randomize_va_space=2(ALSR全开启)时,且Linux可执行文件未开启PIE保护:

  • 正常运行程序(包括root权限):堆地址会随机化,代码段不会随机化
  • gdb调试程序(包括root权限):程序的内存分布不会随机化

当randomize_va_space=0(ALSR未开启)时,且Linux可执行文件未开启PIE保护:

  • 正常运行程序(包括root权限):堆地址不会随机化,代码段不会随机化
  • gdb调试程序(包括root权限):程序的内存分布不会随机化