@@ -4,12 +4,26 @@ import (
44 "flag"
55 "fmt"
66 "github.com/sandflysecurity/sandfly-entropyscan/pkg/ssh"
7+ "golang.org/x/term"
78 "log"
89 "os"
910 "sync"
1011 "time"
1112)
1213
14+ type sshConfig struct {
15+ Host string
16+ User string
17+ Passwd string
18+ KeyFile string
19+ KeyFilePassphrase string
20+ Version string
21+ Port int
22+ Agent bool
23+ Prompt bool
24+ Timeout time.Duration
25+ }
26+
1327type outputConfig struct {
1428 delimChar string
1529 csvOutput bool
@@ -18,17 +32,6 @@ type outputConfig struct {
1832 outputFile string
1933}
2034
21- type sshConfig struct {
22- Host string
23- User string
24- Passwd string
25- KeyFile string
26- Version string
27- Port int
28- Agent bool
29- Timeout time.Duration
30- }
31-
3235type inputConfig struct {
3336 filePath string
3437 dirPath string
@@ -60,6 +63,31 @@ type config struct {
6063
6164var cfgOnce sync.Once
6265
66+ func (scfg * sshConfig ) prompt () {
67+ ploop:
68+ for {
69+ switch {
70+ case scfg .Host == "" :
71+ _ , _ = fmt .Printf ("Host: " )
72+ _ , _ = fmt .Scanln (& scfg .Host )
73+ case scfg .User == "" :
74+ _ , _ = fmt .Printf ("[%s] User: " , scfg .Host )
75+ _ , _ = fmt .Scanln (& scfg .User )
76+ case scfg .KeyFile != "" && scfg .KeyFilePassphrase == "" :
77+ _ , _ = fmt .Printf ("[%s] Pass: " , scfg .KeyFile )
78+ pb , _ := term .ReadPassword (int (os .Stdin .Fd ()))
79+ scfg .KeyFilePassphrase = string (pb )
80+ case scfg .KeyFile == "" && scfg .Passwd == "" :
81+ _ , _ = fmt .Printf ("[%s] Pass: " , scfg .Host )
82+ pb , _ := term .ReadPassword (int (os .Stdin .Fd ()))
83+ scfg .Passwd = string (pb )
84+ default :
85+ break ploop
86+ }
87+ }
88+ print ("\n " )
89+ }
90+
6391func (cfg * config ) parseFlags () {
6492 sumMD5 , sumSHA1 , sumSHA256 , sumSHA512 := true , true , true , true
6593
@@ -70,37 +98,74 @@ func (cfg *config) parseFlags() {
7098 & sumSHA512 : HashTypeSHA512 ,
7199 }
72100
101+ // # Strings
102+
73103 flag .StringVar (& cfg .inCfg .filePath , "file" , "" , "full path to a single file to analyze" )
74104 flag .StringVar (& cfg .inCfg .dirPath , "dir" , "" , "directory name to analyze" )
75105 flag .StringVar (& cfg .outCfg .delimChar , "delim" , constDelimeterDefault , "delimeter for CSV output" )
76- flag .StringVar (& cfg .outCfg .outputFile , "output" , "" , "output file to write results to (default stdout) (only json and csv formats supported)" )
77-
78- flag .Float64Var (& cfg .entropyMaxVal , "entropy" , 0 , "show any file with entropy greater than or equal to this value (0.0 - 8.0 max 8.0, default is 0)" )
79-
80- flag .BoolVar (& cfg .elfOnly , "elf" , false , "only check ELF executables" )
81- flag .BoolVar (& cfg .procOnly , "proc" , false , "check running processes" )
82- flag .BoolVar (& cfg .outCfg .csvOutput , "csv" , false , "output results in CSV format (filename, path, entropy, elf_file [true|false], MD5, SHA1, SHA256, SHA512)" )
83- flag .BoolVar (& cfg .outCfg .jsonOutput , "json" , false , "output results in JSON format" )
84- flag .BoolVar (& cfg .outCfg .printInterimResults , "print" , false , "print interim results to stdout even if output file is specified" )
85- flag .BoolVar (& cfg .version , "version" , false , "show version and exit" )
86-
87- flag .BoolVar (& sumMD5 , "md5" , true , "calculate and show MD5 checksum of file(s)" )
88- flag .BoolVar (& sumSHA1 , "sha1" , true , "calculate and show SHA1 checksum of file(s)" )
89- flag .BoolVar (& sumSHA256 , "sha256" , true , "calculate and show SHA256 checksum of file(s)" )
90- flag .BoolVar (& sumSHA512 , "sha512" , true , "calculate and show SHA512 checksum of file(s)" )
106+ flag .StringVar (
107+ & cfg .outCfg .outputFile , "output" , "" ,
108+ "output file to write results to (default stdout) (only json and csv formats supported)" ,
109+ )
110+
111+ // # Floats
112+
113+ flag .Float64Var (
114+ & cfg .entropyMaxVal , "entropy" , 5.0 ,
115+ "show any file with entropy greater than or equal to this value (0.0 - 8.0, max 8.0) (def: 5.0)" ,
116+ )
117+
118+ // # Bools
119+
120+ flag .BoolVar (& cfg .elfOnly , "elf" , true , "only check ELF executables (def: true)" )
121+ flag .BoolVar (& cfg .procOnly , "proc" , false , "check running processes (def: false)" )
122+ flag .BoolVar (
123+ & cfg .outCfg .csvOutput , "csv" , false ,
124+ "output results in CSV format (def: false)\n " +
125+ "(filename, path, entropy, elf_file [true|false], MD5, SHA1, SHA256, SHA512)" ,
126+ )
127+ flag .BoolVar (& cfg .outCfg .jsonOutput , "json" , false , "output results in JSON format (def: false)" )
128+ flag .BoolVar (
129+ & cfg .outCfg .printInterimResults , "print" , false ,
130+ "print interim results to stdout even if output file is specified (def: false)" ,
131+ )
132+ flag .BoolVar (& cfg .version , "version" , false , "show version and exit (def: false)" )
133+ flag .BoolVar (& sumMD5 , "md5" , true , "calculate and show MD5 checksum of file(s) (def: true)" )
134+ flag .BoolVar (& sumSHA1 , "sha1" , true , "calculate and show SHA1 checksum of file(s) (def: true)" )
135+ flag .BoolVar (
136+ & sumSHA256 , "sha256" , true ,
137+ "calculate and show SHA256 checksum of file(s) (def: true)" ,
138+ )
139+ flag .BoolVar (
140+ & sumSHA512 , "sha512" , true ,
141+ "calculate and show SHA512 checksum of file(s) (def: true)" ,
142+ )
143+ flag .BoolVar (& cfg .ignoreSelf , "ignore-self" , true , "ignore self process (def: true)" )
144+ flag .BoolVar (
145+ & cfg .goFast , "fast" , false ,
146+ "use worker pool for concurrent file processing (experimental)" ,
147+ )
148+
149+ // # SSH
91150
92151 flag .StringVar (& cfg .inCfg .sshConfig .Host , "ssh-host" , "" , "SSH host to connect to" )
93152 flag .StringVar (& cfg .inCfg .sshConfig .User , "ssh-user" , "" , "SSH user name" )
94153 flag .StringVar (& cfg .inCfg .sshConfig .Passwd , "ssh-pass" , "" , "SSH password" )
95154 flag .StringVar (& cfg .inCfg .sshConfig .KeyFile , "ssh-key" , "" , "SSH private key file" )
155+ flag .StringVar (
156+ & cfg .inCfg .sshConfig .KeyFilePassphrase ,
157+ "ssh-key-pass" , "" , "SSH private key passphrase" ,
158+ )
96159 flag .DurationVar (& cfg .inCfg .sshConfig .Timeout , "ssh-timeout" , 30 * time .Second , "SSH connection timeout" )
97- flag .StringVar (& cfg .inCfg .sshConfig .Version , "ssh-version" , "SSH-2.0-EntropyScanner" , "SSH version string" )
160+ flag .StringVar (
161+ & cfg .inCfg .sshConfig .Version , "ssh-version" , "SSH-2.0-SFScan" , "SSH version string" ,
162+ )
98163 flag .IntVar (& cfg .inCfg .sshConfig .Port , "ssh-port" , 22 , "SSH port" )
99164 flag .BoolVar (& cfg .inCfg .sshConfig .Agent , "ssh-agent" , false , "use SSH agent" )
100-
101- flag . BoolVar ( & cfg .goFast , "fast " , false , "use worker pool for concurrent file processing (experimental)" )
102-
103- flag . BoolVar ( & cfg . ignoreSelf , "ignore-self" , true , "ignore self process" )
165+ flag . BoolVar (
166+ & cfg .inCfg . sshConfig . Prompt , "ssh-prompt " , false ,
167+ "prompt for credentials (def: false)" ,
168+ )
104169
105170 flag .Parse ()
106171
@@ -134,6 +199,10 @@ func newConfigFromFlags() *config {
134199 log .Fatal ("only one of -file, -dir, or -ssh-host can be specified" )
135200 }
136201
202+ if cfg .inCfg .sshConfig .Prompt {
203+ cfg .inCfg .sshConfig .prompt ()
204+ }
205+
137206 if cfg .inCfg .sshConfig .Host != "" && cfg .inCfg .sshConfig .User == "" {
138207 log .Fatal ("ssh-host requires ssh-user" )
139208 }
@@ -146,6 +215,7 @@ func newConfigFromFlags() *config {
146215 ! cfg .inCfg .sshConfig .Agent &&
147216 cfg .inCfg .sshConfig .KeyFile == "" &&
148217 cfg .inCfg .sshConfig .Passwd == "" {
218+
149219 log .Fatal ("ssh mode requires ssh-key, ssh-pass, or ssh-agent" )
150220 }
151221
0 commit comments