2025能源安全初赛部分wp

一整天打比赛真的好累,晚上十点只想上床睡觉😥

能源行业

lava

二血

die发现有upx壳

修补upx特征码

脱壳之后发现是rc4

init有魔改

按伪c一直得不到正确的S盒,直接提取初始化后的s盒

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
def rc4(data, key):
# S = list(range(256))
# j = 0
out = []

for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
tmp=S[i]
S[i] =(S[i] + S[j])%256
S[j] =(tmp + S[j])%256

S=[]
S=[0x4E, 0xD7, 0x0E, 0x5B, 0x81, 0x1E, 0x1A, 0x2B, 0x83, 0xFF,
0xA9, 0xAD, 0x8C, 0x60, 0x90, 0x6F, 0x50, 0x5A, 0x24, 0x9C,
0x4A, 0xFE, 0x97, 0xE5, 0x5F, 0x8E, 0x85, 0x13, 0x93, 0xE5,
0x4E, 0xE0, 0xEA, 0xD4, 0x29, 0x6F, 0x93, 0x1C, 0x66, 0xAA,
0xF3, 0x13, 0x9F, 0xB0, 0xCE, 0xEE, 0xF5, 0xF7, 0x12, 0xB7,
0xFA, 0xC4, 0x6C, 0xA2, 0xC4, 0xDB, 0x46, 0x03, 0x56, 0xCE,
0x3A, 0x54, 0xEA, 0x9C, 0xB2, 0xE0, 0xF4, 0xEC, 0x6A, 0x1C,
0x7D, 0xE8, 0x67, 0x4E, 0xA1, 0x2F, 0xB9, 0xE9, 0xD9, 0xD5,
0x27, 0x28, 0x28, 0x49, 0x0A, 0xD3, 0x0D, 0x82, 0xB8, 0xF7,
0x84, 0xD4, 0x40, 0xBA, 0xCC, 0xCB, 0x33, 0x27, 0xE4, 0x75,
0x71, 0xC2, 0xD6, 0x85, 0xBE, 0x90, 0xF5, 0xEC, 0x35, 0x31,
0x2A, 0x16, 0x5E, 0xDE, 0x75, 0x7B, 0xD3, 0x26, 0x37, 0x51,
0xC6, 0x3B, 0xA8, 0xB8, 0x16, 0x13, 0x7D, 0x1D, 0x7D, 0x50,
0x85, 0x39, 0x40, 0x23, 0x06, 0xA2, 0xAE, 0xE6, 0xD5, 0xD4,
0x00, 0x7E, 0x5A, 0x86, 0x30, 0x8B, 0x6F, 0x92, 0xDE, 0x75,
0x17, 0x3C, 0xA2, 0xDF, 0x6F, 0xEA, 0x05, 0x18, 0xA2, 0xA0,
0x23, 0xA2, 0x6A, 0x66, 0xA5, 0xBB, 0x29, 0x06, 0x79, 0xDE,
0xF6, 0x8A, 0xAA, 0x82, 0x81, 0x66, 0x5D, 0xDD, 0x27, 0x36,
0x32, 0x25, 0xFE, 0x79, 0x79, 0xEF, 0x37, 0xA5, 0x59, 0xEE,
0xED, 0x28, 0x84, 0x24, 0x34, 0xDF, 0xDE, 0x97, 0x7F, 0xE3,
0x13, 0x04, 0x29, 0xFA, 0x2C, 0x11, 0xD0, 0x31, 0x23, 0xBB,
0x23, 0xB4, 0x6A, 0xA8, 0x4A, 0x64, 0xD4, 0xB0, 0x03, 0xBA,
0xAA, 0xD0, 0x60, 0x09, 0x6B, 0xA9, 0x1D, 0x17, 0x50, 0x24,
0x9C, 0xD6, 0xD0, 0xD4, 0x6B, 0x01, 0xD9, 0x40, 0x24, 0x8E,
0xF5, 0x2B, 0x75, 0x64, 0xF5, 0xFE, 0x81, 0xF7, 0x2C, 0xF6,
0x4E, 0xA1, 0x0D, 0xD0, 0x18, 0xC6]

i = j = 0
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
char = char + S[(S[i] + S[j]) % 256]
char%=256
out.append(char)

return bytes(out)


