CLI 앱
Noir가 CLI 애플리케이션의 커맨드라인 공격 표면(서브커맨드, 플래그, 위치 인자, 사용되는 환경 변수)을 21개 언어에 걸쳐 어떻게 매핑하는지 설명합니다.
Noir는 CLI 애플리케이션의 커맨드라인 인터페이스도 엔드포인트로 추출합니다. CLI의 인자 파서도 공격 표면입니다. 외부에서 들어온 플래그, 위치 인자, 환경 변수가 셸, SQL 쿼리, 파일 경로, 네트워크 호출까지 닿을 수 있습니다.
Noir는 각 (서브)커맨드를 엔드포인트 하나로 보고, 그 커맨드가 받는 입력을 기록합니다.
엔드포인트 모델
CLI 진입점은 method = "CLI", protocol = "cli"를 가진 엔드포인트입니다. URL은 커맨드를 가리킵니다.
| URL 형태 | 의미 |
|---|---|
cli://<binary> |
루트 커맨드(서브커맨드 없이 실행되는 프로그램) |
cli://<binary>/<subcommand> |
서브커맨드(git commit, tool serve 등) |
바이너리 이름은 프로젝트 매니페스트가 있으면 거기서 가져오며(go.mod, Cargo.toml, package.json의 bin/name, *.csproj, argparse(prog=...) 등), 없으면 소스 파일이나 디렉터리 이름을 씁니다.
입력은 파라미터로 기록되고 param_type으로 구분합니다.
| param_type | 의미 | 예시 |
|---|---|---|
flag |
이름이 있는 옵션 / 스위치 | --port, -v, --config |
argument |
위치 인자 | arg1, source, files |
env |
커맨드가 읽는 환경 변수 | API_TOKEN, DATABASE_URL |
plain 출력에서는 flags / arguments / env 항목으로 나옵니다.
CLI cli://mytool/serve
○ flags: port, verbose
○ arguments: config
○ env: API_TOKEN
지원 언어 및 라이브러리
Noir는 각 언어의 내장 argv / flag / 환경 변수 메커니즘과 주요 CLI 라이브러리를 탐지합니다. 환경 변수를 직접 읽는 코드는 조건부로 잡습니다. 실제 CLI 진입점일 때만 결과에 나오므로, 환경 변수에서 설정을 읽는 웹 서버가 엉뚱한 cli:// 엔드포인트를 만들지 않습니다.
| 언어 | 내장 | 라이브러리 |
|---|---|---|
| Go | os.Args, flag, os.Getenv/LookupEnv |
cobra (+ viper env), urfave/cli, pflag, go-arg, go-flags, kong, kingpin, mitchellh/cli |
| Python | sys.argv, argparse, getopt, os.environ/getenv |
click, typer, fire, docopt, Abseil (absl-py), Cleo |
| Rust | std::env::args/var |
clap (derive), structopt, argh, getopts |
| JavaScript / TypeScript | process.argv, util.parseArgs, Deno.args, Bun.argv, process.env |
commander, yargs, cac, sade, meow, minimist, arg, command-line-args, getopts, citty |
| Ruby | ARGV, OptionParser, ENV |
Thor, GLI, Slop, TTY::Option, commander, Optimist, Clamp, dry-cli |
| C# | Main(string[]), GetCommandLineArgs, GetEnvironmentVariable |
System.CommandLine, CommandLineParser, CliFx, Spectre.Console.Cli, McMaster.Extensions.CommandLineUtils, Cocona |
| Java | main(String[]), System.getenv |
picocli, args4j, JCommander, commons-cli, airline, JOpt Simple |
| Kotlin | main(Array<String>), System.getenv |
clikt (+ envvar), kotlinx-cli, picocli |
| PHP | $argv, getopt(), $_ENV, getenv() |
Symfony Console, Laravel Artisan ($signature), Robo, WP-CLI |
| C++ | main(argc, argv), getenv |
CLI11, getopt/getopt_long, cxxopts, boost::program_options, gflags, Abseil Flags, p-ranav/argparse |
| Swift | CommandLine.arguments, ProcessInfo.environment |
swift-argument-parser, SwiftCLI |
| Crystal | ARGV, OptionParser, ENV |
clim, admiral, commander |
| Elixir | System.argv, OptionParser, System.get_env |
Optimus |
| Dart | main(List<String>), Platform.environment |
args (ArgParser / CommandRunner), dcli |
| Haskell | getArgs, getEnv/lookupEnv |
optparse-applicative, cmdargs, System.Console.GetOpt, turtle |
| Scala | args, sys.env |
scopt, decline, mainargs, Scallop, twitter-util |
| Zig | std.process.args, getEnvVarOwned |
zig-clap, zig-cli, zig-args, yazap |
| Clojure | *command-line-args*, System/getenv |
clojure.tools.cli, cli-matic, babashka.cli, environ |
| Lua | arg, os.getenv |
argparse, lua_cliargs |
| Perl | @ARGV, Getopt::Long/Getopt::Std, %ENV |
App::Cmd, Getopt::Long::Descriptive, MooX::Options |
| Groovy | args, System.getenv |
CliBuilder, picocli, commons-cli, JCommander |
출력 동작
CLI 엔드포인트는 애플리케이션 표면의 일부이므로 구조화된 인벤토리(JSON, JSONL, YAML, TOML, SARIF, Markdown table, mermaid, HTML)에 남습니다. 반면 HTTP 형태의 출력과 전송(cURL, HTTPie, PowerShell, OpenAPI 2.0 / 3.0, Postman, 능동 프로브 / 프록시 전송)에서는 빠집니다. 명령 실행은 보낼 수 있는 HTTP 요청이 아니기 때문입니다. HTTP 파라미터 취약점을 분류하는 HUNT 태거도 CLI 입력은 건너뜁니다.
참고 및 한계
- 탐지는 라인 스캔 기반(전체 파싱 아님)이므로, 깊게 중첩되었거나 메타프로그래밍이 많은 커맨드 트리는 일부만 해석될 수 있습니다. 여러 파일에 흩어진 플래그, 인자, 환경 변수 읽기는 URL 기준으로 하나의 커맨드로 병합됩니다.
- 일부 빌더 스타일 API는 CLI 신호로 인식되지만 개별 인자까지 완전히 파싱되지는 않습니다(예: Rust의 clap 빌더 API). derive / 어노테이션 스타일은 끝까지 파싱합니다.
- 서브커맨드는 단일 레벨로 평탄화됩니다(
cli://tool/serve). 더 깊은 중첩은 아직 모델링되지 않습니다.