当前位置:首页 >> 政史地 >>

练习二 缓冲区溢出


2012-2013 学年第 2 学期 《网络安全课程设计》实验报告

实验名称: 缓冲区溢出——本地缓冲区溢出 完成时间: 2014.6.18 姓 名: 柳 鑫 鸿 学号: 110342118 班级: 110342A

指导教师: 崔

实验效果

实验报告

总评

r /> 任务一
本练习单人为一组。

利用跳转指令实现缓冲区溢出

首先使用“快照 X”恢复 Windows 系统环境。 一.溢出程序演示 (1)进入实验平台,单击工具栏“演示目录”按钮,进入实验目录。进入 Mission1 目 录,双击 overflow_win.exe,加载 ShellCode 执行溢出操作。

二.溢出实现 本练习操作通过缓冲区溢出来实现弹出消息框(MessageBox 对话框) 。针对 windows 平台实现缓冲区溢出,该实验实现溢出的方式及流程具有着一定的通用性。 我们需要开发实现两部分内容:一部分是漏洞程序 overflow ,该程序通过 memcpy 函 数实现缓冲区溢出(添加 shellcode 的代码到缓冲区中,使缓冲区溢出) ,当然你也可以通过 其它函数实现溢出。另一部分内容则是生成 shellcode,shellcode 是程序溢出后欲执行的指 令代码,如通过 shellcode 实现程序溢出后弹出对话框等功能。

对照图 22-2-1,在程序正常执行时,memcpy 函数被执行完毕后,指令指针会返回至 ret 地址处,继续执行 memcpy 函数调用处的后续指令;同时,执行完 ret 指令后 ESP 指针也会 指向堆栈原始区(调用 memcpy 函数前一时刻的堆栈分布) 。因此,我们可以将溢出代码 shellcode 存在堆栈原始区,而剩下的工作就是在 memcpy 执行 ret 返回时让 EIP 指针指向原 始区(也就是 ESP 指针指向的地址)即可。如何通过 ret 返回地址确定此时的堆栈 ESP 指针指 向呢?在这里采用的方法是通过跳转指令“jmp esp”(无条件跳转至 esp 指向处执行)。通过 在用户地址空间中查找到包含有“jmp esp”指令的存储地址,用该地址覆盖 ret 返回地址就 可以了。 在具体实现时,我们通过三个步骤完成缓冲区溢出: (1)编写前导码。 所谓前导码就是用于覆盖局部变量到 ret 返回地址之间的堆栈空间(不包括 ret 返回地址 空间)的指令码。前导码仅是用于填充堆栈,所以其内容不受限制。我们需要在实际的调试 中来确定前导码的大小。 「说明」 cl、 gcc 等诸多 C 编译器在为局部变量申请内存空间时, 经常要多出若干字节。 (2)查找 jmp esp 指令地址。 用”jmp esp”指令的地址覆盖 ret,就可以在 memcpy 执行返回后,让 CPU 执行跳转指 令,所以首要解决的是在用户空间中找到含有“jmp esp”指令的地址。通过 VC++6.0 的反 汇编功能得到“jmp esp”指令的机器码为 0xFFE4。利用 FindJmpesp 工具进行指令查找,确 定一个含有“jmp esp”指令的内存地址。 「注」在用户地址空间中会存在多个包含有 jmp esp 指令的地址。 (3)shellcode 功能体。 shellcode 功能体实现了溢出后主要的执行功能,如创建超级用户,提升用户权限等。在 这里我们通过自定义指令来实现弹出用户对话框。 1.编写前导码 单击工具栏“VC6”按钮,启动 VC++6.0。选择“File”|“Open Workspace?”加载工 程文件“C:\ExpNIS\NetAD-Lab\Projects\OverFlow\Mission1\overflow.dsw ” ,该工程包含两个 项目,overflow 和 CreateShellcode 项目,建议在 debug 版下进行开发调试。

将 overflow 项目设置为启动项目( Set as Active Project ) ,该项目仅有一个源文件 overflow.c ,在此源文件中提供了部分代码,注释的地方需要你根据实际调试结果来填写。 程序中提供了一个超长前导码,你需要对程序进行调试来确定实际需要的前导码长度。 调试过程如图 22-2-2 所示。

