Пентест в стиле Матрицы

Предисловие
В первой части фильма Матрица 1999 года есть занятный эпизод. Мы видим спящего Томаса Андерсона, известного хакера под псевдонимом Нео (кстати, кто не знал — Neo является анаграммой слова «One» — «Избранный»). При этом, на экране его компьютера происходит автоматизированный поиск в интернете.

Как в последствии мы узнаем, Нео долгое время ищет в сети другого хакера с псевдонимом Морфеус. Да, уже тогда, в 1999 году, Нео автоматизировал свой поиск в интернете, чтобы нужная информация искалась даже ночью, пока он спит.
В предыдущей части мы с вами подобрали инструменты и разработали относительно простой скрипт автоматизации для пентеста конкретного сайта, а в этой части, вдохновившись Матрицей, мы его улучшим.
Идея
1) Скрипт автоматически запускается вечером в определённое время;
2) Он случайным образом выбирает сайт в зоне Ru;
3) Проводится анализ сайта сканером ZAP, а результаты анализа сохраняются в файл;
4) п.2 и п.3 повторяются в цикле всю ночь до самого утра, пока скрипт принудительно не остановится Планировщиком задач;
5) Для анализа полученных за ночь отчётов, напишем отдельный скрипт-анализатор.
Т.е. вечером мы оставляем компьютер включенным, а утром просыпаемся и видим результаты сканирования случайных сайтов в зоне RU, проводим анализ отчётов по ним и принимаем дальнейшие решения о том, как этим ресурсам помочь улучшить безопасность.
Ну как вам идея? Давайте начнём!
Но прежде чем начнём, хочу уточнить! Да, в этой части уже надо написать, что все описанное ниже надо использовать только в образовательных целях и неправомерный взлом преследуется по закону!
Реализация идеи
Скрипт случайным образом выбирает сайт в зоне Ru
Надо сказать, что тут я сразу столкнулся с трудностями. Ранее меня никогда не заботила подобная задача, но как оказалось, удобных сервисов, которые можно было бы «дёрнуть» и получить действительно рандомный рабочий URL в зоне RU просто нет. Пришлось думать и экспериментировать. В итоге тестирования нескольких вариантов, я остановился на сервисе:

