软件安全第四章 软件漏洞

4.1 缓冲区溢出漏洞

4.1.1 基本概念
(1)漏洞的基本概念
(2)缓冲区溢出漏洞
  • 缓冲区定义:

    • 缓冲区是一块连续的内存区域,用于存放程序运行时加载到内存的运行代码和数据。

  • 缓冲区溢出:

    • 缓冲区溢出是指程序运行时,向固定大小的缓冲区写入超过其容量的数据,多余的数据 会越过缓冲区的边界覆盖相邻内存空间,从而造成溢出。

    • 缓冲区的大小是由用户输入的数据决定的,如果程序不对用户输入的超长数据作长度检 查,同时用户又对程序进行了非法操作或者错误输入,就会造成缓冲区溢出。

(3)缓冲区溢出攻击
  • 定义:

    • 缓冲区溢出攻击是指发生缓冲区溢出时,溢出的数据会覆盖相邻内存空间的返回地址、 函数指针、堆管理结构等合法数据,从而使程序运行失败、或者发生转向去执行其它程序代 码、或者执行预先注入到内存缓冲区中的代码。

  • 出现的原因:

    1. 缺乏类型安全功能的程序设计语言(C、C++等)出于效 率的考虑,部分函数不对数组边界条件和函数指针引用等进行边界检查。

      • 例如,C 标准库中 和字符串操作有关的函数,像strcpy、strcat、sprintf、gets等函数中,数组和指针都没 有自动边界检查。

  • 要求:程序员必须进行自我检查

4.1.2 栈溢出漏洞
(1)基本概念
  • 栈溢出漏洞,即发生在栈区的溢出漏洞。当被调用的子函数中写入数据的长度,大于栈 帧的基址到esp之间预留的保存局部变量的空间时,就会发生栈的溢出。要写入数据的填充 方向是从低地址向高地址增长,多余的数据就会越过栈帧的基址,覆盖基址以上的地址空间。

(2)栈溢出漏洞示例
  1. 修改返回地址

主函数调用函数f,并没有调用why_here,但是运行结果出现了字符串

#include <stdio.h>;  
#include <stdlib.h>;  
//Have we invoked this function? 
void why_here(void) 
{ 
    printf("why u r here?!\n");  
    exit(0);  
} 
void f() 
{ 
    int buff[1]; 
    buff[2] = (int)why_here; 
}  
int main(int argc, char * argv[]) 
{ 
    f(); 
    return 0; 
}

2. 覆盖临界变量

4.1.3 堆溢出漏洞
(1)基本概念
  • 堆溢出是指在堆中发生的缓冲区溢出。堆溢出后,数据可以覆盖堆区的不同堆块的数据, 带来安全威胁。实验一:==使用OllyDBG运行示例4-1生成的可执行程序,观察栈帧变化情况,特别是返 回地址的数值在调用函数f之前和调用f时候的变化,进一步掌握OllyDBG的使用。

(2)堆溢出漏洞利用
  • 堆溢出的实现难度更大,而且往往要求进程在内存中具备特定的组织结 构。然而,堆溢出攻击也已经成为缓冲区溢出攻击的主要方式之一。堆溢出带来的威胁远远 不止上面示例演示的那样,结合堆管理结构,堆溢出漏洞可以在任意位置写入任意数据。

Dword Shoot 攻击:通过堆溢出覆写了一个空闲堆块的块首的前向指针 flink 和后向指针 blink,我们可以精心构造一个地址和一个数据,当这个空闲堆块从链表里卸下 的时候,就获得一次向内存构造的任意地址写入一个任意数据的机会。这种能够向内存任意 位置写入任意数据的机会称为“Arbitrary Dword Reset”(又称 Dword Shoot)。具体如下 图所示。

4.1.4 SEH 结构覆盖

异常处理结构体:是 Windows 异常处理机制所采 用的重要数据结构。

  • SEH结构体存放在栈中,栈中的多个SEH通过链表指针在栈内由栈顶向栈底串成单向链表,

  • 位于链表最顶端的SEH通过线程环境块(TEB,Thread Environment Block) 0 字节偏移处的指针标识。

  • 每个SEH包含两个DWORD指针:SEH链表指针和异常处理函数句柄, 共8个字节。SEH链表结构图如下图所示。