实验结果及截图: 设置断点:

遇到 ret 返回指令:

执行 ret 指令之后跳转到 49484746 地址处:

0x46,0x47,0x48,0x49 被替换,需要替换成 JMP ESP 指令地址:

在图 22-2-2 中可以看出, 0x49484746 四字节覆盖了 ret 返回地址, 请根据调试结果重新 确定 shellcode 指令集长度,确定 ret 返回地址能够被前导码的后续 4 字节覆盖。 2.查找 jmp esp 指令地址 我们需要在用户地址空间中找到包含有 jmp esp 指令(机器码为 0xFFE4)的地址。运行 FindJmpesp 工具,选取一个地址追加到 shellcode 尾(追加填加地址时注意数组高字节对应 地址高位) ,所选 jmp esp 指令地址是 0x77e424da 。

跟踪调试程序,确定在 memcpy 执行返回时 jmp esp 指令是否被执行。调试过程如图 22-2-3 所示。 「说明」 可以在 shellcode 尾部继续追加空指令(0x90,空指令不进行任何操作),这样 便 于 确 定 执 行 jmp esp 后 指 令 指 针 的 指 向 。

实现结果及截图: 在 cmd 下查找 JMP ESP 指令的地址:

将查找到得 JMP ESP 地址写入 shellcode[] ,并在后边添加 0x90 空指令用于调试:

即将要执行 ret 返回指令:

执行到 jmp esp 指令处:

进入 jmp esp 指令中执行(我们想要执行 jmp esp 指令跳转到 shellcode 程序) :

从图 22-2-3 可以看出, 在 jmp esp 指令执行完毕后, 指令指针紧接着执行了 3 个空指令, 而空指令是追加在 shellcode 尾部的。所以我们下一步所要做的工作就是将实现弹出对话框 的指令码追加至 shellcod 中 jmp esp 指令地址的后面。 3.生成实现弹出对话框的指令码 我们最终的目的是要通过缓冲区溢出实现弹出消息对话框,而这些功能都应该在 shellcode 得以实现。 通过在 shellcode 中调用 MessageBoxA API 函数, 并确定好 MessageBoxA 所需的 4 个参数: 窗体句柄、 标题显示、 内容显示和风格即可以实现弹出指定内容的对话框。 根据 Windows API 文档,MessageBoxA 依赖于 user32.lib,也就是说它位于 user32.dll 动态链接库中。单击工具栏“Depends ”按钮,启动 Depends 工具,Depends 打开应用程序 C:\ExpNIS\NetAD-Lab\Tools\OverFlow\Mission1\overflow_win.exe , 可 以 发 现 它 将 加 载 user32.dll。然后寻找 MessageBoxA 函数的内存位置。具体操作如图 22-2-4 所示。

(1)在左侧 Module 树状视图中选中“USER32.DLL”节点; (2)在右侧导出函数列表视图中遍历 Function 属性列,查找函数“MessageBoxA” (序 号 480) ; (3)在下侧 Module 列表视图中遍历 Module 属性列,查找模块“USER32.DLL” 。 在这里的 user32.dll 中,MessageBoxA( ASCII 版本)函数的偏移量(Entry Point)为 0x0003D8DE。 User32.dll(Module) 在内存中的起始地址(Base)为 0x77E10000。将两者相加即 可得到 MessageBoxA 函数的绝对内存地址。所以我们需要在汇编代码中正确设置堆栈并调 用 MessageBoxA 函 数 的 绝 对 内 存 地 址 , 该 地 址 为 0x0003D8DE + 0x77E10000 =0x77E4D8DE 。 另外还需要调用执行函数 ExitProcess( 位于 KERNEL32.dll 中),其目的就是在单击弹出 框 “ 确 定 ” 按 钮 后 程 序 自 动 退 出 , 函 数 ExitProcess 的 绝 对 内 存 地 址 0x00013039+0x7c800000=0x7c813039 。 在 overflow 工程中将 Createshellcode 项目设置为启动项目,该项目仅有一个源文件 Createshellcode.c ,在此源文件中提供了全部的代码及注释说明。代码的主体部分是用汇编

