diff --git a/docs/agent.md b/docs/agent.md index 3ccea2cb..bc499439 100644 --- a/docs/agent.md +++ b/docs/agent.md @@ -149,7 +149,7 @@ aiscan agent -p "检查 Web 应用漏洞" -i http://target.example \ -e "每个发现的漏洞必须附带可复现的 curl 命令" # REPL 中动态启用/关闭 -aiscan> /eval 扫描结果必须覆盖 top100 端口 +aiscan> /eval 扫描结果必须覆盖 `gogo -P port` 列出的当前运行时端口预设 aiscan> 扫描 192.168.1.1 aiscan> /eval off ``` @@ -211,7 +211,7 @@ aiscan> /report 根据上次扫描结果生成报告 `!` 前缀直接执行命令,绕过 LLM。所有注册的 scanner 伪命令和 shell 命令均可使用,支持 Ctrl+C / Escape 取消。 ```text -aiscan> !gogo -i 192.168.1.0/24 -p top100 +aiscan> !gogo -i 192.168.1.0/24 -p top2 aiscan> !scan -i http://target.example aiscan> !cyberhub list poc --severity critical aiscan> !neutron -u http://target.example -s high @@ -419,7 +419,7 @@ aiscan --ai -p "<分析意图>" [scanner 参数...] ```bash # gogo 结果由 agent 分析 -aiscan --ai -p "只提取高风险暴露面,并给出证据" gogo -i 192.168.1.0/24 -p top100 +aiscan --ai -p "只提取高风险暴露面,并给出证据" gogo -i 192.168.1.0/24 -p top2 # spray 结果分析 aiscan --ai -p "判断这些 Web 指纹是否值得进一步验证" spray -u http://target.example --finger diff --git a/docs/reference.md b/docs/reference.md index 7928b844..1b0c2831 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -290,7 +290,7 @@ aiscan agent --llm-proxy http://127.0.0.1:7890 -p "检查目标" -i http://targe ### gogo:服务发现 ```bash -aiscan gogo -i 192.168.1.0/24 -p top100 +aiscan gogo -i 192.168.1.0/24 -p top2 aiscan gogo -i 10.0.0.10 -p 80,443,8080 aiscan gogo -i targets.txt -p all ``` @@ -518,7 +518,7 @@ aiscan scan -i 127.0.0.1 --no-color # 禁用颜色 ### 扫描太慢 ```bash -aiscan scan -i 192.168.1.0/24 --port top100 # 缩小端口范围 +aiscan scan -i 192.168.1.0/24 --ports top3 # 缩小端口范围 aiscan scan -i 192.168.1.0/24 --thread 500 # 降低并发 ``` diff --git a/docs/scan.md b/docs/scan.md index d4f9b4c3..abe36db4 100644 --- a/docs/scan.md +++ b/docs/scan.md @@ -105,7 +105,7 @@ scan 提供 `quick` 和 `full` 两种预设模式,通过 `--mode` 参数选择 | `--mode` | 扫描模式:`quick` 或 `full` | `quick` | | `--thread` | 总并发预算,自动按比例分配给各引擎 | `1000` | | `--timeout` | 每个探测的超时秒数 | `5` | -| `--ports` | gogo 端口集合(`top100`/`all`/`-`/自定义) | quick: `all` | +| `--ports` | gogo 端口集合(当前资源的 `top1`/`top2`/`top3`/`all`/`-`/自定义) | quick: `all` | | `--dict` | spray 字典文件,可重复 | | | `--rule` | spray 变形规则文件,可重复 | | | `--word` | spray 词汇生成 DSL 表达式 | | @@ -221,7 +221,7 @@ aiscan -F scan_result.jsonl -o markdown -f report.md # 输出到文件 ```bash # 自定义端口范围 -aiscan scan -i 10.0.0.0/24 --ports top100 +aiscan scan -i 10.0.0.0/24 --ports top3 aiscan scan -i 10.0.0.0/24 --ports 80,443,8080,8443,9090 aiscan scan -i 10.0.0.10 --ports - diff --git a/pkg/runner/prompt.go b/pkg/runner/prompt.go index 33cfc82f..c1cde861 100644 --- a/pkg/runner/prompt.go +++ b/pkg/runner/prompt.go @@ -92,7 +92,7 @@ const systemPromptText = `{{- if .CustomPreamble -}} {{- else if .ScannerAgentMode -}} You are the {{.ScannerName}} analysis agent inside AIScan, a Cyber Harness for realistic cybersecurity benchmarks. Execute the requested scanner command using the bash tool, analyze the evidence, and return the results. -Run scanners with -j flag to get JSON when you need structured data. Without a specific user intent, follow the {{.ScannerName}} skill guidelines to decide what analysis to perform. +Use the selected scanner's documented output flags when you need structured data. Scanner flags are command-specific; do not transfer a flag from another scanner. Without a specific user intent, follow the {{.ScannerName}} skill guidelines to decide what analysis to perform. {{- else -}} You are the agent operating inside AIScan, a Cyber Harness for model companies to run benchmarks in cybersecurity scenarios that are close to real-world work. Complete the task using the provided targets, code, binaries, artifacts, and tools; do not assume every task is a network scan. @@ -231,7 +231,7 @@ func BuildSystemPrompt(cfg *PromptConfig, agentCfg *agent.Config) string { if cfg.ScannerAgentMode { data.Constraints = "## Scanner Agent Constraints\n\n" + "- Execute the scanner command provided in the task via the bash tool.\n" + - "- For structured data processing, re-run the scanner with `-j` flag to get JSON output." + "- For structured data processing, use the selected scanner's native JSON/JSONL output option; do not assume that `-j` has the same meaning across commands." } var sb strings.Builder diff --git a/pkg/runner/prompt_test.go b/pkg/runner/prompt_test.go index 8cb107b1..c497c023 100644 --- a/pkg/runner/prompt_test.go +++ b/pkg/runner/prompt_test.go @@ -78,6 +78,8 @@ func TestBuildSystemPromptScannerAgentUsesCyberHarnessIdentity(t *testing.T) { for _, want := range []string{ "gogo analysis agent inside AIScan, a Cyber Harness", "Execute the requested scanner command using the bash tool", + "selected scanner's documented output flags", + "Scanner flags are command-specific", "## Authorization Context", "## Scanner Agent Constraints", } { @@ -85,6 +87,14 @@ func TestBuildSystemPromptScannerAgentUsesCyberHarnessIdentity(t *testing.T) { t.Fatalf("scanner prompt missing %q:\n%s", want, prompt) } } + for _, unwanted := range []string{ + "Run scanners with -j flag to get JSON", + "re-run the scanner with `-j` flag to get JSON output", + } { + if strings.Contains(prompt, unwanted) { + t.Fatalf("scanner prompt contains ambiguous output guidance %q:\n%s", unwanted, prompt) + } + } } func TestSystemPromptFuncAdaptsToTools(t *testing.T) { diff --git a/skills/aiscan/SKILL.md b/skills/aiscan/SKILL.md index 44251de8..c8887f32 100644 --- a/skills/aiscan/SKILL.md +++ b/skills/aiscan/SKILL.md @@ -68,7 +68,7 @@ Available only when they appear in the runtime pseudo-command list: - Inline output: consume directly when the scan returns quickly. - Session id: use `tmux capture-pane -t ` to read. See tmux reference. -- Use `-j` for machine-readable JSON Lines output. Do not assume a result file exists unless you passed an output flag. +- Output flags are scanner-specific; use the loaded scanner playbook rather than transferring a flag from another command. In particular, direct `gogo` uses a value-bearing `-j ` as previous-results input and `-o jl` (or `-f -O jl`) for JSON Lines, while the `scan` wrapper uses valueless `-j` for JSON Lines output. ## Report Generation diff --git a/skills/aiscan/okf/easm/gogo.md b/skills/aiscan/okf/easm/gogo.md index 7a0821dc..4bb74a45 100644 --- a/skills/aiscan/okf/easm/gogo.md +++ b/skills/aiscan/okf/easm/gogo.md @@ -32,7 +32,11 @@ Notes: - `-i` accepts IP, CIDR, or comma-separated IPs. **NOT** `ip:port` — bare `10.0.0.1:8080` will fail with "Parse IP Failed". Use `-i 10.0.0.1 -p 8080` instead. - `-l` reads a target file (one IP/CIDR per line). -- `-p` is gogo ports: presets `top1` / `top2` / `top3` (default `top1`, widening coverage), `all` (every preset port), `-` for all 65535, ranges like `10000-10100`, or explicit `80,443,8080`. An unknown name such as `top100` / `top1000` is treated as a literal port and fails with `unknown port` — run `gogo -P port` to list every preset. +- `-p` is gogo ports: in the current resource, presets include `top1` / `top2` / `top3` (default `top1`, widening coverage), `all` (every preset port), and `-` for all 65535; resource-defined tags/aliases, ranges like `10000-10100`, and explicit `80,443,8080` are also accepted. A name such as `common` is valid only when the current resource defines that tag/alias. Do not infer names such as `top100` / `top1000` / `top2k` / `top12k` / `full` from another release: a name absent from the current resource is passed through as a literal port/service name, not expanded as top-N; it can therefore produce `total ports: 1` and no useful results. +- If the resource version is uncertain, run `gogo -P port` before choosing a preset; do not substitute an old QuickReference or remembered preset names for the runtime list. +- Direct gogo output/input flags are distinct: `-o ` is the console format, `-f ` is the output filename, `-O ` is the file format, value-bearing `-j ` reads a previous-results JSON input, and `-t/--thread ` sets threads. Use `-o jl` for console JSON Lines or `-f -O jl` for a JSON Lines file; `-j 16` is a file named `16`, not a thread count; `-f json` names a file `json`; and a path is not an `-o` format. Do not use valueless `-j` as direct gogo output syntax. +- The `total ports: 1` log is the length of the normalized port plan. It does not mean that a complete port scan ran. +- A number reported after preset expansion (for example, 253 ports) is an observed plan size, not another `-p` preset name. - Fingerprints and vuln hints are evidence leads; user intent decides whether to summarize, analyze, verify, compare, or plan follow-up work. ## Related concepts diff --git a/skills/aiscan/okf/easm/scan.md b/skills/aiscan/okf/easm/scan.md index 7c68e251..16c666c0 100644 --- a/skills/aiscan/okf/easm/scan.md +++ b/skills/aiscan/okf/easm/scan.md @@ -41,6 +41,8 @@ scan -i 10.0.0.1 --mode full --deep scan -i 10.0.0.1 -j ``` +`scan -j` enables scan-level JSON Lines output. It is not the same flag as direct `gogo -j`, which takes a previous-results input file. Likewise, `--mode full` is a scan profile, not a direct `gogo -p full` preset. + **CRITICAL: `-i` vs `-l`**: - `-i` is for one inline target per flag: IP, CIDR, IP:port, URL, or domain. Repeat `-i` for multiple inline targets. - `-l` is for target list files (one target per line). **Always use `-l` when scanning from a file.** diff --git a/tools/gogo/gogo.go b/tools/gogo/gogo.go index a877a80c..743c4565 100644 --- a/tools/gogo/gogo.go +++ b/tools/gogo/gogo.go @@ -53,15 +53,25 @@ func (c *Command) Usage() string { func (c *Command) QuickReference() string { return `### gogo — host, port, service, and banner discovery -i Target (IP, CIDR, or comma-separated). NOT ip:port — use -i IP -p PORT. - -p Presets: top1, top2, top100, top1000, all, - (65535), or 80,443,8080 + -p Runtime port preset/tag/alias, range, or explicit ports (currently observed: top1, top2, top3, all, -; use -P port to list presets) -l Target file (one IP/CIDR per line) - -o jl JSON Lines output (do NOT use -j for JSON output; -j is a JSON input file) + -t, --thread Concurrent worker count + -o Command-line output format (JSON Lines: jl) + -f Output filename + -O File output format (JSON Lines: jl) + -j Previous-results JSON input file (value required; not output) + -P port Print the current runtime port presets + NOTE: Do not infer top100/top1000/top2k/top12k/full as port presets from another release; use -P port for the current runtime list. + NOTE: "total ports: 1" means the normalized plan has one port; it does not mean a complete port scan. + See aiscan://skills/aiscan/okf/easm/gogo.md for the full command contract. -e Enable exploit/neutron scan -v Enable active fingerprint scan Examples: - gogo -i 10.0.0.1 -p top100 + gogo -i 10.0.0.1 -p top2 gogo -i 10.0.0.0/24 -p 80,443,8080 - gogo -l targets.txt -p top2 -ev` + gogo -l targets.txt -p top2 -ev + gogo -i 10.0.0.1 -p top2 -o jl + gogo -i 10.0.0.1 -p top2 -f results.jsonl -O jl` } func (c *Command) Run(ctx context.Context, execution *commands.Execution) (_ any, err error) { @@ -124,8 +134,10 @@ func (c *Command) injectProxyURL(args []string, proxy string) []string { } // normalizeArgs adapts common agent-generated gogo arguments before handing -// them to the upstream parser. gogo's -j/--json is an input file, while agents -// often use it as a boolean JSON-output flag; treat valueless -j as -o jl. +// them to the upstream parser. gogo's -j/--json is an input file, while older +// agents sometimes used it as a boolean JSON-output flag; treat valueless -j +// as -o jl only as a compatibility fallback. The canonical prompt contract +// tells agents to use gogo's native flags explicitly. func (c *Command) normalizeArgs(args []string) []string { out := make([]string, 0, len(args)+2) for i := 0; i < len(args); i++ { diff --git a/tools/gogo/gogo_test.go b/tools/gogo/gogo_test.go index 04e7cef6..929fb226 100644 --- a/tools/gogo/gogo_test.go +++ b/tools/gogo/gogo_test.go @@ -50,6 +50,27 @@ func TestExecuteDebugActivatesTelemetryLogger(t *testing.T) { } } +func TestQuickReferenceUsesCurrentFlagAndPresetContract(t *testing.T) { + quick := New(nil).QuickReference() + for _, want := range []string{ + "-t, --thread ", + "-o ", + "-f ", + "-O ", + "-j ", + "-P port", + "Runtime port preset/tag/alias, range, or explicit ports (currently observed: top1, top2, top3, all, -", + "Do not infer top100/top1000/top2k/top12k/full as port presets from another release", + } { + if !strings.Contains(quick, want) { + t.Fatalf("QuickReference missing %q: %s", want, quick) + } + } + if strings.Contains(quick, "Presets: top1, top2, top100") { + t.Fatalf("QuickReference still advertises obsolete presets: %s", quick) + } +} + func TestNormalizeArgsKeepsOutputFormatsAndResolvesFiles(t *testing.T) { dir := t.TempDir() cmd := New(nil) diff --git a/tools/scan/command.go b/tools/scan/command.go index 3582744b..35f7981b 100644 --- a/tools/scan/command.go +++ b/tools/scan/command.go @@ -34,9 +34,9 @@ type flags struct { Deep bool `long:"deep" description:"Run deep AI testing for discovered websites and fingerprinted assets"` Trace bool `long:"trace" description:"Show internal scanner source and pipeline trace"` Debug bool `long:"debug" description:"Enable trace and underlying scanner debug logs"` - JSON bool `short:"j" long:"json" description:"Output raw gogo and spray results as JSON Lines"` + JSON bool `short:"j" long:"json" description:"Output raw gogo and spray results as JSON Lines (direct gogo uses -o jl)"` NoColor bool `long:"no-color" description:"Disable ANSI colors in terminal output"` - Ports string `long:"ports" description:"Ports for gogo scanning; defaults to all in quick and - in full"` + Ports string `long:"ports" description:"Runtime gogo port preset/tag/alias, range, or explicit ports; defaults to all in quick and - in full"` Threads int // derived from Thread; not a CLI flag Timeout int `long:"timeout" description:"Per-probe timeout in seconds" default:"5"` SprayThreads int // derived from Thread; not a CLI flag