
Сценарий Proof of concept для эксплуатации CVE2021-38297 GO WASM переполнения буфера
WebAssembly (WASM) — это двоичный формат инструкций, исполняемый в большинстве современных веб-браузеров. Он служит целью компиляции для различных языков высокого уровня, таких как C, C++, Rust и GO, позволяя писать код на этих языках и компилировать его в WASM.
CVE-2021-38297 описывает критическую ошибку в процессе компиляции и загрузки GO-скомпилированных WASM-бинарных файлов. Уязвимость находится в JS-загрузчике wasm (wasm_exec.js), предоставляемом GO, который позволяет загружать WASM-бинарные файлы с неограниченными данными в аргументе argv. Поскольку argv хранится в линейной памяти WASM, злоумышленники могут использовать это для перезаписи линейной памяти GO-скомпилированной WASM-программы с помощью чрезмерно большого ввода argv.
Эта уязвимость сохранялась в версиях GO до 1.17.2.
Эта proof-of-concept демонстрирует приложение социальной сети Vuln-Twitter, позволяющее нескольким пользователям публиковать сообщения и комментарии. Веб-сервер, построенный на Node.js, использует SQLite для хранения данных постов и комментариев.
Фронтенд использует обычный JS вместе с модулем GO WASM, названным wordprocessor.wasm. Этот модуль предоставляет такие методы, как toLeetSpeak, преобразующие входные строки в «LeetSpeak» (например, «Hello!» становится «h3ll0!»).
Модули GO WASM помогают отображать посты и комментарии в LeetSpeak.

В процессе рендеринга на фронтенде, при получении постов и комментариев с сервера, каждый комментарий преобразуется в «LeetSpeak» с помощью модуля GO WASM. Комментарий для каждого поста передаётся как часть переменной argv после загрузки модуля GO WASM.
Кроме того, в модуле GO существует метод processSharedVar(), предназначенный для чтения строки, расположенной по адресу 0x5000, и преобразования её в упрощённую речь (например, «How are you?» становится «How r u?»). Исходный пост явно добавляется по адресу 0x5000 в линейную память для доступа этим методом, изменяя содержимое поста.
См. соответствующий участок кода на изображении:

Диаграмма линейной памяти WASM при рендеринге комментария:

Вкратце:
argv и посты по адресу памяти 0x5000.toLeetSpeak и processSharedVar соответственно.Учитывая отсутствие проверок размера в argv в соответствии с CVE-2021-38297, возникает потенциальная угроза. Если злоумышленник оставит комментарий чрезмерного размера к посту, который ему не принадлежит, этот комментарий будет передан через argv во время рендеринга. Поскольку ограничения на размер нет, содержимое по адресу 0x5000 (исходный пост) становится уязвимым для перезаписи.
Используя эту уязвимость, злоумышленник может фактически изменить содержимое исходного поста, что аналогично атаке «хранимая XSS». Впоследствии, когда другие пользователи просматривают страницу, изменённое содержимое отображается для всех, поскольку общая логика фронтенда применяется при рендеринге каждого пользователя, в результате чего перезаписанный пост виден всем.

Примечание: Для воспроизведения необходимо локально установить версию GO go1.17.1, которая является уязвимой версией, используемой в данном сценарии. Вы можете обратиться к официальной документации GO по установке конкретных версий.
Теперь давайте попробуем воспроизвести описанный выше сценарий:
git clone [email protected]:gkrishnan724/CVE-2021-38297.git && cd vuln-twitternpm install для установки всех зависимостей.npm run resetDB, чтобы инициализировать базу данных несколькими постами и комментариями.npm run dev, чтобы запустить локальный сервер; откройте localhost:3000 в браузере — вы должны увидеть страницу входа.Теперь войдите в систему с учётной записью злоумышленника: имя пользователя I_CANT_HACK, пароль hacker. После входа вы должны увидеть ленту с несколькими постами.
Этот пост выглядит довольно интересно:
Amazon: ready 4 black friday? https://www.amazon.com/blackfriday
Что, если, используя описанную технику, мы сможем перезаписать пост от Amazon.com, чтобы он указывал на вредоносную ссылку?
Обратитесь к файлу exploit.txt — он содержит комментарий, заполненный заполнением из букв «A», чтобы перезаписать всё до адреса 0x5000. В конце вы можете увидеть текст ready for black friday? https://evil.com/blackfriday. Если скопировать этот текст и оставить его в качестве комментария к указанному посту, мы сможем перезаписать исходный пост этим текстом.
Попробуйте сами и посмотрите :)

В этом приложении я также предоставил скрипт исправления. Он использует новую версию go:
npm run patchServerЭто перекомпилирует файл go с новой версией и запустит сервер с исправленной версией.
Теперь вы должны заметить, что пост не перезаписывается, а если посмотреть в консоль, то вместо этого вы увидите ошибку Argument length too long.

Мы продемонстрировали сценарий, в котором использование переполнения буфера WASM в линейной памяти позволило выполнить атаку «хранимая XSS». Однако важно отметить специфичность этого эксплойта: он требовал манипуляции с текстом по жёстко заданному адресу в линейной памяти. В реальных веб-приложениях обнаружение таких уязвимостей может быть чрезвычайно сложным из-за такой специфичности. Более того, перезапись произвольных данных в линейной памяти без сбоя системы — сложная задача, особенно при работе с внутренними модулями и данными GO, в значительной степени из-за отсутствия полной документации по компоновке памяти GO.
Исходя из нашего понимания, мы считаем, что компоновка линейной памяти GO выглядит следующим образом:

Хотя данная эксплуатация вводит интересные векторы атак в веб-разработке, особенно в контексте WASM, она также вносит внутренние риски безопасности, связанные с языками программирования. Например, рассмотрим сценарий, в котором программа на C компилируется в WASM. Если исходная программа на C содержит переполнения или уязвимости, эти риски переносятся в среду WASM, подвергая её аналогичным уязвимостям и угрозам.