流量分析_SnakeBackdoor-6

SnakeBackdoor-6

我们在前面的分析中已经拿到了最关键的钥匙:加密密钥。现在,我们需要利用这把钥匙,从 Wireshark 的流量中把被加密的 Flag 还原出来

根据题目描述"攻击者获取服务器中的flag",说明是受害机(运行木马的机器)执行了命令,并将 Flag 作为结果回传给了 C2 服务器(192.168.1.201)。解题思路如下:

bash 复制代码
解题思路:

1、计算密钥:用题目5从 Wireshark 流量中提取服务端发送的 4 字节随机种子(34952046),在 Linux 环境下模拟 srand 和 rand 逻辑,计算出本次会话的 16 字节会话密钥

2、逆向算法:在 IDA 中根据密钥扩展算法分析加密算法

3、提取密文:在 Wireshark 中定位受害者发往攻击者(Client -> Server)的回传数据包,去除前 4 字节的长度头,提取剩余的 Hex 密文

4、编写解密脚本:编写 Python 脚本,结合计算出的会话密钥和提取的算法参数,对密文进行解密,最终还原出 Flag
​

1、计算密钥

在题目5中我们已经从 Wireshark 流量中提取服务端发送的 4 字节随机种子(34952046),这个种子会计算出会话的 16 字节会话密钥

所以我们需要编写脚本,模拟 srand 和 rand 的逻辑计算出1616 字节会话密钥,构造脚本如下:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    // 1. 填入 Wireshark 提取的种子
    unsigned int seed = 0x34952046;
    
    // 2. 初始化随机数生成器 (模拟木马行为)
    // 注意:必须在 Linux 环境编译运行 (如 OnlineGDB 选择 C 语言)
    srand(seed);
    
    printf("Session Key: ");
    
    // 3. 生成 16 字节密钥
    for(int i = 0; i < 4; i++) {
        int r = rand();
        // 模拟内存中的小端序存储
        unsigned char *p = (unsigned char *)&r;
        printf("%02x%02x%02x%02x", p[0], p[1], p[2], p[3]);
    }
    printf("\n");
    return 0;
}

计算出来,其实也就是我们题目5中计算出来的

a、提取出密钥

bash 复制代码
KEY_HEX = "ac46fb610b313b4f32fc642d8834b456"

2、IDA逆向分析会话加密算法以及算法相关参数

根据题目5在IDA中反编译出的main函数伪代码

(1)分析分组长度

根据代码行v16 = 16 * (v23 / 16 + 1); 和 memset(&s, 48, 0x10uLL); 知道分组长度, 数据被强制对齐到 16 字节(128位)。这说明使用的是 分组加密算法,且分组大小为 128 bit

候选算法:AES, SM4, Camellia, Aria 等。排除 DES(64 bit)和 RC4(流加密)

(2)分析密钥长度

由代码v8[16]; ... *(_DWORD *)&v8[4 * i] = rand();分析知道生成了 4 个 4 字节的随机数,共 16 字节(128 bit)

密钥长度为128-bit 的会话密钥

(3)分析加密模式并提取加密算法相关参数

分析知道sub_13B4(密钥扩展)和 sub_1860(加密/解密核心)

sub_1860 调用时没有传递 IV(初始化向量),且存在 Padding 填充逻辑 ,说明极有可能是 ECB 模式(电子密码本模式)

b.提取SM4算法的系统参数FK

双击进入 sub_13B4 (密钥扩展函数),是典型的 SM4 密钥扩展算法 (Key Expansion / Key Schedule)。它的作用是把输入的 128 位(16 字节)主密钥,扩展成 32 个 32 位的轮密钥

循环 4 次,异或一个常量数组 dword_2120,这个dword_2120 就是 SM4 的 系统参数 FK

双击查看 dword_2120,可以看到0A3B1BAC6h, 56AA3350h等参数,吻合SM4 的 系统参数 FK,进一步证实了是SM4算法

bash 复制代码
FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]

c.提取SM4算法的固定参数CK

