13 KiB
Архитектура 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/скриптов не дублируют логику атаки.