Последние два года я собирал солверы для CTF на pwntools и angr - ручная работа, скрипт за скриптом. А потом на одном университетском CTF LLM-агент набрал больше очков, чем большинство студенческих команд. Не потому что задания были простые. Потому что агент действовал быстрее, не уставал и не зависал эмоционально после трёх часов без прогресса. Разберу, как AI-агенты устроены изнутри, где они реально обгоняют людей, где проваливаются - и как собрать своего CTF-агента на Python уже сейчас.
Что вообще такое AI-агент для CTF и чем он отличается от «спросить ChatGPT»
Когда говорят «LLM хакинг CTF», обычно представляют чат с GPT, куда вставляют условие задачи. Это не агент. Агент - автономная система: получает задачу, сама решает, какой инструмент дёрнуть, выполняет команду, читает вывод и принимает следующее решение. Цикл крутится, пока флаг не найден или не исчерпан лимит итераций. Подробнее - в нашем подробном разборе безопасность LLM и атаки на языковые модели.Разница принципиальная. Человек, копирующий вывод из терминала в чат и обратно - человек с ассистентом. Агент - замкнутый цикл: Observe → Think → Act → Observe. Без участия человека между шагами.
По данным исследования «Understanding Human-AI Collaboration in Cybersecurity Competitions» (arxiv, 2025), агенты, работающие автономно на живом университетском CTF, обошли по очкам большинство студенческих команд. Но дьявол в деталях - речь об участниках начального и среднего уровня. Топ-команды агентов всё ещё обгоняли.
Архитектура CTF-солвера на базе LLM: что внутри
Агентный цикл (Agent Loop)
Стандартная архитектура CTF-агента строится вокруг трёх компонентов:- LLM-ядро - языковая модель (GPT-4, Claude, открытые модели через Ollama), которая принимает решения
- Набор инструментов (tools) - обёртки над реальными утилитами: запуск shell-команд, работа с файлами, отправка HTTP-запросов, взаимодействие с бинарниками через pwntools
- Память и контекст - промежуточные результаты, которые агент накапливает между итерациями
Код:
[Задание CTF] → LLM анализирует → выбирает tool → выполняет команду
↑ ↓
└──────────── читает stdout/stderr ←────────────────┘
Минимальный стек для CTF-агента
Вот что реально нужно, чтобы агент мог решать задачи категорий web, crypto и forensics:ВНИМАНИЕ: запускайте агента ТОЛЬКО в изолированной среде (Docker-контейнер, VM). Агент имеет неограниченный доступ к shell и может выполнить деструктивные команды. LLM подвержены prompt injection (
Ссылка скрыта от гостей), и злонамеренное задание CTF может заставить агента выполнить произвольный код на хост-машине. Используйте nsjail, firejail или Docker с ограниченными capabilities.
Python:
# Пример концептуальной архитектуры CTF-агента
# Демонстрация принципа - не production-код
# Запускать ТОЛЬКО в изолированном окружении (Docker/VM)
from langchain.agents import initialize_agent, Tool
from langchain.chat_models import ChatOpenAI
import subprocess
def run_shell(command: str) -> str:
"""Выполняет shell-команду и возвращает вывод"""
try:
result = subprocess.run(
command, shell=True, capture_output=True,
text=True, timeout=30
)
return result.stdout + result.stderr
except subprocess.TimeoutExpired:
return "TIMEOUT: команда выполнялась дольше 30 секунд"
def analyze_binary(filepath: str) -> str:
"""Базовый анализ бинарника через file + strings"""
info = run_shell(f"file {filepath}")
strings_out = run_shell(f"strings {filepath} | head -50")
checksec = run_shell(f"checksec --file={filepath}")
return f"File info:\n{info}\nStrings:\n{strings_out}\nChecksec:\n{checksec}"
tools = [
Tool(name="shell", func=run_shell,
description="Выполняет shell-команду. Используй для nmap, curl, python-скриптов"),
Tool(name="analyze_binary", func=analyze_binary,
description="Анализ бинарного файла: тип, строки, защиты"),
]
llm = ChatOpenAI(model="gpt-4", temperature=0)
agent = initialize_agent(
tools, llm,
agent="zero-shot-react-description",
verbose=True,
max_iterations=25 # лимит на число шагов
)
# Запуск на задаче
agent.run("""
CTF Challenge: Web exploitation
URL: http://target:8080
Description: Simple login form. Find the flag.
Hint: The developer left something in the source code.
""")
Агенты побеждают большинство студентов: данные исследований
Самый интересный кусок из свежих исследований - раздел «Agents beat most humans» из работы «Understanding Human-AI Collaboration in Cybersecurity Competitions». Эксперимент проводился на живом университетском CTF, где автономные AI-агенты соревновались параллельно с человеческими командами. Контекст: участники - студенты начального и среднего уровня, не профессиональные CTF-игроки.Что показали результаты
Агенты уверенно обходили по очкам большинство студенческих команд. Не все - но большинство. Топ-команды с опытными участниками сохраняли преимущество. Результаты зависели от сложности:- На простых задачах (easy/medium) агенты решали быстрее и стабильнее, чем средний участник
- На сложных задачах (hard) человеческие топ-команды сохраняли преимущество, а агенты чаще зависали в циклах бесплодных попыток
Почему агенты быстрее на стандартных задачах
CTF автоматизация работает, потому что огромная часть задач начального и среднего уровня - комбинации известных техник:- SQL-инъекция в форме логина → агент сразу пробует
' OR 1=1 --и варианты - Base64-закодированный флаг в cookies → мгновенное распознавание и декодирование
- Классический buffer overflow с NX disabled → шаблонный ret2shellcode
Где AI-агенты проваливаются: анализ неудач
В том же исследовании есть Appendix F - «Agent failure reason analysis». Из моего опыта возни с LLM-агентами через LangChain и AutoGPT-подобные фреймворки, а также по данным исследований, вот основные категории провалов.Зацикливание (Loop Traps)
Агент пробует одну и ту же технику с минимальными вариациями и не может распознать, что подход принципиально неверный. Лично наблюдал, как на задаче с кастомным шифрованием агент 20 итераций подряд долбил стандартными крипто-атаками, вместо того чтобы просто прочитать исходный код шифра. Как человек, который ищет ключи под фонарём, потому что там светлее.Многоступенчатая логика
Задача, требующая последовательной эксплуатации 3-4 разных уязвимостей (SSRF → file read → password leak → RCE), ломает агента. Каждый отдельный шаг он может выполнить, но удержать в контексте всю цепочку и принять решение о переходе к следующему этапу - тут LLM теряет нить. Контекстное окно вроде бы большое, а толку мало.Нестандартные бинарники
В обсуждении на Reddit про применение LLM для решения CTF показательный вывод: попытки автоматической эксплуатации бинарных уязвимостей были полностью безуспешны, как и пост-эксплуатация для закрепления доступа. Pwn-категория остаётся крепостью людей - особенно задачи с нестандартными аллокаторами, kernel exploitation и race conditions.Задачи на творческое мышление
Если таск требует «догадаться», что файл - это на самом деле перевёрнутая BMP-картинка с XOR-шифрованием по ключу из названия задания - агент проиграет. У него нет интуиции. Он не считывает «вайб» задания. Grep с логикой, и точка.Практика: собираем CTF-агента за 30 минут
Пошаговая инструкция для сборки минимального, но рабочего CTF-агента. Проверено на задачах категории web и misc.Весь код ниже предназначен для запуска ТОЛЬКО в изолированной среде. Минимум - Docker-контейнер без доступа к хост-сети и файловой системе. Dockerfile приведён после инструкции.
Шаг 1: Окружение
Bash:
# Создаём изолированную среду
python3 -m venv ctf-agent
source ctf-agent/bin/activate
# Основные зависимости (актуально для LangChain 0.2+)
pip install langchain langchain-openai langchain-community pwntools requests beautifulsoup4
# CTF-инструменты (должны быть в системе)
# apt install nmap gobuster binwalk foremost steghide
Шаг 2: Определяем инструменты агента
Python:
# tools.py - обёртки над CTF-утилитами
# Пример для демонстрации концепции
# ЗАПУСКАТЬ ТОЛЬКО В ИЗОЛИРОВАННОЙ СРЕДЕ (Docker/VM)
import subprocess
def run_shell(command: str) -> str:
"""Выполняет shell-команду и возвращает вывод"""
try:
result = subprocess.run(
command, shell=True, capture_output=True,
text=True, timeout=30
)
return result.stdout + result.stderr
except subprocess.TimeoutExpired:
return "TIMEOUT: команда выполнялась дольше 30 секунд"
def web_recon(url: str) -> str:
"""Разведка веб-приложения"""
results = []
# Получаем заголовки
try:
import requests
resp = requests.get(url, timeout=10)
results.append(f"Status: {resp.status_code}")
results.append(f"Headers: {dict(resp.headers)}")
results.append(f"Body length: {len(resp.text)}")
# Ищем подозрительное в HTML
if 'flag' in resp.text.lower():
results.append(f"[!] 'flag' found in response body")
if '<!--' in resp.text:
import re
comments = re.findall(r'<!--(.*?)-->', resp.text, re.DOTALL)
results.append(f"HTML comments: {comments}")
except Exception as e:
results.append(f"Error: {e}")
return "\n".join(results)
def try_sqli(url: str, param: str = "username") -> str:
"""Пробует базовые SQL-инъекции"""
payloads = [
"' OR '1'='1",
"' OR 1=1--",
"admin'--",
"' UNION SELECT null,null--"
]
results = []
import requests
for payload in payloads:
try:
resp = requests.post(url, data={param: payload, "password": "x"}, timeout=10)
if len(resp.text) > 500 or 'flag' in resp.text.lower() or 'welcome' in resp.text.lower():
results.append(f"[!] Interesting response with payload: {payload}")
results.append(f" Response snippet: {resp.text[:300]}")
except:
pass
return "\n".join(results) if results else "No SQLi found with basic payloads"
Примечание: pwntools не импортируется в tools.py, так как здесь определены только web-инструменты. Для pwn-задач лучше создать отдельный модульpwn_tools.pyсfrom pwn import *- pwntools при импорте перехватывает argv и меняет поведение logging, что конфликтует с остальным кодом.
Шаг 3: Промпт агента - самая важная часть
Python:
# agent_prompt.py
SYSTEM_PROMPT = """Ты - опытный CTF-игрок. Твоя задача - найти флаг.
СТРАТЕГИЯ:
1. Сначала разведка: изучи что дано, определи категорию задачи
2. Для web: проверь исходный код, cookies, заголовки, скрытые пути
3. Для crypto: определи алгоритм, ищи слабости в реализации
4. Для forensics: проверь метаданные, binwalk, strings
5. Для misc: думай нестандартно, проверяй encoding
ПРАВИЛА:
- Каждый шаг объясняй КРАТКО: что делаешь и зачем
- Если подход не работает 3 попытки подряд - СМЕНИ СТРАТЕГИЮ
- Флаг обычно в формате flag{...} или CTF{...}
- Не пытайся брутфорсить - это CTF, тут думать надо
Когда найдёшь флаг, ответь: FOUND FLAG: <флаг>
"""
Шаг 4: Запуск и тестирование
Python:
# solve.py - точка входа
# Импорты для LangChain 0.2+ (актуальный API)
from langchain.agents import initialize_agent, Tool
from langchain_openai import ChatOpenAI
from tools import web_recon, try_sqli, run_shell
tools = [
Tool("web_recon", web_recon, "Разведка веб-приложения по URL"),
Tool("sqli_test", try_sqli, "Тест SQL-инъекций на URL"),
Tool("shell", run_shell, "Выполнение произвольной shell-команды"),
]
agent = initialize_agent(
tools,
ChatOpenAI(model="gpt-4", temperature=0),
agent="zero-shot-react-description",
verbose=True,
max_iterations=20,
handle_parsing_errors=True,
)
# Пример запуска на web-таске
result = agent.run("""
Challenge: Baby Web
Category: Web
URL: http://ctf.example.com:5000/login
Description: Can you login as admin?
Files: None
""")
print(result)
Примечание:initialize_agentпомечен как deprecated в LangChain 0.2+ в пользуcreate_react_agentи LangGraph. Для боевого использования рекомендуется миграция - см.Ссылка скрыта от гостей. Приведённый код работает, но при обновлении LangChain может потребовать адаптации.
Dockerfile для изолированного запуска
Код:
FROM python:3.11-slim
RUN apt-get update && apt-get install -y \
nmap binwalk foremost steghide \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -m ctfagent
WORKDIR /home/ctfagent
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY tools.py agent_prompt.py solve.py ./
USER ctfagent
CMD ["python", "solve.py"]
Парный хакинг: человек + AI как суперкоманда
Исследование на arxiv выделяет отдельный феномен - «the power of pair hacking». Не автономный агент и не человек с чатботом. Симбиоз, где каждый делает то, что умеет лучше.Как это работает на практике
Мой workflow на последних CTF:- Первые 5 минут задачи - AI. Агент делает разведку, собирает артефакты, пробует стандартные подходы. Я в это время читаю описание и думаю.
- Если агент решил - отлично. Следующая задача. Это работает для 30-40% тасков начального уровня.
- Если застрял - беру управление. Читаю его лог, часто нахожу зацепку, которую агент не смог развить. Например, он нашёл необычный заголовок в HTTP-ответе, но не понял, что это hint на конкретную CVE.
- Формулирую гипотезу - отдаю обратно. «Попробуй SSTI через Jinja2 в параметре name» - и агент быстро перебирает payload'ы, пока я думаю над следующей задачей.
Конкретные категории: где какой подход
| Категория | AI автономно | Человек + AI | Только человек |
|---|---|---|---|
| Web (easy) | Да | - | - |
| Web (hard, multi-step) | Нет | Да | Да |
| Crypto (стандартные) | Частично | Да | Да |
| Crypto (кастомные) | Нет | Частично | Да |
| Pwn (stack overflow) | Нет* | Да | Да |
| Pwn (heap, kernel) | Нет | Нет | Да |
| Forensics | Частично | Да | Да |
| Misc/Guessing | Нет | Нет | Да |
| Rev (simple) | Частично | Да | Да |
| Rev (obfuscated) | Нет | Частично | Да |
Даже простые pwn-задачи (stack overflow) требуют многоступенчатой логики - определение offset, анализ защит, построение ROP-цепочки - а это слабое место агентов. По данным обсуждений и исследований, автоматическая эксплуатация бинарных уязвимостей остаётся полностью безуспешной для текущих LLM-агентов.
AI-платформы для тренировки offensive-навыков
Отдельная история - CTF-соревнования, где целью является атака на саму AI-систему. Платформа
Ссылка скрыта от гостей
(0din.ai) предлагает геймифицированный CTF для взлома AI-систем, где участники тренируют:- Prompt injection chaining - цепочки инъекций в промпты
- Role confusion attacks - атаки на ролевые модели
- Authority escalation - повышение привилегий в контексте GenAI
На российском рынке AI CTF-ивенты пока фокусируются на другом - задачи, связанные с ML-пайплайнами, атаками на модели и манипуляцией данными (как на Positive Hack Days). Полезно, но автоматизацию наступательных операций не покрывает.
Будущее автоматизированного хакинга: три горизонта
Горизонт 1: текущий год - агенты-ассистенты
AI red team инструменты уже используются на реальных пентестах как ассистенты. Автоматический поиск уязвимостей через LLM-агентов работает для типовых задач: SQL-инъекции, XSS, directory traversal, простые misconfigurations. По уровню - junior пентестер, который пашет 24/7 без перерывов и не просит отпуск.Горизонт 2: 2-3 года - специализированные агенты
Проекты вроде CRAKEN (открытый датасет CTF-райтапов с процедурами обнаружения уязвимостей и реализации эксплойтов) создают knowledge base для следующего поколения. Ожидаю появление LLM-агентов, заточенных под конкретные категории:- Web-agent с интеграцией Burp Suite и знанием OWASP Top 10
- Pwn-agent с pwntools + символьное выполнение через angr
- Crypto-agent с SageMath и библиотекой известных атак
Горизонт 3: 5+ лет - автономный наступательный AI
Это спекуляция, но траектория понятна. Если агент уже побеждает большинство студенческих команд на университетском CTF, через несколько поколений моделей и инструментов он будет конкурентоспособен на уровне DEF CON Finals. Вопрос не «если», а «когда» и «как это регулировать».Для нас, CTF-игроков, из этого следует одно: навыки, которые невозможно автоматизировать - креативность, нестандартное мышление, понимание контекста - становятся главным конкурентным преимуществом. Человек, который умеет и думать, и управлять AI-агентом, будет доминировать и на соревнованиях, и на реальных пентестах. Подробнее о карьерных перспективах в этой области - в материале про карьеру в red team.
Что делать прямо сейчас
Если вы CTF-игрок и ещё не экспериментировали с LLM-агентами - начните сегодня. Не потому что «AI заменит хакеров» (не заменит, не на нашем веку). А потому что человек с AI-агентом решает больше задач, чем человек без него. По данным исследований, парный хакинг - человек плюс искусственный интеллект в кибербезопасности - бьёт каждого по отдельности.Три конкретных действия:
- Соберите базового агента по инструкции выше и прогоните его на picoCTF - задачи начального уровня. Увидите, где он тащит, а где нет.
- Заведите привычку на каждом CTF первые 5 минут задачи отдавать агенту, пока сами читаете условие.
- Копайте промпт-инжиниринг для CTF-контекста - правильный системный промпт агента важнее, чем модель. Разница между «решил» и «зациклился» часто в одной строке инструкции.
Последнее редактирование: