Metasploit Module: Netis Router Exploit Chain Reactor (CVE-2024-48455, CVE-2024-48456 and CVE-2024-48457).
Type: exploit
Path: modules/exploits/linux/http/netis_unauth_rce_cve_2024_48456_and_48457.rb
Platform: linux
Disclosure date: 2024-12-27
References: CVE-2024-48455, CVE-2024-48456, CVE-2024-48457, URL-https://attackerkb.com/topics/L6qgmDIMa1/cve-2024-48455, URL-https://attackerkb.com/topics/Urqj4ggP4j/cve-2024-48456, URL-https://attackerkb.com/topics/ty1TOgc40f/cve-2024-48457, URL-https://github.com/users/h00die-gr3y/projects/1
Targets: Linux Dropper

Description:
Several Netis Routers including rebranded routers from GLCtec and Stonet suffer from a command injection
          vulnerability at the change admin password page of the router web interface (see CVE-2024-48456 for more details).
          The vulnerability stems from improper handling of the 'password' and 'new password' parameter within the
          router's web interface. Attackers can inject a command in the 'password' or 'new password' parameter,
          encoded in base64, to exploit the command injection vulnerability. When exploited, this can lead to
          command execution, potentially allowing the attacker to take full control of the router.
          An attacker needs to be authenticated to initiate this RCE, however CVE-2024-48457 allows an unauthenticated
          attacker to reset the Wifi and router password, hence gaining full root access to the router to execute the RCE.

          Last but not least, CVE-2024-48455 allows for unauthenticated information disclosure revealing sensitive configuration
          information of the router which can be used by the attacker to determine if the router is running specific vulnerable
          firmware.

          The following router firmware versions are vulnerable:
          * netis_MW5360_V1.0.1.3031_fw.bin
          * Netis_MW5360-1.0.1.3442.bin
          * Netis_MW5360_RUSSIA_844.bin
          * netis_NC21_V3.0.0.3800.bin (https://www.netisru.com/support/downinfo.html?id=40)
          * netis_NC63_V3.0.0.3327.bin (https://www.netis-systems.com/support/downinfo.html?id=35)
          * netis_NC63_v4_Bangladesh-V3.0.0.3889.bin (https://www.netis-systems.com/support/downinfo.html?id=35)
          * Netis_NC63-V3.0.0.3833.bin (https://www.netisru.com/support/downinfo.html?id=35)
          * netis_app_BeeWiFi_NC63_v4_Bangladesh-V3.0.0.3503.bin
          * netis_NC65_V3.0.0.3749.bin
          * Netis_NC65_Bangladesh-V3.0.0.3508.bin (https://www.netis-systems.com/support/downinfo.html?id=34)
          * Netis_NC65v2-V3.0.0.3800.bin (https://www.netisru.com/support/downinfo.html?id=34)
          * netis_NX10_V2.0.1.3582_fw.bin
          * netis_NX10_V2.0.1.3643.bin
          * Netis_NX10_v1_Bangladesh-V3.0.0.4142.bin (https://www.netis-systems.com/support/downinfo.html?id=33)
          * netis_NX10-V3.0.1.4205.bin (https://www.netisru.com/support/downinfo.html?id=33)
          * netis_app_BeeWiFi_NC21_v4_Bangladesh-V3.0.0.3329.bin
          * netis_app_BeeWiFi_NC21_v4_Bangladesh-V3.0.0.3500.bin
          * Netis_NC21_v2_Bangladesh-V3.0.0.3854.bin (https://www.netis-systems.com/support/downinfo.html?id=40)
          * GLC_ALPHA_AC3-V3.0.2.115.bin (https://drive.google.com/drive/folders/1P69yUfzeZeR6oABmIdcJ6fG57-Xjrzx6)
          * potentially others...

Check method (fingerprinting):
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&.code == 200 && res.body.include?('version')

    # trying to get the model and version number
    # unfortunately JSON parsing fails for some routers, so we need to use this ugly REGEX :-(
    # Examples:
    # {'version':'Netis(MW5360)-V1.0.1.98','vender':'RUSSIA','model':'MW5360','time_now':'2024/12/29 01:37:58','sys_date':'2024'}
    # {"version":"netis(NC65)-V3.0.0.3800","vender":"CIS","easy_mesh":"EASYMESH","module":"NC65v2","ax_support":"0"}
    version = res.body.match(/(?:version\s*'|")\s*:\s*.?((\\|[^'|"])*)/)
    # when found, remove whitespaces and make all uppercase to avoid suprises in string splitting and comparison
    unless version.nil?
      version_number = version[1].upcase.split('-V')[1].gsub(/[[:space:]]/, '')
      # The model number part is usually something like Netis(NC63)-V3.0.0.3131,
      # but occassionally you see things like Stonet-N3D-V3.0.0.4142, or NX10-V3.0.0.4142
      if version[1].upcase.split('-V')[0].include?('(')
        model_number = version[1].upcase.split('-V')[0][/\(([^)]+)/, 1].gsub(/[[:space:]]/, '')
      elsif version[1].upcase.split('-V')[0].include?('-')
        model_nu