data = bytes([0x64, 0x3A, 0xD0, 0x79, 0xB9, 0xE9, 0x75, 0x52, 0x6E, 0xE9,
0xFB, 0x0E, 0x52, 0x24, 0x1C, 0xB6, 0x2B, 0xE4, 0x86, 0xF8,
0x69, 0x52, 0x53, 0x3E, 0x3C, 0x8E, 0xB0, 0x16, 0x62, 0xE6,
0x98, 0x7F])
print(len(data))
key = b'rc4IsEasy'
decrypted = rc4(data, key)
print(decrypted)
#b'2404c9b8af2dd18f92dd9018c85f76fe'

usb

经典usb流量

过滤hid data列,后面跑脚本提取

1
flag{whoami && rm -rf /opt}

easymodbus-3

恢复不了符号表,也没找到网上类似的题

/bin/sh字符串,可能要发送符合格式的数据再getshell

Crypto

NumberTheory

yafu分解发现hint能被233整除,经过尝试之后发现可以用费马小定理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from math import gcd
from Crypto.Util.number import long_to_bytes, inverse

n = 113310007043671810845854958178261892350466329031075849658400622797220639822165853920670375240421584770086737199174179404426269461807205919265215015318558583279307342189066142674684812629436201594710931246023579402265860654799773575870718232197419475376859857859160478517321102794376573133320398421013885294803 # n
c = 71140184512977657248678802858923889906469994653365050397942639686285067049311597229075083243014006139628135512648917088910957708595173169740778384396383007676160125041429483214711040860094456744628950189892189206308633008723823236088821678663574778449944147445444557428696970338207423613161971095287158528268 # c
hint = 304302625376181653586904104401793052942691958380766622476796502085769101118223423483198426870687288772995446524917404481734386549400612667029785738864459729312716240418284186683690152478372081937338184159203750009565388703480806423176123558900518577576731229725343401015296144240503499943327828404875279740222104515371853890423856666710430710428991178833598803175224026696772717334264841725910496575249477684269365734094608409667005577061258227602330654989600297462 # hint

e = 65537

L = hint // 233
p = gcd(pow(c, L, n) - 1, n)
q = n // p

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)
print(flag)
#flag{d0bafb7185f2acfd371c566cbae25af9}

数据安全

狠狠破防

数据脱敏-3

为了抵抗黑客攻击导致数据拖库等问题,需要将敏感数据识别并脱敏存储成⼀个表。给定脱敏算法逻辑,要求选⼿⽣成脱敏后的数据表数据(所有数据均为随机⽣成,与现实世界⽆任何联系)。为了防⽌⼀些隐私数据泄漏,现需要对该数据表进⾏脱敏操作,请按照指定要求对各字段进⾏脱敏处理,并按照先行后列拼接字符串(不包含标题行),对此字符串进行md5计算,得到答案。 脱敏要求: - 编号:⽆需脱敏。 - 姓名:⼆字姓名对最后⼀位字使⽤ * 进⾏替换,三字姓名对中间⼀位字使⽤ * 进⾏替换,四字姓名对中间两位字使⽤ * 进⾏替换。 - 手机号:请对中间五位信息使⽤ * 进⾏替换。 - 身份证号码:请对除了前6位信息使⽤ * 进⾏替换。 - 银⾏卡:请对前四位和后十位信息使⽤ * 进⾏替换。 - Email:请对字符 @ 前除 . 外的字符使⽤ * 进⾏替换。 - 性别:替换成未知。 - 微信号:请对为字符的信息使用 * 进行替换。

提示:000001,章三,17955640890,319540678369985756,3612632840753013460,bvsfvb@outlook.com,女,bcv6349

000001,章*,179890,319540,63284,@outlook.com,未知,**

加逗号和不加逗号都试过

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
80
81
82
83
84
85
86
87
88
89
90
91
92
import pandas as pd
import re
import hashlib

# 脱敏规则函数
def desensitize_name(name):
"""姓名脱敏规则:二字姓名对最后一位字使用 * 替换,三字姓名对中间一位字使用 * 替换,四字姓名对中间两位字使用 * 替换"""
if len(name) == 2:
return name[0] + "*"
elif len(name) == 3:
return name[0] + "*" + name[2]
elif len(name) == 4:
return name[0] + "*" + "*" + name[3]
else:
return name

def desensitize_phone(phone):
"""手机号脱敏规则:对中间五位信息使用 * 进行替换"""
phone = str(phone).strip() # 确保没有空格
if len(phone) == 11: # 假设手机号长度为11
return phone[:3] + "*****" + phone[8:]
return phone # 如果长度不对,直接返回原始手机号

def desensitize_id(id_number):
"""身份证号脱敏规则:保留前六位,剩下的用 * 替代"""
id_number = str(id_number).strip() # 去除空格
if len(id_number) >= 6:
return id_number[:6] + "**************"
return id_number # 如果长度不足6位,直接返回

