1. 漏洞利用实战:从伪随机数到flag获取的全过程解析
最近在练习CTF中的pwn题目时,遇到一道名为"dice_game"的题目,这道题巧妙利用了C语言中伪随机数的特性,结合栈溢出漏洞,最终实现了对flag的获取。下面我将详细拆解这道题的解题思路和实现过程。
1.1 题目背景与初步分析
题目提供了两个关键文件:一个可执行程序dice_game和一个libc动态链接库。从文件名和内容来看,这是一个模拟骰子游戏的程序,玩家需要通过猜测随机数来获胜。但作为安全研究者,我们需要透过表象看本质。
首先使用checksec工具检查程序的安全保护机制:
code复制Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
可以看到除了Canary保护关闭外,其他保护全开。这意味着:
- 没有栈保护(Canary),可能存在栈溢出漏洞
- NX(不可执行栈)开启,无法直接执行shellcode
- PIE(地址随机化)开启,需要处理地址偏移问题
1.2 程序逻辑逆向分析
使用IDA Pro对程序进行反编译,可以清晰地看到程序的执行流程:
主函数逻辑
- 打印游戏介绍
- 读取玩家姓名(存在栈溢出风险)
- 初始化随机数种子(srand)
- 进入游戏循环(sub_A20函数)
- 当胜利次数达到50次时,调用sub_B28函数
关键点在于随机数种子的初始化位置和玩家姓名输入的缓冲区大小。
随机数生成分析
程序使用srand设置随机数种子,然后通过rand生成随机数。这里需要理解C语言随机数的本质:
- srand(seed)设置种子
- rand()根据种子生成伪随机数序列
- 相同种子必然产生相同的随机数序列
关键函数sub_B28
这个函数会在玩家胜利50次后被调用,其功能非常简单:直接打开并读取flag文件内容。这显然是我们需要触发的目标。
2. 漏洞利用思路
2.1 栈溢出漏洞定位
通过分析栈帧结构,发现玩家姓名输入缓冲区(buf)和随机数种子(seed)在栈上是相邻的:
code复制+-