SEH的作用:

  1. 线程初始化的时候,自动向栈中安装一个SEH,作为线程默认的异常处理。如果程序 源代码中使用了_try{}_except{}或者Assert宏等异常处理机制,编译器将最终通过向当前函数栈帧中安装一个SEH来实现异常处理。

  2. 当异常发生时,操作系统会中断程序,并首先从TEB的0字节偏移处取出距离栈顶 最近的SEH,使用异常处理函数句柄所指向的代码来处理异常。当最近的异常处理函 数运行失败时,将顺着SEH链表依次尝试其他的异常处理函数。

  3. 如果程序安装的所有异常处理函数都不能处理这个异常,系统会调用默认的系统处 理程序,通常显示一个对话框,你可以选择关闭或者最后将其附加到调试器上的调 试按钮。如果没有调试器能被附加于其上或者调试器也处理不了,系统就调用 ExitProcess终结程序。

SEH攻击:

  • 通过栈溢出或者其他漏洞,使用精心构造的数据覆盖SEH链表的入口地址、 异常处理函数句柄或链表指针等,实现程序执行流程的控制。

  • 因为发生异常的时候,程序会 基于SEH链表转去执行一个预先设定的回调函数,攻击者可以利用这个结构进行漏洞利用攻 击。

  • 由于SEH存放在栈中,利用缓冲区溢出可以覆盖SEH;如果精心设计溢出数据,则有可能把SEH中异常处理函数的入口地址更改为恶意程序的入口地址,实现进程的控制。

4.1.5 单字节溢出

单字节溢出是指程序中的缓冲区仅能溢出一个字节。单字节溢出的原理通过下面的样例进行分析。

void single_func(char *src) 
{ 
char buf[256]; 
int i; 
for(i = 0;i <= 256;i++) 
buf[i] = src[i]; 
} 
  • 缓冲区溢出一般是通过覆盖堆栈中的返回地址,使程序跳转到shellcode或指定程序处 执行。

  • 然而在一定条件下,当缓冲区只溢出一个字节时,单字节溢出也是可以利用的,但实 际上利用难度较大。

  • 因为它溢出的一个字节必须与栈帧指针紧挨,就是要求必须是函数中首 个变量,一般这种情况很难出现。尽管如此,程序员也应该对这种情况引起重视,因为毕竟 可能造成程序的异常。

4.2 格式化字符串漏洞

1. 格式化字符串的定义
  1. printf()函数的一般形式为:printf("format", 输出表列)

    format 的结构为:\%标志.精度类型,其中类型有以下常见的几种:

    1. %d整型输出

    2. %ld长整型输出

    3.  %o以八进制数形式输出整数

    4. %x以十六进制数形式输出整数

    5. %u以十进制数输出unsigned型数据(无符号数)

    6. %c用来输出一个字符

    7. %s用来输出一个字符串

    8. %f用来输出实数,以小数形式输出。

2. 格式化字符串漏洞的利用-数据泄露
特性一:格式化函数允许可变函数
  • C 语言中的格式化函数(*printf 族函数,包括 printf,fprintf,sprintf,snprintf 等)允许可变参数,它根据传入的格式化字符串获知可变参数的个数和类型,并依据格式化 符号进行参数的输出。

  • 调用这些函数时,如果给出了格式化符号串,但没有提供实际对应参数时,这些函数会 将格式化字符串后面的多个栈中的内容弹出作为参数,并根据格式化符号将其输出。当格式 化符号为%x时以16进制的形式输出堆栈的内容,为%s时则输出对应地址所指向的字符串。 利用这个特点,通过提供过多的%x等格式化符号,就可以获得内存中的数据。

void formatstring_func1(char *buf) 
{ 
char mark[] = “ABCD”; 
    printf(buf);
} 

调用时如果传入”%x%x…%x”,则 printf 会打印出堆栈中的内容,不断增加%x 的个数 会逐渐显示堆栈中高地址的数据,从而导致堆栈中的数据泄漏。

内存泄露利用漏洞

实验四:完成示例4-6的实验,注意观察栈帧结构状态。

#include <stdio.h> 
int main(void) 
{ 
int a=1,b=2,c=3; 
char buf[]="test"; 
printf("%s %d %d %d\n",buf,a,b,c); 
return 0; 
}

我们编译之后运行(Debug模式): test 1 2 3 接下来我们做一下测试,我们增加一个printf()的format参数,改为: ==printf("%s %d %d %d %x\n",buf,a,b,c)==, 编译后运行(Debug模式): test 1 2 3 12C62E

  1. 利用-任意内存数据获取

    #include <stdio.h> 
    int main(int argc, char *argv[]) 
    { 
        char str[200]; 
        fgets(str,200,stdin); 
        printf(str); 
        return 0; 
    } 
    ​

