В этой статье мы поговорим о баге в Apache Tomcat, популярнейшем веб-сервере для сайтов на Java. Баг позволяет загружать любые файлы на сервер, так что, загрузив файл JSP, можно добиться выполнения произвольного кода. Разберемся, как работает эта уязвимость.
Наряду с Apache Struts 2, уязвимость в котором мы разбирали в прошлой статье, под раздачу багов попал и веб-сервер Tomcat. За последнее время было найдено сразу несколько уязвимостей.
19 сентября команда разработчиков в очередной рассылке официально подтвердила наличие и успешный фикс двух уязвимостей, которые получили статус критических. Первая значится под номером CVE-2017-12615. После того как ее запатчили, сразу же нашелся способ обойти заплатку (CVE-2017-12616), и последовал новый фикс. Не поверишь, но вскоре обошли и его — уязвимость носит номер CVE-2017-12617, и ее общий смысл сводится к тому, что неавторизированный пользователь, манипулируя именем файла в PUT-запросе, может создать JSP-файл с произвольным содержимым. Уязвимости подвержены все ветки, начиная с 5.x и заканчивая 9.x.
Статья адресована специалистам по безопасности и тем, кто собирается ими стать. Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.
Сначала, как водится, поднимаем тестовый стенд. Я буду использовать версии Tomcat для Windows, так как CVE-2017-12615 и CVE-2017-12616 касаются только их.
Для проверки уязвимостей можно использовать любую из версий — 7.0.81, 8.5.20 или 9.0.0.M26. Все они уязвимы.
Также ты всегда можешь использовать Docker, благо у Apache есть официальный репозиторий, из которого можно поднять любую версию Tomcat одной командой.
docker run -it --rm -p 8888:8080 tomcat:7.0.81
Теперь на порте 8888 у тебя обитает выбранная версия веб-сервера.
После успешного запуска нужно отредактировать конфигурационный файл web.xml и добавить в него вот такие строки.
<init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param>
Они идут в этот раздел:
<servlet> <servlet-name>default</servlet-name>
Таким образом мы выключаем параметр readonly
, что позволяет использовать запросы PUT
и DELETE
. Но простое включение этой опции, конечно же, не открывает нам возможность записывать и удалять JSP-файлы.
Для обработки запросов к JSP и JSPX скрипты используют класс org.apache.jasper.servlet.JspServlet
.
246: <servlet> 247: <servlet-name>jsp</servlet-name> 248: <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
А за обработку остальных файлов отвечает org.apache.catalina.servlets.DefaultServlet
. Именно в нем и реализован метод PUT.
539: /** 540: * Process a PUT request for the specified resource. ... 548: @Override 549: protected void doPut(HttpServletRequest req, HttpServletResponse resp) 550: throws ServletException, IOException { 551: 552: if (readOnly) { 553: resp.sendError(HttpServletResponse.SC_FORBIDDEN); 554: return; 555: }
Как видишь, работа этого метода зависит от опции readOnly
, которую мы и выключили, так как по умолчанию она установлена в true.
162: protected boolean readOnly = true;
Идея эксплоита заключается в том, чтобы заставить PUT-запрос к файлу JSP обрабатываться с помощью DefaultServlet
. Это можно провернуть несколькими способами. Чтобы лучше вникнуть в детали, сначала мы поговорим о методах, которые можно использовать только в версиях для Windows.
Давай запустим Tomcat версии 7.0.79 и выполним такой запрос:
PUT /read.txt%20 HTTP/1.1 Host: tomcat.visualhack:8080 Connection: close Content-Length: 3 any
Если ты знаешь про особенности и ограничения в названиях файлов системы Windows, то, увидев пробел в конце пути, сразу же все поймешь. Дело в том, что файлы, создаваемые штатными методами ОС, не могут содержать пробелы в начале или в конце имени — те просто отбрасываются. Но ведь Tomcat написан на Java, скажешь ты. Чтобы все прояснить, посмотрим на ключевые шаги обработки нашего запроса.
Ты уже знаешь, что за его обработку отвечает DefaultServlet
. Если файл еще не существует, то выполнение передается методу bind
.
Cтатьи из последних выпусков журнала можно покупать отдельно только через два месяца после публикации. Чтобы читать эту статью, необходимо купить подписку.
Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке
1 год4570 р. Экономия 1400 рублей! |
1 месяц490 р. 25-30 статей в месяц |
Уже подписан?
Читайте также
Последние новости