语言实现的,其功能就是在实现了弹出对话框后自动退出程序。 将函数 MessageBoxA 和 ExitProcess 的绝对内存地址填写到指定位置。 在理解了 Createshellcode.c 中的汇编部分代码后, 就可以利用 VC++6.0 反汇编功能获取 代码字节,调试过程如图 22-2-5 所示。

将代码字节以十六进制数据形式继续追加到 shellcode 尾。 重新编译执行。 实验结果及截图: 打开 C:\ExpNIS\NetAD-Lab\Tools\OverFlow\Mission1\overflow_win.exe:

寻找 MessageBoxA 函数的入口地址,查找到 Entry Point 为 0x0003D8DE:

查找 MessageBoxA 函数的起始地址(Base)为 0x77E10000:

寻找执行函数 ExitProcess( 位于 KERNEL32.dll 中 ) 的入口地址,查找到 Entry Point 为 0x00013039:

查找 ExitProcess 函数的起始地址(Base)为 0x7C800000:

填写绝对地址到源文件 Createshellcode.c 中:

在 shellcode 尾添加代码:

任务二

定位参数地址实现缓冲区溢出

一.溢出程序演示 (1)进入实验平台,单击工具栏“演示目录”按钮,进入实验目录。进入 Mission2 目 录,该目录中有三个文件: OverFlowClient.exe 该文件是执行体文件,功能是新建 Administrators 组用户 jlcss ,用户密码 1234。 CreateShellCode.exe 该文件是 shellcode 生成文件, 功能是从 OverFlowClient.exe 文件中提取功能代码, 并最 终生成完整的 shellcode.shc 文件。 OverFlowServer.exe 该文件是漏洞溢出文件,功能是加载 shellcode.shc 文件,并实现通过缓冲区溢出完成新 建 Administrators 组用户 jlcss 。 (2)执行 OverFlowClient 执行 OverFlowClient 文件,当出现“ShellCode 执行完毕,请按回车退出”提示信息时, 表明程序已被成功执行,退出程序。右键单击“我的电脑” ,选择“管理”进入“计算机管 理” ,依次选择“本地用户和组”|“用户” ,查看右侧“jlcss”用户信息及其隶属组。删除 jlcss 用户。 程序已被成功执行:

“jlcss ”用户信息及其隶属组:

删除 jlcss 用户:

(3)执行 CreateShellCode 执行 CreateShellCode 文件,当出现“Shellcode 指令集生成完毕,请按回车退出”提示 信息时,表明程序已被成功执行,并且 shellcode.shc 文件已成功生成。右键单击生成的 shellcode.shc 文件,使用“ UltraEdit-32”打开,查看 shellcode 指令码。这些指令码就是 CreateShellCode 从 OverFlowClient.exe 中提取出来的功能码。退出 UltraEdit-32。 执行 CreateShellCode 文件,shellcode.shc 文件成功生成:

shellcode 指令码:

(4)执行 OverFlowServer 执行 OverFlowServer.exe,当出现“溢出成功! 请按回车键退出”提示信息时,表明 程序已被成功执行,并且缓冲区溢出操作成功。再次打开“计算机管理”查看系统用户 jlcss 信息。OverFlowServer.exe 就是加载了 shellcode.shc 文件,在缓冲区溢出后执行了其中的指 令码。 执行 OverFlowServer.exe:

OverFlowServer.exe 就是加载 shellcode.shc 文件,生成用户 jlcss 成功:

二.溢出实现 「注」 进行此操作步骤前,删除 jlcss 用户。 1.进入工程 单击工具栏“VC6”按钮,启动 VC++6.0。选择“File”|“Open Workspace?”加载工 程文件“C:\ExpNIS\NetAD-Lab\Projects\OverFlow\Mission2\OverFlowServer.dsw ” 。该工程包 含三个项目:CreateShellCode、OverFlowClient 和 OverFlowServer 。项目功能说明见源文件。

