![](https://habrastorage.org/getpro/habr/upload_files/814/856/be5/814856be5bad586a1bc3b82638dceadf.png)
Grammarly — компания-единорог, которая в сентябре прошлого года объявила о старте своей программы вознаграждения за найденные ошибки. С тех пор было подано множество заявок, а выплаты составили внушительную сумму. При этом оказалось, что некоторые из обнаруженных у Grammarly уязвимостей можно перенести и на другие ресурсы. Так, недавно выявленная XSS-уязвимость позволяет также обходить AWS WAF.
Отчет об этой уязвимости выделяется на фоне других. Во-первых, данный отчет был представлен Франсом Розеном (Frans Rosen), одним из лучших хакеров платформы HackerOne, где он занимает 6 место в абсолютном рейтинге.
Во-вторых, за отчет было выплачено целых $3000, в то время как сотни постоянно выявляемых XSS-уязвимостей обычно оцениваются платформой в максимум $50-$100.
Заголовок отчета на скрине ниже: «Config override using non-validated query parameter allows at least reflected XSS by injecting configuration into state» («Переопределение параметра config через непроверяемый атрибут запроса позволяет провести, по крайней мере, отраженную XSS-атаку путем внедрения новой конфигурации») https://hackerone.com/reports/1082847.
![](https://habrastorage.org/getpro/habr/upload_files/b89/f3b/b5d/b89f3bb5d6597186f721211b9f81bbb4.png)
Указанная уязвимость — это отличный пример глубокого исследования JavaScript, которые проводит Франс. Более того, по какой-то причине код XSS, который Франс использовал для проверки данной уязвимости Grammarly, обходит AWS WAF.
Разберемся, как это происходит
На первый взгляд отправляемый код выглядит как ничем не примечательный XSS:
https://app.grammarly.com/docs/new?config={%22account%22:{%22subscription%22:%22javascript:alert(document.domain)//%22},%22api%22:{%22redirect%22:%22javascript:alert(document.domain)//%22}}
Он содержит параметр config в формате JSON для уязвимого приложения. Атрибуты JSON subscription и redirect содержат обычный XSS-код вызова функции alert(). Отправляя этот запрос, чтобы проверить, как его обнаруживает mod_security WAF, получаем следующее:
2021/03/03 01:10:44 [error] 41#41: *1 [client 172.17.0.1] ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Ge' with parameter `5' against variable `TX:ANOMALY_SCORE' (Value: `28' ) [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "80"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 28)"] [data ""] [severity "2"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "172.17.0.1"] [uri "/docs/new"] [unique_id "161473384455.381362"] [ref ""], client: 172.17.0.1, server: localhost, request: "GET /docs/new?config={%22account%22:{%22subscription%22:%22javascript:alert(document.domain)//%22},%22api%22:{%22redirect%22:%22javascript:alert(document.domain)//%22}} HTTP/1.1", host: "localhost:8080"
В то же время AWS WAF пропустит этот код без блокировки:
![](https://habrastorage.org/getpro/habr/upload_files/737/f19/e17/737f19e178969de41c9df9ab78d2df14.png)
Однако, если удалить объект JSON и отправить тот же код в виде обычного текста, AWS WAF заблокирует его:
![](https://habrastorage.org/getpro/habr/upload_files/c8c/764/3dc/c8c7643dc4e87c4dd5ef488065c55682.png)
Внимательный читатель может заметить, что мы изменили код, добавив атрибут onerror, чтобы код представлял собой инъекцию HTML-атрибута. Все верно. Но если теперь снова добавить префикс JSON, результат будет следующим:
![](https://habrastorage.org/getpro/habr/upload_files/2c7/fb0/5fe/2c7fb05fe2764173ab33e5ed8bd541eb.png)
Изначально мы решили, что причина этого обхода кроется в парсере JSON. Как обсуждалось в недавней статье, возможность декодирования JSON в WAF необходима для защиты от угроз API, таких как CVE-2020-13942 Apache Unomi RCE.
Однако причина здесь совсем в другом, поскольку AWS WAF вообще не обладает функцией парсинга JSON. Удаляя все лишнее из кода Grammarly, в итоге получаем, что следующий запрос блокируется AWS WAF:
![](https://habrastorage.org/getpro/habr/upload_files/0de/d54/009/0ded54009c464b1b72ccb84f3e3174ea.png)
Однако добавление всего одной дополнительной двойной кавычки приводит к обходу WAF:
![](https://habrastorage.org/getpro/habr/upload_files/cb6/931/0b4/cb69310b4d1d3255842827399992c51c.png)
Причина не в префиксе JSON, а в самих двойных кавычках. Можно легко убрать все фигурные скобки, а код ""onerror=javascript:alert('I-LOVE-AWS-WAF!') все также будет обходить WAF.
Это кажется абсурдным, но добавление любого числа двойных кавычек перед кодом XSS позволяет обходить AWS WAF. Тестирование было выполнено при 1500 включенных правил.
![](https://habrastorage.org/getpro/habr/upload_files/8ba/8fb/7d5/8ba8fb7d5f0d5ffdb7ee9e7fe04866c4.png)
Надеемся, данные примеры были вам полезны. Спасибо за интерес!
czz
Друзья, конечно, мы умеем гуглить, но хорошим тоном было бы начать с разъяснения того, что такое AWS WAF.