CVE-2020-1350 详解与复现
# 漏洞简介 |
在Windows上,DNS服务器是域控制器,其管理员是Domain Admins组的一部分。默认情况下,Domain Admins组是已加入域的所有计算机上Administrators组的成员,包括域控制器[8]。如果利用得当,攻击者可以在易受攻击的系统上远程执行代码,并获得Domain Admin权限,从而有效地损害了整个公司的基础架构。 |
DNS服务器-dns.exe负责在安装了DNS角色的Windows服务器上回答DNS查询。 |
CVE-2020-1350是DNS.exe在处理畸形DNS Sig消息时,由于对数据包的字段校验不严格,导致了整型溢出。DNS SIG 消息中包含对DNS记录集合的数字签名,DNS记录集合就是一种名字相同,或者类型相同的DNS消息集合。 |
漏洞类型:整数溢出导致基于堆的缓冲区溢出 |
# 攻击流程 |
攻击者可以配置一个恶意的域名evildomain.com,该域名的DNS指向的DNS服务器作为本次攻击的目标。 |
> 1. 当客户端查询evildomain.com的DNS记录; |
> 2. 目标DNS服务器向根域名服务器查询evildomain.com的NS记录; |
> 3. 根域名服务器告诉目标DNS,evildomain.com的权威DNS服务器是3.3.3.3,并该记录缓存起来; |
> 4. 客户端向目标服务器查询evildomain.com的Sig记录; |
> 5. 目标服务器将请求转发给权威DNS服务器; |
> 6. 权威DNS服务器返回畸形Sig查询结果; |
目标DNS服务器处理SigQuery的畸形消息时,将此消息缓存到自己的记录中,触发漏洞。 |
# 漏洞函数 |
简言之就是整数溢出后导致堆溢出,将该漏洞抽象为以下模型: |
```c |
void Examples(char*` `in ){ unsigned short len_p1 = len( in.p1); unsigned short len_p2 = len( in.p2); unsigned short len_p = len_p1 +` `len_p2; char buf =` `(char )malloc(len_p); memcpy(buf, in.p1, len_p1); } |
``` |
问题就出在 len_p 的计算上,假设 len_p1 = 0xFFD0,len_p2 = 0x40,相加后高位数据被丢弃,那么 0xFFD0 + 0x40 = 0x10010 = 0x10 ,所以实际分配的内存是 0x10 而不是 0x10010,而之后往 0x10 的空间内拷贝 0xFFD0 长度的数据,自然造成了内存溢出。 |
而在dns.exe!SigWireRead 函数里面也有类似的溢出漏洞,如图所示第11行: |
漏洞成因如下:ushort类型,为无符号16位类型。RR_AllocateEx 分配的大小只有16个bit,大小为0~65535,所以只要构造size 大于65535,造成整数溢出,而系统就会分配一个比实际数据量小的堆块,进而造成堆溢出,将整数溢出转化成堆溢出漏洞。 |
# 漏洞利用: |
因此,触发此漏洞所需的全部操作就是让受攻击的DNS服务器向我们查询SIG记录,并使用长签名(长度&>=64KB)对其作出SIG响应。但是,UDP上的DNS的大小限制为512字节(如果服务器支持EDNS0,则为4096字节)。在任何情况下,这都不足以触发漏洞。 |
CheckPoint 找到一种方法可以突破上述限制:UDP 响应时将 DNS 头部的 TC 标志置 1,表示被截断,之后客户端便会尝试用 TCP 协议和服务器建立连接,并通过 TCP 协议传递数据。由于消息的前两个字节表示其长度,因此TCP上的DNS中消息的最大大小表示为16位,因此限制为64KB。TCP 协议在 53 端口上可传输长度最大为 65535 的 DNS 数据,这无疑给该漏洞创造了先决条件。如下图:红框中的表示TC置位字段: |
但是,即使是长度为65,535的消息也不足以触发漏洞,因为消息长度包括报头和原始查询。计算传递给RR_AllocateEx的大小时不考虑此开销。那么,该漏洞如何触发呢?继续往下看,首先了解一下域名编码和域名压缩。 |
## 域名编码 |
eg:对于完整的一个域名www.baidu.com,需要14个字节: |
可以看到第一个字节 是3,表示之后会有3个字节的字符。 |
## 域名压缩 |
域名压缩是 DNS 协议节省空间的一种方式,因为请求中的域名字符会频繁出现在响应包的内,故采用了一种标志+偏移的格式来压缩域名。压缩方式很简单:1 + 1 + offset ,即最高 2bit 位为 1 时代表了将采用域名压缩,剩余的组合为偏移值(基地址为 DNS 头),如下图:响应区域中的 Name 字段为 0xc00c ,明显是被压缩过的,最高 2bit 位是标志,剩余的 bit 位组合得到的值为 0xc,所以当前 Name 表示的字符串在 DNS 头部向后偏移 0xc 的位置,也就是图中红框中 0x3 开始(0x50 表示 DNS 头起始位置)的域名 bbs.pediy.com 。 |
因此,可以将域名压缩的偏移值指向一片可控的区域,而不是指向查询时域名,就完全有可能使得域名的长度大大增加,比如在这里修改为c0 0d ,那么表示域名从0x62开始,说明后面有0x62个字节的字符,然后依次。这样就使得源代码第11行中的 sigName.Length 的大小变大。 |
注意:DNS name长度最大为0XFF |
所以,可以在不改变原来数据包大小的情况下,将sigLength+sigName.length+0x16 的大小,大于65535,造成整数溢出。分配一个小的空间缓存,然后导致堆溢出。 |
# POC分析和漏洞复现 |
部分poc代码,大体就是构造sig响应消息。具体POC,在这里:https://github.com/maxpl0it/CVE-2020-1350-DoS |
## 实验环境: |
Windows Server 2008 R2 sp1 和 kali linux |
## 复现过程: |
1.在windows server 2008 安装dns服务器,并配置静态ip |
2.在kali 中运行脚本sudo python sigred_dos.py evil_domain_name |
3.在受害者服务器配置转发器,转发器ip为kali 机的ip。 |
4.在受害者服务器使用nslookup命令查询9.evil_domain_name: |
```shell |
nslookup -type=sig 9.ibrokethe.net 127.0.0.1 |
``` |
5.查看kali,发现会发现收到了一个UDP连接,又收到了一个TCP连接。 |
## 复现结果: |
抓包结果如下: |
由于本地无法解析“ibrokethe.net”,因此会以UDP协议向恶意服务器kali发送DNS查询,也就是kali收到的第一个UDP连接。恶意服务器查到了该域名,就向受害者发送响应包,设置TC位,通知受害者采用TCP重发原来的查询请求,并允许返回的响应报文超过512个字节。这是第二个DNS包。然后进行三次握手,受害者再次以TCP协议发送请求,这就是kali收到的TCP连接。之后,恶意服务器就可以利用TCP传输大于64KB的响应包发给受害者,触发漏洞,造成堆溢出。 |
然后,就可以进行远程代码执行等操作了。 |
可以看到在复现的过程,产生堆溢出,dns.exe进程发生崩溃,从而产生DOS攻击。如下图: |
# 漏洞修复 |
临时修复方案,修改注册表,限制tcp包的长度,TcpReceivePacketSize的值为 0xFF00 |
```shell |
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DNS\Parameters |
DWORD = TcpReceivePacketSize |
Value = 0xFF00 |
``` |
注意:必须重新启动 DNS 服务才能生效。 |
# 总结: |
协议方面多多少少都会有我们所疏忽的问题,对于dns.exe开发者,最开始并未考虑到最大可以超过65535,造成溢出,代码并没有问题,造成该漏洞的关键点,主要是因为域名压缩。往往很多个疏忽点,凑到了一起就成了攻击者利用的漏洞。 |
# 参考链接: |
CVE-2020-1350 Windows Server DNS漏洞复现 |
漏洞利用剖析:带有CVE-2020-1350 SIGRed的RCE |
CVE-2020-1350: Windows DNS Server蠕虫级远程代码执行漏洞分析 |
CVE-2020-1350 详解与复现的更多相关文章
- SENet详解及Keras复现代码
转: SENet详解及Keras复现代码 论文地址:https://arxiv.org/pdf/1709.01507.pdf 代码地址:https://github.com/hujie-frank/S ...
- IntelliJ IDEA 2020.1.1 x64 Debug 断点调试模式详解
前言 对于初入职场的萌新们来说,很多都还不会 Debug 断点模式.记得我刚写代码的时候,也是通过 System.out.println() 一行一行的把变量打印出来看.其实强大的编辑器已经帮我们做好 ...
- 2020你还不会Java8新特性?方法引用详解及Stream 流介绍和操作方式详解(三)
方法引用详解 方法引用: method reference 方法引用实际上是Lambda表达式的一种语法糖 我们可以将方法引用看作是一个「函数指针」,function pointer 方法引用共分为4 ...
- 2020了你还不会Java8新特性?(五)收集器比较器用法详解及源码剖析
收集器用法详解与多级分组和分区 为什么在collectors类中定义一个静态内部类? static class CollectorImpl<T, A, R> implements Coll ...
- MVC图片上传详解 IIS (安装SSL证书后) 实现 HTTP 自动跳转到 HTTPS C#中Enum用法小结 表达式目录树 “村长”教你测试用例 引用provinces.js的三级联动
MVC图片上传详解 MVC图片上传--控制器方法 新建一个控制器命名为File,定义一个Img方法 [HttpPost]public ActionResult Img(HttpPostedFile ...
- linux查看端口及端口详解
今天现场查看了TCP端口的占用情况,如下图 红色部分是IP,现场那边问我是不是我的程序占用了tcp的链接,,我远程登陆现场查看了一下,这种类型的tcp链接占用了400多个,,后边查了一下资料,说E ...
- cron表达式详解
@Scheduled(cron = "* * * * * *") cron表达式详解 1.cron表达式格式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份( ...
- VSFTPD全攻略(/etc/vsftpd/vsftpd.conf文件详解)
/etc/vsftpd/vsftpd.conf文件详解,分好类,方便大家查找与学习 #################匿名权限控制############### anonymous_enable=YE ...
- CNN详解
CNN详解 版权声明:本文为博主原创文章,转载请指明转载地址 http://www.cnblogs.com/fydeblog/p/7450413.html 前言 这篇博客主要就是卷积神经网络(CNN) ...
随机推荐
- 【hacker101 CTF】Photo Gallery
0x01 打开首页看到 查看源代码,发现图片都是通过"fetch?id=1"这种方式加载的 简单测了一下存在SQL注入. 直接上sqlmap跑 第一个flag: ^FLAG^d45 ...
- Ubuntu-搭建Clang Static Analyzer环境
其实也就是一个开源的漏洞扫描器 专门扫描C/C++ 0BJECT-C++这种,实不相瞒我搭建了5天这个环境,最后我发现了一种超级方便的办法 前面怎么走的坑还是不分享了吧,由于没有看到前面很多人的办法或 ...
- A. 【例题1】数字反转
题目解析 字符串的基础操作,注意判断零即可 #include <bits/stdc++.h> using namespace std; int i; char c[15]; int mai ...
- [状压DP]子矩阵
子 矩 阵 子矩阵 子矩阵 题目描述 给出如下定义: 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序)被称为原矩阵的一个子矩阵 如,下面左图中选取第 2 . 4 ...
- 北航OO第一单元作业总结(1.1~1.3)
经过了三次作业之后,OO第一单元告一段落,作为一个蒟蒻,我初步了解了面向对象的编程思想,并将所学内容用于实践. 一.第一次作业 1.架构分析 本次作业需要完成的任务为简单多项式导函数的求解.表达式仅支 ...
- 如何用 Electron + WebRTC 开发一个跨平台的视频会议应用
在搭建在线教育.医疗.视频会议等场景时,很多中小型公司常常面临 PC 客户端和 Web 端二选一的抉择.Electron 技术的出现解决了这一难题,只需前端开发就能完成一个跨平台的 PC 端应用.本文 ...
- 【源码解析】- ArrayList源码解析,绝对详细
ArrayList源码解析 简介 ArrayList是Java集合框架中非常常用的一种数据结构.继承自AbstractList,实现了List接口.底层基于数组来实现动态容量大小的控制,允许null值 ...
- 消息中间件-ActiveMQ高可用集群和持久化机制
1.修改active.mq的xml文件 2.延时.调度消息 package com.study.mq.b1_message; import org.apache.activemq.ActiveMQCo ...
- Java高级【Junit、反射、注解】
1.Junit单元测试 * 测试分类: 1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值. 2. 白盒测试:需要写代码的.关注程序具体的执行流程. * Junit使用 ...
- Linux pgrep命令
1 pgrep pgrep是一个根据名称查找进程ID的命令,返回的是进程ID,若存在当个进程,则分为不同的行返回ID(默认实现). 2 示例 查找java进程: pgrep java 上图还显示了ps ...