循环 32 次,每次异或一个常量数组 dword_2140,调用一个子函数 sub_1311。这个dword_2140 就是 SM4 的 固定参数 CK;sub_1311 是 线性/非线性变换函数

双击dword_2140,查看参数,吻合 SM4 算法的标准固定参数 CK

bash 复制代码
CK = [
    0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
    0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
    0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
    0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
]

d.提取SM4算法的S-Box (S盒)

根据前面的分析,sub_1311 是 线性/非线性变换函数,实现了 SM4 算法中的 S盒代换 + 线性变换

这里将 32 位输入拆成 4 个 8 位字节,然后分别传入 sub_1229,推断sub_1229 就是 S-Box 查表函数

双击 sub_1229,看待调用了byte_2020,双击查看得到了SM4 算法中的S盒

这里的S盒只保留了SM4算法标准S 盒的前几行,后面的内容修改了的

bash 复制代码
SboxTable = [
    0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,
    0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
    0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,
    0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6,
    0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,
    0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,
    0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87,
    0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E,
    0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1,
    0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3,
    0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F,
    0xD5, 0xDB, 0x39, 0xB8, 0x31, 0x11, 0x0C, 0x5A, 0xCB, 0x3E, 0x0A, 0x45, 0xE5, 0x94, 0x77, 0x5B,
    0x8D, 0x6D, 0x48, 0x41, 0x10, 0xBD, 0x09, 0xC1, 0x4A, 0x89, 0x0D, 0x6E, 0x97, 0xA1, 0x1D, 0x16,
    0x0A, 0xD9, 0x88, 0x6A, 0x96, 0xD1, 0x6B, 0x32, 0x02, 0x35, 0x46, 0x06, 0x7D, 0x65, 0x49, 0x8C,
    0xF0, 0x3E, 0x2D, 0x7A, 0x15, 0xFF, 0x05, 0x8E, 0x01, 0x84, 0x3C, 0x3A, 0x38, 0x53, 0x87, 0x7B,
    0x0B, 0x2B, 0x7E, 0x0F, 0xF6, 0x69, 0xA8, 0x5A, 0xB5, 0x4C, 0x1B, 0x39, 0x7F, 0x08, 0x8D, 0x1C
]

3、wireshark中定位通信会话数据包,提取通信密文

根据我们之前的分析,受害者是 192.168.1.200,而攻击者(接收 Flag 的 C2 服务器)是 192.168.1.201。为了提取 Flag,我们需要的是 受害者发给攻击者 的流量

bash 复制代码
ip.src == 192.168.1.200 && ip.dst == 192.168.1.201 && tcp.port == 58782 && tcp.len > 0

可以看到大量 Len=4 和 Len=16 的小包,这是受害者木马在不断询问服务器:"有命令吗?"服务器回复:"没命令"或者保持连接,这是一种典型的 C2 维持机制

Len=4:根据逆向代码,这是通信协议的长度头(Header)

Len=16:这是 SM4 加密后的最小分组长度(128位)

把大于等于48的数据包的密文全部提取出来,然后一起进行解密

bash 复制代码
ip.addr == 192.168.1.201 && tcp.port == 58782 && tcp.len >=48

分别复制出里面的数据,以其中一个为例

e、提取密文

bash 复制代码
CIPHER_LIST = [
    "87e8faa921f3e67c530f1b6740a9d439794e426716d49f5e949d5d56f81ed54a97f6cc6752fcf7aa408a94e6a59029e7",
    "91fc3c4dc278b1afc5636adeca578f3fe37c16fa66fae433d0d7eb331e7926025ad84833f28fc2641bf05e058be36ed06b3ba79fb66a1ae4192c51152e87a1c6abf66f0a1038689d2137f94d6a686b946120ea2d6fbe312786411b701a353ab035de9c7dc81abfa0dfef55c14cd1f99e07c",
    "0f8e8c73baeb70cada6aa30d3a91d0c8f4f2a26dd4e3e7ad0c99810245ae92a05893d4b74323a37247cc6c9c417f8082ccef101bd31acdc79c8a673396353a030358d2a3db37019672b8042929a68fea5ba9965e5145940355e00debe46e80b75dd31b646f39d4cb3e057bc64c8e3b39a7c",
    "4331cfda21eeab8922fcc7acced16d1a17b02e8d2d9dfee48dc8f18e0dbbb2e4c4547e39d8c4aa2418d9fca52c9c4770",
    "7f4b0ef4806983f164af6f46b71d3fce1e3c0bd00c4dd162b72c156f0f3aecd2afcabf551e08380db6fd20316f8a2729",
    "de7cc756e5c97fed18a72a95af102dac48dc0810752bd7755157e5909974cbe0ce87241e7f01e3169e7a763a22008029"
]