2.生成 shellcode 功能体 (1)首先设置 OverFlowClient 项目为启动项。 (2) 双击打开 OverFlowClient.cpp 源文件, 在该源文件中需要填写的代码有: kernel32.dll 基址(第 21 行) ,LoadlibraryA 函数的绝对内存地址(第 23 行)和 shellExecuteA 函数(隶 属 于 Shell32.dll 动 态 库 ) 的 绝 对 内 存 地 址 ( 第 25 行 ) 。 使 用 Depends 工 具 打 开 C:\ExpNIS\NetAD-Lab\Tools\BufferLeakTools\FindShellBase\FindShellBase.exe 文件定位上述 内存地址,具体操作参见任务一。

kernel32.dll 基址:

LoadlibraryA 函数地址:

Shell32.dll 基址:

shellExecuteA 函数函数地址 :

(3)编译并生成 OverFlowClient.exe,执行 OverFlowClient.exe,确定系统是否新建了 jlcss 用户,并隶属 Administrators 组。

3.生成 shellcode 指令码 (1)设置 CreateShellCode 为启动项。 双击打开 CreateShellCode.cpp 源文件, CreateShellCode 的工作流程是: 首先生成 shellcode 头,并将相关指令码写入 shellcode.shc 文件中;接下来是生成 shellcode 功能体,功能体代 码来自 OverFlowClient.exe 中 shellcode 函数执行体,将功能体代码追加到 shellcode.shc 中; 最后是生成 shellcode 尾,同样将其指令码追加到 shellcode.shc 中。 (2)这里需要填写的宏数值有: 第 16 行 SHELLCODE_BODY_START (OverFlowClient.exe 中 ShellCode 主体起始偏移 地址) ; 第 17 行 SHELLCODE_BODY_LEN(OverFlowClient.exe 中 ShellCode 主体代码长度) ; 第 18、66 行 CORRECT_RET URN_ADDR(OverFlowServer 中 overflow 调用完成后程 序正常执行返回地址,即 OverFlow 正常调用完成后的下一条指令地址) ; 第 72 行在 OverFlowServer 中函数 OverFlow 调用执行前,ebp 基地指针地址; 第 76 行 OverFlow 溢出返回地址,即函数溢出后 shellcode 得以执行的首地址。 ① 获取 SHELLCODE_BODY_START 、SHELLCODE_BODY_LEN 值 调试 OverFlowClient.exe(将该项目设置为启动项)确定 ShellCode 函数入口偏移地址 及函数体大小,调试过程参见图 22-2-6 所示。

ShellCode 函数入口偏移地址 :

ShellCode 函数结束偏移地址:

两者相减得 shellcode 大小为 0x00000197。. ②根据调试结果填写 CreateShellCode.cpp 源文件中 SHELLCODE_BODY_START 宏和 SHELLCODE_BODY_LEN 宏的值。

③ 其它数值需要通过调试 OverFlowServer 来获取, 而 OverFlowServer 的执行又依赖于 shellcode.shc 文件,所以暂且编译生成 CreateShellCode.exe 文件,执行该文件生成临时 shellcode.shc 文件。

4.调用 OverFlowServer 上接步骤 3,我们已经获得了 ShellCode 执行体指令码,还需要获取溢出后程序正常返 回地址、OverFlow 函数调用前 ebp 基础指针地址和 shellcode 执行的缓冲区首地址。 (1)OverFlow 正常调用返回时的下一条指令地址。 设置 OverFlowServer files 为启动项, 双击打开 OverFlowServer.cpp 文件。 程序首先打开 存放 shellcode 指令码的文件(默认名称为 shellcode.shc) ,读取 shellcode.shc 的全部内容至接 收缓冲区中。接下来就是利用 memcpy 函数实现接收缓冲区的拷贝,目标地址是 OverFlow 函数内的局部缓冲区, 该缓冲区默认大小为 450 字节, 需要根据实际调试结果重新确定其大 小。最后在 OverFlow 调用完成后程序继续执行(溢出执行后程序依然能够正常继续运行)。 调整 TempBuffer 缓冲区大小,使其大于临时 shellcode 指令码长度,这样做的目的是让 程序正常执行(不发生溢出) ,以便我们能够获取 OverFlow 函数执行调用后的正确返回地 址。 调试获取 OverFlow 函数正常调用执行后的下一条指令地址。 调试过程如图 22-2-7 所示。

