碎碎念

第一次参加这个赛,因为一些原因,组好队了才知道只有web misc 和crypto方向的题,队伍里只有我一个对得上的,最后只能独自奋战了。不过比较好的是红明谷的题目难度还可以,不算难。misc这边全都是脚本题,有对应思路搞个脚本就做出来了(甚至直接gpt) 最后拿了个44名,还不错,下次数字中国积分赛争取能跟队友们冲个决赛qwq

异常行为溯源

知识点省流

本题考查流量取证

WP

用tshark把data.data导出,然后写脚本解码,最后统计哪个ip最多

tshark导出(有很多奇怪的协议导不出来,但其实不影响)

1tshark -r network_traffic.pcapng -T fields -e data.data > data.txt

用脚本处理数据

 1import base64
 2import json
 3
 4def hex_to_ascii(file_path, output_path):
 5    try:
 6        with open(file_path, 'r', encoding='utf-8') as infile, open(output_path, 'w', encoding='utf-8') as outfile:
 7            for line in infile:
 8                line = line.strip()  # 去除换行符和空格
 9                try:
10                    ascii_text = bytes.fromhex(line).decode('ascii')  # hex解码
11                    base64_decoded_text = base64.b64decode(ascii_text).decode('utf-8')  # Base64 解码
12                    json_data = json.loads(base64_decoded_text)  # 解析JSON数据
13                    if 'msg' in json_data:
14                        base64_encoded_msg = json_data['msg']  # 提取msg字段
15                        final_decoded_msg = base64.b64decode(base64_encoded_msg).decode('utf-8')  # 再次Base64解码
16                        outfile.write(final_decoded_msg + '\n')
17                except (ValueError, base64.binascii.Error, UnicodeDecodeError, json.JSONDecodeError):
18                    print(f"无法解码的行: {line}")
19    except FileNotFoundError:
20        print("文件未找到,请检查路径是否正确!")
21
22# 示例用法
23input_file = "data.txt"  # 你的hex编码数据文件
24output_file = "decoded_output.txt"  # 解码后的输出文件
25hex_to_ascii(input_file, output_file)
26print("解码完成,结果已保存到", output_file)

导入linux,统计ip出现次数,最多那个就是flag

1cat decoded_output.txt | awk '{print$1}' | sort | uniq -c | sort -nr | more

数据校验

知识点省流

本题考查写脚本

WP

1742653854156

要保证每一条都是合规,要注意ip也得检验(要符合xxx.xxx.xxx.xxx,xxx不能大于255)

 1import csv
 2import hashlib
 3import re
 4import ecdsa
 5import base64
 6import os
 7
 8
 9def md5_hash(value):
10    return hashlib.md5(value.encode('utf-8')).hexdigest()
11
12
13def verify_signature(serial_number, username, signature):
14    try:
15        # Ensure the public key file exists based on the serial_number
16        public_key_file = os.path.join('ecdsa-key', f"{serial_number}.pem")
17
18        if not os.path.isfile(public_key_file):
19            raise FileNotFoundError(f"公钥文件未找到: {public_key_file}")
20
21        # Read the public key from the file
22        with open(public_key_file, 'r') as key_file:
23            public_key = key_file.read()
24
25        verifier = ecdsa.VerifyingKey.from_pem(public_key)
26        signature_bytes = base64.b64decode(signature)
27        verifier.verify(signature_bytes, username.encode('utf-8'))
28        return True
29    except (ecdsa.BadSignatureError, ValueError, FileNotFoundError) as e:
30        print(f"验证签名失败: {e}")
31        return False
32
33
34def validate_row(index, row):
35    errors = []
36
37    # 校验 UserName 格式
38    if not re.fullmatch(r'User-\w+', row[1]):
39        errors.append("UserName 格式错误")
40
41    # 校验 UserName_Check
42    if row[2] != md5_hash(row[1]):
43        errors.append("UserName_Check 错误")
44
45    # 校验 Password 格式
46    if not re.fullmatch(r'[A-Za-z0-9]+', row[3]):
47        errors.append("Password 格式错误")
48
49    # 校验 Password_Check
50    if row[4] != md5_hash(row[3]):
51        errors.append("Password_Check 错误")
52
53    # 校验 Signature
54    if not verify_signature(row[0],row[1], row[6]):  # Use Serial_Number for public key lookup
55        errors.append("Signature 校验失败")
56
57    # 校验 IP 格式
58    ip = row[5]
59    ip_pattern = r"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
60    if not re.match(ip_pattern, ip):
61        errors.append("IP 格式错误")
62
63    if errors:
64        print(f"第 {index + 1} 行数据不合规: {', '.join(errors)}")
65
66
67def read_csv(file_path):
68    with open(file_path, mode='r', encoding='utf-8') as file:
69        reader = csv.reader(file)
70        headers = next(reader)  # 读取并跳过表头
71
72        for index, row in enumerate(reader):
73            validate_row(index, row)
74
75
76# 示例调用
77csv_file_path = "data.csv"  # 请将此路径更改为你的 CSV 文件路径
78read_csv(csv_file_path)

