软件安全复习
一、缓冲区溢出基础
1、缓冲区溢出原理
缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过 了缓冲区本身的容量溢出的数据覆盖在合法数据上。
2、进程内存空间分区
①虚拟内存相关知识

②PE文件与虚拟内存之间的映射




3、系统栈的工作原理-内存的不同用途
①缓冲区溢出漏洞危害
成功地利用缓冲区溢出漏洞可以修改内存中的变 量的值,甚至可以劫持进程,执行恶意代码,最 终获得主机的控制券。

②内存的四个部分

③函数栈帧


④函数调用步骤


⑤函数返回步骤


二、字符串安全
导致缓冲区溢出、程序栈、弧注入、代码注入
1、常见的字符串操作错误
①无界字符串复制
无边界字符串复制发生于从一个无边界数据源复制数据到一个定长的字符数组时。
②复制和连接字符串
复制和连接字符串时也容易出现错误,因为标准 strcpy() 和strcat() 函数执行的都是无边界复制操作。
③空结尾错误

当使用C风格字符时,另一个常见的问 题是 字符串末尾没有正确的空字符。
④字符串截断

⑤数组写入越界

⑥差一错误
⑦不恰当的数据处理
2、恶意代码


3、弧注入

4、缓解措施

黑名单、白名单


5、不安全的字符串API


三、软件漏洞基础
1、软件漏洞的概念
把一类能够引起软件做一些“超出设计范围的事情”的bug称为漏洞

2、软件漏洞的危害
- 关键数据丢失
- 秘密信息泄露
- 被安装木马病毒
3、安全漏洞出现的原因

四、漏洞利用技术
1、ShellCode与Exploit的概念

-
向进程中植入一段用于获得shell的代码,这段 代码称为shellcode
- 后来统一用shellcode来统称缓冲区溢出攻击中植入进程的代码。
-
植入代码之前需要做调试工作
- 弄清楚程序的输入点,输入会当做哪个函数的参数读取到内存的哪一个区域,哪一个输入会造成栈溢出等等。
- 调试后计算函数返回地址和缓冲区的偏移并淹没返回地址来使得shellcode得到执行。
- 这个代码的植入过程就是漏洞利用,即exploit。
2、栈帧移位与jmp esp
①栈帧移位---返回地址为固定地址

②jmp esp
一般情况下,ESP寄存器中的地址总是指向系统栈中,且不会被溢出的数据破坏。函数返回的时候,ESP所指的位置恰好是我们所淹没的返回地址的下一个位置。

在利用跳板之前,必须在进程空间中找到一条jmp esp指令的地址作为“跳板”。除了PE文件的代码被读入到内存空间,一些经常被用到的动态链接库也将会一同被映射到内存。其中,注入kernel32.dll,user32.dll之类的动态链接库几乎会被所有的进程加载,且加载基址始终相同。
3、缓冲区的组成


另外一种shellcode组织方式

可能会遇到的问题

解决:抬高栈顶

增加nop来增加靶子面积

五、漏洞挖掘与模糊测试
1、fuzz测试的概念与主要目标
①概念
- 测试用例往往是带有攻击性的畸形数据,用来出发各种类型的漏洞。
- 利用“暴力”来实现对目标程序的自动化测试,然后监视检查其最后的结果。
②目标
- 使得程序产生报错,发现漏洞
- 不断地输入不同长度的字符串,检测缓冲区溢出攻击。
2、文件格式fuzz测试的主要步骤


- 以一个正常的文件模板作为基础,按照一定规则产生一批畸形文件。
- 将畸形文件逐一送入软件进行解析,并监视软件是否会抛出异常。
- 记录软件产生的错误信息,如寄存器状态、栈状态等等。
- 用日志或者其他UI形式向测试人员展示异常信息,以进一步鉴定这些错误是否能被利用。
3、smart fuzz的主要特征
- 面向逻辑
- 首先明确要测试的目标是解析文件的程序逻辑,而不是文件本身。
- 面向数据类型
- 可以生成的数据包括:算术型(HEX,ASCII等各种数值),指针型(包括NUll、合法/非法的内存指针),字符串型(超长字符串,缺少终止符),特殊字符。
- 基于样本
- 测试前首先构造一个合法的样本文件(也叫模板文件),样本要尽可能多的包含测试所用到文件的数据结构。
- 以这个文件为模板,每次只改动一小部分数据和逻辑来生成畸形文件。(也称为变异)
4、FTPfuzz

