Do you have good eyes? (Breizh CTF) 解题Writeup

发布时间:2026/7/4 2:06:12
Do you have good eyes? (Breizh CTF) 解题Writeup 题目概述这是一个涉及侧信道攻击的密码学挑战。题目名称Do you have good eyes?暗示我们需要仔细观察某些细微的差异这些差异可能来自时间、功率消耗或其他侧信道信息。题目信息连接地址archive.cryptohack.org 43607挑战文件do-you-have-good-eyes.zip目标获取 BZHCTF{FLAG} 格式的flag初步分析1. 下载并解压挑战文件bash复制下载unzip do-you-have-good-eyes.zip查看文件结构bash复制下载ls -la通常这类挑战会包含服务端代码server.py加密/认证实现可能的测试数据2. 分析服务端行为连接服务查看其行为python复制下载from pwn import *r remote(archive.cryptohack.org, 43607)print(r.recvline())print(r.recvline())print(r.recvline())典型的服务端会显示一些加密后的数据要求你区分两种不同的情况根据你的回答决定是否给出flag3. 理解挑战类型根据题目名称和Can you tell the difference?的描述这很可能是一个选择明文攻击或区分攻击的挑战。常见的场景Padding Oracle Attack通过观察填充错误的时间差异Timing Attack通过测量操作时间差异Bleichenbacher AttackRSA PKCS#1 v1.5 填充攻击GCM/DSS 侧信道通过时间/功率差异恢复密钥深入分析挑战文件查看源代码python复制下载# 假设 server.py 的内容类似from Crypto.Cipher import AESfrom Crypto.Util.Padding import pad, unpadimport osimport timeFLAG BZHCTF{...}def encrypt():key os.urandom(16)iv os.urandom(16)cipher AES.new(key, AES.MODE_CBC, iv)# 某些操作...return ciphertextdef main():print(Can you tell the difference?)# 显示一些信息# 要求用户判断关键漏洞识别根据经验这类挑战常见的漏洞是1. RSA解密时间差异python复制下载def decrypt(ciphertext):# 不安全的解密实现if ciphertext[0] ! 0x00:return Invalid padding# 解密操作...# 如果padding正确返回时间更长2. AES-CBC MAC验证python复制下载def verify_mac(data, tag):# 使用比较时提前返回for i in range(len(tag)):if data[i] ! tag[i]:return Falsetime.sleep(0.01) # 故意添加延迟return True3. 字符串比较漏洞python复制下载def check_password(password):# 不安全的字符串比较for i in range(len(password)):if password[i] ! secret[i]:return Falsereturn True具体攻击方法场景1Timing Attack - 字符串比较如果挑战涉及比较两个字符串攻击者可以通过测量响应时间来逐字符恢复秘密。python复制下载from pwn import *import timedef timing_attack():r remote(archive.cryptohack.org, 43607)# 逐字符恢复secret charset 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}_for position in range(50): # 假设flag长度best_char best_time 0for char in charset:guess secret char A * (50 - len(secret) - 1)# 测量响应时间start time.time()r.sendline(guess.encode())response r.recvline()end time.time()elapsed end - startif elapsed best_time:best_time elapsedbest_char charsecret best_charprint(fRecovered: {secret})if } in secret:breakr.close()return secret场景2Padding Oracle Attack如果服务端使用CBC模式且会返回填充错误信息可以实施Padding Oracle攻击。python复制下载from Crypto.Util.Padding import pad, unpadfrom Crypto.Cipher import AESimport osdef padding_oracle_attack():Padding Oracle Attack on CBC mode当服务器返回Invalid padding或Padding error时def xor_bytes(a, b):return bytes([x ^ y for x, y in zip(a, b)])# 获取目标密文r remote(archive.cryptohack.org, 43607)data r.recvline().decode().strip()# 解析IV和密文iv bytes.fromhex(data[:32])ciphertext bytes.fromhex(data[32:])# 逐字节解密blocks [ciphertext[i:i16] for i in range(0, len(ciphertext), 16)]plaintext bfor block_idx in range(len(blocks)):# 为每个字节构造paddingblock blocks[block_idx]decrypted_block [0] * 16for byte_pos in range(15, -1, -1):# 尝试所有可能的字节值for guess in range(256):# 构造中间值# 根据padding oracle的原理pass# 使用oracle验证# 如果成功记录中间值return plaintext场景3GCM/DSS 时间侧信道如果是GCM相关的挑战与上一个挑战相关可能涉及python复制下载def gcm_timing_attack():利用GCM验证时间差异如果验证tag时提前返回可以逐个字节猜测tagr remote(archive.cryptohack.org, 43607)# 获取密文和IVr.recvuntil(bciphertext: )ciphertext bytes.fromhex(r.recvline().strip().decode())r.recvuntil(bIV: )iv bytes.fromhex(r.recvline().strip().decode())# 逐个字节爆破tagforged_tag bfor pos in range(16):best_byte 0max_time 0for b in range(256):# 构造部分tagtest_tag forged_tag bytes([b]) b\x00 * (15 - pos)# 测量响应时间start time.perf_counter()r.sendlineafter(btag: , test_tag.hex().encode())response r.recvline()elapsed time.perf_counter() - startif elapsed max_time:max_time elapsedbest_byte bforged_tag bytes([best_byte])print(fRecovered tag bytes: {forged_tag.hex()})return forged_tag场景4概率性攻击 - 区分两种加密模式如果挑战是区分两种不同的加密算法或模式可以通过统计分析python复制下载def distinguish_attack():区分AES-CBC和AES-CTR模式CBC模式下相同明文块会产生不同密文块CTR模式下相同明文块会产生相同密文块r remote(archive.cryptohack.org, 43607)# 请求两个相同明文的加密plaintext bAAAAAAAAAAAAAAAA # 16字节对齐的块r.sendlineafter(bplaintext: , plaintext.hex().encode())ct1 bytes.fromhex(r.recvline().strip().decode())r.sendlineafter(bplaintext: , plaintext.hex().encode())ct2 bytes.fromhex(r.recvline().strip().decode())# 判断是CBC还是CTRif ct1 ct2:# 如果两次加密结果相同可能是CTR模式使用相同IV# 也可能是ECB模式return CTRelse:# 如果不同可能是CBC模式使用随机IVreturn CBC完整的解决方案基于实际挑战的推测根据挑战名称Do you have good eyes?和前面的Authentification 2挑战同一个作者skilo这个挑战很可能也涉及GCM或认证加密但这次是关于观察差异。可能是相同明文在GCM下的不同表现使用相同的nonce或不同的nonce时间侧信道攻击验证MAC时的微小时间差异区分攻击区分随机数据和加密数据通用攻击脚本python复制下载#!/usr/bin/env python3from pwn import *import timeimport hashlibfrom Crypto.Util.Padding import pad, unpadfrom Crypto.Util.number import bytes_to_long, long_to_bytesimport json# 配置HOST archive.cryptohack.orgPORT 43607class EyesAttack:def __init__(self):self.r Noneself.flag def connect(self):self.r remote(HOST, PORT)log.info(Connected to server)def get_challenge(self):接收挑战数据data self.r.recvuntil(bYour answer: )return data.decode()def timing_oracle(self, payload):时间Oracle发送payload并测量响应时间start time.perf_counter()self.r.sendline(payload.encode())response self.r.recvline()elapsed time.perf_counter() - startreturn elapsed, responsedef byte_by_byte_attack(self):逐字节恢复秘密recovered charset 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}_!#$%^*()for pos in range(100): # 最多100个字符best_char best_time 0for c in charset:# 构造猜测test_str recovered c# 填充到固定长度如果需要test_str test_str.ljust(100, A)# 发送并测量时间elapsed, _ self.timing_oracle(test_str)log.debug(fTesting {c}: {elapsed:.6f}s)if elapsed best_time:best_time elapsedbest_char crecovered best_charlog.info(fRecovered: {recovered})# 检查是否完成if recovered.endswith(}):breakreturn recovereddef side_channel_attack(self):侧信道攻击主函数self.connect()# 获取初始信息banner self.r.recvline()log.info(fBanner: {banner.decode().strip()})# 执行特定的攻击# 根据服务端的具体行为选择不同的攻击向量# 示例时间攻击self.flag self.byte_by_byte_attack()# 发送最终答案self.r.sendline(self.flag.encode())final_response self.r.recvall()log.info(final_response.decode())return self.flagdef padding_oracle_attack(self):Padding Oracle攻击self.connect()# 获取加密数据self.r.recvuntil(bEncrypted: )encrypted bytes.fromhex(self.r.recvline().strip().decode())# 解析IV和密文iv encrypted[:16]ciphertext encrypted[16:]# 解密每个块plaintext bblocks [ciphertext[i:i16] for i in range(0, len(ciphertext), 16)]for i in range(len(blocks)):# 对每个块进行解密decrypted self.decrypt_block(iv if i 0 else blocks[i-1], blocks[i])plaintext decryptedreturn plaintextdef decrypt_block(self, iv, block):解密单个块Padding Oracledecrypted bytearray(16)for byte_pos in range(15, -1, -1):# 尝试所有可能的字节for guess in range(256):# 构造中间块test_iv bytearray(iv)# 设置paddingpadding_val 16 - byte_posfor j in range(byte_pos 1, 16):test_iv[j] decrypted[j] ^ padding_valtest_iv[byte_pos] guess# 发送测试请求test_data bytes(test_iv) blockself.r.recvuntil(bEnter ciphertext: )self.r.sendline(test_data.hex().encode())response self.r.recvline()# 检查是否返回有效填充if bValid in response:decrypted[byte_pos] guess ^ padding_valbreak# 去除填充padding_len decrypted[-1]return bytes(decrypted[:-padding_len])def gcm_forgery_attack(self):GCM伪造攻击利用时间差异self.connect()# 获取挑战数据self.r.recvuntil(bIV: )iv bytes.fromhex(self.r.recvline().strip().decode())self.r.recvuntil(bCiphertext: )ciphertext bytes.fromhex(self.r.recvline().strip().decode())# 逐字节猜测标签forged_tag bfor pos in range(16):best_byte 0max_delay 0for b in range(256):test_tag forged_tag bytes([b]) b\x00 * (15 - pos)# 测量验证时间start time.perf_counter()self.r.sendlineafter(bTag: , test_tag.hex().encode())response self.r.recvline()delay time.perf_counter() - start# 有效字节会导致更长的处理时间因为要继续验证后续字节if delay max_delay:max_delay delaybest_byte bforged_tag bytes([best_byte])log.info(fRecovered tag byte {pos1}: {best_byte:02x})return forged_tagdef main():attack EyesAttack()try:# 根据提示选择攻击方法# 方法1时间侧信道攻击flag attack.side_channel_attack()# 方法2Padding Oracle攻击# plaintext attack.padding_oracle_attack()# 方法3GCM时间攻击# tag attack.gcm_forgery_attack()log.success(fFlag: {flag})except Exception as e:log.error(fAttack failed: {e})finally:if attack.r:attack.r.close()if __name__ __main__:main()实际利用思路最可能的漏洞场景基于题目名称Do you have good eyes?最可能的攻击是1. 时序攻击Timing Attack服务端使用不安全的比较函数python复制下载def check_tag(provided_tag, computed_tag):for i in range(len(provided_tag)):if provided_tag[i] ! computed_tag[i]:return False# 微妙的时间差异return True2. 盲注式攻击通过观察正确和错误响应的差异逐字节恢复flag。快速利用脚本python复制下载from pwn import *import timedef exploit():r remote(archive.cryptohack.org, 43607)# 接收提示print(r.recvline())print(r.recvline())flag charset 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}_# 逐字符爆破flagfor i in range(50):for c in charset:guess flag c# 发送猜测r.sendline(guess.encode())start time.time()response r.recvline()elapsed time.time() - start# 根据响应时间判断if elapsed 0.1: # 阈值根据实际情况调整flag cprint(fFound: {flag})breakelse:breakprint(fFlag: {flag})r.close()if __name__ __main__:exploit()解决方案总结关键要点识别漏洞类型通过观察服务端行为判断是时间攻击、Padding Oracle还是其他侧信道收集信息响应时间差异错误消息差异加密数据格式构造攻击逐字符或逐字节猜测利用时间差异作为Oracle自动化攻击过程验证结果提交flag确认防御措施使用常数时间比较hmac.compare_digest统一错误消息添加随机延迟但这不是根本解决方案使用恒定时间算法实现最终答案成功利用漏洞后服务端返回的flag格式为BZHCTF{...}具体的flag值需要在运行时通过攻击获取。实际获得的flag取决于服务端的具体实现和挑战数据。注意由于我没有实际连接到服务端以上代码提供了多种可能的攻击向量。在实际解题时需要根据服务端的响应和行为选择最合适的攻击方法。通常时间侧信道攻击是最常见的好眼力挑战类型。