第八届西湖论剑·中国杭州网络安全安全技能大赛Misc——DSASignatureData题解

用wireshark查看过滤POST之后发现传输的信息

先用脚本提取其中的信息保存在extracted_data.json文件中

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
import pyshark
from urllib.parse import urlparse, parse_qs
import json

# 用于存储提取的数据
extracted_data = []

# 读取PCAP文件并过滤 HTTP POST 请求
cap = pyshark.FileCapture("1.pcapng", display_filter="http.request.method == POST")

# 遍历捕获的数据包,提取 HTTP POST 请求
for packet in cap:
if "HTTP" in packet:
try:
# 尝试从 packet.http.uri 获取 URI
uri = packet.http.uri if hasattr(packet.http, 'uri') else None
# 如果没有找到 uri,尝试使用 full_uri
if uri is None and hasattr(packet.http, 'request_full_uri'):
uri = packet.http.request_full_uri

if uri:
# 从 URI 中提取 userid 参数
parsed_uri = urlparse(uri)
query_params = parse_qs(parsed_uri.query)
userid = query_params.get("userid", [None])[0] # 获取userid参数

# 如果找到了userid,就继续处理
if userid:
print(f"UserID Found: {userid}")

# 提取并打印 POST 请求体数据(如果有的话)
if hasattr(packet.http, 'file_data'):
# 获取 POST 数据,数据是十六进制字符串
raw_data = packet.http.file_data
# 去掉冒号,将十六进制字符串转为字节
raw_data_no_colon = raw_data.replace(":", "")

try:
# 将十六进制字符串转换为字节
byte_data = bytes.fromhex(raw_data_no_colon)
decoded_data = byte_data.decode('utf-8')

# 处理 Unicode 转义字符
decoded_data = decoded_data.encode('utf-8').decode('unicode_escape')

# 提取 name, idcard, phone
data = json.loads(decoded_data)
if all(k in data for k in ['name', 'idcard', 'phone']):
# 将 userid, name, idcard, phone 保存到字典中
extracted_data.append({
"userid": userid,
"name": data["name"],
"idcard": data["idcard"],
"phone": data["phone"]
})
except UnicodeDecodeError:
print("Unable to decode POST data as UTF-8.")

except AttributeError as e:
print(f"Error parsing packet: {e}")

# 将提取的数据保存到一个 JSON 文件
with open("extracted_data.json", "w", encoding="utf-8") as f:
json.dump(extracted_data, f, ensure_ascii=False, indent=4)

print(f"Extracted data saved to extracted_data.json")

再对json文件进行转换,其中包含排序和去重操作,并保存在output_sorted_unique.csv中

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
import csv
import json

# 假设你的数据在 extracted_data.json 中,首先读取数据
with open("extracted_data.json", "r", encoding="utf-8") as f:
json_data = json.load(f)

# 如果数据是字典格式(仅有一个记录),将其转换为列表
if isinstance(json_data, dict):
json_data = [json_data]

# 将所有字段转换为文本,确保统一格式
for entry in json_data:
for key in entry:
entry[key] = str(entry[key]) # 将每个字段转换为字符串

# 去重:使用集合对去重
unique_data = {tuple(entry.items()) for entry in json_data}

# 将去重后的数据重新转换为字典
unique_data = [dict(item) for item in unique_data]

# 排序:根据 userid 排序,确保按数字顺序排序
unique_data.sort(key=lambda x: int(x["userid"])) # 按照 userid 排序,先转成整数


# 指定输出的 CSV 文件名称
csv_file = "output_sorted_unique.csv"

# 打开 CSV 文件进行写入
with open(csv_file, mode='w', newline='', encoding='utf-8') as file:
# 创建 DictWriter 对象,字段名称根据 JSON 字典的键来设置
fieldnames = ["userid", "name", "idcard", "phone"]
writer = csv.DictWriter(file, fieldnames=fieldnames)

# 写入表头
writer.writeheader()

# 写入每一行数据
writer.writerows(unique_data)

print(f"CSV 文件已保存为 {csv_file}")

下面就开始对签名进行验证,并将验证不成功即被篡改的数据放到flag.csv中

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 csv
from Crypto.PublicKey import DSA
from Crypto.Signature import DSS
from Crypto.Hash import SHA256
import base64

# 1. 加载公钥
def load_public_key(filename):
with open(filename, 'rb') as f:
key = DSA.import_key(f.read())
return key

# 2. 验证数字签名
def verify_signature(data, signature, public_key):
h = SHA256.new(data.encode()) # 计算数据的哈希值
verifier = DSS.new(public_key, 'fips-186-3') # 使用DSA算法进行签名验证
try:
# 解码Base64签名并验证
verifier.verify(h, base64.b64decode(signature))
return True # 验证通过
except ValueError:
return False # 验证失败

# 3. 读取数据文件并进行签名验证
def validate_signatures(data_file, signature_file, flag_file):
# 打开flag.csv文件,用于保存验证失败的记录
with open(flag_file, 'w', newline='', encoding='utf-8') as f_flag:
flag_writer = csv.writer(f_flag)
flag_writer.writerow(['userid', 'name', 'idcard', 'phone']) # 写入表头

# 读取数据文件和签名文件
with open(data_file, 'r', encoding='utf-8') as f_data, open(signature_file, 'r', encoding='utf-8') as f_sig:
reader_data = csv.reader(f_data)
reader_sig = csv.reader(f_sig)

# 跳过标题行
next(reader_data)
next(reader_sig)

# 对每一行数据进行签名验证
for data_row, sig_row in zip(reader_data, reader_sig):
userid, name, idcard, phone = data_row
username, name_signature, idcard_signature, phone_signature = sig_row

# 获取对应用户的公钥
public_key_filename = f"public/public-{userid.zfill(4)}.pem"
public_key = load_public_key(public_key_filename)

# 验证每个字段的签名
is_name_valid = verify_signature(name, name_signature, public_key)
is_idcard_valid = verify_signature(idcard, idcard_signature, public_key)
is_phone_valid = verify_signature(phone, phone_signature, public_key)

# 检查是否有任意一项验证失败
if not is_name_valid or not is_idcard_valid or not is_phone_valid:
# 如果有验证失败,则将这一行写入flag.csv
flag_writer.writerow([userid, name, idcard, phone])

# 输出验证结果
print(f"用户{userid}验证结果:")
print(f" 姓名签名验证{'通过' if is_name_valid else '失败'}")
print(f" 身份证签名验证{'通过' if is_idcard_valid else '失败'}")
print(f" 电话签名验证{'通过' if is_phone_valid else '失败'}")
print("-" * 30)

# 文件路径
data_file = 'output_sorted_unique.csv' # 你的数据文件
signature_file = 'data-sign.csv' # 你的签名文件
flag_file = 'flag.csv' # 保存验证失败记录的文件

# 执行签名验证并保存不通过的数据到flag.csv
validate_signatures(data_file, signature_file, flag_file)

最终在平台提交flag.csv得到flag

提交即可