20199108 2019-2020-2 《网络攻防实践》第10周作业
1.实践内容
软件安全漏洞威胁
美国国家标准技术研究院NIST将安全漏洞定义为:在系统安全流程、设计、实现或内部控制中所存在的缺陷或弱点,能够被攻击者所利用并导致安全侵害或对系统安全策略的违反。
- 三个基本元素
系统的脆弱性或缺陷
攻击者对缺陷的可访问性
攻击者对缺陷的可利用性
- 软件安全困境
复杂性
可扩展性
连通性
- 软件安全的漏洞威胁
内存安全违规类:
-
在软件开发过程中在处理RAM内存访问时所引入的安全缺陷 缓冲区溢出漏洞是一种最基础的内存安全问题
-
输入验证类:
输入验证类安全漏洞是指软件程序在对用户输入进行数据验证存在的错误,没有保证输入数据的正确性、合法性和安全性,从而导致可能被恶意攻击与利用。
XSS、SQL注入、远程文件包含、HTTP Header注入等 -
竞争条件类:
竞争条件类缺陷是系统或进程中一类比较特殊的错误,通常在涉及多进程或多线程处理的程序中出现,是指处理进程的输出或结果无法预测,并依赖于其他进程事件发生的次序或时间时,所导致的错误。 -
权限混淆与提升类:
权限混淆与提升漏洞是指计算机程序由于自身编程疏忽或被第三方欺骗,从而滥用其权限,或赋予第三方不该给予的权限。
跨站请求伪造、FTP反弹攻击、权限提升、“越狱"等
缓冲区溢出
缓冲区溢出基本概念
- 缓冲区溢出是计算机程序中存在的一类内存安全违规类漏洞,在计算机程序向特定缓冲区内填充数据时,超出了缓冲区本身的容量,导致外溢数据覆盖了相邻内存空间的合法数据,从而改变程序执行流程破坏系统运行完整性
缓冲区溢出攻击背景知识
编译器与调试器的使用
汇编语言基础知识(特别是IA32)
进程内存管理
函数调用过程
调用:调用者将函数调用参数、函数调用下一条指令的返回地址压栈,并跳至被调用函数的入口地址
序言:被调用函数开始执行首先会进入序言阶段,将对调用函数的栈基址进行压栈保存,创建函数自身结构栈等工作
返回:被调用函数执行完功能将指令控制权返回给调用者之前,会进行返回阶段的操作
- 缓冲区溢出攻击原理
栈溢出
堆溢出
内核溢出
缓冲区溢出的根本问题在于,用户输入可控制的缓冲区操作缺乏对目标缓冲区的边界安全保护。如果用户输入无法到达漏洞利用点,那么这类缓冲区溢出只能被称为安全缺陷,而不能被称为安全漏洞。
Linux平台上的栈溢出与shellcode
Linux平台栈溢出攻击技术
NSR模式
适用于被溢出的缓冲区变量比较大,足以容纳shellcode的情况
RNS模式
一般用于被溢出的变量比较小,不足容纳shellcode的情况
RS模式
这种模式能够精确地定位出shellcode在目标漏洞程序进程空间中的起始地址
Linux系统中本地shellcode的产生过程
先用高级编程语言,C,来编写shellcode程序
编译并反汇编调试这个shellcode程序
从汇编语言代码级别分析程序执行流程
整理生成的汇编代码,尽量减少它的体积使他可注入,并可通过嵌入C语言进行运行测试和调试
提取汇编代码所对应的opcode二进制指令,创建shellcode指令数组
通过系统调用 execve 函数返回 shell
#include<unistd.h>
#include<stdlib.h>
char *buf [] = {"/bin/sh", NULL};
void main()
{
execve("/bin/sh", buf, 0);
exit(0);
}
execve函数在父进程中 fork 一个子进程,在子进程中调用exec函数启动新的程序。
execve()用来执行第一参数字符串所代表的文件路径,第二个参数是利用指针数组来传递给执行文件,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。
从程序中可以看出,如果通过 C 语言调用execve来返回 shell 的话,首先需要引入相应的头文件,然后在主函数中调用系统调用函数execve,同时传入三个参数。
Windows平台上的栈溢出与shellcode
成功攻击应用程序中栈溢出漏洞密切相关的主要有以下三点:
对程序运行过程中废弃栈的处理方式差异
进程内存空间的布局差异
系统功能调用实现方式差异
Windows平台shellcode实现技术
shellcode必须可以找到所需要的Windows32 API函数,并生成函数调用表
为了能够使用API函数,shellcode必须找到目标程序已加载的函数地址
shellcode需考虑消除空字节,以免在字符串操作函数中被截断
shellcode需确保自己可以正常退出,并使原来的目标程序进程继续运行或终止
在目标系统环境存在异常处理和安全防护机制时,shellcode需进一步考虑如何应对这些机制
打开控制台窗口的 C 程序如下:
#include <windows.h>
int main()
{
LoadLibrary(“msvcrt.dll”); //调用 msvcrt.dll 动态链接库
system(“command.com”); //使用 system 函数,执行弹窗命令
return 0;
}
修改后的版本:
#include <windows.h>
#include <winbase.h>
typedef void (*MYPROC) (LPTSTR); //定义一个函数指针,指向函数的参数是字符串,返回值是空
int main()
{
HINSTANCE LibHandle;
MYPROC ProcAdd;
LibHandle = LoadLibrary(“msvcrt.dll”); //加载 msvcrt.dll 这个动态链接库,句柄赋给 LibHandle
ProcAdd = (MYPROC)GetProcAddress(LibHandle, “system”); //获得 system 的真实地址,之后再使用这个真实地址来调用 system 函数,ProcAdd 存的是 system 函数的地址
(ProcAdd)(“command.com”); //调用 system(“ command,com”),实现功能
return 0;
}
堆溢出攻击
-堆溢出是缓冲区溢出中第二种类型的攻击方式,由于堆中的内存分配与管理机制较栈更复杂,不同操作系统平台的实现机制具有显著的差异。
函数指针改写
C++类对象虚函数表改写
Linux下堆管理glibc库free()函数本身漏洞
缓冲区溢出攻击的防御技术
- 要是缓冲区溢出攻击奏效,攻击者通常先通过溢出植入攻击代码,然后通过修改关键数据结构改变执行流程,最后让攻击代码执行。
尝试杜绝溢出的防御技术
允许溢出但不让程序改变执行流程的防御技术
无法让攻击代码执行的防御技术
2.学习中遇到的问题及解决
- 问题1:对于书中获取 shell 权限代码不太理解
- 问题1解决方案:通过资料查询,阅读具体案列
3.实践总结
本章内容不仅涉及到高级语言、汇编语言等,还进一步拓展到了操作系统底层的内容,需要反复研究和学习,是很有难度的。