4、编写脚本进行SM4解密

根据前面得到的 密钥、SM4算法的系统参数FK、SM4算法的固定参数CK、SM4算法的S-Box、密文****编写脚本进行解密

python 复制代码
import struct
import binascii

# ==================== 配置区 ====================
KEY_HEX = "ac46fb610b313b4f32fc642d8834b456"

# 魔改 S-Box
SBOX = bytes([
    0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
    0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
    0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
    0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
    0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
    0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
    0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
    0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
    0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
    0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
    0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
    0xd5, 0xdb, 0x39, 0xb8, 0x31, 0x11, 0x0c, 0x5a, 0xcb, 0x3e, 0x0a, 0x45, 0xe5, 0x94, 0x77, 0x5b,
    0x8d, 0x6d, 0x48, 0x41, 0x10, 0xbd, 0x09, 0xc1, 0x4a, 0x89, 0x0d, 0x6e, 0x97, 0xa1, 0x1d, 0x16,
    0x0a, 0xd9, 0x88, 0x6a, 0x96, 0xd1, 0x6b, 0x32, 0x02, 0x35, 0x46, 0x06, 0x7d, 0x65, 0x49, 0x8c,
    0xf0, 0x3e, 0x2d, 0x7a, 0x15, 0xff, 0x05, 0x8e, 0x01, 0x84, 0x3c, 0x3a, 0x38, 0x53, 0x87, 0x7b,
    0x0b, 0x2b, 0x7e, 0x0f, 0xf6, 0x69, 0xa8, 0x5a, 0xb5, 0x4c, 0x1b, 0x39, 0x7f, 0x08, 0x8d, 0x1c
])

FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]
CK = [
    0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
    0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
    0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
    0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
]

CIPHER_LIST = [
    "87e8faa921f3e67c530f1b6740a9d439794e426716d49f5e949d5d56f81ed54a97f6cc6752fcf7aa408a94e6a59029e7",
    "91fc3c4dc278b1afc5636adeca578f3fe37c16fa66fae433d0d7eb331e7926025ad84833f28fc2641bf05e058be36ed06b3ba79fb66a1ae4192c51152e87a1c6abf66f0a1038689d2137f94d6a686b946120ea2d6fbe312786411b701a353ab035de9c7dc81abfa0dfef55c14cd1f99e07c",
    "0f8e8c73baeb70cada6aa30d3a91d0c8f4f2a26dd4e3e7ad0c99810245ae92a05893d4b74323a37247cc6c9c417f8082ccef101bd31acdc79c8a673396353a030358d2a3db37019672b8042929a68fea5ba9965e5145940355e00debe46e80b75dd31b646f39d4cb3e057bc64c8e3b39a7c",
    "4331cfda21eeab8922fcc7acced16d1a17b02e8d2d9dfee48dc8f18e0dbbb2e4c4547e39d8c4aa2418d9fca52c9c4770",
    "7f4b0ef4806983f164af6f46b71d3fce1e3c0bd00c4dd162b72c156f0f3aecd2afcabf551e08380db6fd20316f8a2729",
    "de7cc756e5c97fed18a72a95af102dac48dc0810752bd7755157e5909974cbe0ce87241e7f01e3169e7a763a22008029"
]

