信息提供: |
安全公告 |
漏洞类别: |
边界条件错误 |
攻击类型: |
远程攻击和本地攻击 |
发布日期: |
2005-10-11 |
更新日期: |
2005-10-24 |
受影响系统: |
Nortel Networks Centrex IP Element Manager 8.0 |
安全系统: |
无 |
漏洞报告人: |
Derek Soeder |
漏洞描述: |
Bugtraq ID:15065 Windows 即插即用存在一个缓存溢出漏洞。这是由于对用户提供的数据在拷入空间不足的内存缓冲器之前缺乏适当的边界检查导致的。 当PnP服务处理包含过多数据的异常信息时,就会产生该漏洞。 |
测试方法: |
警告 以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负! [email protected]提供拒绝服务攻击方法。WINNY THOMAS <[email protected]>提供另一个拒绝服务攻击方法(upnp_getdevicelist_DOS.c) 。 |
解决方法: |
Avaya 为其产品发布 ASA-2005-214 ,详见: ASA-2005-214 - Windows Security Updates for October 2005 - (MS05-044- MS05-052) (Avaya)
|
具体漏洞检测代码
#include "winsock2.h" #include "windows.h" #include <winnetwk.h> #include <Rpc.h> #include "stdio.h" #include "string.h" #pragma comment(lib, "ws2_32") #pragma comment(lib, "mpr") #pragma comment(lib, "Rpcrt4") //72字节netbios会话请求,若445端口连接不成功,访问139 的时候就先发送这个 unsigned char reqNBSS[] = "\x81\x00\x00\x44\x20\x43\x4B\x46\x44\x45\x4E\x45\x43\x46\x44\x45" "\x46\x46\x43\x46\x47\x45\x46\x46\x43\x43\x41\x43\x41\x43\x41\x43" "\x41\x43\x41\x43\x41\x00\x20\x46\x44\x45\x44\x46\x46\x43\x4E\x45" "\x46\x44\x47\x44\x48\x44\x44\x46\x49\x45\x44\x46\x47\x46\x43\x45" "\x4C\x45\x49\x44\x44\x41\x41\x00"; //Negotiate 协议 unsigned char SMB_Negotiate[] = "\x00\x00\x00\x2f\xFF\x53\x4D\x42\x72\x00\x00\x00\x00\x18\x01\xC5" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFE" "\x00\x00\x00\x00\x00\x0C\x00\x02\x4E\x54\x20\x4C\x4D\x20\x30\x2E" "\x31\x32\x00"; //建立会话 unsigned char SMB_SessionSetupAndX[] = "\x00\x00\x00\xa6\xFF\x53\x4D\x42\x73\x00\x00\x00\x00\x18\x01\xC5" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFE" "\x00\x00\x01\x00\x0D\xFF\x00\x00\x00\x00\x20\x32\x00\x00\x00\x00" "\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xD4\x00\x00\x00\x69" "\x00\x00\x00\x00\x00\x00\x57\x00\x69\x00\x6E\x00\x64\x00\x6F\x00" "\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00" "\x53\x00\x65\x00\x72\x00\x57\x00\x69\x00\x6E\x00\x64\x00\x6F\x00" "\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00" "\x53\x00\x65\x00\x72\x00\x00\x00\x41\x00\x41\x00\x41\x00\x41\x00" "\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00" "\x41\x00\x41\x00\x41\x00\x41\x00\x00\x00"; //列出要访问的共享资源---命名管道 unsigned char SMB_TreeConnectAndX[] = "\x00\x00\x00\x3a\xFF\x53\x4D\x42\x75\x00\x00\x00\x00\x18\x01\xC5" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFE" "\x00\x08\x03\x00\x04\xFF\x00\x00\x00\x08\x00\x01\x00\x0E\x00\x00" "\x49\x00\x50\x00\x43\x00\x24\x00\x00\x00\x49\x50\x43\x00"; //扫描数据 char szScan[] = "\x05\x00\x00\x03\x10\x00\x00\x00\xF8\x00\x00\x00\x01\x00\x00\x00" "\x00\xE0\x00\x00\x00\x00\x36\x00\x3D\x00\x00\x00\x00\x00\x00\x00" "\x3D\x00\x00\x00\x50\x00\x43\x00\x49\x00\x5C\x00\x56\x00\x45\x00" "\x4E\x00\x5F\x00\x31\x00\x30\x00\x31\x00\x31\x00\x26\x00\x44\x00" "\x45\x00\x56\x00\x5F\x00\x30\x00\x30\x00\x30\x00\x39\x00\x26\x00" "\x53\x00\x55\x00\x42\x00\x53\x00\x59\x00\x53\x00\x5F\x00\x32\x00" "\x31\x00\x31\x00\x34\x00\x30\x00\x41\x00\x30\x00\x30\x00\x26\x00" "\x52\x00\x45\x00\x56\x00\x5F\x00\x32\x00\x30\x00\x5C\x00\x33\x00" "\x26\x00\x32\x00\x36\x00\x37\x00\x41\x00\x36\x00\x31\x00\x36\x00" "\x41\x00\x26\x00\x30\x00\x26\x00\x35\x00\x30\x00\x00\x00\xAF\x72" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x7F\xEC\x00\x00\x00\x00\x00\x00" "\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00"; BYTE PRPC[0x48] = { 0x05,0x00,0x0B,0x03,0x10,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00, 0xB8,0x10,0xB8,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00, 0x6A,0x28,0x19,0x39,0x0C,0xB1,0xD0,0x11,0x9B,0xA8,0x00,0xC0,0x4F,0xD9,0x2E,0xF5, 0x00,0x00,0x00,0x00,0x04,0x5D,0x88,0x8A,0xEB,0x1C,0xC9,0x11,0x9F,0xE8,0x08,0x00, 0x2B,0x10,0x48,0x60,0x02,0x00,0x00,0x00 }; //RPC接口属性 struct RPCBIND { BYTE VerMaj; BYTE VerMin; BYTE PacketType; BYTE PacketFlags; DWORD DataRep; WORD FragLength; WORD AuthLength; DWORD CallID; WORD MaxXmitFrag; WORD MaxRecvFrag; DWORD AssocGroup; BYTE NumCtxItems; WORD ContextID; WORD NumTransItems; GUID InterfaceUUID; //16字节的GUID对象 WORD InterfaceVerMaj; WORD InterfaceVerMin; GUID TransferSyntax; DWORD SyntaxVer; }; //转换为UNICODE void convert_name(char *out, char *name) { unsigned long len; len = strlen(name); out += len * 2 - 1; while (len--) { *out-- = '\x00'; *out-- = name[len]; } } //设置RPC接口属性,并通过管道browser进行访问 BOOL BindRpcInterface(HANDLE PH, char *Interface, char *InterfaceVer) { BYTE rbuf[0x1000]; DWORD dw; struct RPCBIND RPCBind; BOOL bRet; memcpy(&RPCBind, &PRPC, sizeof(RPCBind)); UuidFromString((unsigned char *)Interface, &RPCBind.InterfaceUUID); UuidToString(&RPCBind.InterfaceUUID, (unsigned char **)&Interface); RPCBind.InterfaceVerMaj = atoi(&InterfaceVer[0]); RPCBind.InterfaceVerMin = atoi(&InterfaceVer[2]); bRet = TransactNamedPipe(PH, &RPCBind, sizeof(RPCBind), rbuf, sizeof(rbuf), &dw, NULL); //printf("%d\n", WSAGetLastError()); return bRet; } //扫描函数 BOOL ScanPNP(HANDLE PipeHandle) { BYTE rbuf[0x100] = {0}; DWORD dw; if(!TransactNamedPipe(PipeHandle, szScan, sizeof(szScan), rbuf, sizeof(rbuf), &dw, NULL)) { printf("Cann't get scan data!\n"); return FALSE; } if(dw != 0x48) { return FALSE; } if(rbuf[0x44] != 0x0b) { return FALSE; } return TRUE; } //主函数 int main(int argc, char **argv) { if (argc < 2) { printf("Usage: %s <host>\n", argv[0]); return 1; } WSADATA wsa; if(WSAStartup(MAKEWORD(1, 0), &wsa) != 0) { printf("1\n"); return -1; } //创建套接字 SOCKET ClientSock; sockaddr_in ClientAddr; int len; unsigned char szRecv[0x1000] = {0}; ClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ClientAddr.sin_family = AF_INET; ClientAddr.sin_port = htons(445); ClientAddr.sin_addr.S_un.S_addr = inet_addr(argv[1]); printf("[*] Connecting to 445 ... "); //先连接445端口,如果不成功,则连接139 if(connect(ClientSock, (const sockaddr *)&ClientAddr, sizeof(ClientAddr)) < 0) { printf("Cann't connecting to 445 ... "); printf("[*] Connecting to 445 ... "); ClientAddr.sin_port = htons(139); if(connect(ClientSock, (const sockaddr *)&ClientAddr, sizeof(ClientAddr)) < 0) { printf("Cann't create NULL session!\n"); return -1; } //发送72字节的reqNBSS if(send(ClientSock, (const char *)reqNBSS, sizeof(reqNBSS) - 1, 0) < 0) { printf("[-] Send reqNBSS failed\n"); closesocket(ClientSock); return -1; } len = recv(ClientSock, (char *)szRecv, sizeof(szRecv) - 1, 0); if(len < 0) { printf("2\n"); closesocket(ClientSock); return -1; } } printf("ok!\n"); //发送SMB_Negotiate if (send(ClientSock, (const char *)SMB_Negotiate, sizeof(SMB_Negotiate) - 1, 0) < 0) { printf("\n[-] send SMB_Negotiate failed\n"); return -1; } len = recv(ClientSock, (char *)szRecv, sizeof(szRecv) - 1, 0); if ((len <= 10) || (szRecv[9] != 0)) { printf("3\n"); return -1; } //发送SMB_SessionSetupAndX if (send(ClientSock, (const char *)SMB_SessionSetupAndX, sizeof(SMB_SessionSetupAndX)-1, 0) < 0) { printf("\n[-] send SMB_SessionSetupAndX failed\n"); return -1; } len = recv(ClientSock, (char *)szRecv, 4096, 0); if (len <= 10 || (szRecv[9] != 0)) { printf("4\n"); exit(0); } //发送SMB_TreeConnectAndX if (send(ClientSock, (const char *)SMB_TreeConnectAndX, sizeof(SMB_TreeConnectAndX), 0) < 0) { printf("\n[-] send failed\n"); return -1; } len = recv(ClientSock, (char *)szRecv, 4096, 0); if ((len <= 10) || (szRecv[9] != 0)) { printf("6\n"); return -1; } //下面就是获取管道客户端句柄 char szPipe[MAX_PATH]; HANDLE hFile; //打开命名管道“\\server\pipe\browser”客户端句柄 _snprintf(szPipe, sizeof(szPipe), "\\\\%s\\pipe\\browser", argv[1]); hFile = CreateFile(szPipe, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(hFile == (HANDLE)(-1)) { printf("cann't find named pipe\n"); return -1; } //BIND rpc接口 if(!BindRpcInterface(hFile, "8d9f4e40-a03d-11ce-8f69-08003e30051b", "1.0")) { printf("can't get namedpipe! %d\n", GetLastError()); return -1; } //发送请求RPC request包 BOOL ret = ScanPNP(hFile); closesocket(ClientSock); if(ret) { printf("Vulnerable\n"); return 0; } else printf("Not Vulnerable\n"); return 0; }