前情提要
众所周知,在选择dl攻击时,往往没有回显,也就是无法得到attachment、libc、ld的在内存中的加载基址,
一般来说,这三者的加载地址应该是互不相关的,但根据个人经验来看,libc和ld一般是连在一起的(中间可能有别的内存页),也就是知道其中一个的基址以及内存的布局,就可以知道另一个的基址
那么__dl_runtime_resolve
时如何找到,这三者的关系,依靠的是在ld中的linkmap表,这个表记录三个文件(或许更多)的linkmap地址,而linkmap中就含有加载基址的信息。
以下的所有调试和maps的查看均以之前的boss题为例,但实际上重点在于该程序mmap()
一个0x2000大小可读写的内存段,本文的一个重心将会是这个mmap()
得到的内存的相对位置。
pwndbg> linkmap
Node Objfile Load Bias Dynamic Segment
0x7ffff7ffe2e0 <Unknown, likely /home/pwn/worktable/cnss2024/boss/src/attachment> 0x555555554000 0x555555557df8
0x7ffff7ffe890 linux-vdso.so.1 0x7ffff7fc1000 0x7ffff7fc13a0
0x7ffff7fbb160 /lib/x86_64-linux-gnu/libc.so.6 0x7ffff7d83000 0x7ffff7f9cbc0
0x7ffff7ffdaf0 /lib64/ld-linux-x86-64.so.2 0x7ffff7fc3000 0x7ffff7ffce80
值得注意的是,linkmap的位置在ld.so中的一段可读写的位置,也就是说算好偏移就可以篡改linkmap。
调试方法不同时内存布局的不同
首先探索的是调试方法不同时,内存布局的不同
一般使用gdb
有两种方法,gdb attachment
以及gdb --pid=xxxx
,也就是gdb
直接调试文件或者链接进程进行调试,实际上这两者就算仅仅是从效果上看就有很大不同。
首先看gdb --pid=xxx
的vmmap,这个结果更加接近一个进程的真实vmmap,也就是和cat /proc/xxx/maps
的结果相近
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x5631723b9000 0x5631723ba000 r--p 1000 0 /home/pwn/worktable/cnss2024/boss/src/attachment
0x5631723ba000 0x5631723bb000 r-xp 1000 1000 /home/pwn/worktable/cnss2024/boss/src/attachment
0x5631723bb000 0x5631723bc000 r--p 1000 2000 /home/pwn/worktable/cnss2024/boss/src/attachment
0x5631723bc000 0x5631723bd000 r--p 1000 2000 /home/pwn/worktable/cnss2024/boss/src/attachment
0x5631723bd000 0x5631723be000 rw-p 1000 3000 /home/pwn/worktable/cnss2024/boss/src/attachment
0x7f99a605f000 0x7f99a6062000 rw-p 3000 0 [anon_7f99a605f]
0x7f99a6062000 0x7f99a608a000 r--p 28000 0 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7f99a608a000 0x7f99a621f000 r-xp 195000 28000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7f99a621f000 0x7f99a6277000 r--p 58000 1bd000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7f99a6277000 0x7f99a6278000 ---p 1000 215000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7f99a6278000 0x7f99a627c000 r--p 4000 215000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7f99a627c000 0x7f99a627e000 rw-p 2000 219000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7f99a627e000 0x7f99a628b000 rw-p d000 0 [anon_7f99a627e]
0x7f99a6298000 0x7f99a629c000 rw-p 4000 0 [anon_7f99a6298] # <---mmap得到的空间
0x7f99a629c000 0x7f99a629e000 r--p 2000 0 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7f99a629e000 0x7f99a62c8000 r-xp 2a000 2000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7f99a62c8000 0x7f99a62d3000 r--p b000 2c000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7f99a62d4000 0x7f99a62d6000 r--p 2000 37000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7f99a62d6000 0x7f99a62d8000 rw-p 2000 39000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffd84bf2000 0x7ffd84c14000 rw-p 22000 0 [stack]
0x7ffd84c46000 0x7ffd84c4a000 r--p 4000 0 [vvar]
0x7ffd84c4a000 0x7ffd84c4c000 r-xp 2000 0 [vdso]
然后是使用gdb attachment
的效果,可以看到的是mmap得到的空间和ld.so之间多了0x6000的[vvar]和[vsdo]
,这两个本来是在栈段下方的。
其次,如果多次调试发现,attachment、libc、ld的加载地址实际上是固定的,也就是0x555555554000、0x7ffff7d83000、0x7ffff7fc3000实际上没变,应该是出于方便调试所以固定了加载地址。
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x555555554000 0x555555555000 r--p 1000 0 /home/pwn/worktable/cnss2024/boss/src/attachment
0x555555555000 0x555555556000 r-xp 1000 1000 /home/pwn/worktable/cnss2024/boss/src/attachment
0x555555556000 0x555555557000 r--p 1000 2000 /home/pwn/worktable/cnss2024/boss/src/attachment
0x555555557000 0x555555558000 r--p 1000 2000 /home/pwn/worktable/cnss2024/boss/src/attachment
0x555555558000 0x555555559000 rw-p 1000 3000 /home/pwn/worktable/cnss2024/boss/src/attachment
0x7ffff7d80000 0x7ffff7d83000 rw-p 3000 0 [anon_7ffff7d80]
0x7ffff7d83000 0x7ffff7dab000 r--p 28000 0 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7dab000 0x7ffff7f40000 r-xp 195000 28000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f40000 0x7ffff7f98000 r--p 58000 1bd000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f98000 0x7ffff7f99000 ---p 1000 215000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f99000 0x7ffff7f9d000 r--p 4000 215000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f9d000 0x7ffff7f9f000 rw-p 2000 219000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f9f000 0x7ffff7fac000 rw-p d000 0 [anon_7ffff7f9f]
0x7ffff7fb9000 0x7ffff7fbd000 rw-p 4000 0 [anon_7ffff7fb9] # <-- mmap得到的地方
0x7ffff7fbd000 0x7ffff7fc1000 r--p 4000 0 [vvar]
0x7ffff7fc1000 0x7ffff7fc3000 r-xp 2000 0 [vdso]
0x7ffff7fc3000 0x7ffff7fc5000 r--p 2000 0 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7fc5000 0x7ffff7fef000 r-xp 2a000 2000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7fef000 0x7ffff7ffa000 r--p b000 2c000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ffb000 0x7ffff7ffd000 r--p 2000 37000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ffd000 0x7ffff7fff000 rw-p 2000 39000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffffffdd000 0x7ffffffff000 rw-p 22000 0 [stack]
使用patchelf后的内存布局
一般pwn题时,尤其C的pwn题时,会选择使用patchelf
,更改libc和ld为指定glibc版本的来获得和远程相近的本地环境,但是patchelf
也会使进程的内存布局发生变化。
首先获得一个patchelf
后的文件
$ ldd attachment # patchelf之前
linux-vdso.so.1 (0x00007ffd469a6000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8a8e7db000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8a8ea1a000)
$ patchelf --replace-needed libc.so.6 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6 attachment
$ patchelf --set-interpreter /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/ld-linux-x86-64.so.2 attachment
$ ldd attachment
linux-vdso.so.1 (0x00007ffd73beb000)
/home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6 (0x00007f9a1054c000)
/home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f9a1077d000)
然后gdb --pi=xxx
尝试调试。
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x56272a397000 0x56272a398000 r--p 1000 0 /home/pwn/testtable/attachment
0x56272a398000 0x56272a399000 r-xp 1000 1000 /home/pwn/testtable/attachment
0x56272a399000 0x56272a39a000 r--p 1000 2000 /home/pwn/testtable/attachment
0x56272a39a000 0x56272a39b000 r--p 1000 2000 /home/pwn/testtable/attachment
0x56272a39b000 0x56272a39e000 rw-p 3000 3000 /home/pwn/testtable/attachment
0x7fc2b8155000 0x7fc2b815a000 rw-p 5000 0 [anon_7fc2b8155] # <-----mmap的位置
0x7fc2b815a000 0x7fc2b8182000 r--p 28000 0 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6
0x7fc2b8182000 0x7fc2b8317000 r-xp 195000 28000 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6
0x7fc2b8317000 0x7fc2b836f000 r--p 58000 1bd000 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6
0x7fc2b836f000 0x7fc2b8373000 r--p 4000 214000 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6
0x7fc2b8373000 0x7fc2b8375000 rw-p 2000 218000 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6
0x7fc2b8375000 0x7fc2b8384000 rw-p f000 0 [anon_7fc2b8375]
0x7fc2b8384000 0x7fc2b8386000 r--p 2000 0 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/ld-linux-x86-64.so.2
0x7fc2b8386000 0x7fc2b83b0000 r-xp 2a000 2000 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/ld-linux-x86-64.so.2
0x7fc2b83b0000 0x7fc2b83bb000 r--p b000 2c000 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/ld-linux-x86-64.so.2
0x7fc2b83bc000 0x7fc2b83be000 r--p 2000 37000 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/ld-linux-x86-64.so.2
0x7fc2b83be000 0x7fc2b83c0000 rw-p 2000 39000 /home/pwn/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/ld-linux-x86-64.so.2
0x7fff90916000 0x7fff90938000 rw-p 22000 0 [stack]
0x7fff90968000 0x7fff9096c000 r--p 4000 0 [vvar]
0x7fff9096c000 0x7fff9096e000 r-xp 2000 0 [vdso]
可以看到,mmap获得的空间现在变成了在libc上方,原因暂时未知。
xinted转发会话时启动的进程
之前docker内可行的exp,在访问端口(本地docker或者服务器远程)上的题目时,发现无法打通,于是猜测是xinted转发的进程内存布局不同
在正式查看之前,先做准备工作,第一步先修改以下xinted的设置
service ctf
{
disable = no
socket_type = stream
protocol = tcp
wait = no
user = root
type = UNLISTED
port = 9999
bind = 0.0.0.0
# 设置xinetd连接启动后的服务程序
server = /usr/sbin/chroot
# 设置chroot的相关参数
server_args = --userspec=0000:0000 /home/ctf ./attachment # <---- 这里改为以root用户执行文件,否则之后看maps没权限
banner_fail = /etc/banner_fail
# safety options
per_source = 10 # the maximum instances of this service per source IP address
rlimit_cpu = 20 # the maximum number of CPU seconds that the service may use
#rlimit_as = 1024M # the Address Space resource limit for the service
#access_times = 2:00-9:00 12:00-24:00
}
然后构建镜像
$ docker build -t boss .
$ docker run -p 8000:9999 boss
# 切换一个shell
$ docker exec -it <容器名> /bin/bash
<容器名>/home/ctf$ apt-get install gdb
再打开一个shell,nc localhost 8000
,现在docker容器中就存在一个attachment的进程,由xindted转发
此时先找到pid
<容器名>/home/ctf$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4364 3164 ? Ss 00:16 0:00 /bin/bash /docker-entrypoint.sh
root 19 0.0 0.0 2792 1036 ? S 00:16 0:00 sleep infinity
root 20 0.0 0.0 13784 2392 ? Ss 00:16 0:00 /usr/sbin/xinetd -pidfile /run/xinetd.pid -stayalive -inetd_c
root 21 0.0 0.0 4628 3720 pts/0 Ss 00:16 0:00 /bin/bash
root 29 0.0 0.0 2652 264 ? Ss 00:17 0:00 ./attachment # <--- 在这里
root 30 0.0 0.0 7064 1552 pts/0 R+ 00:17 0:00 ps aux
现在调试这个pid
<容器名>/home/ctf$ gdb --pi=29
(gdb) x/10gx 0x56341ccb5000 + 0x40a0
0x56341ccb90a0: 0x00007ff9322bc000 0x0000000000000000
0x56341ccb90b0: 0x0000000000000000 0x0000000000000000
0x56341ccb90c0: 0x0000000000000000 0x0000000000000000
0x56341ccb90d0: 0x0000000000000000 0x0000000000000000
0x56341ccb90e0: 0x0000000000000000 0x0000000000000000
<容器名>/home/ctf$ cat /proc/29/maps
56341ccb5000-56341ccb6000 r--p 00000000 08:30 20412 /home/ctf/attachment
56341ccb6000-56341ccb7000 r-xp 00001000 08:30 20412 /home/ctf/attachment
56341ccb7000-56341ccb8000 r--p 00002000 08:30 20412 /home/ctf/attachment
56341ccb8000-56341ccb9000 r--p 00002000 08:30 20412 /home/ctf/attachment
56341ccb9000-56341ccba000 rw-p 00003000 08:30 20412 /home/ctf/attachment
7ff9322bc000-7ff9322c1000 rw-p 00000000 00:00 0 # <------- 这里
7ff9322c1000-7ff9322e9000 r--p 00000000 08:30 19693 /home/ctf/lib/x86_64-linux-gnu/libc.so.6
7ff9322e9000-7ff93247e000 r-xp 00028000 08:30 19693 /home/ctf/lib/x86_64-linux-gnu/libc.so.6
7ff93247e000-7ff9324d6000 r--p 001bd000 08:30 19693 /home/ctf/lib/x86_64-linux-gnu/libc.so.6
7ff9324d6000-7ff9324d7000 ---p 00215000 08:30 19693 /home/ctf/lib/x86_64-linux-gnu/libc.so.6
7ff9324d7000-7ff9324db000 r--p 00215000 08:30 19693 /home/ctf/lib/x86_64-linux-gnu/libc.so.6
7ff9324db000-7ff9324dd000 rw-p 00219000 08:30 19693 /home/ctf/lib/x86_64-linux-gnu/libc.so.6
7ff9324dd000-7ff9324ec000 rw-p 00000000 00:00 0
7ff9324ec000-7ff9324ee000 r--p 00000000 08:30 19672 /home/ctf/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ff9324ee000-7ff932518000 r-xp 00002000 08:30 19672 /home/ctf/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ff932518000-7ff932523000 r--p 0002c000 08:30 19672 /home/ctf/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ff932524000-7ff932526000 r--p 00037000 08:30 19672 /home/ctf/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ff932526000-7ff932528000 rw-p 00039000 08:30 19672 /home/ctf/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ffdbc5a8000-7ffdbc5c9000 rw-p 00000000 00:00 0 [stack]
7ffdbc5ec000-7ffdbc5f0000 r--p 00000000 00:00 0 [vvar]
7ffdbc5f0000-7ffdbc5f2000 r-xp 00000000 00:00 0 [vdso]