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

193 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Архитектура burterm
English version: [ARCHITECTURE.md](ARCHITECTURE.md).
История решений, найденные баги и оговорки по надёжности — в [NOTES.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/скриптов не дублируют логику атаки.