from hashlib import sha256 from Crypto.Cipher import AES import math
# =============================================================== # 第一部分:椭圆曲线和 Point 类的定义 # ===============================================================
# 椭圆曲线 secp256r1 (NIST P-256) 的参数 p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff a = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
# 定义标量乘法 (s * P) def__mul__(self, s): current = self res = None# 这是无穷远点 # 使用快速幂的思想 (二进制展开法) while s > 0: if s & 1: # 如果当前位是 1 if res isNone: res = current else: res = res + current current = current + current # 点倍增 s >>= 1# 右移一位 return res
# 定义点的相等性 def__eq__(self, other): if other isNone: returnFalse returnself.x == other.x andself.y == other.y
# =============================================================== # 第二部分:实现并运行大步小步法 (BSGS) 来找到 s # ===============================================================
defbsgs(base_point, target_point, search_limit): """ 使用大步小步法求解椭圆曲线离散对数问题 (s * base_point = target_point) :param base_point: 基点 P :param target_point: 目标点 Q :param search_limit: s 的最大搜索范围 (2^40) :return: 整数 s """ m = int(math.sqrt(search_limit)) + 1 print(f"步长 (m) 设置为: {m}")
# 1. 计算小步 (Baby Steps) 并存入哈希表 baby_steps_table = {} current_point = None# 0 * P for j inrange(m): if current_point notin baby_steps_table: baby_steps_table[current_point] = j if current_point isNone: current_point = base_point else: current_point = current_point + base_point print("小步表已生成完成。") # 2. 计算大步的步进 (mP) mP = base_point * m mP_inv = -mP
# 3. 计算大步 (Giant Steps) 并查找匹配 giant_step_point = target_point for i inrange(m): # 查找 Q - i*m*P 是否在小步表中 if giant_step_point in baby_steps_table: j = baby_steps_table[giant_step_point] s = i * m + j # 由于0*P和负点的情况,可能需要微调 if base_point * s == target_point: return s giant_step_point = giant_step_point + mP_inv returnNone# 没有找到解
# Given IV IV = b64decode("Mkoz9OBLUA4EgWqbuheBcg==") print(f"IV: {IV.hex()}")
# Step 1: Create C-B-C pattern # We need C1 = C3 != C2 # # For CBC mode: # C1 = E(P1 ⊕ IV) # C2 = E(P2 ⊕ C1) # C3 = E(P3 ⊕ C2) # # Strategy: # 1. Choose P1 and P2 arbitrarily # 2. Encrypt to get C1, C2 # 3. Set P3 = P1 ⊕ IV ⊕ C2 so that P3 ⊕ C2 = P1 ⊕ IV # This makes C3 = E(P3 ⊕ C2) = E(P1 ⊕ IV) = C1
print("\n=== Step 1: Creating C-B-C ciphertext ===") print("Strategy: Choose P1, P2, then set P3 = P1 ⊕ IV ⊕ C2") print("This will make C3 = C1")
# For the first encryption, we can choose any P1 and P2 # But we need to know C1 and C2 to compute P3 # So we'll need to do this interactively
print("\nFirst, encrypt with P1=00...00 (16 zeros), P2=01...01, P3=00...00 (temporary)") P1 = b'\x00' * 16 P2 = b'\x01' * 16 P3_temp = b'\x00' * 16 plaintext1_temp = P1 + P2 + P3_temp print(f"Temporary plaintext (base64): {b64encode(plaintext1_temp).decode()}") print("After getting C1 and C2 from server, calculate:") print("P3 = P1 ⊕ IV ⊕ C2") print("Then encrypt again with the corrected plaintext")
print("\n=== Step 2: Creating C-C-B ciphertext ===") print("After getting C and B from step 1:") print("We need C1 = C2 = C and C3 = B") print("\nStrategy:") print("1. Set P1 such that E(P1 ⊕ IV) = C") print(" So P1 = D(C) ⊕ IV - but we can't decrypt without the key") print("\nAlternative strategy:") print("Since C1 from step 1 satisfies C1 = E(P1 ⊕ IV),") print("We need to reuse that same P1") print("For C2 = C1, we need E(P2 ⊕ C1) = C1") print("So P2 ⊕ C1 = P1 ⊕ IV") print("Therefore P2 = P1 ⊕ IV ⊕ C1") print("\nFor C3 = B (which is C2 from step 1):") print("We need E(P3 ⊕ C2) = B") print("Since C2 = C1 (both equal to C), P3 ⊕ C1 = P2_old ⊕ C1_old") print("From step 1, C2_old = E(P2_old ⊕ C1_old) = B") print("So we need P3 ⊕ C = P2_old ⊕ C (where C = C1_old)") print("Therefore P3 = P2_old")
print("\n=== Practical Solution ===") print("1. Get IV from server") print("2. Encrypt P1||P2||temp with P1=zeros, P2=ones to get C1||C2||C3_temp") print("3. Calculate P3 = P1 ⊕ IV ⊕ C2") print("4. Encrypt P1||P2||P3 to get C||B||C (C-B-C pattern)") print("5. Calculate P2' = P1 ⊕ IV ⊕ C") print("6. Encrypt P1||P2'||P2 to get C||C||B (C-C-B pattern)") print("7. Get flag!")
# Helper function to XOR bytes defxor_bytes(a, b): returnbytes(x ^ y for x, y inzip(a, b))
print("\n=== Interactive Solver ===") print("Step 1: Use option 1 to encrypt this plaintext:") P1 = b'\x00' * 16 P2 = b'\xff' * 16# Changed to all 0xFF to ensure P2 != P1 P3_temp = b'\x00' * 16 plaintext_temp = P1 + P2 + P3_temp print(f"{b64encode(plaintext_temp).decode()}") print("\nAfter you get the ciphertext, paste it here (base64):") print("(Or type 'manual' to calculate manually)")
try: ct1 = input().strip() if ct1.lower() != 'manual'and ct1: ct1_bytes = b64decode(ct1) C1 = ct1_bytes[:16] C2 = ct1_bytes[16:32] print(f"\nC1: {C1.hex()}") print(f"C2 (this is B): {C2.hex()}") # Calculate correct P3 for C-B-C P3 = xor_bytes(xor_bytes(P1, IV), C2) plaintext_cbc = P1 + P2 + P3 print(f"\n=== C-B-C Plaintext (base64) ===") print(b64encode(plaintext_cbc).decode()) # Calculate P2' for C-C-B P2_prime = xor_bytes(xor_bytes(P1, IV), C1) plaintext_ccb = P1 + P2_prime + P2 print(f"\n=== C-C-B Plaintext (base64) ===") print(b64encode(plaintext_ccb).decode()) print("\nUse these plaintexts in order when prompted for option 2!") else: print("\nManual calculation formulas:") print("Given C1||C2||C3 from temporary encryption:") print("P3_correct = P1 ⊕ IV ⊕ C2") print("P2' = P1 ⊕ IV ⊕ C1") print("\nC-B-C plaintext: P1 || P2 || P3_correct") print("C-C-B plaintext: P1 || P2' || P2") except: print("\nUse the formulas above to calculate manually")
defrecover_secret(vector, vector_name): global found_secret if found_secret: return
print(f"\n--- 正在检查向量: {vector_name} ---") for direction in [1, -1]: v_cand = vector * direction if v_cand.is_zero(): continue
first_nonzero_val = next((val for val in v_cand if val != 0), None) for byte_val inrange(1, 256): if first_nonzero_val % byte_val == 0: k = first_nonzero_val // byte_val if k == 0: continue s_cand = v_cand / k ifall(c.is_integer() and0 <= c <= 255for c in s_cand): secret_bytes = bytes([int(c) for c in s_cand]) print(f"[+] 成功! 在 '{vector_name}' 中找到可能的 secret") print(f"[-] secret: {secret_bytes.hex()}") found_secret = True return
from Crypto.Cipher import AES from Crypto.Util.Padding import unpad
# 1. PEGA AQUÍ EL TEXTO CIFRADO COMPLETO DE 160 CARACTERES. # El que proporcionaste tiene 156 caracteres (78 bytes), le faltan 4 caracteres (2 bytes) al final. # Asegúrate de copiarlo entero. hex_ciphertext = "83c9b4db1e036eada862d24928ae12641f7e56f713598661600da434cf3bc3e74429cbb807173626516dd030d964ad1f06ef2f9da03722943ba57653c4e0733b8474d57d450b01a331b1bd7ea36dcc4b"# <--- ¡REEMPLAZA ESTO CON EL VALOR COMPLETO!
# 2. La clave fija del programa. key = b'0xGame2025awaQAQ' block_size = AES.block_size # 16 bytes
# --- Script de Desencriptación Correcto --- try: full_ciphertext = bytes.fromhex(hex_ciphertext) # Comprobación de la longitud iflen(full_ciphertext) % block_size != 0: print(f"[!] ADVERTENCIA: La longitud del texto cifrado ({len(full_ciphertext)} bytes) no es un múltiplo de 16.") print("[!] Esto indica que el texto cifrado está incompleto. El resultado será incorrecto.")
iflen(full_ciphertext) < block_size: raise ValueError("El texto cifrado es demasiado corto.")
# El primer bloque del texto cifrado (C_1) actúa como el IV para descifrar el resto del mensaje. iv_for_decryption = full_ciphertext[0:block_size]
# El texto cifrado que queremos descifrar es todo lo que sigue al primer bloque (C_2, C_3, ...). ciphertext_to_decrypt = full_ciphertext[block_size:] # Crear un nuevo cifrador CFB usando C_1 como IV. cipher = AES.new(key, AES.MODE_CFB, iv=iv_for_decryption) # Descifrar para obtener (padded_flag + urandom_final). decrypted_payload = cipher.decrypt(ciphertext_to_decrypt) print(f"[+] Contenido descifrado: {decrypted_payload}")
# El mensaje original era: padded_flag(48 bytes) + urandom(16 bytes). # Por lo tanto, el contenido descifrado debería tener 64 bytes. iflen(decrypted_payload) < 48: # Necesitamos al menos los 48 bytes de la flag. raise ValueError("El contenido descifrado es demasiado corto para contener la flag.")
# Aislamos los bloques que deberían contener la flag con padding (los primeros 48 bytes del payload). padded_flag = decrypted_payload[:48]
# Intentar quitar el padding de la parte de la flag. flag = unpad(padded_flag, block_size) flag_str = flag.decode() if flag_str.startswith("0xGame{") and flag_str.endswith("}"): print("\n" + "="*40) print(f"[+] ¡ÉXITO! La flag es: {flag_str}") print("="*40) else: print("\n[!] Se descifró un texto, pero no parece tener el formato de la flag.") print(f"[!] Texto obtenido: {flag_str}")
except (ValueError, IndexError) as e: print(f"\n[!] ERROR: No se pudo descifrar la flag. Causa probable: {e}") print("[!] Por favor, comprueba que has copiado el texto cifrado completo (160 caracteres hexadecimales).") except Exception as e: print(f"\n[!] Ocurrió un error inesperado: {e}")