填写该指针地址到 CreateShellCode.cpp 文件中。 18 行:

66 行:

(2)OverFlow 函数调用前 ebp 基地址指针。 单步调试程序定位到 OverFlow 函数入口处,获取此时的 EBP 指针地址,如图 22-2-8 所示。

填写 EBP 指针地址到 CreateShellCode.cpp 文件中。

(3)最后我们来确定 shellcode 的最后 4 字节,从实验原理中可知需用这 4 字节数覆盖 调用返回地址,使得 shellcode 得以执行。从 OverFlowServer 程序又可知 shellcode 最后被加 载到 TempBuffer 缓冲区,所以只要用 TempBuffer 缓冲区首地址覆盖调用返回地址,在程序 溢出后 shellcode 便会执行了。调用 OverFlowServer.exe 确定 OverFlow 调用执行过程中 TempBuffer 缓冲区的首地址。调试过程如图 22-2-9 所示。

将 TempBuffer 缓冲区首地址填写到 CreateShellCode.cpp 文件中。

至此全部的 shellcode 指令生成完毕,运行 Createshellcode.exe 生成完整的 shellcode.sh 文件,使用 UltraEdit 编辑器对其进行查看。 5.调试确定 TempBuffer 缓冲区大小 调试 OverFlowServer.exe 得到 OverFlow 调用返回时的地址, 将返回地址与 shellcode.shc 中的十六数相比较,有三种比较结果:

(1)返回地址是 shellcode 最后 4 字节数据。函数返回时执行 shellcode。 (2)返回地址没有在 shellcode.sh 中,缓冲区空间过大,溢出未发生。可以缩小缓冲区 空间或在最后 8 个字节前用 0x90(空指令)补充。 (3)返回地址在 shellcode.sh 中(不是最后 4 字节数据),缓冲区空间过小。放大缓冲区 空间。 当改变 TempBuffer 缓冲区大小时,其首地址可能会发生变动,调试确定 TempBuffer 首 地址,重新填写 CreateShellCode.cpp,并重新生成 shellcode.shc 。 经过多次调试后确定缓冲区大小, 当满足第一种比较结果时, 缓冲区溢出就可以执行下 去。运行程序,查看系统用户 jlcss( 若 jlcss 用户已存在,请先将其删除再运行程序)及其所属 用户组。 6.回答问题 请根据调试结果填写实验结果。 (1)OverFlowServer.exe 程序中,shellcode 函数入口偏移地址 0x00401020 大小 0x00000197 (字节)。 及函数体

( 2 ) OverFlowServer.exe 程 序 中 , 在 OverFlow 调 用 前 ebp 基 地 址 0x0012ff80 和正常调用返回时的指令地址 0x0040110a 。 (3) OverFlowServer.exe 程序中, TempBuffer 缓冲区内存地址 (首地址) 及其大小 430 (字节)。 0x0012f968

Createshellcode:

OverFlowClient:

OverFlowServer:


相关文章:
练习二 缓冲区溢出
2012-2013 学年第 2 学期 《网络安全课程设计》实验报告 实验名称: 缓冲区溢出——本地缓冲区溢出 完成时间: 2014.6.18 姓名: 柳鑫鸿 学号: 110342118 班级:...
网络信息安全教学实验系统v3.2(参考答案)
网络信息安全教学实验系统v3.2(参考答案)_IT/计算机_专业资料。保存 ...39 练习一 缓冲区溢出攻击 ... 39 练习二 本地缓冲区溢出 ......
网络信息安全综合实验系统v3.5(原理篇)
283 练习一 缓冲区溢出攻击 ... 283 练习二 本地缓冲区溢出 ... 285 任务一 利用跳转指令实现缓冲区溢出 ... 285 任务二 定位参数地址...
1.网络信息安全教学实验系统实验教程(实验篇)
283 练习四 Wireshark 工具的使用与 TCP 数据包分析 ... 286 IV 练习五 使用...293 练习二 本地缓冲区溢出 ... 298 任务一 利用跳转指令实现缓冲区溢出 .....
更多相关标签: