Разбираем уязвимость в фреймворке Apache Struts 2
https://t.me/plastikruСегодня мы вернемся к Apache Struts, популярному веб-фреймворку, который за последнее время натерпелся от исследователей безопасности и явил миру несколько критических уязвимостей. В этой статье я хочу обсудить уязвимость в модуле, отвечающем за REST API. Она приводит к выполнению произвольного кода и открывает широкие возможности (такие, например, как слив личных данных половины населения США).
Наш подопытный
Все свои манипуляции я буду производить на ОС Windows 10. В качестве сервера я использую Apache Tomcat 8.5.20. Версию фреймворка Apache Struts я возьму из ветки 2.5, и это последняя уязвимая до патча — 2.5.12. Скачать можно, разумеется, на официальном сайте. Чтобы не пришлось искать, вот тебе прямая ссылочка (ZIP). Также можешь скачать только исходники, если захочешь заглянуть внутрь и лучше понять, как все устроено.
После установки сервера нужно распаковать архив с фреймворком, взять из папки apps приложение struts2-rest
(файл struts2-rest-showcase.war
) и положить в папку webapps
сервера Tomcat. После этого можно запускать сервер.
Теперь, перейдя по адресу http://127.0.0.1:8080/struts2-rest-showcase
, ты можешь наблюдать нашего подопытного.
Копаемся в исходниках
Для начала несколько слов о ContentTypeHandler
. Это интерфейс, который предоставляется фреймворком для конвертирования данных в объекты Java. Десериализацию здесь используют, чтобы преобразовать переданные данные в объекты. Поэтому каждый класс, реализующий этот интерфейс, представляет потенциальный интерес для нас как исследователей. Ведь все мы любим десериализацию юзердаты.
Так вот, в Struts имеется такой класс, как XStreamHandler
.
/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java
30: /** 31: * Handles XML content 32: */ 33: public class XStreamHandler implements ContentTypeHandler {
Он используется при обработке данных в формате XML, отправленных на сервер.
Заглянем в конфигурационный файл.
/plugins/rest/src/main/resources/struts-plugin.xml
35: <bean type="org.apache.struts2.rest.handler.ContentTypeHandler" name="xml" class="org.apache.struts2.rest.handler.XStreamHandler" /> ... 47: <constant name="struts.action.extension" value="xhtml,,xml,json" />
Как видишь, обработка XML-запросов включена по умолчанию, и занимается этим именно класс XStreamHandler.
Во время обработки пользовательского запроса класс ContentTypeInterceptor определяет MIME-тип отправленных данных и направляет выполнение кода в нужное русло — для обработки данных выбирается соответствующий обработчик.
/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java
38: public class ContentTypeInterceptor extends AbstractInterceptor { ... 48: public String intercept(ActionInvocation invocation) throws Exception { 49: HttpServletRequest request = ServletActionContext.getRequest(); 50: ContentTypeHandler handler = selector.getHandlerForRequest(request);
Чтобы превратить переданные данные в объект, существует метод с подходящим названием toObject. Он и вызывается из обработчика, определенного с помощью intercept.
/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java
59: InputStreamReader reader = new InputStreamReader(is); 60: handler.toObject(reader, target);
/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java
43: public void toObject(Reader in, Object target) { 44: XStream xstream = createXStream(); 45: xstream.fromXML(in, target); 46: }
Объект in — это не что иное, как пользовательские данные, отправленные определенному методу REST API. Эти данные передаются в XStream.fromXML.