Первое, я надеюсь, что автор сервиса, Пахолков Юрий, не будет против, что мы таким образом будем использовать его сайт. Второе — Юрий, вам персональный респект, потому что за 3 дня пассивного поиска, я не нашёл в интернете сервиса, удобнее Вашего для целей нашего исследования.
Есть конечно и минусы. Основной — Юрий немного слукавил в заголовке «Настоящий случайный сайт». Мои эксперименты показали, что при 130 запросах, сайт выдаёт от 50 до 70 уникальных URL, а после где-то 150 найденных «уникальных» URL, сайт вообще практически перестаёт выдавать новые уникальные результаты. Не знаю, баг это или так и задумано, но за неимением лучшего решения будем использовать это. Важна сама концепция, а улучшать можно будет сколько угодно в будущем!
Алгоритм следующий:
В рамках бесконечного цикла;
1) Дёргаем сайт «Настоящий случайный сайт»;
2) Получаем весь html-контент страницы;
3) Выдергиваем из всего контента «случайный» URL. Тут пришлось тоже экспериментировать, потому что во всём html-коде страницы много разных URL, но оказалось, что нужная нам ссылка в коде присутствует несколько раз, но только один раз в формате «URL/favicon.ico». Поэтому ищем её в таком виде, а после «favicon.ico» просто обрезаем;
4) В рамках сессии сохраняем все уникальные ссылки в хэш-таблицу. Если URL приходит та, которую уже получали ранее, снова переходим в начало к п. 1, а если URL уникальна, то успех.
Ниже представлен PowerShell-скрипт, который реализует описанный выше алгоритм: как всегда — каждая строка прокомментирована, чтобы у вас не осталось вопросов по логике его работы.
Кстати, все описанные ниже скрипты я выложил на свой GitHub, чтобы вам было удобно забирать их себе.
# Указываем URL страницы, с которой будем получать случайные ссылки
$randomurl = "https://upread.ru/random_site.php"
# Создаем хэш-таблицу для хранения уникальных URL, чтобы не проверять одни и те же адреса в рамках одной сессии.
$uniqueUrls = @{}
# Бесконечный Цикл, который можно разорвать только принудительно
while ($true) {
try {
# Выполняем запрос к странице и получаем HTML-контент
$response = Invoke-WebRequest -Uri $randomurl -ErrorAction Stop
#Получаем весь HTML-контент страницы
$htmlContent = $response.Content
# Используем регулярное выражение для поиска URL в HTML-контенте
# Ищем ссылки, заканчивающиеся на /favicon.ico, и захватываем основную часть URL (этот способ подобран экспериментально)
$urlPattern = '(https?://[^"\s]+)/favicon\.ico'
$match = [regex]::Match($htmlContent, $urlPattern)
# Если URL найден
if ($match.Success) {
$baseUrl = $match.Groups[1].Value # Извлекаем основную часть URL (без /favicon.ico)
# Проверяем, был ли этот URL уже сохранён
if (-not $uniqueUrls.ContainsKey($baseUrl)) {
$uniqueUrls[$baseUrl] = $true # Добавляем URL в хэш-таблицу
Write-Output "Найден уникальный URL: $baseUrl" #это, собственно то место, где мы получили уникальный URL
}
}
} catch {
# На всякий случай отлавливаем ошибки и показываем их в консоли
Write-Output "Ошибка при запросе к $randomurl"
}
}
Проводится анализ сайта сканером ZAP, а результаты сохраняются анализа в файл
Тут уже проще, потому что мы должны теперь объединить скрипт выше с тем скриптом, который у нас получился в прошлой части и убрать всё лишние. Итак, вот что у меня получилось:
Файл: MatrixScanScript.ps1
# Указываем URL страницы, с которой будем получать случайные ссылки
$randomurl = "https://upread.ru/random_site.php"
# Создаем хэш-таблицу для хранения уникальных URL, чтобы не проверять одни и те же адреса в рамках одной сессии.
$uniqueUrls = @{}
# Путь к файлу zap.bat. Замените путь, если установили ZAP в другую папку
$zapPath = "C:\Program Files\ZAP\Zed Attack Proxy\"
# Переходим в папку ZAP
Set-Location $zapPath
# Путь к папке ZAPSCAN на рабочем столе, куда будут сохраняться отчёты
$outputDir = "$env:USERPROFILE\Desktop\ZAPSCAN"
# Проверяем, существует ли папка ZAPSCAN, если нет - создаем её
if (-not (Test-Path $outputDir)) {
New-Item -ItemType Directory -Path $outputDir | Out-Null
}
# Бесконечный Цикл, который можно разорвать только принудительно
while ($true) {
try {
# Выполняем запрос к странице и получаем HTML-контент
$response = Invoke-WebRequest -Uri $randomurl -ErrorAction Stop
#Получаем весь HTML-контент страницы
$htmlContent = $response.Content
# Используем регулярное выражение для поиска URL в HTML-контенте
# Ищем ссылки, заканчивающиеся на /favicon.ico, и захватываем основную часть URL (этот способ подобран экспериментально)
$urlPattern = '(https?://[^"\s]+)/favicon\.ico'
$match = [regex]::Match($htmlContent, $urlPattern)
# Если URL найден
if ($match.Success) {
$baseUrl = $match.Groups[1].Value # Извлекаем основную часть URL (без /favicon.ico)
# Проверяем, был ли этот URL уже сохранён
if (-not $uniqueUrls.ContainsKey($baseUrl)) {
$uniqueUrls[$baseUrl] = $true # Добавляем URL в хэш-таблицу
# Формируем имя файла отчёта в формате сегодняшняядата_url.txt
$date = Get-Date -Format "yyyyMMdd_HHmmss"
$outputFile = "$outputDir\$($date)_$($baseurl -replace '[^\w]', '_').txt"
# Выполняем команду zapit для нашего сайта и сохраняем результат в файл
.\zap.bat -zapit $baseurl -cmd | Out-File -FilePath $outputFile
}
}
} catch {
# На всякий случай отлавливаем ошибки в консоли, но ошибок быть не должно
Write-Output "Ошибка при запросе к $randomurl"
}
}
Скрипт автоматически запускается и работает всю ночь
Тут я не буду вам снова приводить множество шагов и скриншотов того, как это сделать с помощью Планировщика задач (Task Scheduler) Windows. Всё достаточно подробно описал в предыдущей части. Уверен, вы справитесь и настроите «Старт-Стоп» скрипта так, как вам удобно. Если возникнут сложности, напишите в комментариях, обязательно помогу и подскажу.
Итог работы скрипта
Итак, проснувшись утром, вы получите примерно такую картину:

Как видим, всё работает. Результаты сканирования каждого сайта сохраняются в отдельный файл. Также видна производительность работы: 1–2 сайта в минуту, что, имхо, очень не плохо.
Теперь давайте посмотрим ещё раз внутрь отчётов:

В отчёте нам важны 2 момента:
1) В предыдущей части, когда мы ставили и настраивали ZAP, мы установили плагин «Technology Detection», который прекрасно работает и очень часто из-за ошибок конфигурации или настроек сайта выдаёт информацию не только об используемой технологии, но и о её версии. Ну, а зная используемую версию, всегда можно посмотреть известные уязвимости;
2) Предупреждения (alerts), особенно уровней «High» и «Medium». Тут не буду долго расписывать, но уровень «High» — это, как правило, очень критичные уязвимости на сайте.
Понимая эти 2 момента, мы конечно можем начать каждый отчёт просматривать вручную, но мы же хакеры и нам лень тратить столько времени впустую, поэтому напишем отдельный скрипт-анализатор.
Анализ полученных отчётов
Анализатор — это отдельный Powershell-скрипт, который в указанной папке просмотрит каждый txt-файл и если в файле содержится слово «High», то к названию файла в начале добавляется буква «H», если содержит, например «PHP (7.3.33)», то к началу названия файла добавляется знак »+». Таких параметров может быть ещё несколько, т.е. должна быть возможность их легко добавлять в скрипт.
Вот, что у меня получилось:
Файл: ScanAnalysis.ps1
# Укажите путь к папке с файлами
$folderPath = "C:\Users\chumi\Desktop\ZAPSCAN"
# Получаем все txt файлы в указанной папке
$files = Get-ChildItem -Path $folderPath -Filter *.txt
# Перебираем каждый файл
foreach ($file in $files) {
$content = Get-Content -Path $file.FullName
$newName = $file.Name
# Проверяем наличие слова "High" в файле
if ($content -match '\bHigh\b') {
$newName = "H" + $newName
}
# Проверяем наличие строки "PHP (VER)" в файле
if ($content -match "PHP \(7\.3\.33\)") {
$newName = "+" + $newName
}
# Добавьте другие условия по аналогии
# if ($content -match "AnotherPattern") {
# $newName = "AnotherPrefix" + $newName
# }
# Если имя файла изменилось, переименовываем файл
if ($newName -ne $file.Name) {
$newPath = Join-Path -Path $folderPath -ChildPath $newName
Rename-Item -Path $file.FullName -NewName $newPath
}
}
Как видим, всё достаточно просто и эффективно. Скрипт отрабатывает очень быстро, а нам остаётся посмотреть только те файлы, которые переименовались.

В моих отчётах нашлось 4 сайта, которые построены с использованием PHP версии 7.3.33. Гуглим эту версию и видим:

В данной версии PHP есть 2 уязвимости с очень высоким рисковым рейтингом.
Итоги и планы на будущее
Вдохновившись фильмом Матрица, мы с вами на 100% реализовали нашу идею и получили скрипты автоматизации пентеста, которые помогают существенно повысить эффективность первичной разведки. Надеюсь, я смог вам доказать, что любую рутинную работу в windows можно и нужно автоматизировать, чтобы оставалось больше времени на образование и творчество.
Что можно улучшить:
1) Ну конечно же надо улучшать функцию получения случайной URL. Тут вариантов реализации много. Предлагайте свои варианты;
2) Сейчас скрипт проверяет уникальность URL, которую нужно сканировать, только в рамках одной сессии. Можно этот механизм улучшить, чтобы уникальность проверялась в рамках настраиваемого периода, например, месяца;
3) Можно очень много чего улучшить в скрипте анализаторе, как вариант, пропускать отчёты через модель искусственного интеллекта.
Мне очень важны ваша обратная связь и реакции по этой статье и если вам она понравится, то чуть позже сделаю 4 часть, где мы подключим и будем локально использовать модель искусственного интеллекта в первичной разведке и анализе.
Поэтому, поставьте мне «лайк» за старания, напишите ваши мысли в комменты и подписывайтесь на мой Телеграм!