def desensitize_bank_card(bank_card):
"""银行卡号脱敏规则:前四位和后十位信息使用 * 替换"""
bank_card = str(bank_card).strip()
if len(bank_card) >= 14:
return "****" + bank_card[4:-10] + "**********"
return bank_card # 如果银行卡号不符合要求,返回原始值

def desensitize_email(email):
"""Email脱敏规则:@前部分除 . 外的字符使用 * 替换"""
local, domain = email.split('@')
local = re.sub(r'[^\.\*]', '*', local)
return local + '@' + domain

def desensitize_gender(gender):
"""性别脱敏规则:替换为 '未知'"""
return "未知"

def desensitize_wechat(wechat):
"""微信号脱敏规则:将所有字符替换为 '*'"""
if isinstance(wechat, str):
return '*' * len(wechat) # 替换所有字符为 *
return wechat # 如果不是字符串,直接返回原值

# 读取 Excel 文件
df = pd.read_excel("data.xlsx", dtype=str)

# 脱敏处理数据
for column in df.columns:
for i, value in enumerate(df[column]):
if column == "编号":
# 保持编号不变
continue
elif column == "姓名" and isinstance(value, str):
df.at[i, column] = desensitize_name(value)
elif column == "手机号" and isinstance(value, str):
df.at[i, column] = desensitize_phone(value)
elif column == "身份证号" and isinstance(value, str):
df.at[i, column] = desensitize_id(value)
elif column == "银行卡号" and isinstance(value, str):
df.at[i, column] = desensitize_bank_card(value)
elif column == "Email" and isinstance(value, str):
df.at[i, column] = desensitize_email(value)
elif column == "性别" and isinstance(value, str):
df.at[i, column] = desensitize_gender(value)
elif column == "微信号" and isinstance(value, str):
df.at[i, column] = desensitize_wechat(value)

# 保存脱敏后的数据到新 Excel 文件
df.to_excel("desensitized_data.xlsx", index=False)

# 生成拼接字符串(按行拼接,每列数据之间用逗号隔开)
data_str = ''.join(df.astype(str).values.flatten())

# 去除所有可能的换行符和回车符
data_str = data_str.replace('\n', '').replace('\r', '')

# 计算 MD5
md5_hash = hashlib.md5(data_str.encode()).hexdigest()

# 输出 MD5 结果
print(data_str)
print("MD5:", md5_hash)

结构化数据识别-3

### 题目描述: 请参赛选手对给定的结构化文件《data.xlsx》进行处理,文件中包括手机号、身份证号码、银行卡号、邮箱等四类敏感数据以及干扰的脏数据(数据不满足特征)。具体数据检测规则可参考下文。参赛选手需要对数据进行清洗,编写规则,识别其中正确的敏感数据,并输出识别结果。仅当一行中所有的数据命中数据类型的规则时,才认为该行命中某一数据类型。 请参赛选手编写程序对数据进行识别,计算全部都命中的行数,计算答案的 MD5 值(MD5 值英文字符全小写,长度 32 个字符;计算答案的 MD5 值时,用 UTF-8 字符编码),并将答案的 MD5 值提交至平台。 1. 手机号是指11 位纯数字的民用手机号, 具体规则为:a) 1-3 位—— 138——运营商网络识别号,运营商包括中国移动、中国联通、中国电信、中国广电b) 4-7 位——8888——地区编码或其他(无规律)c) 8-11 位——8888——用户编码 2. 身份证号码是指18 位二代身份证号码, 具体规则为:a) 1-6 位—— 140521——为行政区代码(不定年份有修订)b) 7-14 位—— 19701231——为出生年月日,出生年月日不早于 1930 年1 月 1 日, 不晚于当前日期c) 15-17 位——543——顺序码,任意 3 位数字,第 17 位奇数为男性,偶数位女性d) 18 位——2——校验位,取值范围为 0~9 或 X。身份证号校验算法参照国标GB11643-1999《公民身份号码》。 3. 银行卡号是指19 位纯数字的银行卡号, 具体规则为:银行卡号规则是银行卡号由发卡银行标识、账户标识、校验位等部分组成。发卡银行标识为开头的6 位数字,不同的银行有不同的BIN。银行卡号的中间部分用于标识持卡人的账户信息,包括账户类型、账户分行等,通常包含12 位数字。银行卡号的最后一位通常是校验位,用于检查卡号是否合法,计算方法按照一定的算法生成。银行卡号校验位采用Luhn 算法。 4. 邮箱由用户名@域名组成,不限制长度,例如:123456789@163.com 具体规则为:用户名@域名,用户名可由字母、数字、下划线构成,不以下划线开始;域名:至少包含一个”.”,以最后一个”.”分割为两个部分,前半部分由字母、数字或”.”构成,”.”不能在最前面;后半部分由字母或数字构成。 正确答案示例:2323行,md5后答案提交为:flag{149815eb972b3c370dee3b89d645ae14}