六、指针安全
1、基本概念
指针安全是通过修改指针指来利用程序漏洞的方法的统称。
- 可以通过覆盖函数指针将程序的控制权移到攻击者提供的shellcode
- 对象指针也可以被修改,从而执行任意代码
①缓冲区溢出覆写指针条件

2、修改指令指针



3、虚函数攻击


4、windows内存安全机制:GS编译、DEP、Heap cookie、safe Unlink、ASLR
操作系统在程序运行时候可能遇到的错误:除0,非法内存访问,文件打开错误,内存不足,磁盘读写错误、外设操作失败。
①S.E.H概述

结构体:

S.E.H链表




②GS编译技术
- 在函数返回地址前首先检测SecurityCookie是否被覆盖,从而把针对操作系统的栈溢出变得非常困难。



③DEP



④Heap Cookie



⑤ASLR



七、格式化输出
1、格式化输出函数原理

2、典型的格式化输出函数和格式化符
①格式化输出函数
- fprintf()按照格式字符串的内容,将输出写入到流中。
- 流与格式字符串和变参列表一起作为参数提供给函数。
- sprintf()等同于fprintf(),但是输出不是写入流,而是写入数组中。
- snprintf()等同于sprintf(),但是它指定了可写入字符的最大值n。
- 还有vsnprintf(),vsprintf()等等函数
②格式化符与格式字符串
详解
基础知识:
-
格式字符串是由普通字符(包括%)和转换规范构成的字符序列。
-
普通字符被原封不动地复制到输出流中。
-
转换规范根据与实参对应的转换指示符对其进行转换,然后将结果写入到输出流中。
-
转换规范通常以%开始按照从左向右的顺序解释。
-
参数过多,多余的参数将被忽略,参数不足,结果就是没有定义的。
-
转换规范的组成:
- 可选域:
- 标志、宽度、精度以及长度修饰符
- 必须域:
- 转换指示符

- 可选域:
例子说明:
%-10.8ld
# -是标志位
# 10代表宽度:用来指定输出字符的最小个数的十进制非负整数,如果输出的字符个数比指定的宽度小,就用空白字符补足。
# 8代表精度:用来指示打印字符的个数、小数位数或者有效数字个数的十进制非负整数。
# l是长度修饰符
# d是转换指示符
将一个long int型的参数按照十进制格式打印,在一个最小宽度为10个字符的域中保持最少8位左对齐。
3、格式化输出函数可能导致的安全问题
①缓冲区溢出

②查看栈内容



4、可扩展的缓冲区
案例一



5、使程序崩溃


6、覆写内存


八、整数安全
1、整数表示方法:原码、反码、补码
解释:https://www.cnblogs.com/zh-dream/p/11663569.html


正数的反码不变

2、带符号和无符号整数
①带符号整数
- 用来表示正值和负值

②无符号整数

③标准类型与扩展类型


3、整数取值范围


short占两个字节,int占4个字节
4、整数转换、整型提升、隐式转换

整型提升


隐式转换

5、整数转换规则
①整数转换级别
每 一 种 整 数类 型 都 有 一个 相 应 的 整型 转 换 级 别 ( integer conversion rank),决定了转换操作将会如何执行

②从无符号整型转换


转换表

③带符号整型转换


可以说是最高位为1,直接转换,那指定是非常大。

④转换例子

6、整数溢出类别及原理:整数溢出、截断错误、符号错误
①整数溢出



②截断错误



1000 0000 0000 0000 0000 0000 0000 0011(-3的原码)
1111 1111 1111 1111 1111 1111 1111 1100(-3的反码)
1111 1111 1111 1111 1111 1111 1111 1101(-3的补码)
③符号错误



更多文章请关注《万象专栏》
转载请注明出处:https://www.wanxiangsucai.com/read/cv129819