feat: allow multiple added passwords

Fixes #584
This commit is contained in:
ZacharyZcR
2026-06-01 02:06:15 +08:00
parent bfc0e0fb52
commit ea17b5b1bc
9 changed files with 142 additions and 6 deletions
+2
View File
@@ -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)
+2
View File
@@ -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)
+1 -1
View File
@@ -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 |
+17 -2
View File
@@ -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
+19
View File
@@ -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)
}
}
+60 -1
View File
@@ -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参数
+39
View File
@@ -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)
}
})
}
}
+1 -1
View File
@@ -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:
+1 -1
View File
@@ -43,7 +43,7 @@ flag_password:
flag_add_users:
other: "额外用户名"
flag_add_passwords:
other: "额外密码"
other: "额外密码,支持逗号或空格分隔多个值"
flag_users_file:
other: "用户名字典文件"
flag_passwords_file: