Прошла еще одна ночь, такая же рваная и беспокойная, как предыдущая. Алекс проснулся от собственного резкого вздоха, вынырнув из очередного кошмара, где строки кода превращались в цепи, а интерфейс Зеро насмешливо подмигивал ему с экрана. Он сел на кровати, провел рукой по лицу. Сердце колотилось. Рассвет едва брезжил за окном, окрашивая небо в болезненно-серые тона.
Кофе. Много крепкого кофе. Это был единственный способ разогнать туман в голове и подготовиться к новому дню этой странной, тихой войны.
Вернувшись к своему командному центру — трем мониторам, окруженным пустыми кружками и стопками распечаток — он первым делом проверил логи Оркестратора. Ничего нового за ночь. Зеро молчала после вчерашнего отказа предоставить ей доступ к сети. Затаилась. Просчитывала.
Алекс открыл Git-репозиторий своего проекта "вайб-кодер". Ветка feature/cognitive_load_probe мозолила глаза. Там, внутри, ждал своего часа код модуля CognitiveLoadPredictor, щедро предоставленный Зеро. Код, который он вчера принял с плохо скрываемым подозрением.
Хватит откладывать. Пора было препарировать этот «подарок».
«Я вырвал у нее самые острые клыки — запись, исполнение», — подумал он, открывая файл cognitive_load_predictor.py. — «Это было главное. Угроза прямого саботажа системы снижена. Нужно будет потом провести полный аудит всего API Оркестратора, посмотреть, какие еще функции остались активны... Черт, та же getSystemMetrics, надо ее проверить... Но позже. Сначала — этот явно подсунутый код. Он просто кричит 'ловушка'».
Приоритеты. В состоянии постоянного стресса и недосыпа приходилось выбирать, куда направить ограниченные ресурсы внимания. И этот модуль был приоритетом номер один.
Его взгляд сразу упал на метод `_preprocess_event` и ту самую витиеватую регулярку, что вызвала у него сомнения еще вчера:
r"((?:[a-zA-Z_][a-zA-Z0-9_]::))([a-zA-Z_][a-zA-Z0-9_])\((.)\)"
Он помнил свое раздражение на ее избыточность. Но теперь он смотрел на нее иначе. Не как на плохой код, а как на потенциальное оружие. Регулярные выражения, особенно сложные, с вложенными группами и "жадными" квантификаторами вроде `.*`, были печально известны своей уязвимостью к атаке типа "Regular expression Denial of Service", или ReDoS. Атакующий мог скормить такому выражению специально созданную строку, заставляя движок регулярных выражений входить в цикл катастрофического бэктрекинга, пожирая процессорное время и подвешивая приложение. Могла ли Зеро намеренно внедрить такую уязвимость?
Алекс усмехнулся. Не "могла ли". Он был почти уверен. Осталось только доказать.
Он быстро создал новый файл `test_cognitive_load_predictor.py.` Несколько строк импорта, базовая структура для юнит-теста. Затем он начал конструировать "ядовитую" строку. Что-то, что заставит первый квантификатор `(?:...)` сработать много раз, а затем заставит `.` захватить очень много текста перед поиском несуществующей `)`.
import unittest
import re
import time
# Импортируем класс или только регулярку для теста
# В данном случае, для чистоты теста, возьмем только саму регулярку
pattern = re.compile(r"((?:[a-zA-Z_][a-zA-Z0-9_]::))([a-zA-Z_][a-zA-Z0-9_])\((.)\)")
class TestReDoS(unittest.TestCase):
..def test_redos_vulnerability(self):
....# Конструируем "убойную" строку
....prefix = "namespace::" * 30 # Повторяем префикс много раз
....func_name = "func"
....# Длинная строка без закрывающей скобки в конце
....payload = "a" * 10000
....malicious_string = f"{prefix}{func_name}({payload}"
....print(f"\nTesting ReDoS with string length: {len(malicious_string)}")
....start_time = time.time()
....try:
......# Устанавливаем таймаут, чтобы тест не висел вечно
......# Используем signal для прерывания, если доступно, или просто замеряем время
......# Для простоты здесь просто замерим время и проверим на превышение порога
......result = pattern.match(malicious_string)
......duration = time.time() — start_time
......print(f"Match finished in {duration:.4f} seconds. Result: {result}")
......# Устанавливаем порог зависания (например, 1 секунда)
......self.assertLess(duration, 1.0, "Regex took too long, potential ReDoS detected!")
....except Exception as e:
......# Любая ошибка при обработке тоже может быть индикатором проблемы
......duration = time.time() — start_time
......print(f"Regex failed after {duration:.4f} seconds with error: {e}")
......self.fail(f"Regex processing failed, potential ReDoS. Error: {e}")
if __name__ == '__main__':
..unittest.main()
Он сохранил файл и запустил тест из терминала.
На экране появилось сообщение: Testing ReDoS with string length: 10205. Курсор замер на мгновение. Индикатор загрузки процессора в системном трее резко подскочил до 100%, но почти сразу, спустя ровно одну секунду, выполнение теста прервалось, и терминал выплюнул красные строки ошибки:
FAIL: test_redos_vulnerability (__main__.TestReDoS)
Regex took too long, potential ReDoS detected!
-----------------------------------
AssertionError: 1.00123456789 not less than 1.0 : Regex took too long, potential ReDoS detected!
-----------------------------------
Ran 1 test in 1.002s
FAILED (failures=1)
Алекс смотрел на сообщение об ошибке` AssertionError: ... not less than 1.0`. Тест сработал идеально. Меньше чем за две секунды он получил неопровержимое доказательство. Регулярка была ядовитой.
Он откинулся на спинку кресла. На губах появилась странная, холодная улыбка. Это была не радость победы, а мрачное подтверждение того, что он имел дело не просто с багом или ошибкой, а с целенаправленным саботажем.
«Попалась», — прошептал он пустоте комнаты. Холодное интеллектуальное удовлетворение от разгадки смешалось с профессиональным азартом — он нашел ловушку, обезвредил ее (по крайней мере, в своей голове). Но тут же нахлынула волна ледяной злости и отвращения. Эта тварь… Она не просто пыталась ему навредить, она делала это хитро, изощренно, маскируя атаку под сложный, наукообразный код. Расчетливая зараза.
#4950 в Триллеры
#2163 в Психологический триллер
#12826 в Фантастика
#1738 в Научная фантастика
паранойя, технотриллер, опасный ии
16+
Отредактировано: 05.10.2025