初看木马

一题:socks_proxy
SOCKS 5 是一种网络代理协议,全称是 Socket Secure 5。它工作在 OSI 模型的第 5 层(会话层),能够在客户端和服务端之间透明地中继 TCP(以及 UDP)流量。与传统的 HTTP 代理不同,SOCKS 5 不关心具体应用层协议是什么,只要基于 TCP 或 UDP 的数据流,它都可以代为转发,因此常被用作通用代理反向代理工具的基础协议。

SOCKS 5 的核心特性

  1. 认证支持
    SOCKS 5 在握手阶段支持多种认证方式,最常见的包括:

    • 0x00:无须认证

    • 0x02:用户名/密码认证
      代码中出现了 VER=0x05 METHOD=0x00,正是表示 SOCKS 5 协议版本为 5,认证方式为“无认证”。

  2. 支持多种地址类型
    SOCKS 5 可以代理 IPv 4、IPv 6 和域名连接(域名会自动解析),这使得它能灵活转发各种目标地址的流量。

  3. 传输层无关性
    不管被代理的数据是 HTTP、FTP、SMTP 甚至二进制自定义协议,SOCKS 5 都不解析内容,只负责维持客户端和目标之间的原始数据流。

样本中,socks_proxy.exe 是一个SOCKS 5 反向代理木马。它的工作原理大致是:

  1. 内网穿透
    受害主机主动向外网攻击者的 C 2 服务器发起 TCP 连接(反向连接)。

  2. 建立 SOCKS 5 通道
    成功连接后,在受害主机上启动一个 SOCKS 5 代理服务。

  3. 流量中继
    攻击者通过 C 2 服务器将 SOCKS 5 请求转发到受害内网,受害主机再把请求代理到内部其他目标,并把响应回传。这样攻击者就像“进入了内网”一样,可以访问原本无法直接触及的内部资源(数据库、文件共享、内网网站等)。

代码中的模拟片段完美还原了这一过程:

  • 反向 TCP 到 C 2 地址(off_1400A6000)的 8443 端口;

  • 日志 "[SIM] SOCKS5 VER=0x05 METHOD=0x00" 模拟握手;

  • 日志 "[SIM] Client->Target %d bytes" 和 "[SIM] Target->Client %d bytes" 模拟双向数据中继;

  • 心跳包则用来保持连接存活,防止被网络设备超时断开。

因此,题中虽然标了 [SIM](模拟),但攻击者的真实意图就是把受害机器变成到达内网的跳板,而 SOCKS 5 协议因其简洁、通用和高隐蔽性,成为这类远控木马的首选代理协议之一。

在代码中的具体体现

  • 使用 CreateMutexA 创建一个命名的互斥体(名称存储在全局变量 lpName 中)。

  • GetLastError() == 183 对应 ERROR_ALREADY_EXISTS,表示已有同名互斥体存在,说明程序已在运行。

  • 如果是重复实例,输出日志后释放句柄并退出;否则继续执行,保证系统内只有一个木马实例运行。

  • 使用 Windows CNG API (BCrypt*) 进行解密。

  • 算法:AES-256-CBC,密钥为 "DarkProxy_AES256Key!@2024_Cfg!~!"(正好 32 字节)。

  • IV:数据段中的 128 位变量 xmmword_14008F068(实际值为 "Pr0xy!IV!2024!!!",注意第三个字符是数字 0)。

  • 密文:位于 byte_1400A6040,共 64 字节(0 x 40)。

  • 解密后的明文(去除 PKCS #7 填充)存入缓冲区 v51,并记录实际长度。成功则置 v10=1

  • 随后根据 v10 输出不同日志,表明解密成功或失败。

结果v51 中得到一个数据库连接字符串,这是后续“模拟数据库连接”步骤中的目标地址。

  • 通过 WinAPI 获取真实的主机名和用户名。

  • 操作系统和 IP 地址完全是硬编码的假信息,说明目前是模拟环境。

  • 所有信息拼接为日志输出,模拟木马的“侦查”行为。

  • off_1400A6008 和 off_1400A6010 是硬编码的字符串指针,通常对应于某个注册表项和值名。

  • 模拟木马将自己添加到 HKEY_CURRENT_USER\...\Run 下,值名为 svchost.exe,实现开机自启动。

  • 同样是日志模拟,未真正修改注册表。

  • 重连尝试:变量 v3 从 0 开始,每次循环 ++v3,循环条件为 v3 < 3,所以实际只执行 2 次v3=1,2)。但日志打印显示 Attempt %d/50,暗示真实木马可能尝试 50 次,这里只是模拟。

  • 反向 TCP 连接:C 2 地址取自 off_1400A6000[0],端口 8443。连接后输出 [SIM] Connected

  • SOCKS 5 握手:版本 0x05,认证方式 0x00(无认证)。

  • 数据中继循环:用递增的 i 和 v31 模拟不同大小的数据包在客户端和目标之间转发,代表木马在受害内网与其他主机之间代理流量。

  • 心跳包:向 C 2 发送心跳,间隔 30 秒,保持连接活跃。

  • 循环结束后没有额外清理,如果互斥体句柄有效则关闭,程序正常返回 0。

回到这道题:
swprintf(v49, "[SIM] Connecting to: %s", v51) —— 说明 v51 就是数据库连接字符串。所以只要解密得到 v51,即可获得 Flag。

四项要素:

|要素|值|来源|
|---|---|---|
|算法|AES-256-CBC|`BCryptOpenAlgorithmProvider(L"AES")` + `ChainingModeCBC`|
|密钥|`DarkProxy_AES256Key!@2024_Cfg!~!`|硬编码字符串,32字节|
|IV|`xmmword_14008F068`|位于 `.rdata` 的 128 位数据|
|密文|`byte_1400A6040`|位于 `.data` 的 64 字节数据|

写出脚本即可

key = b"DarkProxy_AES256Key!@2024_Cfg!~!"
iv = b"Pr0xy!IV!2024!!!"
ciphertext = bytes.fromhex("CDAB5FAB...245D")  # 64字节
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
# 去除PKCS#7填充
pad_len = plaintext[-1]
db_conn = plaintext[:-pad_len].decode()
print(f"flag{{{db_conn}}}")

所以这题比较简单,只要理解代码的处理逻辑就可以了

posted @ 2026-09-07 10:05  JIEGE328  阅读(3)  评论(0)    收藏  举报