Strange_Database

知识点省流

本题考查脚本小子,rc4加密,rsa加密 pem私钥解密

WP

500个db文件里的数据都进行了RSA加密,要写脚本解出来

同时每个pem文件都用openssl加密过,也要逐一解密

看了一下key里面的私钥,都是加密过的,数量太多只能用脚本解了

 1#!/usr/bin/env python3
 2import glob
 3import os
 4from cryptography.hazmat.primitives import serialization
 5from cryptography.hazmat.backends import default_backend
 6
 7
 8def decrypt_pem_file(filename):
 9    # 读取加密的 PEM 文件
10    with open(filename, "rb") as f:
11        encrypted_key = f.read()
12
13    # 从文件名中提取密码:取最后一个 '-' 后面的部分,去除扩展名
14    base_name = os.path.basename(filename)
15    password_with_ext = base_name.split('-')[-1]
16    password = password_with_ext.rsplit('.', 1)[0]
17
18    try:
19        # 加载并解密 PEM 文件,password 需要为字节串
20        private_key = serialization.load_pem_private_key(
21            encrypted_key,
22            password=password.encode(),
23            backend=default_backend()
24        )
25    except Exception as e:
26        print(f"文件 {filename} 解密失败:{e}")
27        return None
28
29    # 将解密后的私钥转换为不加密的 PEM 格式
30    try:
31        decrypted_key = private_key.private_bytes(
32            encoding=serialization.Encoding.PEM,
33            format=serialization.PrivateFormat.TraditionalOpenSSL,
34            encryption_algorithm=serialization.NoEncryption()
35        )
36    except Exception as e:
37        print(f"序列化私钥时出错 {filename}: {e}")
38        return None
39
40    return decrypted_key
41
42
43def batch_decrypt():
44    output_dir = "decrypted"
45    if not os.path.exists(output_dir):
46        os.makedirs(output_dir)
47
48    # 遍历当前目录下所有符合 OAEP-*.pem 格式的文件
49    pem_files = glob.glob("key/OAEP-*.pem")
50    if not pem_files:
51        print("未找到符合格式的 PEM 文件。")
52        return
53
54    counter = 0  # Initialize the counter
55
56    for pem_file in pem_files:
57        print(f"正在解密文件 {pem_file} ...")
58        decrypted_key = decrypt_pem_file(pem_file)
59        if decrypted_key:
60            output_file = os.path.join(output_dir, f"OAEP-{counter}.pem")  # Use the counter for the output file name
61            with open(output_file, "wb") as f:
62                f.write(decrypted_key)
63            print(f"文件 {pem_file} 解密成功,输出文件为 {output_file}\n")
64            counter += 1  # Increment the counter for the next file
65        else:
66            print(f"文件 {pem_file} 解密失败。\n")
67
68
69if __name__ == "__main__":
70    batch_decrypt()