特性二:利用%n格式符写入数据

数据写入

  • 更危险的格式化符号是%n,它的作用是将格式化函数输出字符串的长度,写入函数参数

  • 指定的位置。%n不向printf传递格式化信息,而是令printf把自己到该点已打出的字符总数放到相应变元指向的整形变量中,比如 printf(“Jamsa%n”, &first_count)将向整型变量first_count 处写入整数5。

int formatstring_func2(int argc,char *argv[]) 
{ 
    char buffer[100]; 
    sprintf(buffer,argv[1]);
} 

Sprintf 函数的作用是把格式化的数据写入某个字符串缓冲区。函数原型为: int sprintf( char *buffer, const char *format, [ argument] … ); 如果调用这段程序时用”aaaabbbbcc%n”作为命令行参数,则最终数值10就会被写入地 址为0x61616161(aaaa)的内存单元。

特性三:自定义打印字符串宽度
#include <stdio.h> 
main() 
{ 
    int num=66666666; 
    printf("Before: num = %d\n", num); 
    printf("%d%n\n", num, &num); 
    printf("After: num = %d\n", num);  
}
#include <stdio.h> 
main() 
{ 
    int num=66666666;  
    printf("Before: num = %d\n", num); 
    printf("%100d%n\n", num, &num); //%100d表示前面的长度至少为100
    printf("After: num = %d\n", num); 
​
    printf("%0134512640d%n\n", num, &num); 
    printf("After: num = %x\n", num);
}

4.3 整数溢出漏洞

  1. 存储溢出

    • 存储溢出是使用另外的数据类型来存储整型数造成的。例如,把一个大的变量放入一个 小变量的存储区域,最终是只能保留小变量能够存储的位,其他的位都无法存储,以至于造 成安全隐患。

  2. 运算溢出

    • 运算溢出是对整型变量进行运算时没有考虑到其边界范围,造成运算后的数值范围超出 了其存储空间。

  3. 符号问题

    • 运算溢出是对整型变量进行运算时没有考虑到其边界范围,造成运算后的数值范围超出了其存储空间。

整数溢出一般不能被单独利用,而是用来绕过目标程序中的条件检测,进而实现其他攻击,正如上面的例子,利用整数溢出引发缓冲区溢出。

4.4 攻击 C++虚函数

  1. C++虚函数和类在内存中的位置关系如图所示:

    • 虚表指针保存在对象的内存空间中,紧接着虚表指针的是其他成员变量;

    • 虚函数入口地址被统一存在虚表中。

image-20250526213039531

4.5 其他类型漏洞

4.5.1 注入类漏洞
  1. SQL注入:将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器,进而传给数据库服务器以执行数据库命令。

  2. 操作系统命令注入:操作系统命令注入攻击(OS Command Injection)是指通过Web应用,执行非法的操作 系统命令达到攻击的目的。

  3. web脚本语言注入:常用的ASP/PHP/JSP等web脚本解释语言支持动态执行在运行时生成的代码这种特点, 可以帮助开发者根据各种数据和条件动态修改程序代码,

    攻击来自下面两个方面

    • 合并了用户提交数据的代码的动态执行,构造设计的输入,使得合并用户提交数据后的代码蕴含设定的非正常业务逻辑。通过代码执行来实施特定攻击

    • 根据用户提交的数据指定的代码文件的动态包含。多数脚本语言都支持使用包含文件。

      • 文件包含允许开发者把可重复执行的代码插入到单个文件中,在需要的时候将他们包含到相关的代码文件中。

      • 如果攻击者能修改这个文件中的代码,就让受攻击者执行攻击者的代码

  4. SOAP注入

    • SOAP:简单对象访问协议,是一个简单的XML的协议,让应用程序跨HTTP进行信息交换。主要出现在web服务中,通过浏览器访问的Web应用程序常常使用SOAP在后端应用程序组件之间进行通信

    • 由于XML也是一种解释型语言,因此SOAP也易于遭受代码注入攻击。XML元素通过元字 符<>和/以语法形式表示。如果用户提交的数据中包含这些字符,并被直接插入到SOAP消息 中,攻击者就能够破坏消息的结构,进而破坏应用程序的逻辑或造成其他不利影响。

4.5.2 权限类漏洞
  1. 水平越权:相同级别权限的用户或者同一角色的不同用户之间,可以越权访问、 修改或者删除的非法操作。如果出现此类漏洞,那么将可能会造成大批量数据泄露,严重的 甚至会造成用户信息被恶意篡改。

  2. 垂直越权:向上越权、向下越权

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值