[范例]从正在运行的Linux进程中dump出内存内容

时间:2021-05-07 05:03:02

参考:
https://colin.guru/index.php?title=Dumping_Ram_From_Running_Linux_Processes

最近看到有个CTF题感觉挺有意思,就是从一个bin中找到一个secret key,然后用来签名session cookies用来怼一个使用go的Web服务器。通常这种类型题的flag都比较直接。可以直接用strings怼这个bin就可以了,然而这次的这个题目中的bin不同,因为有太多杂碎(noise)要过滤了。于是在此我就来展示一下如何用一些基本的Linux命令配合gdb从进程中dump出内存中的信息。
先file一下,

$ file ctf-bin
ctf-bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

发现是64位的Linux可执行文件。
然后strings一下,

$ strings -n 10 ctf-bin | wc | uniq
71085 106643 2081483

发现字符串太多,还是先不看,再研究深一点吧。
然后先运行一下程序,

$ ./ctf-bin

然后再另一个终端找到这个进程的PID

$ ps -elf | grep ctf-bin
4 S root 6686 5777 0 80 0 - 8403 - 17:02 pts/0 00:00:00 ./ctf-bin
0 S root 6701 6694 0 80 0 - 3179 - 17:02 pts/2 00:00:00 grep ctf-bin

然后cat一下它的内存(太长不看TL;DR)

$ cat /proc/6686/maps
00400000-007bd000 r-xp 00000000 08:01 1727726 /root/ctf/q3ctf/ctf-bin
007bd000-00bb9000 r--p 003bd000 08:01 1727726 /root/ctf/q3ctf/ctf-bin
00bb9000-00bdb000 rw-p 007b9000 08:01 1727726 /root/ctf/q3ctf/ctf-bin
00bdb000-00bff000 rw-p 00000000 00:00 0
016b2000-016d3000 rw-p 00000000 00:00 0 [heap]
c000000000-c000001000 rw-p 00000000 00:00 0
c81fff0000-c820200000 rw-p 00000000 00:00 0
...

似乎太多了有点可怕,但是不用害怕。
然后启动gdb,将改进程attach到gdb上。

$ gdb attach 6686

然后就是gdb命令

(gdb) dump memory /root/memory.dump 0xc81fff0000 0xc820200000

解释一下语法:
- "dump memory"是命令
- "/root/memory.dump"是我们想保存dump出的内容的路径。
- 两个hex是内存地址区间,这跟/proc/6686/maps的格式有些不一样。这是以0x开头的而且没有连字符。

然后就是用strings命令找出刚才dump出的文件的字符串,我喜欢最少10个长度的字符串(-n 10)来过滤掉一些无用的信息(noise)。
结果如下:

$ strings -n 10 /root/memory.dump
XDG_VTNR=2
XDG_SESSION_ID=1SHELL=/bin/bash
VTE_VERSION=4201USER=rootSHLVL=1USERNAME=root
LANG=en_US.UTF-8XDG_SEAT=seat0
HOME=/root
LOGNAME=root
...
Thu Feb 4 21:00:57 -0800 2010
aBCdEfJ2cPhLzQ2l111oZMHuADgJQVlkA
Wed Sep 28 17:02:15 EDT 2016
Wed Sep 28 17:02:15 EDT 2016
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"
#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
Starting scrum-cookies-server on port 9000.
Starting scrum-cookies-server on port 9000.
Wed Sep 28 17:02:15 EDT 2016 - INFO - main.go:110 - Starting scrum-cookies-server on port 9000.

可以看到好像有个hash值,为了不泄露CTF题的答案,我已经把hash值改了。

总结

好了,你已经找到运行的进程的PID,dump出了那个进程的内存内容,然后用gdb,strings命令找出了有用的数据。

以上翻译自:
https://colin.guru/index.php?title=Dumping_Ram_From_Running_Linux_Processes


Let’s get your hands dirty

Down to business

于是我也想试一下啊,然而我想找一个执行命令之后不退出的进程还蛮难的,最终我想到了apache,然而必须要有客户端与apache建立TCP长连接,如果是那种5xx的错误,比如这个,
就会发现TCP连接建立之后马上又断开了。

cqq@snort-ids:/proc$ tcp|grep "172.18.xx.xx"
sshd 6502 root 3u IPv4 138454 0t0 TCP 172.18.yy.yy:22->172.18.xx.xx:64724 (ESTABLISHED)
sshd 6524 cqq 3u IPv4 138454 0t0 TCP 172.18.yy.yy:22->172.18.xx.xx:64724 (ESTABLISHED)
apache2 13660 www-data 14u IPv6 179548 0t0 TCP 172.18.yy.yy:80->172.18.xx.xx:53496 (ESTABLISHED)
sshd 18442 root 3u IPv4 180814 0t0 TCP 172.18.yy.yy:22->172.18.xx.xx:52149 (ESTABLISHED)
sshd 18454 cqq 3u IPv4 180814 0t0 TCP 172.18.yy.yy:22->172.18.xx.xx:52149 (ESTABLISHED)
cqq@snort-ids:/proc$ tcp|grep "172.18.xx.xx"
sshd 6502 root 3u IPv4 138454 0t0 TCP 172.18.yy.yy:22->172.18.xx.xx:64724 (ESTABLISHED)
sshd 6524 cqq 3u IPv4 138454 0t0 TCP 172.18.yy.yy:22->172.18.xx.xx:64724 (ESTABLISHED)
sshd 18442 root 3u IPv4 180814 0t0 TCP 172.18.yy.yy:22->172.18.xx.xx:52149 (ESTABLISHED)
sshd 18454 cqq 3u IPv4 180814 0t0 TCP 172.18.yy.yy:22->172.18.xx.xx:52149 (ESTABLISHED)

于是只能弄一个TCP长连接吧。返回200的那种应该可以。
结果发现还是不行。
于是通过htop漫无目的地找吧,于是还是找apache的主进程吧。
通过htop发信apache的主进程的PID为6900,
于是

cqq@snort-ids:/proc$ sudo gdb attach 6900

(注意:要以root的身份启动,否则可能没有权限。)
然后gdb就开始调试6900进程了,一顿输出啊,几秒之后到达gdb的命令行。
然后dump出heap中的内容。

(gdb) dump memory /root/memory.dump 0x557b9000 0x557fb000
(gdb) dump memory /root/memory2.dump 0x557fb000 0x559eb000

然后在/root目录找到了那两个dump出来的文件,

-rw-r--r--  1 root root 2.0M May 29 20:55 memory2.dump
-rw-r--r-- 1 root root 264K May 29 20:54 memory.dump

从任意一个dump中找出10个字符以上的字符串吧。

root@snort-ids:~# strings -n 10 memory.dump
log_config
/usr/lib/apache2/modules/mod_authn_file.so
/usr/lib/apache2/modules/mod_authz_core.0
{U/lib/apache2/modules/mod_authz_host.`
}U/lib/apache2/modules
mod_authz_host.so
oid_section
alg_section
SRVName otherName form
id-on-dnsSRV
Main thread
DEBUG_BACKTRACE_IGNORE_ARGS
PHP_CONFIG_FILE_PATH
E_RECOVERABLE_ERROR

Done :)