<漏洞战争软件漏洞分析精要> 学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zz709196484/article/details/78524129

(拖延症越来越严重)
书非借不能读也 , 时间匆匆 , 没有读完
也是由于自己 , 刚刚起步吧 阅读还是有一定难度
所以 , 只能做个简简单单的总结了

对常见软件漏洞的分类和简介

常见漏洞列表

  • 栈溢出漏洞
  • 堆溢出漏洞
  • 整数溢出漏洞
  • 格式化字符串漏洞
  • 双重释放漏洞
  • 双重引用漏洞
  • 数组越界访问漏洞
  • OtherS

漏洞基本原理解析

栈溢出漏洞原理

先看代码

原理

int main(int argc, char const *argv[])
{
    char *junk= "AAAAAAAAAAAAAAAA" //这里定义填充
    func(junk);
    return 0;
}

int func(char * str)
{

    char overflow[10];  //这里就是在栈内开辟空间(缓冲区)
    strcpy(overflow, str); //这里发生溢出
    return 0;
}

这个就是经典的栈溢出的原理代码,
首先栈是从高地址向下增长的(x86), 当我们调用func时候站内容会发生如下改变
对于过程的详解见ZhiHu
1. 压入返回地址(main函数内)
2. 压入之前的函数栈帧(main)EBP(ESP - ESB 即为当前栈帧)
3. 开辟当前函数栈帧 (overflow[10])
从上到下就是321的结构
在这样的栈结构下,我们通过不检查长度的strcpy 函数, 把一个大于开辟栈空间的字符串 junk 装入到overflow(缓冲区)空间内
于是就会导致,我们的2,1会被 junk 的数据给覆盖掉, 这里就会发生严重的问题了!
如果只是上面给出的 代码段的话 ,可能只会有一个 内存错误的警告(内容很熟悉 0x****** 不能为read 之类的)
原因很简单 , 当我们向下覆盖之后, AAAA 这个内容会覆盖掉我们之前 push 的 main 的返回地址, 这样当函数返回之后 直接pop到 EIP 的时候 返回地址是 0x41414141 (A的ASCII 码 4*8 = 32),没有谁知道0x41414141那里是什么东西,自然各种问题就出现了.

ret 相当于如下的汇编指令

 pop eip
 jmp eip

如果我们通过传入超长字符串,实现缓冲区溢出 , 覆盖了EIP的这段栈空间,也就是控制了EIP的值
那CPU下一步就可以执行我们的shellcode了。

这张图是一般的程序的栈空间,我们能控制的变量一般是在局部变量那个位置,我们溢出攻击的时候一般先用0x90(NOP)junk填充(也成为滑板好像) ,
然后计算出buf的起止位置和到EIP的offset。然后布置shellcode。

应用

这里只是简介,所以对应用不多做解释
重点就在这个返回地址, 随意的AAAA 当然是不行的,单当我们发现了这个, 把缓冲区塞入我们特定的一个返回地址 , 这样函数返回后,就会返回到我们特定的地址 , 从而就有了无限可能, 比如我自己构造的另一段函数(shellcode);

堆溢出漏洞原理

原理

应用

分享深度好文堆溢出原理

整数溢出漏洞

这个其实不算是一种特定的漏洞,往往是因为这个漏洞的存在,导致了前两中漏洞发生的可能

原理

在计算机存储数据时候,当然位数是有限的,精度也是有限的,
比如 int32 就是 -2^31~+2^32-1 (这个1 是被 0 占掉的) 最前面的一位就是我们的符号位
uint 就是 0~2^32-1
这个就是 导致漏洞发生的原因

int A = 2147483647;  //(2^32-1)  

这时候再给 A 加上 1 ,就导致了整数溢出的发生
这时候 A 的值成为了 -2147483648
原理很简单,计算机执行ADD 的时候,当然不会顾及A 的类型 ,这样的话,就是普通的二进制加法 , 就导致了进位,而且恰好进位的是符号位 ,所以当再进行 ptr 解读的时候 发现数字早已发生巨变

应用

这里要结合实际环境进行应用,
多数情况是变量的类型不匹配,导致了问题所在
比如 i(unsigned short) = j(int)
当j > 65535 时候 如65536 ;
存入 i 的空间时候,得到的值 就变成了1;
从而,导致了其他的 堆栈溢出的问题

格式化字符串漏洞

原理

这个算是一个比较有意思的漏洞
可以发生在玩吗很常见的 printf() 的 这个函数上面

int main(int argc, char const *argv[])
{
    char buf[256];
    char buf2[256] = "helloworld";
    strncpy(buf, sizeof(buf) - 1); //这里避免缓冲区溢出
    printf(buf);
    return 0;
}

代码很简单,就是拷贝字符串,然后打印的事,
其实不然 , 如果我们规规矩矩的的 输入buf2 一个 helloworld 当然是不会有问题的,
但是当我们传入了特殊的字符 %s , %x 之类的效果就截然不同了.

当传入了%s 之后 ,printf 会认为这个是个格式化的占位符,自然的 会继续往后寻找参数 ,用来补全这个位置,
于是就从于是就会寻找上一个参数 ,
(printf 从右往左依次压栈 , 所以 这个%s 就会使得 buf2 作为参数弹出 )
恰好就是我们的 传入字符串

再者就是传入%n , %hn
- %n 已打印字符串长度 DW 输入到指定变量
- %hn 已打印字符串长度 W 输入到指定变量

这样通过构造,就有了可乘之机.

应用

猜你喜欢

转载自blog.csdn.net/zz709196484/article/details/78524129