挺奇怪的一点点筛选下来,如果直接匹配银行卡号前六位就什么都没有,因为要求比较精确且一分钟内提交有限制,最后也没试出来

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import pandas as pd
import re
import hashlib


# 正则表达式规则
def is_valid_phone(phone):
phone_pattern = r'^(1(3[4-9]|4[7]|5[0-3]|5[5-9]|6[6]|7[0-3]|8[0-9]|9[1-9]|70[0-9]|9[9]))\d{8}$'
return bool(re.match(phone_pattern, phone))


import re
from datetime import datetime


def calculate_check_digit(id_card):
# 权重系数
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
# 校验位映射
check_map = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']

# 计算加权和
weighted_sum = sum(int(id_card[i]) * weights[i] for i in range(17))

# 取模操作
remainder = weighted_sum % 11

# 返回校验位
return check_map[remainder]


# 身份证号校验
def is_valid_id_card(id_card):
if len(id_card) != 18 or not id_card[:17].isdigit():
return False

# 第一位不能是0或9
if id_card[0] in {'0', '9'}:
return False

# 检查省级行政区划代码是否合法(11-65,71-82)
province_code = int(id_card[:2])
if not (11 <= province_code <= 65 or 71 <= province_code <= 82):
return False

#特殊校验:第一位为7时第二位只能是1;第一位为8时第二位只能是1或2
if id_card[0] == '7' and id_card[1] != '1':
return False
if id_card[0] == '8' and id_card[1] not in {'1', '2'}:
return False

# 区域码应为前6位的数字
if not re.match(r'^\d{6}', id_card):
return False

# 出生日期合法性校验
birth_date = id_card[6:14]
try:
datetime.strptime(birth_date, '%Y%m%d')
except ValueError:
return False

# 顺序码应为数字
if not id_card[14:17].isdigit():
return False

# 校验位判断
if id_card[17].upper() != calculate_check_digit(id_card):
return False

return True

def is_valid_bank_card(bank_card):
if len(bank_card) != 19 or not bank_card.isdigit():
return False

if bank_card[0] == '0' or bank_card[0] == '7' or bank_card[0] == '8':
return False
# Luhn 校验
total = 0
reverse_digits = bank_card[::-1]
for i, digit in enumerate(reverse_digits):
n = int(digit)
if i % 2 == 1:
n *= 2
if n > 9:
n -= 9
total += n
return total % 10 == 0


def is_valid_email(email):
email_regex = r'^[a-zA-Z0-9][a-zA-Z0-9_]*@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]{2,})+$'
return bool(re.match(email_regex, email))


# 读取Excel文件
def read_and_process_data(file_path):
df = pd.read_excel(file_path)
valid_count = 0

for _, row in df.iterrows():
phone_valid = is_valid_phone(row['col2'])
id_card_valid = is_valid_id_card(row['col1'])
bank_card_valid = is_valid_bank_card(row['col4'])
email_valid = is_valid_email(row['col3'])

# 如果一行的所有数据都符合规则
if phone_valid and id_card_valid and bank_card_valid and email_valid:
valid_count += 1
print(valid_count)
return valid_count


# 计算MD5值
def calculate_md5(valid_count):
return hashlib.md5(str(valid_count).encode('utf-8')).hexdigest()

def print_valid_data(file_path):
df = pd.read_excel(file_path)
for _, row in df.iterrows():
phone_valid = is_valid_phone(row['col2'])
id_card_valid = is_valid_id_card(row['col1'])
bank_card_valid = is_valid_bank_card(row['col4'])
email_valid = is_valid_email(row['col3'])

if phone_valid and id_card_valid and bank_card_valid and email_valid:
print(f"Valid data: {row.to_dict()}")

# 主程序
def main():
file_path = 'data.xlsx' # 替换为文件路径
valid_count = read_and_process_data(file_path)
md5_result = calculate_md5(valid_count)
print_valid_data(file_path)
print(f"MD5 Result: flag{{{md5_result}}}")

if __name__ == "__main__":
main()

2025能源安全初赛部分wp
https://j1ya-22.github.io/2025/04/24/2025能源安全初赛部分wp/
作者
j1ya
发布于
2025年4月24日
许可协议