В этой статье мы поговорим о баге в Apache Tomcat, популярнейшем веб-сервере для сайтов на Java. Баг позволяет загружать любые файлы на сервер, так что, загрузив файл JSP, можно добиться выполнения произвольного кода. Разберемся, как работает эта уязвимость.
 

Общая информация

Наряду с Apache Struts 2, уязвимость в котором мы разбирали в прошлой статье, под раздачу багов попал и веб-сервер Tomcat. За последнее время было найдено сразу несколько уязвимостей.

19 сентября команда разработчиков в очередной рассылке официально подтвердила наличие и успешный фикс двух уязвимостей, которые получили статус критических. Первая значится под номером CVE-2017-12615. После того как ее запатчили, сразу же нашелся способ обойти заплатку (CVE-2017-12616), и последовал новый фикс. Не поверишь, но вскоре обошли и его — уязвимость носит номер CVE-2017-12617, и ее общий смысл сводится к тому, что неавторизированный пользователь, манипулируя именем файла в PUT-запросе, может создать JSP-файл с произвольным содержимым. Уязвимости подвержены все ветки, начиная с 5.x и заканчивая 9.x.

WARNING

Статья адресована специалистам по безопасности и тем, кто собирается ими стать. Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.

 

Стенд

Сначала, как водится, поднимаем тестовый стенд. Я буду использовать версии 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-файлы.

Нельзя просто так взять и загрузить шелл через PUT
Нельзя просто так взять и загрузить шелл через PUT
 

Базовые детали уязвимостей

Для обработки запросов к JSP и JSPX скрипты используют класс org.apache.jasper.servlet.JspServlet.

/conf/web.xml
246:     <servlet>
247:         <servlet-name>jsp</servlet-name>
248:         <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>

А за обработку остальных файлов отвечает org.apache.catalina.servlets.DefaultServlet. Именно в нем и реализован метод PUT.

/java/org/apache/catalina/servlets/DefaultServlet.java
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.

/java/org/apache/catalina/servlets/DefaultServlet.java
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 комментарий

Подпишитесь на ][, чтобы участвовать в обсуждении

Обсуждение этой статьи доступно только нашим подписчикам. Вы можете войти в свой аккаунт или зарегистрироваться и оплатить подписку, чтобы свободно участвовать в обсуждении.

Check Also

Tips’n’Tricks из арсенала андроидовода. Самые интересные, полезные и нестандартные трюки с Android

Многие годы мы рассказывали про самые разные способы оптимизировать, модифицировать и твик…