news 2026/4/30 9:34:04

【攻防世界】reverse | hackme 详细题解 WP

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【攻防世界】reverse | hackme 详细题解 WP

【攻防世界】reverse | hackme 详细题解 WP

下载附件

sub_400F8E函数伪代码:

__int64 __fastcallsub_400F8E(__int64 a1,inta2,inta3,inta4,inta5,inta6){intv6;// edxintv7;// ecxintv8;// r8dintv9;// r9dintv10;// ecxintv11;// r8dintv12;// r9dcharv14;// [rsp+0h] [rbp-C0h]charv15;// [rsp+0h] [rbp-C0h]charv16[136];// [rsp+10h] [rbp-B0h] BYREFintv17;// [rsp+98h] [rbp-28h]charv18;// [rsp+9Fh] [rbp-21h]intv19;// [rsp+A0h] [rbp-20h]unsigned__int8 v20;// [rsp+A6h] [rbp-1Ah]charv21;// [rsp+A7h] [rbp-19h]intv22;// [rsp+A8h] [rbp-18h]intv23;// [rsp+ACh] [rbp-14h]intv24;// [rsp+B0h] [rbp-10h]intv25;// [rsp+B4h] [rbp-Ch]_BOOL4 v26;// [rsp+B8h] [rbp-8h]inti;// [rsp+BCh] [rbp-4h]sub_407470((unsignedint)"Give me the password: ",a2,a3,a4,a5,a6,a2);sub_4075A0((unsignedint)"%s",(unsignedint)v16,v6,v7,v8,v9,v14);for(i=0;v16[i];++i);v26=i==22;v25=10;do{v10=(int)sub_406D90()%22;v22=v10;v24=0;v21=byte_6B4270[v10];v20=v16[v10];v19=v10+1;v23=0;while(v23<v19){++v23;v24=1828812941*v24+12345;}v18=v24^v20;if(v21!=((unsigned__int8)v24^v20))v26=0;--v25;}while(v25);if(v26)v17=sub_407470((unsignedint)"Congras\n",(unsignedint)v16,v24,v10,v11,v12,v15);elsev17=sub_407470((unsignedint)"Oh no!\n",(unsignedint)v16,v24,v10,v11,v12,v15);return0LL;}

exp:

# 核心:22位密码 = 密文字节 ^ 对应索引的哈希值低字节defcalculate_hash(idx):"""计算索引idx对应的哈希值(低字节)"""hash_val=0# 迭代次数 = idx + 1 次for_inrange(idx+1):hash_val=1828812941*hash_val+12345# 仅保留低字节(unsigned __int8)returnhash_val&0xFFdefcrack_full_password():# 1. 密文byte_6B4270的22个字节(idx 0-21)cipher_bytes=[0x5F,0xF2,0x5E,0x8B,0x4E,0x0E,0xA3,0xAA,0xC7,0x93,0x81,0x3D,0x5F,0x74,0xA3,0x09,0x91,0x2B,0x49,0x28,0x93,0x67]password=[]# 2. 遍历每个索引计算密码字符foridxinrange(22):# 计算当前索引的哈希值低字节hash_low=calculate_hash(idx)# 异或逆运算:input[idx] = 密文 ^ 哈希低字节char_byte=cipher_bytes[idx]^hash_low# 转换为ASCII字符(过滤不可打印字符,用.替代)char=chr(char_byte)if32<=char_byte<=126else'.'password.append(char)# 打印中间过程(可选,用于验证)print(f"索引{idx:2d}| 密文:0x{cipher_bytes[idx]:02X}| 哈希低字节:0x{hash_low:02X}| 密码字符:{char}")# 3. 拼接最终密码full_password=''.join(password)returnfull_password# 执行破解if__name__=="__main__":print("=== 22位密码破解过程 ===")final_password=crack_full_password()print("\n=== 最终破解结果 ===")print(f"完整22位密码:{final_password}")

运行 exp 脚本:

flag{d826e6926098ef46}

【攻防世界】reverse | hackme 详细题解 WP 原理深度解析:

【CTF 逆向实战】攻防世界 hackme 深度解析:从 0 到 1 破解 22 位密码验证逻辑

引言:CTF 逆向中的 “密码验证” 题型

在 CTF 逆向领域,“密码验证类” 题目是经典的入门到进阶题型。这类题目通常隐藏着明确的 “输入 - 验证 - 输出” 链路,核心矛盾在于 “如何从程序逻辑中反推正确输入”。本文以攻防世界hackme为例,从静态分析到动态验证,完整拆解一道 64 位 ELF 程序的密码验证逻辑。

一、题目初探:程序类型与核心场景定位

1. 程序基础信息

通过file命令和初步静态分析:

  • 程序类型:64 位 Linux ELF 可执行文件(x86-64 架构)
  • 核心功能:接收用户输入的密码,验证通过输出Congras,失败输出Oh no!
  • 关键特征:包含字符串"Give me the password:""Congras""Oh no!",是典型的交互型密码验证程序

2. 核心函数定位技巧

在逆向分析中,字符串是 “锚点”。通过 IDA 或 Ghidra 的 “交叉引用” 功能,快速定位:

  • 输入提示字符串"Give me the password:"对应函数sub_400F8E(地址sub_400F8E+18
  • 成功 / 失败字符串"Congras"/"Oh no!"同样指向sub_400F8E(地址sub_400F8E+12Asub_400F8E:loc_4010CC

由此确定:sub_400F8E是密码验证的核心函数,关键逻辑在此处。

二、核心函数逆向:sub_400F8E 全链路解析

1. 函数框架概览

sub_400F8E的执行流程可简化为 5 步,关键节点:

2. 逐行拆解关键逻辑

(1)输入处理:密码存储位置
// 输出提示:"Give me the password: "sub_407470((unsignedint)"Give me the password: ",...);// 接收输入到v16数组(栈上136字节缓冲区)sub_4075A0((unsignedint)"%s",(unsignedint)v16,...);

解析:用户输入的密码被存储在栈上的v16数组中,验证围绕该数组展开。

(2)第一道防线:长度校验
// 计算输入字符串长度for(i=0;v16[i];++i);// 验证长度必须为22v26=i==22;

关键结论:密码长度严格固定为 22 位,长度不符直接失败。优先破解可排除大量无效尝试。

(3)核心验证:10 轮随机校验的 “陷阱”
v25=10;// 循环10次do{// 生成0-21的随机索引(覆盖22位密码)v10=(int)sub_406D90()%22;// 取密文和输入的对应字节v21=byte_6B4270[v10];// 密文字节(全局数据)v20=v16[v10];// 输入密码的第v10位// 计算哈希值v24=0;v19=v10+1;// 迭代次数=索引+1for(v23=0;v23<v19;v23++){v24=1828812941*v24+12345;// 哈希公式}// 验证逻辑:密文 == 哈希低字节 ^ 输入字节if(v21!=((unsigned__int8)v24^v20))v26=0;// 任意一次失败则整体失败v25--;}while(v25);

逆向突破点

  • 看到 “随机验证 10 个位置”,实则是 CTF 经典陷阱:若存在任何一位错误,10 轮随机验证大概率命中错误位置,因此必须保证 22 位全部正确(“随机即全量”)。
  • 验证公式可逆:输入字节 = 密文字节 ^ (哈希值低字节)(异或运算可逆性:若c = a^b,则a = c^b)。
(4)结果输出:验证成功的标志
if(v26)v17=sub_407470((unsignedint)"Congras\n",...);// 成功elsev17=sub_407470((unsignedint)"Oh no!\n",...);// 失败

解析v26是验证结果标志,仅当长度正确且 10 轮验证全通过时为1

三、关键数据提取:密文与哈希参数

1. 密文byte_6B4270提取

从程序数据段(.data 节)中,byte_6B4270是长度为 22 字节的全局数组,对应 22 位密码的验证密文。通过静态分析工具提取其值:

cipher_bytes=[0x5F,0xF2,0x5E,0x8B,0x4E,0x0E,0xA3,0xAA,0xC7,0x93,0x81,0x3D,0x5F,0x74,0xA3,0x09,0x91,0x2B,0x49,0x28,0x93,0x67]

2. 哈希计算参数确认

从代码中提取哈希公式关键参数:

  • 初始值:hash_val = 0
  • 迭代公式:hash_val = 1828812941 * hash_val + 12345(线性同余公式)
  • 迭代次数:idx + 1次(idx为当前密码索引,0-21)
  • 有效位:仅保留低 8 位(hash_val & 0xFF,因验证使用unsigned __int8

四、解题实现:从逻辑到代码

1. 核心思路

基于逆向分析,破解步骤可简化为:

  1. 对每个索引idx(0-21),按公式计算哈希值并取低字节;
  2. 利用异或逆运算计算密码字符:password[idx] = cipher_bytes[idx] ^ (hash_low)
  3. 拼接 22 位字符得到完整密码。

2. Python 解题代码

defcalculate_hash(idx):"""计算索引idx对应的哈希值低8位"""hash_val=0# 迭代次数为idx + 1次for_inrange(idx+1):hash_val=1828812941*hash_val+12345# 仅保留低8位(unsigned __int8)returnhash_val&0xFFdefcrack_password():# 密文byte_6B4270的22个字节cipher_bytes=[0x5F,0xF2,0x5E,0x8B,0x4E,0x0E,0xA3,0xAA,0xC7,0x93,0x81,0x3D,0x5F,0x74,0xA3,0x09,0x91,0x2B,0x49,0x28,0x93,0x67]password=[]foridxinrange(22):# 计算当前索引的哈希低字节hash_low=calculate_hash(idx)# 异或逆运算得到密码字节char_byte=cipher_bytes[idx]^hash_low# 转换为字符(包含扩展ASCII)password.append(chr(char_byte))return''.join(password)if__name__=="__main__":flag=crack_password()print(f"破解结果:{flag}")

3. 运行结果与验证

执行代码得到 22 位密码,在 Linux 终端输入后,程序输出Congras,验证成功。

五、原理深度解析

1. 线性同余哈希的确定性

本题哈希公式hash = a * hash + ba=1828812941b=12345)是典型的线性同余生成器(LCG),其核心特性是确定性

  • 给定初始值(0)和迭代次数(idx+1),哈希值唯一确定,可复现计算;
  • 低字节独立:验证仅使用低 8 位,无需处理高位,简化计算。

2. 异或运算的可逆性

异或是 CTF 中常见的轻量加密手段,因可逆性成为逆向突破口:

  • 运算规则:0^a=aa^a=0a^b^b=a
  • 本题中,已知密文c和哈希低字节h,则原始密码p = c ^ h(由c = p ^ h推导)。

3. 随机验证的本质

程序使用sub_406D90()(伪随机函数)生成索引,看到增加破解难度,实则是 “障眼法”:

  • 伪随机数在固定种子下可预测,但本题无需预测 ——10 轮验证覆盖 22 位的概率极高,必须保证所有位正确;
  • 逆向中遇到 “随机抽样验证”,优先按 “全量验证” 处理(这是 CTF 高频套路)。

六、举一反三:同类题目解题方法论

1. 快速定位核心函数

  • 字符串锚点法:搜索"success""correct""password"等关键字,其交叉引用往往指向验证函数;
  • 输入输出跟踪:找到scanf/fgets(接收输入)和printf(输出结果)的调用处,向上追溯验证逻辑。

2. 关键数据提取技巧

  • 密文识别:在数据段中寻找长度与密码长度匹配的字节数组(如本题 22 字节),尤其注意.data.rodata节;
  • 常数记录:哈希 / 加密公式中的常数(如本题的182881294112345)是逆向计算的关键,务必准确提取。

3. 逻辑简化策略

  • 长度优先破解:优先确定密码长度(如本题的i==22),缩小范围;
  • 去干扰项:忽略线程安全(如原子操作)、日志输出等辅助逻辑,聚焦 “输入→验证→输出” 核心链路;
  • 随机即全量:遇到随机索引验证,默认需所有位置满足条件(避免陷入随机数预测误区)。

4. 动态调试辅助

若静态分析存疑(如哈希计算是否正确),用 GDB 验证:

# 启动程序 gdb ./hackme # 在哈希计算后设断点 b *0x400F8E + 0x80 # 运行并输入临时密码 r testpassword123456789 # 查看索引0的哈希低字节 p/x v24 & 0xFF

七、总结:逆向的本质是 “逻辑还原”

hackme作为典型的密码验证题,其破解过程完美体现了 CTF 逆向的核心思维:从程序逻辑中还原 “输入与输出的映射关系”。无论是线性哈希、异或验证还是随机干扰,本质都是对 “正确输入” 的约束条件。掌握 “定位核心→提取参数→逆向计算” 的流程,就能应对大多数同类题目。

最终 flag:flag{d826e6926098ef46}

通过上述步骤破解得到的 22 位密码即为本题 flag。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 13:35:43

vue和springboot框架开发的户外救援系统_jdzgi247

文章目录具体实现截图主要技术与实现手段关于我本系统开发思路java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;具体实现截图 同行可拿货,招校园代理 vuespringboot_jdzgi247 框架开发的户外救援系统和 主…

作者头像 李华
网站建设 2026/4/23 0:17:59

Kurator深度解析:云原生多集群管理的高效解决方案

导读&#xff1a;在云原生技术飞速发展的今天&#xff0c;企业的集群规模正不断扩大&#xff0c;从单集群部署逐渐转向多集群、分布式架构。随之而来的是集群管理复杂度的激增——如何统一调度多集群资源、保障跨集群应用的一致性部署、简化运维操作并降低管理成本&#xff0c;…

作者头像 李华
网站建设 2026/4/23 15:35:51

Redis 零基础到进阶,Redis 主从复制,笔记55-62

Redis 零基础到进阶&#xff0c;Redis 主从复制&#xff0c;笔记55-62 一、参考资料 【尚硅谷Redis零基础到进阶&#xff0c;最强redis7教程&#xff0c;阳哥亲自带练&#xff08;附redis面试题&#xff09;】 https://www.bilibili.com/video/BV13R4y1v7sP/?p62&share_so…

作者头像 李华
网站建设 2026/4/27 14:06:40

OOM及资源监控管理

背景&#xff1a; 日常的业务应用中&#xff0c;可能因为应用本身的可靠性问题导致内存泄漏&#xff0c;把机器搞挂&#xff0c;影响服务器中其他业务运行。这篇文档主要是简单介绍下 Linux 内核OOM killer功能&#xff0c;以及我们可以通过sytemd来限制服务的资源使用&#x…

作者头像 李华