-联合战队|共同成长-
此次赛事由中国密码学会、宁夏回族自治区密码管理局、中国科学院大学密码学院支持,国家信息技术安全研究中心联合密码科技国家工程研究中心主办,采取线下赛方式,通过模拟仿真重要行业领域密码应用典型场景,预置密码算法模式配置、密钥管理、密码协议、密码服务、网络安全等方面密码应用安全缺陷和网络安全漏洞,综合检验参赛队伍在密码应用安全缺陷识别、密码算法功能编程调用、网络协议数据解析、网络和系统配置核查、源代码审计等方面的实战技能。
初始谜题3
爆破了一下e、尝试解矩阵方程得到s然后拿来解密 思路不太严谨,但是因为答案交对了所以不再深究
from sage.all import *
import sympy as sp
n = 16
q = 251 # 模数
A=sp.Matrix([[147, 237, 27, 163, 107, 149, 136, 159, 71, 190, 44, 102, 109, 208, 237, 14], [124, 77, 87, 82, 28, 109, 223, 25, 140, 42, 214, 144, 156, 221, 126, 163], [27, 130, 111, 70, 209, 48, 240, 150, 116, 28, 225, 218, 154, 8, 0, 116], [74, 237, 235, 17, 37, 182, 26, 50, 11, 86, 40, 156, 207, 30, 48, 49], [248, 7, 35, 249, 153, 181, 244, 210, 239, 223, 198, 107, 196, 53, 65, 135], [171, 152, 239, 97, 168, 232, 94, 184, 100, 47, 143, 147, 113, 175, 79, 38], [132, 46, 95, 230, 20, 139, 13, 73, 101, 172, 20, 76, 65, 111, 49, 237], [138, 21, 191, 138, 180, 95, 69, 120, 83, 215, 223, 112, 79, 193, 175, 246], [245, 191, 174, 248, 72, 26, 108, 118, 199, 133, 217, 0, 177, 163, 67, 103], [22, 192, 6, 87, 20, 13, 246, 171, 10, 201, 0, 155, 194, 37, 65, 248], [146, 226, 103, 6, 162, 185, 167, 137, 146, 244, 146, 247, 10, 218, 108, 100], [73, 109, 188, 121, 192, 85, 70, 37, 191, 214, 154, 30, 50, 83, 65, 6], [88, 1, 75, 89, 160, 20, 175, 150, 99, 214, 157, 82, 56, 148, 118, 30], [130, 25, 43, 25, 1, 13, 157, 28, 108, 107, 240, 161, 88, 119, 49, 75], [243, 202, 232, 128, 207, 193, 217, 94, 9, 103, 139, 55, 205, 0, 196, 10], [97, 191, 247, 139, 82, 119, 115, 52, 164, 195, 124, 220, 167, 21, 48, 156]])
b=sp.Matrix([[1], [205], [220], [195], [79], [84], [137], [199], [11], [135], [23], [215], [137], [69], [185], [142]])
c1=sp.Matrix([[221, 248, 111, 189, 226, 212, 98, 237, 177, 241, 172, 42, 182, 168, 61, 86], [209, 150, 184, 182, 115, 71, 185, 48, 50, 90, 14, 4, 128, 107, 232, 7], [153, 54, 92, 32, 45, 98, 183, 5, 5, 170, 149, 113, 102, 38, 89, 110], [245, 141, 250, 97, 179, 212, 122, 85, 175, 47, 9, 212, 197, 161, 241, 248], [145, 213, 8, 112, 121, 160, 151, 75, 124, 205, 224, 150, 79, 231, 24, 160], [84, 128, 143, 246, 213, 224, 175, 235, 86, 44, 205, 118, 75, 142, 176, 119], [30, 203, 214, 105, 51, 102, 71, 206, 103, 9, 185, 197, 120, 227, 72, 174], [222, 65, 98, 182, 29, 29, 247, 233, 102, 213, 50, 208, 20, 56, 52, 10], [243, 91, 95, 4, 26, 110, 53, 57, 51, 129, 5, 83, 38, 37, 118, 207], [44, 15, 22, 53, 6, 142, 32, 75, 47, 162, 230, 202, 49, 10, 31, 41], [30, 88, 188, 161, 117, 149, 58, 204, 37, 38, 38, 16, 201, 182, 119, 18], [142, 93, 195, 175, 114, 148, 174, 25, 161, 186, 234, 159, 155, 224, 170, 148], [2, 123, 101, 106, 109, 241, 105, 173, 9, 215, 133, 88, 158, 122, 210, 216], [236, 228, 20, 88, 93, 188, 192, 158, 65, 178, 246, 242, 104, 130, 168, 226], [243, 233, 7, 182, 115, 110, 89, 53, 15, 73, 164, 51, 181, 71, 134, 109], [119, 107, 81, 25, 110, 35, 220, 90, 84, 153, 151, 84, 225, 97, 160, 7]])
c2=sp.Matrix([[82], [77], [135], [145], [7], [51], [36], [204], [73], [123], [200], [36], [142], [185], [108], [111]])
def decrypt(c1, c2, s):
m_dec = (c2 - c1 * s) % q
m_rec = m_dec.applyfunc(lambda x: round(2 * x / q) % 2) # 还原消息
m_bin = ''.join([str(bit) for bit in m_rec]) # 将SymPy矩阵转换为二进制字符串
m_rec_int = int(m_bin, 2) # 将二进制字符串转换为整数
return m_rec_int
from tqdm import trange
Ainv = A.inv_mod(q)
for e in trange(2**16):
try:
e = sp.Matrix(list(map(int, bin(e)[2:].zfill(16))))
s = Ainv * (b - e)
m = decrypt(c1, c2, s)
print(s)
print(m)
print(hex(m))
break
except Exception as e:
print(e)
continue
初始谜题1
用第一块已知明文计算得到k然后解密
from sympy import Mod, Integer
from sympy.core.numbers import mod_inverse
def decrypt_message(encrypted_message, key):
num_blocks = len(encrypted_message) // 32
blocks = [encrypted_message[i * 32:(i + 1) * 32] for i in range(num_blocks)]
decrypted_blocks = []
k = key
# 解密每个分组
for block in blocks:
block_int = int.from_bytes(block, byteorder='big')
key_inv = mod_inverse(k, MODULUS)
decrypted_block_int = Mod(block_int * key_inv, MODULUS)
decrypted_blocks.append(decrypted_block_int)
k += 1 # 密钥自增1
# 将解密后的分组连接成最终的明文
decrypted_message = b''.join(
int(block_int).to_bytes(16, byteorder='big') for block_int in decrypted_blocks
)
# 去除前缀
if decrypted_message.startswith(MSG_PREFIX.encode('utf-8')):
decrypted_message = decrypted_message[len(MSG_PREFIX):]
return decrypted_message.rstrip(b'x00').decode('utf-8')
# 模数
N_HEX = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
MODULUS = Integer(int(N_HEX, 16))
MSG_PREFIX = "CryptoCup message:"
c = 'c19ab1f9004f4146bfebc26651ffa839baaad49375cfba3b6a64e86b6447a1fe296be2a43dc5a91a7faf3b6b339ec36ec4cb656b98dd609b8982a6bf81484255c004ce89ae0c6969883d389d66bacd69b87cff758c68df1eefc2c2b66e9e520b1816195a55fd6759c6c23f945c5c32e1fc5da4e192c832033658fb71fefd6287'
c = bytes.fromhex(c)
num_blocks = len(c) // 32
blocks = [c[i * 32:(i + 1) * 32] for i in range(num_blocks)]
block = MSG_PREFIX[:16].encode()
k = int.from_bytes(blocks[0], byteorder='big') * mod_inverse(int.from_bytes(block, byteorder='big'), MODULUS)
print(k)
msg = decrypt_message(c, k)
print(msg)
初始谜题2
sm3 hash extend attack
from functools import reduce
import struct
BIT_BLOCK_H = [0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF]
BIT_BLOCK_L = [0x0, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF]
BIT_EACH = [1, 2, 4, 8, 16, 32, 64, 128, 256]
BIT_EACH_32 = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144,
524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456,
536870912, 1073741824, 2147483648, 4294967296]
IV = [1937774191, 1226093241, 388252375, 3666478592, 2842636476, 372324522, 3817729613, 2969243214]
def rotate_left(a, k):
k %= 32
high, low = divmod(a, BIT_EACH_32[32 - k])
return high + low * BIT_EACH_32[k]
T_j = [0x79cc4519] * 16 + [0x7a879d8a] * 48
T_j_rotate_left = [rotate_left(Tj, j) for j, Tj in enumerate(T_j)]
def PUT_UINT32_BE(n):
return [int((n >> 24) & 0xff), int((n >> 16) & 0xff), int((n >> 8) & 0xff), int(n & 0xff)]
def CF(V_i, B_i):
W = [(B_i[ind] * BIT_EACH_32[24]) + (B_i[ind + 1] * BIT_EACH_32[16]) + (B_i[ind + 2] * BIT_EACH_32[8]) + (
B_i[ind + 3]) for ind in range(0, 64, 4)]
for j in range(16, 68):
high_W3_15, low_W3_15 = divmod(W[-3], BIT_EACH_32[17])
high_W13_7, low_W13_7 = divmod(W[-13], BIT_EACH_32[25])
# P_1
X = W[- 16] ^ W[- 9] ^ (high_W3_15 + low_W3_15 * BIT_EACH_32[15])
high_P1_15, low_P1_15 = divmod(X, BIT_EACH_32[17])
r_l_15 = high_P1_15 + low_P1_15 * BIT_EACH_32[15]
high_P1_23, low_P1_23 = divmod(X, BIT_EACH_32[9])
r_l_23 = high_P1_23 + low_P1_23 * BIT_EACH_32[23]
# return X ^ (rotate_left(X, 15)) ^ (rotate_left(X, 23))
W.append(X ^ r_l_15 ^ r_l_23 ^ (high_W13_7 + low_W13_7 * BIT_EACH_32[7]) ^ W[- 6])
# W.append(P_1(W[- 16] ^ W[- 9] ^ (high_W3_15 + low_W3_15 * BIT_EACH_32[15])) ^ (
# high_W13_7 + low_W13_7 * BIT_EACH_32[7]) ^ W[- 6])
W_1 = [W[j] ^ W[j + 4] for j in range(64)]
A, B, C, D, E, F, G, H = V_i
for j in range(0, 16):
high_A12, low_A12 = divmod(A, BIT_EACH_32[20])
r_l_12 = high_A12 + low_A12 * BIT_EACH_32[12]
high, low = divmod((r_l_12 + E + T_j_rotate_left[j]) & 0xFFFFFFFF, BIT_EACH_32[25])
SS1 = high + low * BIT_EACH_32[7]
SS2 = SS1 ^ r_l_12
# Wj = (B_i[ind] * BIT_EACH_32[24]) + (B_i[ind + 1] * BIT_EACH_32[16]) + (B_i[ind + 2] * BIT_EACH_32[8]) + (B_i[ind + 3])
# FF
TT1 = ((A ^ B ^ C) + D + SS2 + W_1[j]) & 0xFFFFFFFF
# GG
TT2 = ((E ^ F ^ G) + H + SS1 + W[j]) & 0xFFFFFFFF
high_B9, low_B9 = divmod(B, BIT_EACH_32[23])
high_F19, low_F19 = divmod(F, BIT_EACH_32[13])
high, low = divmod(TT2, BIT_EACH_32[23])
r_l_9 = high + low * BIT_EACH_32[9]
high, low = divmod(TT2, BIT_EACH_32[15])
r_l_17 = high + low * BIT_EACH_32[17]
A, B, C, D, E, F, G, H = TT1, A, high_B9 + low_B9 * BIT_EACH_32[9] & 0xffffffff, C, (
TT2 ^ r_l_9 ^ r_l_17) & 0xffffffff, E, high_F19 + low_F19 * BIT_EACH_32[19] & 0xffffffff, G
for j in range(16, 64):
high_A12, low_A12 = divmod(A, BIT_EACH_32[20])
r_l_12 = high_A12 + low_A12 * BIT_EACH_32[12]
high, low = divmod((r_l_12 + E + T_j_rotate_left[j]) & 0xFFFFFFFF, BIT_EACH_32[25])
SS1 = high + low * BIT_EACH_32[7]
SS2 = SS1 ^ r_l_12
# FF
TT1 = (((A & B) | (A & C) | (B & C)) + D + SS2 + W_1[j]) & 0xFFFFFFFF
# GG
TT2 = (((E & F) | ((~ E) & G)) + H + SS1 + W[j]) & 0xFFFFFFFF
high_B9, low_B9 = divmod(B, BIT_EACH_32[23])
high_F19, low_F19 = divmod(F, BIT_EACH_32[13])
high, low = divmod(TT2, BIT_EACH_32[23])
r_l_9 = high + low * BIT_EACH_32[9]
high, low = divmod(TT2, BIT_EACH_32[15])
r_l_17 = high + low * BIT_EACH_32[17]
A, B, C, D, E, F, G, H = TT1, A, high_B9 + low_B9 * BIT_EACH_32[9] & 0xffffffff, C, (
TT2 ^ r_l_9 ^ r_l_17) & 0xffffffff, E, high_F19 + low_F19 * BIT_EACH_32[19] & 0xffffffff, G
return [A ^ V_i[0], B ^ V_i[1], C ^ V_i[2],
D ^ V_i[3], E ^ V_i[4], F ^ V_i[5], G ^ V_i[6], H ^ V_i[7]]
# def CFs(V_i):
def digest(msg, state=(IV, 0)):
msg = str2bytes(msg)
cur_v, cur_len = state
len1 = len(msg) + cur_len
msg.append(0x80)
reserve1 = len1 % 64 + 1
range_end = 56 if reserve1 <= 56 else 120
msg.extend([0] * (range_end - reserve1))
bit_length = len1 * 8
msg.extend(struct.pack(">Q", bit_length))
B = (msg[i:i + 64] for i in range(0, len(msg), 64))
y = reduce(CF, B, cur_v)
b = bytearray()
[b.extend(PUT_UINT32_BE(each)) for each in y]
return bytes(b)
def str2bytes(msg: str, encoding='utf-8'):
"""字符串转换成byte数组"""
msg_bytearray = msg.encode(encoding) if isinstance(msg, str) else msg
return list(msg_bytearray)
def byte2str(msg, decode='utf-8'):
"""byte数组转字符串"""
return msg.decode(decode) if isinstance(msg, (bytes, bytearray)) else msg
def hex2byte(msg):
"""16进制字符串转换成byte列表"""
if not isinstance(msg, str):
raise ValueError('message must be string')
ml = len(msg)
if (ml & 1) != 0:
msg = '0' + msg
return list(bytes.fromhex(msg))
from SM3 import digest as hash_func
import struct
H = hash_func
def attack(pub, apd):
"""
forge based on pub
:param pub: public info
:param apd: data appended bt attacker
:return: forgery
"""
def create_pad(len1):
pad = [0x80]
reserve1 = len1 % 64 + 1
range_end = 56 if reserve1 <= 56 else 120
pad.extend([0] * (range_end - reserve1))
bit_length = len1 * 8
pad.extend(struct.pack(">Q", bit_length))
return bytes(pad)
pub_msg, pub_hsh, sec_len = pub
pad = create_pad(sec_len + len(pub_msg))
msg = pub_msg + pad + apd
cur_v = int.from_bytes(pub_hsh, byteorder="big")
cur_v = [(cur_v >> ((7 - i) * 32)) & 0xFFFFFFFF for i in range(8)]
cur_len = sec_len + len(pub_msg) + len(pad)
state = cur_v, cur_len
sig = H(apd, state)
return msg, sig
counter = 0x55c4c7ef
token = 'ba4f92230b5d4c71c1670955d64fe9e6110fec33558caf64db751c3bc60f45cc'
AppendData, GeneratedHash = attack((
counter.to_bytes((counter.bit_length() + 7) // 8, 'big'),
bytes.fromhex(token),
32),
(counter + 1).to_bytes((counter.bit_length() + 7) // 8, 'big'))
print(AppendData.hex())
print(GeneratedHash.hex())
gitea服务器
写出解密算法后爆破key
#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
#define ROUND 16
//S-Box 16x16
int sBox[16] =
{
2, 10, 4, 12,
1, 3, 9, 14,
7, 11, 8, 6,
5, 0, 15, 13
};
int inv_sBox[16] = {13, 4, 0, 5, 2, 12, 11, 8, 10, 6, 1, 9, 3, 15, 7, 14};
// 将十六进制字符串转换为 unsigned char 数组
void hex_to_bytes(const char* hex_str, unsigned char* bytes, size_t bytes_len) {
size_t hex_len = strlen(hex_str);
if (hex_len % 2 != 0 || hex_len / 2 > bytes_len) {
fprintf(stderr, "Invalid hex string length.n");
return;
}
for (size_t i = 0; i < hex_len / 2; i++) {
sscanf(hex_str + 2 * i, "%2hhx", &bytes[i]);
}
}
// 派生轮密钥
void derive_round_key(unsigned int key, unsigned char *round_key, int length) {
unsigned int tmp = key;
for(int i = 0; i < length / 16; i++)
{
memcpy(round_key + i * 16, &tmp, 4); tmp++;
memcpy(round_key + i * 16 + 4, &tmp, 4); tmp++;
memcpy(round_key + i * 16 + 8, &tmp, 4); tmp++;
memcpy(round_key + i * 16 + 12, &tmp, 4); tmp++;
}
}
// 比特逆序
void reverseBits(unsigned char* state) {
unsigned char temp[16];
for (int i = 0; i < 16; i++) {
unsigned char byte = 0;
for (int j = 0; j < 8; j++) {
byte |= ((state[i] >> j) & 1) << (7 - j);
}
temp[15 - i] = byte;
}
for (int i = 0; i < 16; i++) {
state[i] = temp[i];
}
}
void sBoxTransform(unsigned char* state) {
for (int i = 0; i < 16; i++) {
int lo = sBox[state[i] & 0xF];
int hi = sBox[state[i] >> 4];
state[i] = (hi << 4) | lo;
}
}
void inv_sBoxTransform(unsigned char* state) {
for (int i = 0; i < 16; i++) {
int lo = inv_sBox[state[i] & 0xF];
int hi = inv_sBox[state[i] >> 4];
state[i] = (hi << 4) | lo;
}
}
void leftShiftBytes(unsigned char* state) {
unsigned char temp[16];
for (int i = 0; i < 16; i += 4) {
temp[i + 0] = state[i + 2] >> 5 | (state[i + 1] << 3);
temp[i + 1] = state[i + 3] >> 5 | (state[i + 2] << 3);
temp[i + 2] = state[i + 0] >> 5 | (state[i + 3] << 3);
temp[i + 3] = state[i + 1] >> 5 | (state[i + 0] << 3);
}
for (int i = 0; i < 16; i++)
{
state[i] = temp[i];
}
}
void inv_leftShiftBytes(unsigned char* state) {
unsigned char temp[16];
for (int i = 0; i < 16; i += 4) {
// temp[i + 0] = state[i + 2] >> 5 | (state[i + 1] << 3);
// temp[i + 1] = state[i + 3] >> 5 | (state[i + 2] << 3);
// temp[i + 2] = state[i + 0] >> 5 | (state[i + 3] << 3);
// temp[i + 3] = state[i + 1] >> 5 | (state[i + 0] << 3);
temp[i + 0] = (state[i + 3] >> 3) | (state[i + 2] << 5);
temp[i + 1] = (state[i + 0] >> 3) | (state[i + 3] << 5);
temp[i + 2] = (state[i + 1] >> 3) | (state[i + 0] << 5);
temp[i + 3] = (state[i + 2] >> 3) | (state[i + 1] << 5);
}
for (int i = 0; i < 16; i++)
{
state[i] = temp[i];
}
}
// 轮密钥加
void addRoundKey(unsigned char* state, unsigned char* roundKey, unsigned int round) {
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 8; j++) {
state[i] ^= ((roundKey[i + round * 16] >> j) & 1) << j;
}
}
}
// 加密函数
void encrypt(unsigned char* password, unsigned int key, unsigned char* ciphertext) {
unsigned char roundKeys[16 * ROUND] = {}; //
// 生成轮密钥
derive_round_key(key, roundKeys, 16 * ROUND);
// 初始状态为16字节的口令
unsigned char state[16]; // 初始状态为16字节的密码
memcpy(state, password, 16); // 初始状态为密码的初始值
// 迭代加密过程
for (int round = 0; round < ROUND; round++)
{
reverseBits(state);
sBoxTransform(state);
leftShiftBytes(state);
addRoundKey(state, roundKeys, round);
}
memcpy(ciphertext, state, 16);
}
void decrypt(unsigned char* ciphertext, unsigned int key, unsigned char* plaintext) {
unsigned char roundKeys[16 * ROUND] = {}; //
// 生成轮密钥
derive_round_key(key, roundKeys, 16 * ROUND);
// 初始状态为16字节的口令
unsigned char state[16]; // 初始状态为16字节的密码
memcpy(state, ciphertext, 16); // 初始状态为密码的初始值
// 迭代加密过程
for (int round = ROUND - 1; round >= 0; round--)
{
addRoundKey(state, roundKeys, round);
inv_leftShiftBytes(state);
inv_sBoxTransform(state);
reverseBits(state);
}
memcpy(plaintext, state, 16);
}
int main() {
unsigned char ciphertext[16]; // 16字节的状态
unsigned char plaintext[16]; // 16字节的状态
const char hex_ct[] = "99F2980AAB4BE8640D8F322147CBA409";
hex_to_bytes(hex_ct, ciphertext, 16);
for (unsigned int k = 0xFA000000; k <= 0xFFFFFFFF; ++k) {
if ((k & 0xFFFFFF) == 0) {
printf("%02Xn", k);
}
decrypt(ciphertext, k, plaintext);
if ((plaintext[0] == 112) && (plaintext[1] == 119) && (plaintext[2] == 100) && (plaintext[3] == 58)) {
printf("%02Xn", k);
printf("%sn", plaintext);
break;
}
}
}
// key = 0xFAB7C4D9
// pwd:%@PRjd8)k5TV
数据库管理系统服务器flag3
使用相同的公私钥进行注册,分别为cain1和cain2
pub:
04 b3 21 7d 88 4b c1 75 e6 ba 6b 36 0e b0 e6 d4 39 6e ae a7 25 c3 d6 6e 87 bf a5 be b6 c0 d3 45 6b a5 19 94 45 c5 4b 56 60 2a a6 00 25 e1 90 7b fd 26 b3 0e 86 7d b6 c5 8a 03 42 63 ae 4a 2e 27 c2
prv:
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
在fuzz过程中发现使用,用户名cain1,私钥,cain2的证书可以实现登陆成功
阅读源码发现登陆验证的逻辑存在问题,仅检测是否存在请求登录用户名、证书是否验证、证书用户名是否存在,并没有检测证书用户名和请求登录用户名是否相等。
数据库管理系统flag4
iv与key是线性同余产生的,由于只知道输出的高位,所以可以考虑用hnp求解内部状态 然后即可恢复key,进而解密得到流量包,找到flag4
from sage.all import *
MULTIPLIER = 6364136223846793005
ADDEND = 1
MASK = 0xffffffffffffffff
ITERATIONS = 1000
R = PolynomialRing(Zmod(MASK+1), 'x')
x = R.gens()[0]
f = x
As, Bs = list(), list()
for _ in range(4):
As.append(ZZ(f[1]))
Bs.append(ZZ(f[0]))
for i in range(ITERATIONS):
f = MULTIPLIER*f + ADDEND
print(f)
iv = '90fc5cf2e2f47488a257fd51e0ae615b'
iv = bytes.fromhex(iv)
ivs = [iv[i: i+4] for i in range(0, len(iv), 4)]
ivs = [int(_.hex(), 16) for _ in ivs]
A = matrix(ZZ, 1, 3)
B = matrix(ZZ, 1, 3)
for i in range(3):
iv0, a0, b0 = ivs[0], As[0], Bs[0]
ivi, ai, bi = ivs[i+1], As[i+1], Bs[i+1]
inv = inverse_mod(a0, 2**64)
A[0, i] = ZZ((ai)*inv % 2**64)
B[0, i] = ZZ((bi*a0 - b0*ai + iv0*2**32*ai - ivi*2**32*a0)*inv % 2**64)
L = block_matrix(ZZ, [
[1, A, 0],
[0, 2**64, 0],
[0, B, 2**64]
]).LLL()
for row in L:
if abs(row[-1]) == 2**64:
print([_.nbits() for _ in row])
e0 = abs(row[0])
iv0 = ivs[0]
s0 = iv0*2**32 + e0
for i in range(4):
si = (As[i]*s0 + Bs[i]) % 2**64
print(si >> 32, ivs[i])
print(s0)
from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT
MULTIPLIER = 6364136223846793005
ADDEND = 1
MASK = 0xffffffffffffffff
ITERATIONS = 1000
global_seed = 10447327433143939557
def genRandom():
global global_seed
# print("global_seed", hex(global_seed))
for _ in range(ITERATIONS):
global_seed = (global_seed * MULTIPLIER + ADDEND) & MASK
return (global_seed >> 32) & 0xffffffff
def HexStringToBytes(hex_str):
return bytes.fromhex(hex_str)
# bytes转16进制字符串
def BytesToHexString(byte_seq):
return byte_seq.hex()
def genSM4KeyOrIV():
return HexStringToBytes(''.join(f'{genRandom():08x}' for _ in range(4)))
def SM4Decrypt(cipher_bytes, key_bytes, iv_bytes):
sm4 = CryptSM4()
sm4.set_key(key_bytes, SM4_DECRYPT)
return sm4.crypt_cbc(iv_bytes, cipher_bytes)
x = [genRandom() for _ in range(3)]
print(x)
iv_bytes = bytes.fromhex('90fc5cf2e2f47488a257fd51e0ae615b')
key_bytes = genSM4KeyOrIV()
print("key hex:", BytesToHexString(key_bytes))
with open('cipherText.dat', 'rb') as f3:
cipher2_bytes = f3.read()
plain2_bytes = SM4Decrypt(cipher2_bytes,key_bytes,iv_bytes)
with open('plainText.pcapng', 'wb') as f4:
f4.write(plain2_bytes)
协同签名服务器
关键代码在于server产生signature时,对随机数k2、k3进行了复用 此时可以直接通过签名计算出私钥
while(BN_is_zero(k2)){
if (
!BN_rand_range(k2,n) ||
!BN_copy(k3, k2)
)
{ error(); return res; }
}
from sage.all import *
n = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123
{
"r": "17E44712AF13BCA10BEE11BBD2074F5F590FA28B59D95EE577D7179449FDBA0A",
"s2": "F3AA79E792D9B54BD66F8C1E648B142404F9DE5838C6F1789B1270E4A3E6A43D",
"s3": "D58154A727C52464F9480BD937590EBA68053411E6375FCD1947360A6D2E0729"
}
r = 0x17E44712AF13BCA10BEE11BBD2074F5F590FA28B59D95EE577D7179449FDBA0A
s2 = 0xF3AA79E792D9B54BD66F8C1E648B142404F9DE5838C6F1789B1270E4A3E6A43D
s3 = 0xD58154A727C52464F9480BD937590EBA68053411E6375FCD1947360A6D2E0729
d2 = ZZ((s3 - s2) * inverse_mod(r, n) % n)
print(hex(d2)[2:])
总经理签名提交
题目实现了client、server协同签名
对于client端,产生(P1, Q1, e, r1, s1)作为签名内容 其中:
对于server端,接收并验证client发来的签名,并进一步产生(r, s2, s3)作为签名内容 其中:
最后,client接收server发来的签名,产生(s)作为签名内容 其中:
审计cpp代码,题目的关键漏洞在于server端在产生签名时重用了随机数内容,即k2 = k3
这将导致利用server端的签名,即可计算出私钥d2,即
对于题目给出的流量包,我们已经能够计算d2的内容 进一步地,考虑结合已知数据与d2的内容计算私钥d1,有下列式子
可以发现此时未知量只有d1,因此在GFn上解线性方程即可得到私钥d1 至此,所有私钥的值已经得到,对题目给出的摘要e产生一组合法的签名即可
注意最后需要拼接r+s进行提交,而不是直接提交s,我觉得这是题目描述的问题
from sage.all import *
a = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC
b = 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93
p = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF
n = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123
x = 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7
y = 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0
E = EllipticCurve(GF(p), [a, b])
G = E(x, y)
s = 0xcb524f49515c9a7387210ddcdbf1f32aad1c8806f01a362c62a5d6a5466da158
r = 0x8A6BB033033E79683E81FE36D6394262D451A3DB9D1A0C489D51543D22E67BC4
s2 = 0xB54A6668F644EC08D925552D45F66E348762B460693E7A68CBB0FDF38327DB45
s3 = 0xB50FAE013594F79192898FF7FC0A84D931B1EC56EF9174159023ACF1C708180D
e = 0xeaf0adee014bd35a12180bbc99292e3acf895203aa97f8dbbb760da04da844f6
r1 = 0x125fd6eb66351ca49073a6e55be1fa40cfd6662f80452a6bcea3b25bd69b6b26
s1 = 0x47baaef61c7a3c4c239fc2634ec25a2059d937026c6e0b72df1463fbba5b3a05
d2 = ZZ((s3 - s2) * inverse_mod(r, n) % n)
'''
s1*k1-e = d1^(-1) * r1
r1 = d1*(s1*k1-e)
r1 = d1*k1 * s1 - d1*e
s = d1*k1*s2 + d1*s3 -r
s*s1 = d1*k1*s1 * s2 + d1*s3*s1 - r*s1
s*s1 = (r1+d1*e)*s2 + d1 * s3*s1 - r*s1
'''
R = PolynomialRing(GF(n), 'x')
x = R.gens()[0]
f = (r1 + x*e)*s2 + x*s3*s1 - r*s1 - s*s1
ans = f.roots()
d1 = 90919127323695568397119051689582862352296983775157729258730148362152821090405
d2 = 75133153874808200698750375741973887146735262423059242244009334005845482114914
e = 0x9e810778a6b177c6aa1799365977adfbeef605c19b5ea917527d1541c1339019
k1 = 233
P = inverse_mod(d1, n) * G
Q = k1*G
r1 = ZZ(Q.xy()[0])
s1 = ZZ(inverse_mod(k1, n) * (e + inverse_mod(d1, n) * r1) % n)
k2 = 17
k3 = 71
R = k2*G + k3*Q
x1 = ZZ(R.xy()[0])
r = ZZ((e + x1) % n)
s2 = ZZ(d2 * k3 % n)
s3 = ZZ(d2 * (r+k2) % n)
s = (d1*k1*s2 + d1*s3 - r) % n
print(s)
print(hex(r)[2:])
print(hex(s)[2:])
原文始发于微信公众号(N0wayBack):第二届熵密杯 WP
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论