From ea17b5b1bcb7974d81645cb7e11daee925c62407 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Mon, 1 Jun 2026 02:06:15 +0800 Subject: [PATCH] feat: allow multiple added passwords Fixes #584 --- README.md | 2 ++ README_EN.md | 2 ++ SKILL.md | 2 +- common/config_builder.go | 19 +++++++++-- common/config_builder_test.go | 19 +++++++++++ common/flag.go | 61 ++++++++++++++++++++++++++++++++++- common/flag_args_test.go | 39 ++++++++++++++++++++++ common/i18n/locales/en.yaml | 2 +- common/i18n/locales/zh.yaml | 2 +- 9 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 common/config_builder_test.go create mode 100644 common/flag_args_test.go diff --git a/README.md b/README.md index 5d7d011..eb58ca2 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,8 @@ yay -S fscan-git `fscan.exe -h 192.168.x.x -m ssh -user root -pwd password` ![](image/3.png) +`fscan.exe -h 192.168.x.x -m ssh -user root -pwda pass1 pass2 pass3` (追加多个密码) + `fscan.exe -h 192.168.x.x -p80 -proxy http://127.0.0.1:8080` ![](image/2020-12-12-13-34-44.png) diff --git a/README_EN.md b/README_EN.md index f931296..bcca9e1 100644 --- a/README_EN.md +++ b/README_EN.md @@ -211,6 +211,8 @@ yay -S fscan-git `fscan.exe -h 192.168.x.x -m ssh -user root -pwd password` ![](image/3.png) +`fscan.exe -h 192.168.x.x -m ssh -user root -pwda pass1 pass2 pass3` (add multiple passwords) + `fscan.exe -h 192.168.x.x -p80 -proxy http://127.0.0.1:8080` ![](image/2020-12-12-13-34-44.png) diff --git a/SKILL.md b/SKILL.md index b0b51d2..2a3065f 100644 --- a/SKILL.md +++ b/SKILL.md @@ -67,7 +67,7 @@ fscan -h 192.168.1.0/24 -silent | jq 'select(.type=="VULN")' | `-user` | 用户名 | | `-pwd` | 密码 | | `-usera` | 追加用户名 | -| `-pwda` | 追加密码 | +| `-pwda` | 追加密码,支持逗号或空格分隔多个值 | | `-userf` | 用户名字典文件 | | `-pwdf` | 密码字典文件 | | `-domain` | 域名(SMB/WMI) | diff --git a/common/config_builder.go b/common/config_builder.go index a08c9d2..e14057a 100644 --- a/common/config_builder.go +++ b/common/config_builder.go @@ -124,7 +124,7 @@ func parsePasswords(fv *FlagVars) []string { // 命令行密码 if fv.Password != "" { - passwords = append(passwords, strings.Split(fv.Password, ",")...) + passwords = append(passwords, splitCredentialValues(fv.Password)...) } // 从文件读取 @@ -138,12 +138,27 @@ func parsePasswords(fv *FlagVars) []string { // 额外密码 if fv.AddPasswords != "" { - passwords = append(passwords, strings.Split(fv.AddPasswords, ",")...) + passwords = append(passwords, splitCredentialValues(fv.AddPasswords)...) } return removeDuplicate(passwords) } +func splitCredentialValues(input string) []string { + fields := strings.FieldsFunc(input, func(r rune) bool { + return r == ',' || r == ' ' || r == '\t' || r == '\n' || r == '\r' + }) + + values := make([]string, 0, len(fields)) + for _, field := range fields { + field = strings.TrimSpace(field) + if field != "" { + values = append(values, field) + } + } + return values +} + func parseUserPassPairs(fv *FlagVars) ([]config.CredentialPair, error) { var pairs []config.CredentialPair diff --git a/common/config_builder_test.go b/common/config_builder_test.go new file mode 100644 index 0000000..87a8523 --- /dev/null +++ b/common/config_builder_test.go @@ -0,0 +1,19 @@ +package common + +import ( + "reflect" + "testing" +) + +func TestParsePasswordsSplitsCommaAndWhitespace(t *testing.T) { + fv := &FlagVars{ + Password: "root,admin", + AddPasswords: "pass1 pass2,pass3\tpass4", + } + + got := parsePasswords(fv) + want := []string{"root", "admin", "pass1", "pass2", "pass3", "pass4"} + if !reflect.DeepEqual(got, want) { + t.Fatalf("parsePasswords() = %#v, want %#v", got, want) + } +} diff --git a/common/flag.go b/common/flag.go index 70192a4..2844ba9 100644 --- a/common/flag.go +++ b/common/flag.go @@ -227,7 +227,9 @@ func Flag(Info *HostInfo) error { // parseCommandLineArgs 解析命令行参数 func parseCommandLineArgs() error { - flag.Parse() + if err := flag.CommandLine.Parse(normalizeMultiValueFlagArgs(os.Args[1:], "-pwda")); err != nil { + return err + } // 显示Banner Banner() @@ -236,6 +238,63 @@ func parseCommandLineArgs() error { return checkParameterConflicts() } +func normalizeMultiValueFlagArgs(args []string, names ...string) []string { + multiValueFlags := make(map[string]struct{}, len(names)) + for _, name := range names { + multiValueFlags[name] = struct{}{} + } + + normalized := make([]string, 0, len(args)) + for i := 0; i < len(args); i++ { + arg := args[i] + name, value, ok := splitMultiValueFlag(arg, multiValueFlags) + if !ok { + normalized = append(normalized, arg) + continue + } + + values := []string{} + if value != "" { + values = append(values, value) + } + + j := i + 1 + for ; j < len(args); j++ { + if strings.HasPrefix(args[j], "-") { + break + } + values = append(values, args[j]) + } + i = j - 1 + + if strings.Contains(arg, "=") { + normalized = append(normalized, name+"="+strings.Join(values, ",")) + } else { + normalized = append(normalized, name) + if len(values) > 0 { + normalized = append(normalized, strings.Join(values, ",")) + } + } + } + + return normalized +} + +func splitMultiValueFlag(arg string, names map[string]struct{}) (string, string, bool) { + if _, ok := names[arg]; ok { + return arg, "", true + } + + for name := range names { + prefix := name + "=" + if strings.HasPrefix(arg, prefix) { + return name, strings.TrimPrefix(arg, prefix), true + } + } + + return "", "", false +} + // preProcessLanguage 预处理语言参数,在定义flag之前设置语言 func preProcessLanguage() { // 遍历命令行参数查找-lang参数 diff --git a/common/flag_args_test.go b/common/flag_args_test.go new file mode 100644 index 0000000..a19c481 --- /dev/null +++ b/common/flag_args_test.go @@ -0,0 +1,39 @@ +package common + +import ( + "reflect" + "testing" +) + +func TestNormalizeMultiValueFlagArgs(t *testing.T) { + tests := []struct { + name string + args []string + want []string + }{ + { + name: "space separated pwda values", + args: []string{"-h", "192.168.1.1", "-pwda", "pass1", "pass2", "pass3", "-m", "ssh"}, + want: []string{"-h", "192.168.1.1", "-pwda", "pass1,pass2,pass3", "-m", "ssh"}, + }, + { + name: "equals form with extra values", + args: []string{"-pwda=pass1", "pass2", "-h", "192.168.1.1"}, + want: []string{"-pwda=pass1,pass2", "-h", "192.168.1.1"}, + }, + { + name: "unrelated args unchanged", + args: []string{"-h", "192.168.1.1", "-m", "ssh"}, + want: []string{"-h", "192.168.1.1", "-m", "ssh"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := normalizeMultiValueFlagArgs(tt.args, "-pwda") + if !reflect.DeepEqual(got, tt.want) { + t.Fatalf("normalizeMultiValueFlagArgs() = %#v, want %#v", got, tt.want) + } + }) + } +} diff --git a/common/i18n/locales/en.yaml b/common/i18n/locales/en.yaml index e9c7e88..3b480f4 100644 --- a/common/i18n/locales/en.yaml +++ b/common/i18n/locales/en.yaml @@ -43,7 +43,7 @@ flag_password: flag_add_users: other: "Additional usernames" flag_add_passwords: - other: "Additional passwords" + other: "Additional passwords, separated by commas or spaces" flag_users_file: other: "Username dictionary file" flag_passwords_file: diff --git a/common/i18n/locales/zh.yaml b/common/i18n/locales/zh.yaml index 342f6b0..0659d02 100644 --- a/common/i18n/locales/zh.yaml +++ b/common/i18n/locales/zh.yaml @@ -43,7 +43,7 @@ flag_password: flag_add_users: other: "额外用户名" flag_add_passwords: - other: "额外密码" + other: "额外密码,支持逗号或空格分隔多个值" flag_users_file: other: "用户名字典文件" flag_passwords_file: