前情提要
众所周知,在选择dl攻击时,往往没有回显,也就是无法得到attachment、libc、ld的在内存中的加载基址,
一般来说,这三者的加载地址应该是互不相关的,但根据个人经验来看,libc和ld一般是连在一起的(中间可能有别的内存页),也就是知道其中一个的基址以及内存的布局,就可以知道另一个的基址
那么__dl_runtime_resolve时如何找到,这三者的关系,依靠的是在ld中的linkmap表,这个表记录三个文件(或许更多)的linkmap地址,而linkmap中就含有加载基址的信息。
以下的所有调试和maps的查看均以之前的boss题为例,但实际上重点在于该程序mmap()一个0x2000大小可读写的内存段,本文的一个重心将会是这个mmap()得到的内存的相对位置。
1 | pwndbg> linkmap |
值得注意的是,linkmap的位置在ld.so中的一段可读写的位置,也就是说算好偏移就可以篡改linkmap。
调试方法不同时内存布局的不同
首先探索的是调试方法不同时,内存布局的不同
一般使用gdb有两种方法,gdb attachment以及gdb --pid=xxxx,也就是gdb直接调试文件或者链接进程进行调试,实际上这两者就算仅仅是从效果上看就有很大不同。
首先看gdb --pid=xxx的vmmap,这个结果更加接近一个进程的真实vmmap,也就是和cat /proc/xxx/maps的结果相近
1 | pwndbg> vmmap |
然后是使用gdb attachment的效果,可以看到的是mmap得到的空间和ld.so之间多了0x6000的[vvar]和[vsdo],这两个本来是在栈段下方的。
其次,如果多次调试发现,attachment、libc、ld的加载地址实际上是固定的,也就是0x555555554000、0x7ffff7d83000、0x7ffff7fc3000实际上没变,应该是出于方便调试所以固定了加载地址。
1 | pwndbg> vmmap |
使用patchelf后的内存布局
一般pwn题时,尤其C的pwn题时,会选择使用patchelf,更改libc和ld为指定glibc版本的来获得和远程相近的本地环境,但是patchelf也会使进程的内存布局发生变化。
首先获得一个patchelf后的文件
1 | $ ldd attachment # patchelf之前 |
然后gdb --pi=xxx尝试调试。
1 | pwndbg> vmmap |
可以看到,mmap获得的空间现在变成了在libc上方,原因暂时未知。
xinted转发会话时启动的进程
之前docker内可行的exp,在访问端口(本地docker或者服务器远程)上的题目时,发现无法打通,于是猜测是xinted转发的进程内存布局不同
在正式查看之前,先做准备工作,第一步先修改以下xinted的设置
1 | service ctf |
然后构建镜像
1 | $ docker build -t boss . |
再打开一个shell,nc localhost 8000,现在docker容器中就存在一个attachment的进程,由xindted转发
此时先找到pid
1 | <容器名>/home/ctf$ ps aux |
现在调试这个pid
1 | <容器名>/home/ctf$ gdb --pi=29 |
1 | <容器名>/home/ctf$ cat /proc/29/maps |