fix(core): 修复 stdout 爆破零输出卡死(53a80b5 回归)+ 单 host --concurrency 限流#66
Open
wuchulonly wants to merge 4 commits into
Open
fix(core): 修复 stdout 爆破零输出卡死(53a80b5 回归)+ 单 host --concurrency 限流#66wuchulonly wants to merge 4 commits into
wuchulonly wants to merge 4 commits into
Conversation
Brute results were non-deterministic: the same command would find the password on one run and miss it on another. Root cause: there was no per-host concurrency cap, so with the default -t 100 the brute fired up to 100 simultaneous pre-auth connections at a single SSH target. sshd MaxStartups (default 10:30:100) then randomly dropped connections above the soft limit. zombie treats such network drops as "wrong password", so whenever the attempt carrying the correct password happened to be dropped, it was silently missed — and which attempt got dropped was random, hence the run-to-run flakiness. Fix: add a per-host semaphore (hostLimiter) keyed by ip:port that bounds in-flight connections per target. - acquire is context-aware: if the target is cancelled while waiting for a slot (e.g. another worker already found the password), it returns without dialing, so the post-first-success queue drain does not burst connections. - Skip already-cancelled tasks at the top of the worker. - The gate sits in the outer worker before the timeout select, so time spent queuing for a slot is not counted against the per-task timeout; released via defer for panic safety. - New flag --host-threads (default 8) controls the cap; 0 = unlimited. 8 stays inside sshd's default always-accept zone (MaxStartups starts dropping at 10), while 10 sits exactly on the knee. Verified on an SSH target with default MaxStartups, 40-password dict with the correct password mid-list, repeated runs: unlimited: 46% miss | --host-threads 10: 13% | 8: 0% | 2: 0% In-flight dials now strictly equal --host-threads. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CLI 参数 --host-threads 改名为 --concurrency(纯长参,避开 -c/--cidr 短参冲突); 字段 HostThreads -> Concurrency,默认值与 hostLimiter 行为不变。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
master 已把 go.mod bump 到 `go 1.22.0` + `toolchain go1.24.3`, 但 ci.yml 仍写死 go-version 1.20.x,Go 1.20 无法解析 1.22.0 版本格式 与 toolchain 指令,导致 `go mod download` 解析 go.mod 失败、CI 全红。 改用 go-version-file: go.mod 让 CI 跟随 go.mod 单一事实源。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
53a80b5 gated the OutputHandler goroutine on `OutFunc != nil`, but OutFunc is only set when an output file (-f) is given (options.go: `if opt.OutputFile != ""`). OutputHandler is the sole reader of the unbuffered OutputCh *and* the sole console printer, so whenever results go to stdout with no -f (e.g. `-o jl`, the common case and how SDK/automation callers invoke it) the handler never started: the first Output() blocked forever on `OutputCh <- res` and the whole brute hung with zero output. The host-threads/concurrency work on this branch was silently unusable for the same reason. Replace the OutFunc gate with an explicit ManualDrain flag (default false): the built-in handler runs for every CLI/default invocation, and SDK consumers that drain OutputCh themselves opt out via ManualDrain=true. The outlock Add/Wait accounting is gated on the same flag so it stays balanced with the handler. Verified against live redis/ssh/mysql/postgres targets: stdout-mode brute now cracks (was: hang, success:0); -f file output unchanged; go test ./... green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
本分支两处相关的
core改动:f84a081)—— 这是已在master中的回归。--concurrency(f12fa38、5a642fa)—— 消除爆破"时成时不成"的非确定性漏报。1. OutputHandler 卡死(影响当前 master)
53a80b5(已在master)把OutputHandlergoroutine 的启动门控错绑在OutFunc != nil上,而OutFunc只在指定了输出文件(-f)时才赋值(options.go: if opt.OutputFile != "")。OutputHandler是无缓冲OutputCh的唯一读者,同时也是唯一的 console 打印者——因此当结果输出到 stdout 且未给-f时(例如-o jl,即 SDK/自动化常用路径),handler 不会启动:第一个Output()在OutputCh <- res处永久阻塞,整个爆破卡死且零输出。修复:用显式的
RunnerOption.ManualDrain标志(默认false)替代OutFunc门控。默认/CLI 调用都会启动内建 handler;自行消费OutputCh的 SDK 调用方可通过ManualDrain = trueopt-out。outlock的 Add/Wait 计数同步绑定该标志以保持配对。master 上复现:
zombie -i <redis> -s redis(stdout)卡死/无输出;加上-f out.txt即正常。2. 单 host 并发限流
默认
-t 100下,爆破会朝同一目标同时发起多达 100 条 pre-auth 连接。sshd MaxStartups(默认10:30:100)随即随机丢弃超过软上限的连接;zombie 把这类丢连当成"口令错误",于是承载正确口令的那次连接被随机丢弃时就被静默漏掉——典型的"同一条命令一次成、一次不成"。--concurrency(别名--host-threads,默认8,0= 不限)通过一个 ctx 感知的信号量,按ip:port把在飞连接数封顶(命中后队列排空时不再爆连)。8落在 sshd 的"必然接受"区间内。验证
go test ./...全绿success:0);-f文件输出不变--concurrency 8→ 20/20(0% 漏报)🤖 Generated with Claude Code