burterm/ARCHITECTURE.ru.md
2026-09-14 10:55:07 +03:00

13 KiB
Raw Blame History

Архитектура burterm

English version: ARCHITECTURE.md. История решений, найденные баги и оговорки по надёжности — в NOTES.md.

Обзор

burterm — терминальный инструмент для веб-пентеста, bug bounty и CTF: один статический Go-бинарник, 13 вкладок TUI и headless CLI-режим на том же движке. Сборка без cgo.

cmd/burterm/          точка входа: CLI-флаги или запуск TUI
internal/
  engine/                 ядро Intruder: маркеры, атаки, фильтры
  payload/                 генераторы payload'ов
  cli/                      разбор флагов и payload-спецификаций
  proxy/                     MITM-прокси
  spider/                     краулер
  sitemap/                     scope-правила, дерево сайта
  scanner/                      активные/пассивные проверки уязвимостей
  fuzzer/                        blackbox-фаззер бинарников
  project/                        хранилище сессии (SQLite+FTS5)
  decoder/ comparer/ sequencer/       утилиты
  tui/                                  интерфейс (bubbletea)

Общие принципы

  • Асинхронный I/O через tea.Cmd/tea.Msg. TUI построен на архитектуре Elm: Update(msg) (Model, Cmd). Любой побочный эффект (сеть, диск, таймер) — это tea.Cmd, функция без аргументов, возвращающая tea.Msg, выполняемая фреймворком в отдельной горутине. Update никогда не блокируется на I/O.
  • Потоковые операции — через каналы. Intruder-атаки, Scanner, Spider, Fuzzer стримят результаты через <-chan T. Общий паттерн: горутина-продюсер пишет в канал через select с <-ctx.Done(); TUI читает через waitForXxx(ch) tea.Cmd, переиздающий себя после каждого сообщения.
  • Значения снимаются с модели до ухода tea.Cmd в фон — замыкание не держит ссылку на модель, которая может измениться до того, как команда выполнится.

internal/engine — ядро Intruder

  • §маркеры§ в сыром HTTP-запросе отмечают точки вставки payload'а. ParseMarkers вычленяет их в []InsertionPoint{Start, End} (байтовые смещения в очищенной строке) и возвращает текст без маркеров. InsertBeforeMarker вставляет произвольный текст перед N-м маркером — используется рекурсией (см. ниже).
  • BuildRequest подставляет payload'ы и парсит результат в *http.Request через http.ReadRequest.
  • Четыре режима атаки: RunSniper, RunBattering, RunPitchfork, RunClusterBomb — общий пул воркеров, читающих задания из канала. Pitchfork/ClusterBomb используют drainGenerator, вычитывающий генератор целиком в память перед стартом.
  • EstimateTotal считает ожидаемое число запросов по Len() генераторов до старта атаки — для индикации прогресса в TUI.
  • ParseStatusFilter/ParseLengthFilter/ParseWordFilter/ParseLineFilter — общий синтаксис (>N, <N, N-M, точное число) через один внутренний парсер parseIntRangeFilter.
  • New(cfg) настраивает http.Transport с MaxIdleConnsPerHost: cfg.Concurrency для переиспользования соединений при конкурентных запросах к одному хосту.

internal/payload — генераторы payload'ов

Интерфейс Generator (Next/Reset/Len). Реализации: WordlistGenerator, NumericRangeGenerator, BruteForceGenerator (перебор алфавита заданной длины), ExtensionGenerator (оборачивает любой генератор, добавляя расширения к каждому слову — spec|ext:.php,.html). presets.go — набор готовых заготовок (числа, буквы, частые имена/пароли, SQLi/XSS/path-traversal пробники). smart.go — эвристика подсказки заготовки по имени параметра рядом с маркером.

internal/cli — CLI-флаги

ParsePayloadSpec разбирает строки вида wordlist:<путь> / range:<from>:<to>:<step> / preset:<имя> / brute:<алфавит>:<min>:<max>, с необязательным суффиксом |ext:.... Используется и headless-режимом (cmd/burterm), и TUI — единая грамматика.

internal/proxy — MITM-прокси

  • Server — форвардный прокси с MITM через собственный CA (ca.go, генерируется в ~/.burterm при первом запуске), CONNECT-туннель с tls.Server и динамическим выпуском листовых сертификатов по SNI.
  • Каждая транзакция — Entry{Raw, StatusCode, Length, Headers, ResponseBody, ...} в потокобезопасном Store (sync.Mutex, подписка на новые записи через канал).
  • Server.SetScope(*sitemap.Scope) под sync.RWMutex — если задан, capture/captureErr пропускают запись в Store для запросов вне scope. Сам трафик прокси обслуживает независимо от scope.
  • session.go: ExtractSessionHeaders(entries, host) вытаскивает Cookie/Authorization из истории для конкретного хоста (парсит их из Entry.Raw).

internal/spider — краулер