解完再读取db文件再去解密db里的数据

  1import glob
  2import os
  3import sqlite3
  4from time import sleep
  5
  6from Crypto.PublicKey import RSA
  7from Crypto.Cipher import PKCS1_OAEP
  8import base64
  9
 10
 11def read_db_data(db_file):
 12    # 连接到 SQLite 数据库
 13    conn = sqlite3.connect(db_file)
 14
 15    # 创建一个游标对象,用于执行 SQL 查询
 16    cursor = conn.cursor()
 17
 18    try:
 19        # 执行查询,获取所有表的名字
 20        cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
 21        tables = cursor.fetchall()
 22
 23        if tables:
 24            table_name = tables[0][0]  # 假设我们选择第一个表
 25
 26            # 执行查询,读取表中的数据
 27            cursor.execute(f"SELECT * FROM {table_name};")
 28            rows = cursor.fetchall()
 29
 30            decoded_data = []  # 用于存储所有解码的数据
 31            # 假设数据在第四列(索引为3)
 32            for row in rows:
 33                # 将解码后的数据加入列表
 34                decoded_data.append(base64.b64decode(row[0]))
 35            # print(decoded_data)
 36            return decoded_data  # 返回所有解码后的数据
 37
 38    except sqlite3.Error as e:
 39        print(f"Error reading the database: {e}")
 40    finally:
 41        # 关闭连接
 42        conn.close()
 43
 44
 45def rsa_decrypt(private_key_path, ciphertext):
 46    # 从文件读取私钥
 47    with open(private_key_path, 'rb') as f:
 48        private_key_pem = f.read()
 49
 50    private_key = RSA.import_key(private_key_pem)
 51    cipher = PKCS1_OAEP.new(private_key)
 52
 53    # 解密
 54    decrypted_data = cipher.decrypt(ciphertext)
 55    return decrypted_data.decode()
 56
 57
 58def process_db_and_pem_files(db_directory, pem_directory, output_file):
 59    """处理所有的DB和PEM文件并将解密结果保存到一个txt文件中"""
 60    with open(output_file, 'wb') as out_file:
 61        for i in range(500):
 62            # DB文件路径
 63            db_file_path = os.path.join(db_directory, f'database-{i}.db')
 64
 65            # 查找匹配的PEM文件,格式为 'OAEP-i-xxxxxx-decrypted'
 66            pem_file_pattern = os.path.join(pem_directory, f'OAEP-{i}-*.pem')
 67            pem_files = glob.glob(pem_file_pattern)
 68
 69            if not pem_files:
 70                print(f"没有找到匹配的PEM文件: {pem_file_pattern}")
 71                continue
 72
 73            # 选择找到的第一个PEM文件
 74            pem_file_path = pem_files[0]
 75
 76            # 确保DB文件和PEM文件都存在
 77            if not os.path.exists(db_file_path) or not os.path.exists(pem_file_path):
 78                print(f"文件不存在: {db_file_path}{pem_file_path}")
 79                continue
 80
 81            # 读取DB文件的加密数据
 82            encrypted_data = read_db_data(db_file_path)
 83
 84            # 解密数据
 85            try:
 86                for t in range(20):
 87                    decrypted_data = rsa_decrypt(pem_file_path, encrypted_data[t])
 88                    # print(decrypted_data)
 89                    # 将解密后的数据追加到输出文件
 90                    out_file.write(decrypted_data.encode())  # 将字符串转换为字节写入文件
 91                    out_file.write(b'\n')  # 可以加一个换行符分隔每个文件的内容
 92
 93
 94            except Exception as e:
 95                print(f"解密文件 {db_file_path} 时发生错误: {e}")
 96
 97
 98if __name__ == '__main__':
 99    db_directory = 'database'  # DB文件所在的目录
100    pem_directory = 'decrypted'  # PEM文件所在的目录
101    output_file = 'output/decrypted_data3.txt'  # 总的解密结果保存文件
102
103    process_db_and_pem_files(db_directory, pem_directory, output_file)

将其中一db文件用在线db查看网站查看一下可以看到有如下字段

解密完所有数据后导出Type一列,再简单处理一下会发现里面有Enc和Key两个比较特别的用户,不难看出一个对应密文一个对应密钥

0184cfc6-ca3e-4241-a060-6e686c886686

猜测是某种带Key的加密,分别将他们其对应行号的Remark值拼接,最后用RC4解密即可

1742653947356