2025-第十届上海大学生ctf


web

image-20250806095313765

cryto

 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

known_message_hex = "54686520666c61672069732068696464656e20736f6d65776865726520696e207468697320656e637279707465642073797374656d2e"
known_ciphertext_hex = "b7eb5c9e8ea16f3dec89b6dfb65670343efe2ea88e0e88c490da73287c86e8ebf375ea1194b0d8b14f8b6329a44f396683f22cf8adf8"
flag_ciphertext_hex = "85ef58d9938a4d1793a993a0ac0c612368cf3fa8be07d9dd9f8c737d299cd9adb76fdc1187b6c3a00c866a20"


def xor_hex_strings(hex_str1, hex_str2):
    bytes1 = bytes.fromhex(hex_str1)
    bytes2 = bytes.fromhex(hex_str2)

    # Ensure both byte strings are of the same length
    # If not, truncate the longer one to match the shorter one
    min_len = min(len(bytes1), len(bytes2))
    result_bytes = bytes([b1 ^ b2 for b1, b2 in zip(bytes1[:min_len], bytes2[:min_len])])
    return result_bytes.hex()


# 1. 计算两个密文的异或值
ciphertext_xor_hex = xor_hex_strings(known_ciphertext_hex, flag_ciphertext_hex)

# 2. 将已知明文与异或结果进行异或操作
# 注意:这里需要将已知明文转换为hex,或者直接使用其原始字节表示
# 假设已知明文的长度与密文的有效部分长度相同
known_message_bytes = bytes.fromhex(known_message_hex)
ciphertext_xor_bytes = bytes.fromhex(ciphertext_xor_hex)

# 确保长度匹配,取较短的长度进行异或
min_len = min(len(known_message_bytes), len(ciphertext_xor_bytes))

flag_bytes = bytes([b1 ^ b2 for b1, b2 in zip(known_message_bytes[:min_len], ciphertext_xor_bytes[:min_len])])

print(f"解密得到的flag: {flag_bytes.decode('utf-8', errors='ignore')}")

数据分析

SQLi_Detection

 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
def detect_sql_injection(file_path):
    # 定义检测模式
    boolean_patterns = ["' OR", "' AND"]
    union_patterns = ["' UNION SELECT"]
    stacked_patterns = ["';"]
    dangerous_keywords = ["DROP", "DELETE", "UPDATE", "INSERT", "ALTER", "SHUTDOWN"]
    
    count = 0
    
    with open(file_path, 'r') as file:
        for line in file:
            line_upper = line.upper().strip()
            
            # 检查布尔注入
            if any(pattern in line_upper for pattern in boolean_patterns):
                count += 1
                continue
                
            # 检查联合查询注入
            if any(pattern in line_upper for pattern in union_patterns):
                count += 1
                continue
                
            # 检查堆叠查询注入
            if any(pattern in line_upper for pattern in stacked_patterns):
                if ';' in line:
                    parts = line.split(';')
                    if len(parts) > 1:
                        second_part = parts[1].upper()
                        if any(keyword in second_part for keyword in dangerous_keywords):
                            count += 1
    
    return count

# 使用示例
injection_count = detect_sql_injection('logs.txt')
print(f"flag{{{injection_count}}}")

flag{451}

AES_Custom_Padding

 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
from Crypto.Cipher import AES
import base64

def remove_custom_padding(data):
    """
    移除自定义填充:
    1. 查找最后一个0x80字节
    2. 验证之后的所有字节都是0x00
    3. 返回去除填充的数据
    """
    # 查找最后一个0x80的位置
    last_80_pos = data.rfind(b'\x80')
    
    if last_80_pos == -1:
        raise ValueError("Invalid padding - no 0x80 byte found")
    
    # 检查0x80之后的所有字节是否为0x00
    for i in range(last_80_pos + 1, len(data)):
        if data[i] != 0x00:
            raise ValueError(f"Invalid padding - non-zero byte after 0x80 at position {i}")
    
    return data[:last_80_pos]

def decrypt_aes_cbc(key, iv, ciphertext):
    """
    AES-128-CBC解密并处理自定义填充
    """
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted = cipher.decrypt(ciphertext)
    
    # 移除自定义填充
    plaintext = remove_custom_padding(decrypted)
    
    return plaintext

# 给定的Key和IV
key = bytes.fromhex("0123456789ABCDEF0123456789ABCDEF")
iv = bytes.fromhex("000102030405060708090A0B0C0D0E0F")

# 读取Base64编码的密文文件
with open("cipher.bin", "rb") as f:
    ciphertext_b64 = f.read()

# 解码Base64得到二进制密文
ciphertext = base64.b64decode(ciphertext_b64)

# 解密
plaintext = decrypt_aes_cbc(key, iv, ciphertext)

# 输出解密结果
print("Decrypted plaintext (hex):", plaintext.hex())
print("Decrypted plaintext (str):", plaintext.decode('utf-8', errors='replace'))
image-20250806105802925
 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
from Crypto.Util.number import long_to_bytes
import gmpy2

n = 143504495074135116523479572513193257538457891976052298438652079929596651523432364937341930982173023552175436173885654930971376970322922498317976493562072926136659852344920009858340197366796444840464302446464493305526983923226244799894266646253468068881999233902997176323684443197642773123213917372573050601477
c = 141699518880360825234198786612952695897842876092920232629929387949988050288276438446103693342179727296549008517932766734449401585097483656759727472217476111942285691988125304733806468920104615795505322633807031565453083413471250166739315942515829249512300243607424590170257225854237018813544527796454663165076
dl = 1761714636451980705225596515441824697034096304822566643697981898035887055658807020442662924585355268098963915429014997296853529408546333631721472245329506038801
e = 65537
M = 1 << 530  # 2^530

# 枚举所有可能的k值
for k in range(1, e):
    # 计算k的2-adic估值(能整除2的次数)
    v = 0
    k_temp = k
    while k_temp % 2 == 0:
        v += 1
        k_temp //= 2
    
    # 计算模数M'
    M_prime = M // (2**v)
    
    # 计算B = k*(n+1) - (e*dl - 1)
    B = k * (n + 1) - (e * dl - 1)
    
    # 检查B是否能被2^v整除
    if B % (2**v) != 0:
        continue
    
    B_prime = B // (2**v)
    
    try:
        # 计算k_temp在模M_prime下的逆元
        inv_k_prime = gmpy2.invert(k_temp, M_prime)
    except:
        # 如果逆元不存在,跳过当前k
        continue
    
    # 计算s的候选值
    s_candidate = (B_prime * inv_k_prime) % M_prime
    if s_candidate < 0:
        s_candidate += M_prime
    
    # 验证s_candidate是否有效
    discriminant = s_candidate*s_candidate - 4*n
    if discriminant < 0:
        continue
    
    # 检查判别式是否为完全平方数
    root, exact = gmpy2.iroot(discriminant, 2)
    if not exact:
        continue
    
    # 计算p和q
    p = (s_candidate + root) // 2
    q = (s_candidate - root) // 2
    if p * q != n:
        continue
    
    # 找到有效因子,解密flag
    phi = (p-1)*(q-1)
    d_full = gmpy2.invert(e, phi)
    m = pow(c, int(d_full), n)
    flag = long_to_bytes(m)
    print("Flag found with k =", k)
    print("Flag:", flag)
    break
else:
    print("No solution found.")
image-20250806161914630
谢谢观看