Spider.Crawl — BFS-обход в границах scope *url.URL и maxDepth. extractLinksAndForms парсит HTML, извлекает ссылки и описания форм. GET-формы (Method=="GET") автоматически конвертируются в URL с заглушками test на каждое поле и добавляются в очередь обхода (buildGetFormURL); POST-формы пропускаются. SetHeaders задаёт заголовки для каждого запроса обхода — используется для передачи сессионных Cookie/Authorization из Proxy.

internal/sitemap — scope и дерево сайта

Scope — упорядоченный список include/exclude regex-правил (Add/RemoveAt/Matches/Rules). Tree/Node/Endpoint — дерево путей сайта, строится из потока URL через Build, экспортируется в JSON.

internal/scanner — проверки уязвимостей

  • Check — интерфейс активной проверки (Name/Probes/Analyze), подставляет payload'ы в одну точку вставки через ту же engine.BuildRequest, что и Intruder. Реализации: SQLi, XSS (reflected, с уникальной канарейкой), SSTI, LFI, RCE (time-based), SSRF, XXE.
  • Scanner.Run возвращает канал Event{Kind: EventProgress|EventFinding} — прогресс и находки в одном потоке.
  • CheckCORS — одноразовая проверка через заголовок Origin (не вписывается в интерфейс Check, так как не работает через маркер).
  • DecodeJWT/AlgNoneVariant — разбор JWT и генерация варианта без подписи для проверки обхода.

internal/fuzzer — фаззер бинарников

Blackbox-мутационный фаззер произвольного исполняемого файла (CTF pwn). Config{Target, Args, UseStdin, Timeout, Workers, CrashDir}. Мутации (mutate.go): bit-flip, byte-flip, arithmetic, interesting values, block delete/duplicate, splice, havoc (комбинация нескольких мутаций за проход). Краш определяется по сигналу завершения процесса (SIGSEGV/SIGABRT/SIGFPE/SIGILL/SIGBUS) через syscall.WaitStatus. Run возвращает канал Event{Kind: EventProgress|EventCrash}, каждый воркер — независимая горутина со своим rand.Source.

internal/project — хранилище сессии

SQLite (modernc.org/sqlite, без cgo) с FTS5-индексом в режиме external content (текст хранится один раз в requests, requests_fts держит только инвертированный индекс), синхронизация через триггеры INSERT/UPDATE/DELETE. Store.Open ставит db.SetMaxOpenConns(1). ParseQuery — мини-язык поиска (host:… method:… status:… color:… текст) — известные key:value-токены уходят в структурированный SQL, остальное — в FTS5 MATCH. SaveMeta/LoadMeta — произвольные key-value записи (используется для scope-правил Target). SaveLastPath/LoadLastPath — путь последнего открытого проекта хранится вне самой БД (~/.burterm/last-project).

internal/decoder, comparer, sequencer

decoder — кодеки URL/Base64/HTML/Hex/MD5 и цепочка автоопределения. comparer — токенный LCS-diff. sequencer — статистические тесты FIPS 140-2 (monobit/poker/runs/long-run) на 20000-битных блоках.

internal/tui — интерфейс

  • Model (model.go) — корневая модель, поле active view определяет видимую вкладку. Update делегирует необработанные сообщения активной вкладке.
  • Каждая вкладка — своя xxxModel в отдельном файле (requestbuilder.go, results.go, proxyview.go, repeater.go, spiderview.go, targetview.go, decoderview.go, comparerview.go, sequencerview.go, dashboardview.go, scannerview.go, projectview.go, fuzzerview.go), с методами Update(tea.Msg) (xxxModel, tea.Cmd) и View() string.
  • theme.go — палитра, panel() (рамка с заголовком через lipgloss.RoundedBorder), renderTabs() (таб-бар с заливкой активной вкладки), renderLogo().
  • results.go — кэширует скомпилированные предикаты фильтров (recompileFilters), копит отфильтрованный вывод в strings.Builder инкрементально (AddResult), рендерит во viewport дросселированно по таймеру resultsTickCmd (раз в 300мс), только для видимой атаки.
  • attacks []*attackRun — список независимых параллельных атак, каждая со своим id/каналом/cancel/resultsModel.
  • recursionMeta — параметры авто-рекурсии Intruder в найденные директории: шаблон запроса, точка вставки, спецификации payload'ов, глубина, предикат статусов.
  • Сообщения именуются по паттерну xxxStartedMsg/xxxResultMsg/ xxxDoneMsg/xxxErrMsg для каждой длительной операции.

Хранение на диске

Всё под ~/.burterm/: ca.pem/ca-key.pem (MITM CA), last-project (путь последнего проекта), fuzz-crashes/<unix>/ (крашащие вводы фаззера), sitemap-<unix>.json (экспорт карты сайта).

Режимы запуска

TUI (без аргументов) и headless CLI (-request/-payload/-mode и т.д., см. internal/cli/flags.go) используют один и тот же internal/engine — сценарии CI/скриптов не дублируют логику атаки.