# ==================== 算法核心 ====================
rot = lambda x, n: ((x << n) | (x >> (32 - n))) & 0xffffffff
tau = lambda x: (SBOX[x & 0xff] << 24) | (SBOX[(x >> 8) & 0xff] << 16) | (SBOX[(x >> 16) & 0xff] << 8) | SBOX[x >> 24]
L = lambda x: x ^ rot(x, 2) ^ rot(x, 10) ^ rot(x, 18) ^ rot(x, 24)
Lp = lambda x: x ^ rot(x, 13) ^ rot(x, 23)


def sm4_dec_block(ct, rk):
    x = [struct.unpack('>I', ct[i * 4:i * 4 + 4])[0] for i in range(4)]
    for i in range(31, -1, -1):
        tmp = x[0] ^ L(tau(x[1] ^ x[2] ^ x[3] ^ rk[i]))
        x = x[1:] + [tmp]
    return b''.join(struct.pack('>I', x[3 - i]) for i in range(4))


def sm4_get_rk(key):
    mk = [struct.unpack('>I', key[i * 4:i * 4 + 4])[0] for i in range(4)]
    k = [mk[i] ^ FK[i] for i in range(4)]
    rk = []
    for i in range(32):
        rk.append(k[0] ^ Lp(tau(k[1] ^ k[2] ^ k[3] ^ CK[i])))
        k = k[1:] + [rk[-1]]
    return rk


def try_decrypt(cipher_hex, rk):
    try:
        clean_hex = cipher_hex.replace(" ", "").replace("\n", "").replace("\r", "").strip()
        data = binascii.unhexlify(clean_hex)

        # 自动去头
        payload = data
        if len(data) % 16 != 0:
            if len(data) > 4 and (len(data) - 4) % 16 == 0:
                payload = data[4:]
            else:
                return "[Error] Odd-length string"

        # 解密
        plaintext = b""
        for i in range(0, len(payload), 16):
            if i + 16 <= len(payload):
                plaintext += sm4_dec_block(payload[i:i + 16], rk)

        # 解码并去除两端的空白字符(strip)
        try:
            pad = plaintext[-1]
            if 0 < pad <= 16:
                return plaintext[:-pad].decode(errors='ignore').strip()
            return plaintext.decode(errors='ignore').strip()
        except:
            return plaintext  # 无法解码则返回bytes

    except Exception as e:
        return f"[Error] {e}"


# ==================== 主程序 ====================
def main():
    print(f"[*] 正在尝试解密 {len(CIPHER_LIST)} 条数据...\n")

    key_bytes = binascii.unhexlify(KEY_HEX)
    rk = sm4_get_rk(key_bytes)

    for i, hex_str in enumerate(CIPHER_LIST):
        result = try_decrypt(hex_str, rk)
        print(f"[数据包 {i + 1}]: {result}")
        print("-" * 40)


if __name__ == '__main__':
    main()

解密得到第五条数据包中的数据使我们想要的flag

相关推荐
白山云北诗1 天前
企业网站网络安全防护方案
安全·web安全·网络安全·ddos防护·web应用防火墙·cc防护
2301_780789661 天前
服务器感染的病毒有哪些特点呢?
安全·web安全
上海云盾第一敬业销售1 天前
CC攻击与流量劫持的关系解析
web安全
白帽子黑客杰哥1 天前
在实际渗透测试中,如何系统性地评估一个WAF规则集的有效性?
网络·web安全·kali
clown_YZ1 天前
HKCERTCTF2025--解题记录
ctf·漏洞利用·漏洞原理
yesyesido1 天前
高效安全局域网文件传输平台:零配置、高速度、跨设备的本地数据共享解决方案
安全·web安全·网络安全
派大鑫wink1 天前
网络安全新挑战:AI 驱动的攻防对抗与防护策略(附实战操作)
人工智能·python·安全·web安全
菩提小狗1 天前
vulnhub靶场实战系列-1.靶场实战平台介绍|课程笔记|网络安全|
笔记·安全·web安全
竹等寒1 天前
TryHackMe-SOC-Section 7:网络安全监控
web安全·网络安全