【注】本文最后更新于 August 12, 2018,文中内容可能已经过时。
glibc 2.26开始, 引入了 tcache 技术. 使得对 UAF 漏洞的利用非常困难.
(更: 听 M4x 师傅说其实安全性下降了? thread local caching in glibc malloc)
然后 Arch 的 glibc 已经到了 2.27…. 再加上 pwndbg 的作者与堆相关的一系列命令只对 Ubuntu 做了适配…
pwn 的世界对 Archer 真是充满了恶意 = =
放弃 Arch 是不可能放弃的, 这辈子都不可能放弃的. 所幸有大佬提出, 使用带Debug Symbols的glibc可以成功运行heap等命令,
试了一下果然如此. 可是把默认的 glibc 换成带调试符号的总觉得不好. 而且这样也没有解决 tcache 的问题.
一番尝试之后, 我得到了如下的解决方案,
记录一下以免忘记. 因为已经忘了一次
编译glibc-2.23
第一步
获取 glibc-2.23
/tmp> wget https://ftp.gnu.org/gnu/glibc/glibc-2.23.tar.xz
/tmp> x glibc-2.23.tar.xz
第二步
修改源码, 防止一些奇怪的问题 glibc: add patch fixing the build with binutils 2.29
简要地讲就是把 misc/regexp.c
中的
1
2
3
4
5
|
char *loc1;
char *loc2;
...
...
char *loc;
|
换成
1
2
3
4
5
|
char *loc1 __attribute__ ((nocommon));
char *loc2 __attribute__ ((nocommon));
...
...
char *locs __attribute__ ((nocommon));
|
PS. 原链接中还多了一个 compat_symbol
, 但是我没加也编译过了….就不管了
第三步
建立编译文件夹
/tmp>md glibc-build-32
/tmp>md glibc-build-64
然后随便cd进一个
32位使用如下命令配置
1
|
../glibc-2.23/configure --disable-werror --prefix=/home/aloxaf/.local/lib/glibc-2.23_x86 --host=i686-linux-gnu --build=i686-linux-gnu CC="gcc -m32" CXX="g++ -m32" CFLAGS="-g -O2 -march=i686 -fno-stack-protector" CXXFLAGS="-g -O2 -march=i686 -fno-stack-protector" --enable-debug=yes
|
64位使用如下命令配置
1
|
../glibc-2.23/configure --disable-werror --prefix=/home/aloxaf/.local/lib/glibc-2.23 --enable-debug=yes CFLAGS="-O2 -g" CPPFLAGS="-O2 -g"
|
Note:
--prefix
请自行更改, 简要地讲就是你打算把这个glibc装到哪个地方
- 32位不加
-fno-stack-protector
会出现奇怪的link问题. 反正这个只是用来调试的, 就这样粗暴地解决吧.
配置完以后分别 make -j4 && make install
就安装完成了
配置运行环境
大多数 elf 编译的时候都写死了ld的路径 /usr/lib/ld.so
, 这就比较尴尬. 就算强行让 2.26 的 ld.so 加载 2.23 的libc, 也指不定会出啥奇怪问题.
幸运的是看雪大佬已经给出了方案: 关于不同版本glibc强行加载的方法(附上代码)
虽然很暴力, 但是有效啊.
不过每次都把ld.so复制到当前文件夹下 && 使用 LD_PRELOAD
指定libc好麻烦的样子,
于是结合自己的经验, 修改了一下脚本.
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# https://bbs.pediy.com/thread-225849.htm
from tempfile import gettempprefix
from pwn import *
import os
import sys
def change_ld(binary: str)->str:
"""
更改ELF文件加载的libc版本
:param binary: ELF路径
:param ld: ld.so路径
:param libc: lib.so路径
:return: 新的ELF文件路径
"""
binary = ELF(binary)
for segment in binary.segments:
if segment.header['p_type'] == 'PT_INTERP':
size = segment.header['p_memsz']
addr = segment.header['p_paddr']
data = segment.data()
ld = '/opt/ctf/ld.so' if binary.arch == 'amd64' else '/opt/ctf/ld32.so'
if size <= len(ld):
raise Exception(
"Failed to change PT_INTERP from {} to {}".format(data, ld))
return None
binary.write(addr, ld.ljust(size, '\0').encode())
if not os.access('/tmp/easypwn', os.F_OK):
os.mkdir('/tmp/easypwn')
path = '/tmp/easypwn/{}_debug'.format(
os.path.basename(binary.path))
if os.access(path, os.F_OK):
os.remove(path)
# print("Removing exist file {}".format(path))
binary.save(path)
os.chmod(path, 0b111000000) # rwx------
# print("PT_INTERP has changed from {} to {}. Using temp file {}".format(data, ld, path))
return ELF(path)
if __name__ == '__main__':
change_ld(sys.argv[1]).save(sys.argv[2])
os.chmod(sys.argv[2], 0b111000000)
|
其中 /opt/ctf/ld.so
是 /home/aloxaf/.local/lib/glibc-2.23/lib/ld-2.23.so
的硬链接,
32位版以此类推.
建立硬链接主要是为了缩短路径长度, 保证能够替换掉原来的路径.
然后给这个.py加个硬链接到 ~/.local/bin
, 就可以直接 change_ld test test-debug
让这个 elf 默认加载我们自己编译的glibc了.
愉快地Debug 吧少年, Arch Linux 大法好折腾
文章作者
Aloxaf
上次更新
2018-08-12
许可协议
知识共享署名-非商业性使用 4.0 国际许可协议