├── pkg ├── common │ ├── ipparser │ │ ├── ipprocess_test.go │ │ └── ipprocess.go │ ├── rangectl │ │ ├── range_test.go │ │ └── range.go │ ├── parser_test.go │ ├── service_test.go │ ├── vulconstant.go │ ├── log.go │ ├── Progress.go │ ├── parser.go │ └── engine.TXT ├── Plugins │ ├── base.go │ ├── webtitle.go │ ├── memcached.go │ ├── postgres.go │ ├── mysql.go │ ├── mssql.go │ ├── findnet.go │ ├── mongodb.go │ ├── smb.go │ ├── ftp.go │ ├── ssh.go │ ├── CVE-2020-0796.go │ ├── redis.go │ ├── ms17017.go │ └── NetBIOS.go ├── Ginfo │ ├── Gnbtscan │ │ ├── Gnbtscan_test.go │ │ └── GNetBIOS.go │ └── Ghttp │ │ ├── encodings.go │ │ ├── title.go │ │ └── Ghttp.go ├── log │ └── zap.go ├── options │ └── options.go ├── output │ └── output.go ├── conversion │ └── conversion.go └── report │ └── report.go ├── .gitignore ├── global └── common.go ├── infoscan.assets ├── image-20211105132114094.png ├── image-20211105132301924.png ├── image-20211105134827966.png ├── image-20211105134954709.png ├── image-20211105140102652.png ├── image-20211105140117462.png └── image-20211105140236732.png ├── utils ├── IsContain.go └── Redurl.go ├── scanvul ├── utils │ └── IsContain.go └── cmd │ ├── run.txt │ ├── ScanVul.TXT │ └── ScanVul.go ├── model ├── finger.go └── result.go ├── port ├── runner │ ├── worker.go │ ├── scanner.go │ └── engine.go ├── build.sh ├── options │ └── options.go └── buildAll.sh ├── finger ├── lib │ ├── iconhash │ │ └── iconhash.go │ ├── chinese │ │ └── chinese.go │ ├── slog │ │ └── slog.go │ ├── shttp │ │ └── shttp.go │ └── misc │ │ └── misc.go ├── urlparse │ └── urlparse.go ├── run.go └── gonmap │ └── type-httpfinger.go ├── cmd └── main.go ├── go.mod ├── run └── scan.go ├── README.md ├── imcp └── icmp.go └── go.sum /pkg/common/ipparser/ipprocess_test.go: -------------------------------------------------------------------------------- 1 | package ipparser 2 | -------------------------------------------------------------------------------- /pkg/common/rangectl/range_test.go: -------------------------------------------------------------------------------- 1 | package rangectl 2 | -------------------------------------------------------------------------------- / .gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | release 3 | .DS_Store 4 | ./cmd/demo/* 5 | *.txt 6 | -------------------------------------------------------------------------------- /global/common.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import "go.uber.org/zap" 4 | 5 | var Log *zap.Logger 6 | -------------------------------------------------------------------------------- /infoscan.assets/image-20211105132114094.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/safe6Sec/scaninfo/main/infoscan.assets/image-20211105132114094.png -------------------------------------------------------------------------------- /infoscan.assets/image-20211105132301924.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/safe6Sec/scaninfo/main/infoscan.assets/image-20211105132301924.png -------------------------------------------------------------------------------- /infoscan.assets/image-20211105134827966.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/safe6Sec/scaninfo/main/infoscan.assets/image-20211105134827966.png -------------------------------------------------------------------------------- /infoscan.assets/image-20211105134954709.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/safe6Sec/scaninfo/main/infoscan.assets/image-20211105134954709.png -------------------------------------------------------------------------------- /infoscan.assets/image-20211105140102652.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/safe6Sec/scaninfo/main/infoscan.assets/image-20211105140102652.png -------------------------------------------------------------------------------- /infoscan.assets/image-20211105140117462.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/safe6Sec/scaninfo/main/infoscan.assets/image-20211105140117462.png -------------------------------------------------------------------------------- /infoscan.assets/image-20211105140236732.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/safe6Sec/scaninfo/main/infoscan.assets/image-20211105140236732.png -------------------------------------------------------------------------------- /utils/IsContain.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func IsContain(items []string, item string) bool { 4 | for _, eachItem := range items { 5 | if eachItem == item { 6 | return true 7 | } 8 | } 9 | return false 10 | } 11 | -------------------------------------------------------------------------------- /scanvul/utils/IsContain.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func IsContain(items []string, item string) bool { 4 | for _, eachItem := range items { 5 | if eachItem == item { 6 | return true 7 | } 8 | } 9 | return false 10 | } 11 | -------------------------------------------------------------------------------- /model/finger.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type PackFingers struct { 4 | Fingerprint []Fingers 5 | } 6 | 7 | type Fingers struct { 8 | Cms string `json:"cms"` 9 | Method string `json:"method"` 10 | Location string `json:"location"` 11 | Keyword []string `json:"keyword"` 12 | } 13 | -------------------------------------------------------------------------------- /port/runner/worker.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | func (e *Engine) worker(res chan Addr, wg *sync.WaitGroup) { 8 | go func() { 9 | defer wg.Done() 10 | for addr := range res { 11 | e.Options.Limiter.Take() 12 | e.Scanner(addr.ip, addr.port) 13 | } 14 | 15 | }() 16 | } 17 | -------------------------------------------------------------------------------- /pkg/common/parser_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "testing" 4 | 5 | func TestConfigeFileParse(t *testing.T) { 6 | path := "D:\\gotest\\config.conf" 7 | 8 | ips, err := ConfigeFileParse(path) 9 | if err != nil { 10 | t.Log(err) 11 | } 12 | 13 | for _, line := range ips { 14 | t.Log(line) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pkg/Plugins/base.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | var PluginList = map[string]interface{}{ 4 | "ftp": FtpScan, 5 | "ssh": SshScan, 6 | "findnet": Findnet, 7 | "netbios": NetBIOS, 8 | "smb": SmbScan, 9 | "mssql": MssqlScan, 10 | "mysql": MysqlScan, 11 | "postgresql": PostgresScan, 12 | "redis": RedisScan, 13 | "memcached": MemcachedScan, 14 | "mongodb": MongodbScan, 15 | "1000001": MS17010, 16 | "1000002": SmbGhost, 17 | "1000003": WebTitle, 18 | } 19 | -------------------------------------------------------------------------------- /pkg/Ginfo/Gnbtscan/Gnbtscan_test.go: -------------------------------------------------------------------------------- 1 | package Gnbtscan 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | func TestNbtscan(t *testing.T) { 10 | ipList := make([]int, 255) 11 | wg := sync.WaitGroup{} 12 | wg.Add(255) 13 | for index := range ipList { 14 | ip := fmt.Sprintf("192.168.120.%d", index) 15 | go func() { 16 | result, err := Scan(ip) 17 | if err != nil { 18 | //t.Log(err) 19 | } else { 20 | t.Log(fmt.Sprintf("+%s -> %s", ip, result)) 21 | } 22 | wg.Done() 23 | }() 24 | } 25 | wg.Wait() 26 | } 27 | -------------------------------------------------------------------------------- /scanvul/cmd/run.txt: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/redtoolskobe/scaninfo/options" 5 | "github.com/redtoolskobe/mamba/server/utils" 6 | ) 7 | 8 | func Run(hosts []string, urls []string, name string, scantype string) { 9 | var Info options.HostInfo 10 | option := options.FscanOptions 11 | option.Urls = urls 12 | Info.Ports = options.DefaultPorts 13 | Info.Userdict = options.Userdict 14 | Info.Timeout = 2 15 | Info.Hosts = hosts 16 | Info.Scantype = scantype 17 | Info.TaskName = name 18 | Info.TaskID = utils.NewTaskID() 19 | return 20 | } 21 | -------------------------------------------------------------------------------- /port/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "build macos x64 TxPortMap..." 4 | 5 | CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o release/TxPortMap_macos_x64 cmd/TxPortMap/TxPortMap.go 6 | echo "build windows x64 TxPortMap..." 7 | CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o release/TxPortMap_windows_x64.exe cmd/TxPortMap/TxPortMap.go 8 | echo "build linux x64 TxPortMap..." 9 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o release/TxPortMap_linux_x64 cmd/TxPortMap/TxPortMap.go 10 | 11 | -------------------------------------------------------------------------------- /port/options/options.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import "go.uber.org/ratelimit" 4 | 5 | type Options struct { 6 | CmdIps []string 7 | // cmdExPath string 8 | CmdCofPath string 9 | CmdPorts []string 10 | CmdT1000 bool 11 | CmdRandom bool 12 | NumThreads int 13 | ExcPorts []string // 待排除端口 14 | ExcIps []string // 待排除Ip 15 | IpFile string 16 | Nocolor bool //彩色打印 17 | Json bool 18 | Tracelog string //请求日志 19 | Rstfile string //文件保存 20 | Tout float64 //timeout 21 | Nbtscan bool 22 | Limit int 23 | Limiter ratelimit.Limiter 24 | } 25 | -------------------------------------------------------------------------------- /pkg/common/service_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestComparePacketsMysql(t *testing.T) { 8 | banner := []byte(">\x00\x00\x00\x0a5.0.51a-3ubuntu5\x00\x0e\x00\x00\x00pf.Q.2Mn\x00,ª\x08\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00c'4pXG<56Oh?\x00\x10\x00\x00\x01ÿ\x13\x04Bad handshake") 9 | 10 | size := len(banner) 11 | var szBan string 12 | var szSvcName string 13 | 14 | num := ComparePackets(banner, size, &szBan, &szSvcName) 15 | 16 | if num == 0 { 17 | t.Error("unknown service") 18 | return 19 | } 20 | 21 | t.Log(szBan) 22 | t.Log(szSvcName) 23 | } 24 | -------------------------------------------------------------------------------- /utils/Redurl.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bufio" 5 | "log" 6 | "os" 7 | "strings" 8 | 9 | "github.com/gookit/color" 10 | ) 11 | 12 | func GetUrlList(filename string) (urls []string) { 13 | if filename == "" { 14 | return 15 | } 16 | file, err := os.Open(filename) 17 | if err != nil { 18 | log.Println("Local URLfile read error:", err) 19 | color.RGBStyleFromString("237,64,35").Println("[error] the input file is wrong!!!") 20 | os.Exit(1) 21 | } 22 | scanner := bufio.NewScanner(file) 23 | for scanner.Scan() { 24 | if strings.Contains(scanner.Text(), "http") { 25 | urls = append(urls, scanner.Text()) 26 | } else { 27 | urls = append(urls, "http://"+scanner.Text()) 28 | } 29 | } 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /pkg/log/zap.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "github.com/redtoolskobe/scaninfo/pkg/common" 8 | 9 | "github.com/redtoolskobe/scaninfo/global" 10 | "go.uber.org/zap" 11 | "go.uber.org/zap/zapcore" 12 | ) 13 | 14 | func Log() *zap.Logger { 15 | config := zapcore.EncoderConfig{ 16 | EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { 17 | enc.AppendString(t.Format("2006-01-02 15:04:05")) 18 | }} 19 | //cfg := zap.NewProductionConfig() 20 | file, _ := os.Create(common.Rstfile + ".txt") 21 | core := zapcore.NewCore( 22 | zapcore.NewJSONEncoder(config), 23 | zapcore.AddSync(file), 24 | zapcore.InfoLevel, 25 | ) 26 | return zap.New(core) 27 | } 28 | 29 | func InitLog() { 30 | global.Log = Log() 31 | } 32 | -------------------------------------------------------------------------------- /port/buildAll.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "buildAll TxPortMap..." 4 | os_archs="darwin:amd64 darwin:arm64 freebsd:386 freebsd:amd64 linux:386 linux:amd64 linux:arm linux:arm64 windows:386 windows:amd64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat" 5 | LDFLAGS="-s -w" 6 | for n in $os_archs 7 | do 8 | os=$(echo $n | cut -d : -f 1) 9 | arch=$(echo $n | cut -d : -f 2) 10 | gomips=$(echo $n | cut -d : -f 3) 11 | target_suffix="${os}_${arch}" 12 | echo "Build ${os}_${arch} ...." 13 | env CGO_ENABLED=0 GOOS="${os}" GOARCH="${arch}" GOMIPS="${gomips}" go build -trimpath -ldflags "${LDFLAGS}" -o ./release/TxPortMap_"${target_suffix}" ./cmd/TxPortMap/TxPortMap.go 14 | echo "Build ${os}_${arch} done" 15 | done 16 | 17 | mv ./release/TxPortMap_windows_386 ./release/TxPortMap_windows_386.exe 18 | mv ./release/TxPortMap_windows_amd64 ./release/TxPortMap_windows_amd64.exe 19 | -------------------------------------------------------------------------------- /finger/lib/iconhash/iconhash.go: -------------------------------------------------------------------------------- 1 | package iconhash 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | 10 | "github.com/twmb/murmur3" 11 | ) 12 | 13 | var isUint32 bool 14 | 15 | func standBase64(braw []byte) []byte { 16 | bckd := base64.StdEncoding.EncodeToString(braw) 17 | var buffer bytes.Buffer 18 | for i := 0; i < len(bckd); i++ { 19 | ch := bckd[i] 20 | buffer.WriteByte(ch) 21 | if (i+1)%76 == 0 { 22 | buffer.WriteByte('\n') 23 | } 24 | } 25 | buffer.WriteByte('\n') 26 | return buffer.Bytes() 27 | } 28 | 29 | func mmh3Hash32(raw []byte) string { 30 | var h32 = murmur3.New32() 31 | _, _ = h32.Write(raw) 32 | if isUint32 { 33 | return fmt.Sprintf("%d", h32.Sum32()) 34 | } 35 | return fmt.Sprintf("%d", int32(h32.Sum32())) 36 | } 37 | 38 | func Get(r io.Reader) (string, error) { 39 | body, err := ioutil.ReadAll(r) 40 | return mmh3Hash32(standBase64(body)), err 41 | } 42 | -------------------------------------------------------------------------------- /model/result.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/redtoolskobe/scaninfo/pkg/output" 4 | 5 | type WebFinger struct { 6 | HashFinger string 7 | KeywordFinger string 8 | StatusCode int 9 | Title string 10 | Websitle string 11 | HeaderDigest string 12 | Length int 13 | } 14 | 15 | type WeakPasswd struct { 16 | Type string 17 | Result string 18 | Host string 19 | Port string 20 | Passwd string 21 | Username string 22 | } 23 | 24 | type Plugin struct { 25 | Type string 26 | Result string 27 | Host string 28 | Port string 29 | } 30 | 31 | type ReportResult struct { 32 | PingList []string 33 | PortList []*output.ResultEvent 34 | FingerList []WebFinger 35 | WeakPasswdList []WeakPasswd 36 | PluginList []Plugin 37 | } 38 | 39 | var ResultReport ReportResult 40 | 41 | var WeakPasswdList []WeakPasswd 42 | 43 | var PluginList []Plugin 44 | 45 | var WebFingerList []WebFinger 46 | -------------------------------------------------------------------------------- /finger/urlparse/urlparse.go: -------------------------------------------------------------------------------- 1 | package urlparse 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "regexp" 7 | "strconv" 8 | ) 9 | 10 | type URL struct { 11 | Scheme, Netloc, Path string 12 | Port int 13 | } 14 | 15 | func Load(s string) (*URL, error) { 16 | r := regexp.MustCompile("^(?:(http|https)://)?([A-Za-z0-9.\\-]+(?:\\.[A-Za-z0-9.\\-]+))(?::(\\d+))?(/*[\\w./%]*)?") 17 | o := r.FindStringSubmatch(s) 18 | if len(o) != 5 { 19 | return nil, errors.New("URL格式不正确") 20 | } 21 | 22 | Scheme := o[1] 23 | Netloc := o[2] 24 | Port, _ := strconv.Atoi(o[3]) 25 | Path := o[4] 26 | 27 | if Port == 0 { 28 | switch Scheme { 29 | case "https": 30 | Port = 443 31 | case "http": 32 | Port = 80 33 | } 34 | } 35 | 36 | return &URL{ 37 | Scheme: Scheme, 38 | Netloc: Netloc, 39 | Port: Port, 40 | Path: Path, 41 | }, nil 42 | } 43 | 44 | func (i *URL) UnParse() string { 45 | return fmt.Sprintf("%s://%s:%d%s", i.Scheme, i.Netloc, i.Port, i.Path) 46 | } 47 | -------------------------------------------------------------------------------- /pkg/common/vulconstant.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | var Userdict = map[string][]string{ 4 | "ftp": {"ftp", "admin", "www", "web", "root", "db", "wwwroot", "data"}, 5 | "mysql": {"root", "mysql"}, 6 | "mssql": {"sa", "sql"}, 7 | "smb": {"administrator", "admin", "guest"}, 8 | "postgresql": {"postgres", "admin"}, 9 | "ssh": {"root", "admin"}, 10 | "mongodb": {"root", "admin"}, 11 | } 12 | 13 | var Passwords = []string{"123456", "admin", "admin123", "root", "", "pass123", "pass@123", "password", "123123", "654321", "111111", "123", "1", "admin@123", "Admin@123", "admin123!@#", "{user}", "{user}1", "{user}111", "{user}123", "{user}@123", "{user}_123", "{user}#123", "{user}@111", "{user}@2019", "{user}@123#4", "P@ssw0rd!", "P@ssw0rd", "Passw0rd", "qwe123", "12345678", "test", "test123", "123qwe!@#", "123456789", "123321", "666666", "a123456.", "123456~a", "123456!a", "000000", "1234567890", "8888888", "!QAZ2wsx", "1qaz2wsx", "abc123", "abc123456", "1qaz@WSX", "a11111", "a12345", "Aa1234", "Aa1234.", "Aa12345", "a123456", "a123123", "Aa123123", "Aa123456", "Aa12345.", "sysadmin", "system", "1qaz!QAZ", "2wsx@WSX", "qwe123!@#", "Aa123456!", "A123456s!", "sa123456"} 14 | -------------------------------------------------------------------------------- /pkg/Ginfo/Ghttp/encodings.go: -------------------------------------------------------------------------------- 1 | package Ghttp 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | 7 | "golang.org/x/text/encoding/simplifiedchinese" 8 | "golang.org/x/text/encoding/traditionalchinese" 9 | "golang.org/x/text/transform" 10 | ) 11 | 12 | // Credits: https://gist.github.com/zhangbaohe/c691e1da5bbdc7f41ca5 13 | 14 | // Decodegbk converts GBK to UTF-8 15 | func Decodegbk(s []byte) ([]byte, error) { 16 | I := bytes.NewReader(s) 17 | O := transform.NewReader(I, simplifiedchinese.GBK.NewDecoder()) 18 | d, e := ioutil.ReadAll(O) 19 | if e != nil { 20 | return nil, e 21 | } 22 | return d, nil 23 | } 24 | 25 | // Decodebig5 converts BIG5 to UTF-8 26 | func Decodebig5(s []byte) ([]byte, error) { 27 | I := bytes.NewReader(s) 28 | O := transform.NewReader(I, traditionalchinese.Big5.NewDecoder()) 29 | d, e := ioutil.ReadAll(O) 30 | if e != nil { 31 | return nil, e 32 | } 33 | return d, nil 34 | } 35 | 36 | // Encodebig5 converts UTF-8 to BIG5 37 | func Encodebig5(s []byte) ([]byte, error) { 38 | I := bytes.NewReader(s) 39 | O := transform.NewReader(I, traditionalchinese.Big5.NewEncoder()) 40 | d, e := ioutil.ReadAll(O) 41 | if e != nil { 42 | return nil, e 43 | } 44 | return d, nil 45 | } 46 | -------------------------------------------------------------------------------- /pkg/options/options.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/redtoolskobe/scaninfo/model" 5 | "github.com/redtoolskobe/scaninfo/pkg/common" 6 | "github.com/redtoolskobe/scaninfo/pkg/output" 7 | ) 8 | 9 | type HostInfo struct { 10 | Host string 11 | Ports string 12 | Domain string 13 | Url string 14 | Path string 15 | Timeout int64 16 | Scantype string 17 | Command string 18 | SshKey string 19 | Username string 20 | Password string 21 | Usernames []string 22 | Passwords []string 23 | Infostr []string 24 | Hash string 25 | Hosts []string 26 | TaskName string 27 | TaskID string 28 | Userdict map[string][]string 29 | TaskTotal []string 30 | TaskDown []string 31 | TaskRun []string 32 | Keyword *[]model.Fingers 33 | Favicons *[]model.Fingers 34 | ScanType string 35 | } 36 | 37 | type ScanVul struct { 38 | Info HostInfo 39 | ServicePortList []*output.ResultEvent 40 | UrlList []string 41 | } 42 | 43 | func NewDefaultScanVul(urllist []string) *ScanVul { 44 | return &ScanVul{ 45 | Info: HostInfo{ 46 | Timeout: 3, 47 | Userdict: common.Userdict, 48 | Passwords: common.Passwords, 49 | }, 50 | UrlList: urllist, 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /finger/run.go: -------------------------------------------------------------------------------- 1 | package finger 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/redtoolskobe/scaninfo/model" 7 | 8 | "github.com/redtoolskobe/scaninfo/finger/gonmap" 9 | "github.com/redtoolskobe/scaninfo/finger/lib/shttp" 10 | "github.com/redtoolskobe/scaninfo/finger/urlparse" 11 | ) 12 | 13 | func getHttpFinger(url *urlparse.URL, loop bool, k *[]model.Fingers, f *[]model.Fingers) *gonmap.HttpFinger { 14 | r := gonmap.NewHttpFinger(url, k, f) 15 | if url != nil { 16 | resp, err := shttp.Get(url.UnParse()) 17 | if err != nil { 18 | if loop == true { 19 | return r 20 | } 21 | if strings.Contains(err.Error(), "server gave HTTP response") { 22 | //HTTP协议重新获取指纹 23 | url.Scheme = "http" 24 | return getHttpFinger(url, true, k, f) 25 | } 26 | if strings.Contains(err.Error(), "malformed HTTP response") { 27 | //HTTP协议重新获取指纹 28 | url.Scheme = "https" 29 | return getHttpFinger(url, true, k, f) 30 | } 31 | return r 32 | } 33 | if url.Scheme == "https" { 34 | r.LoadCert(resp) 35 | } 36 | r.LoadHttpResponse(url, resp) 37 | return r 38 | } 39 | return r 40 | } 41 | 42 | func Run(urlx string, k *[]model.Fingers, f *[]model.Fingers) *gonmap.HttpFinger { 43 | url, _ := urlparse.Load(urlx) 44 | return getHttpFinger(url, true, k, f) 45 | } 46 | -------------------------------------------------------------------------------- /pkg/Plugins/webtitle.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "github.com/redtoolskobe/scaninfo/global" 5 | "github.com/redtoolskobe/scaninfo/model" 6 | "github.com/redtoolskobe/scaninfo/pkg/options" 7 | "go.uber.org/zap" 8 | 9 | "github.com/redtoolskobe/scaninfo/finger" 10 | "github.com/redtoolskobe/scaninfo/pkg/common" 11 | ) 12 | 13 | func WebTitle(info *options.HostInfo) error { 14 | Finger(info) 15 | return nil 16 | } 17 | 18 | //flag 1 first try 19 | //flag 2 /favicon.ico 20 | //flag 3 302 21 | //flag 4 400 -> https 22 | 23 | func Finger(info *options.HostInfo) { 24 | res := finger.Run(info.Url, info.Keyword, info.Favicons) 25 | result := model.WebFinger{HeaderDigest: res.HeaderDigest, Websitle: info.Url, Title: res.Title, Length: res.Length, StatusCode: res.StatusCode, 26 | KeywordFinger: res.KeywordFinger, HashFinger: res.HashFinger} 27 | common.LogSuccess(&common.VulInfo{"webtitle", info.TaskID, map[string]interface{}{"webtitle": result}}) 28 | global.Log.Info("webtitle", zap.String("url", info.Url), zap.Int("StatusCode", res.StatusCode), zap.String("Title", res.Title), zap.String("HeaderDigest", res.HeaderDigest), 29 | zap.Int("Length", res.Length), zap.String("KeywordFinger", res.KeywordFinger), zap.String("HashFinger", res.HashFinger)) 30 | model.WebFingerList = append(model.WebFingerList, result) 31 | } 32 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/pterm/pterm" 10 | 11 | "github.com/redtoolskobe/scaninfo/pkg/log" 12 | 13 | "github.com/redtoolskobe/scaninfo/pkg/common" 14 | 15 | "github.com/redtoolskobe/scaninfo/run" 16 | ) 17 | 18 | func init() { 19 | newHeader := pterm.HeaderPrinter{ 20 | TextStyle: pterm.NewStyle(pterm.BgCyan), 21 | BackgroundStyle: pterm.NewStyle(pterm.BgCyan), 22 | Margin: 20, 23 | } 24 | newHeader.Println("scan info v1.1.0") 25 | pterm.FgRed.Println("本工具只做探测没有提供利用方式只供学习,请遵守国家网络安全.") 26 | pterm.FgRed.Println("扫描的时候可以手动停止结果会自动保存,-h查看使用说明-show查看支持的模块.") 27 | pterm.FgRed.Println("漏洞和指纹扫描的时候可能最后几个任务很慢,是因为弱口令爆破,可以手动control+c结束.") 28 | pterm.Warning.Println("默认使用TOP100端口,可以-p指定端口或者使用参数-t1000扫TOP1000.") 29 | flag.Parse() 30 | log.InitLog() 31 | if common.NumThreads < 1 || common.NumThreads > 2000 { 32 | fmt.Println("number of goroutine must between 1 and 2000") 33 | os.Exit(-1) 34 | } 35 | if common.ShowScanType { 36 | showmode() 37 | } 38 | } 39 | 40 | func main() { 41 | ctx, cancel := context.WithCancel(context.Background()) 42 | run.Start(ctx) 43 | //time.Sleep(180 * time.Second) 44 | cancel() 45 | pterm.Success.Println("所有任务已经结束。") 46 | } 47 | 48 | func showmode() { 49 | fmt.Println("The specified scan type does not exist") 50 | fmt.Println("-m") 51 | for _, name := range common.ScanTypeList { 52 | fmt.Println(" [" + name + "]") 53 | } 54 | os.Exit(0) 55 | } 56 | -------------------------------------------------------------------------------- /pkg/Plugins/memcached.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | "time" 8 | 9 | "github.com/redtoolskobe/scaninfo/global" 10 | "go.uber.org/zap" 11 | 12 | "github.com/redtoolskobe/scaninfo/model" 13 | 14 | "github.com/redtoolskobe/scaninfo/pkg/common" 15 | "github.com/redtoolskobe/scaninfo/pkg/options" 16 | ) 17 | 18 | func MemcachedScan(info *options.HostInfo) (err error) { 19 | realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports) 20 | client, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) 21 | if err == nil { 22 | err = client.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second)) 23 | if err == nil { 24 | _, err = client.Write([]byte("stats\n")) //Set the key randomly to prevent the key on the server from being overwritten 25 | if err == nil { 26 | rev := make([]byte, 1024) 27 | n, err := client.Read(rev) 28 | if err == nil { 29 | if strings.Contains(string(rev[:n]), "STAT") { 30 | result := fmt.Sprintf("[+] Memcached %s unauthorized", realhost) 31 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "memcached", Result: result, Host: info.Host, Passwd: "", Username: ""}}} 32 | common.LogSuccess(&res) 33 | global.Log.Warn("weak_passwd", zap.String("memcached", "mecached"), zap.String("host", info.Host), 34 | zap.String("password", ""), zap.String("username", "")) 35 | model.WeakPasswdList = append(model.WeakPasswdList, model.WeakPasswd{"memcached", result, info.Host, info.Ports, "", ""}) 36 | } 37 | client.Close() 38 | } else { 39 | errlog := fmt.Sprintf("[-] Memcached %v:%v %v", info.Host, info.Ports, err) 40 | common.LogError(errlog) 41 | } 42 | } 43 | } 44 | } 45 | return err 46 | } 47 | -------------------------------------------------------------------------------- /pkg/output/output.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "regexp" 5 | "time" 6 | 7 | "github.com/redtoolskobe/scaninfo/global" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | // Writer is an interface which writes output to somewhere for nuclei events. 12 | type Writer interface { 13 | Write(*ResultEvent, *[]*ResultEvent) error 14 | // Request logs a request in the trace log 15 | } 16 | 17 | type Info struct { 18 | Banner string 19 | Service string 20 | Cert string 21 | Url string 22 | } 23 | type ResultEvent struct { 24 | WorkingEvent interface{} `json:"WorkingEvent"` 25 | Info *Info `json:"info,inline"` 26 | Time time.Time `json:"time"` 27 | Target string `json:"Target"` 28 | Ip string `json:"ip"` 29 | Port uint64 `json:"port"` 30 | Url string 31 | } 32 | 33 | var PortList = []*ResultEvent{} 34 | 35 | type StandardWriter struct { 36 | } 37 | 38 | var decolorizerRegex = regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) 39 | 40 | func NewStandardWriter() (*StandardWriter, error) { 41 | writer := &StandardWriter{} 42 | return writer, nil 43 | } 44 | 45 | // Write writes the event to file and/or screen. 46 | func (w *StandardWriter) Write(event *ResultEvent, portlist *[]*ResultEvent) error { 47 | if event == nil { 48 | return nil 49 | } 50 | global.Log.Info("port", zap.String("ip", event.Ip), zap.Uint64("port", event.Port), zap.String("service", event.Info.Service), 51 | zap.String("Banner", event.Info.Banner), zap.String("url", event.Info.Url)) 52 | event.Time = time.Now() 53 | *portlist = append(*portlist, event) 54 | //model.ResultReport.PortList = append(model.ResultReport.PortList, event) 55 | PortList = append(PortList, event) 56 | return nil 57 | } 58 | 59 | type JSONTraceRequest struct { 60 | IP string `json:"ip"` 61 | Port string `json:"port"` 62 | Error string `json:"error"` 63 | Type string `json:"type"` 64 | } 65 | -------------------------------------------------------------------------------- /pkg/common/log.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "strings" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | var Results = make(chan *VulInfo) 10 | var Start = true 11 | var LogSucTime int64 12 | var LogErrTime int64 13 | var WaitTime int64 14 | var Silent bool 15 | var LogWG sync.WaitGroup 16 | var VulList []*VulInfo 17 | 18 | type VulInfo struct { 19 | Name string 20 | TaskID string 21 | Result map[string]interface{} 22 | } 23 | 24 | func CheckErrs(err error) bool { 25 | if err == nil { 26 | return false 27 | } 28 | errs := []string{ 29 | "closed by the remote host", "too many connections", 30 | "i/o timeout", "EOF", "A connection attempt failed", 31 | "established connection failed", "connection attempt failed", 32 | "Unable to read", "is not allowed to connect to this", 33 | "no pg_hba.conf entry", 34 | "No connection could be made", 35 | "invalid packet size", 36 | "bad connection", 37 | "ssh: handshake failed", 38 | } 39 | for _, key := range errs { 40 | if strings.Contains(strings.ToLower(err.Error()), strings.ToLower(key)) { 41 | return true 42 | } 43 | } 44 | return false 45 | } 46 | 47 | func init() { 48 | go SaveLog() 49 | } 50 | 51 | func LogSuccess(result *VulInfo) { 52 | LogWG.Add(1) 53 | LogSucTime = time.Now().Unix() 54 | Results <- result 55 | } 56 | 57 | func SaveLog() { 58 | for result := range Results { 59 | VulList = append(VulList, result) 60 | //TaskResult := model.TaskResult{TakId: result.TaskID, TaskType: "fscan", JsonVulInfo: utils.JsonToByte(result), ResultType: result.Name} 61 | //_ = db.SaveTaskResult(&TaskResult) 62 | LogWG.Done() 63 | } 64 | } 65 | 66 | func LogError(errinfo interface{}) { 67 | if WaitTime == 0 { 68 | //gologger.Info().Msgf("[FSCAN]-[error]]", errinfo) 69 | } else if (time.Now().Unix()-LogSucTime) > WaitTime && (time.Now().Unix()-LogErrTime) > WaitTime { 70 | //gologger.Info().Msgf("[FSCAN]-[error]]", errinfo) 71 | LogErrTime = time.Now().Unix() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /pkg/common/Progress.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/projectdiscovery/gologger" 8 | 9 | "github.com/pterm/pterm" 10 | 11 | "github.com/projectdiscovery/clistats" 12 | ) 13 | 14 | type Progress interface { 15 | Init(Count int64) 16 | IncrementRequests() 17 | Stop() 18 | } 19 | 20 | type StatsTicker struct { 21 | active bool 22 | tickDuration time.Duration 23 | stats clistats.StatisticsClient 24 | Bar *pterm.ProgressbarPrinter 25 | } 26 | 27 | func NewStatsTicker(duration int, active bool) (Progress, error) { 28 | var tickDuration time.Duration 29 | if active { 30 | tickDuration = time.Duration(duration) * time.Second 31 | } else { 32 | tickDuration = -1 33 | } 34 | 35 | progress := &StatsTicker{} 36 | 37 | stats, err := clistats.New() 38 | if err != nil { 39 | return nil, err 40 | } 41 | progress.active = active 42 | progress.stats = stats 43 | progress.tickDuration = tickDuration 44 | 45 | return progress, nil 46 | } 47 | 48 | func (p *StatsTicker) IncrementRequests() { 49 | p.stats.IncrementCounter("requests", 1) 50 | } 51 | 52 | func (p *StatsTicker) Init(Count int64) { 53 | p.stats.AddStatic("startedAt", time.Now()) 54 | p.stats.AddCounter("requests", uint64(0)) 55 | p.Bar, _ = pterm.DefaultProgressbar.WithTotal(int(Count)).WithTitle("[Port Scan]").Start() 56 | if p.active { 57 | if err := p.stats.Start(p.printCallback, p.tickDuration); err != nil { 58 | fmt.Println(err) 59 | } 60 | } 61 | } 62 | 63 | func (p *StatsTicker) printCallback(stats clistats.StatisticsClient) { 64 | requests, _ := stats.GetCounter("requests") 65 | time.Sleep(1 * time.Second) 66 | fmt.Print("") 67 | p.Bar.Current = int(requests) 68 | p.Bar.Add(0) 69 | } 70 | 71 | func (p *StatsTicker) Stop() { 72 | if p.active { 73 | // Print one final summary 74 | p.printCallback(p.stats) 75 | if err := p.stats.Stop(); err != nil { 76 | gologger.Warning().Msgf("Couldn't stop statistics: %s", err) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /pkg/conversion/conversion.go: -------------------------------------------------------------------------------- 1 | package conversion 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | // ToString converts an interface to string in a quick way 10 | func ToString(data interface{}) string { 11 | switch s := data.(type) { 12 | case nil: 13 | return "" 14 | case string: 15 | return s 16 | case bool: 17 | return strconv.FormatBool(s) 18 | case float64: 19 | return strconv.FormatFloat(s, 'f', -1, 64) 20 | case float32: 21 | return strconv.FormatFloat(float64(s), 'f', -1, 32) 22 | case int: 23 | return strconv.Itoa(s) 24 | case int64: 25 | return strconv.FormatInt(s, 10) 26 | case int32: 27 | return strconv.Itoa(int(s)) 28 | case int16: 29 | return strconv.FormatInt(int64(s), 10) 30 | case int8: 31 | return strconv.FormatInt(int64(s), 10) 32 | case uint: 33 | return strconv.FormatUint(uint64(s), 10) 34 | case uint64: 35 | return strconv.FormatUint(s, 10) 36 | case uint32: 37 | return strconv.FormatUint(uint64(s), 10) 38 | case uint16: 39 | return strconv.FormatUint(uint64(s), 10) 40 | case uint8: 41 | return strconv.FormatUint(uint64(s), 10) 42 | case []byte: 43 | return string(s) 44 | case fmt.Stringer: 45 | return s.String() 46 | case error: 47 | return s.Error() 48 | default: 49 | return fmt.Sprintf("%v", data) 50 | } 51 | } 52 | 53 | // ToStringSlice casts an interface to a []string type. 54 | func ToStringSlice(i interface{}) []string { 55 | var a []string 56 | 57 | switch v := i.(type) { 58 | case []interface{}: 59 | for _, u := range v { 60 | a = append(a, ToString(u)) 61 | } 62 | return a 63 | case []string: 64 | return v 65 | case string: 66 | return strings.Fields(v) 67 | case interface{}: 68 | return []string{ToString(v)} 69 | default: 70 | return nil 71 | } 72 | } 73 | 74 | // ToStringMap casts an interface to a map[string]interface{} type. 75 | func ToStringMap(i interface{}) map[string]interface{} { 76 | var m = map[string]interface{}{} 77 | 78 | switch v := i.(type) { 79 | case map[interface{}]interface{}: 80 | for k, val := range v { 81 | m[ToString(k)] = val 82 | } 83 | return m 84 | case map[string]interface{}: 85 | return v 86 | default: 87 | return nil 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /pkg/Plugins/postgres.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "strings" 7 | "time" 8 | 9 | "github.com/redtoolskobe/scaninfo/global" 10 | "go.uber.org/zap" 11 | 12 | "github.com/redtoolskobe/scaninfo/model" 13 | 14 | _ "github.com/lib/pq" 15 | "github.com/redtoolskobe/scaninfo/pkg/common" 16 | "github.com/redtoolskobe/scaninfo/pkg/options" 17 | ) 18 | 19 | func PostgresScan(info *options.HostInfo) (tmperr error) { 20 | starttime := time.Now().Unix() 21 | for _, user := range info.Userdict["postgresql"] { 22 | for _, pass := range info.Passwords { 23 | pass = strings.Replace(pass, "{user}", string(user), -1) 24 | flag, err := PostgresConn(info, user, pass) 25 | if flag == true && err == nil { 26 | return err 27 | } else { 28 | errlog := fmt.Sprintf("[-] psql %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) 29 | common.LogError(errlog) 30 | tmperr = err 31 | if common.CheckErrs(err) { 32 | return err 33 | } 34 | if time.Now().Unix()-starttime > (int64(len(info.Userdict["postgresql"])*len(info.Passwords)) * info.Timeout) { 35 | return err 36 | } 37 | } 38 | } 39 | } 40 | return tmperr 41 | } 42 | 43 | func PostgresConn(info *options.HostInfo, user string, pass string) (flag bool, err error) { 44 | flag = false 45 | Host, Port, Username, Password := info.Host, info.Ports, user, pass 46 | dataSourceName := fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", Username, Password, Host, Port, "postgres", "disable") 47 | db, err := sql.Open("postgres", dataSourceName) 48 | if err == nil { 49 | db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second) 50 | defer db.Close() 51 | err = db.Ping() 52 | if err == nil { 53 | result := fmt.Sprintf("Postgres:%v:%v:%v %v", Host, Port, Username, Password) 54 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "postgres", Result: result, Host: info.Host, Passwd: pass, Username: user}}} 55 | global.Log.Warn("weak_passwd", zap.String("postgres", "postgres"), zap.String("host", info.Host), 56 | zap.String("password", pass), zap.String("username", user)) 57 | common.LogSuccess(&res) 58 | model.WeakPasswdList = append(model.WeakPasswdList, model.WeakPasswd{"postgres", result, info.Host, info.Ports, pass, user}) 59 | flag = true 60 | } 61 | } 62 | return flag, err 63 | } 64 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/redtoolskobe/scaninfo 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/PuerkitoBio/goquery v1.7.1 7 | github.com/denisenkom/go-mssqldb v0.11.0 8 | github.com/fatih/color v1.13.0 9 | github.com/go-sql-driver/mysql v1.6.0 10 | github.com/jlaffaye/ftp v0.0.0-20210307004419-5d4190119067 11 | github.com/lib/pq v1.10.3 12 | github.com/pkg/errors v0.9.1 13 | github.com/projectdiscovery/clistats v0.0.8 14 | github.com/projectdiscovery/gologger v1.1.4 15 | github.com/pterm/pterm v0.12.33 16 | github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 17 | github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8 18 | github.com/twmb/murmur3 v1.1.6 19 | github.com/xuri/excelize/v2 v2.4.1 20 | go.uber.org/ratelimit v0.2.0 21 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 22 | golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b 23 | golang.org/x/text v0.3.7 24 | ) 25 | 26 | require ( 27 | github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect 28 | github.com/andybalholm/cascadia v1.2.0 // indirect 29 | github.com/atomicgo/cursor v0.0.1 // indirect 30 | github.com/goinggo/mapstructure v0.0.0-20140717182941-194205d9b4a9 // indirect 31 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect 32 | github.com/gookit/color v1.4.2 // indirect 33 | github.com/json-iterator/go v1.1.10 // indirect 34 | github.com/logrusorgru/aurora v2.0.3+incompatible // indirect 35 | github.com/mattn/go-colorable v0.1.9 // indirect 36 | github.com/mattn/go-isatty v0.0.14 // indirect 37 | github.com/mattn/go-runewidth v0.0.13 // indirect 38 | github.com/mitchellh/mapstructure v1.4.2 // indirect 39 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 40 | github.com/modern-go/reflect2 v1.0.2 // indirect 41 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect 42 | github.com/richardlehane/mscfb v1.0.3 // indirect 43 | github.com/richardlehane/msoleps v1.0.1 // indirect 44 | github.com/rivo/uniseg v0.2.0 // indirect 45 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect 46 | github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect 47 | go.uber.org/atomic v1.7.0 // indirect 48 | go.uber.org/multierr v1.6.0 // indirect 49 | go.uber.org/zap v1.19.1 // indirect 50 | golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect 51 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect 52 | ) 53 | -------------------------------------------------------------------------------- /pkg/Plugins/mysql.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "strings" 7 | "time" 8 | 9 | "github.com/redtoolskobe/scaninfo/global" 10 | "go.uber.org/zap" 11 | 12 | "github.com/redtoolskobe/scaninfo/model" 13 | 14 | _ "github.com/go-sql-driver/mysql" 15 | "github.com/redtoolskobe/scaninfo/pkg/common" 16 | "github.com/redtoolskobe/scaninfo/pkg/options" 17 | ) 18 | 19 | func MysqlScan(info *options.HostInfo) (tmperr error) { 20 | starttime := time.Now().Unix() 21 | for _, user := range info.Userdict["mysql"] { 22 | for _, pass := range info.Passwords { 23 | pass = strings.Replace(pass, "{user}", user, -1) 24 | flag, err := MysqlConn(info, user, pass) 25 | if flag == true && err == nil { 26 | return err 27 | } else { 28 | errlog := fmt.Sprintf("[-] mysql %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) 29 | common.LogError(errlog) 30 | tmperr = err 31 | if common.CheckErrs(err) { 32 | return err 33 | } 34 | if time.Now().Unix()-starttime > (int64(len(info.Userdict["mysql"])*len(info.Passwords)) * info.Timeout) { 35 | return err 36 | } 37 | } 38 | } 39 | } 40 | return tmperr 41 | } 42 | 43 | func MysqlConn(info *options.HostInfo, user string, pass string) (flag bool, err error) { 44 | flag = false 45 | Host, Port, Username, Password := info.Host, info.Ports, user, pass 46 | dataSourceName := fmt.Sprintf("%v:%v@tcp(%v:%v)/mysql?charset=utf8&timeout=%v", Username, Password, Host, Port, time.Duration(info.Timeout)*time.Second) 47 | db, err := sql.Open("mysql", dataSourceName) 48 | if err == nil { 49 | db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second) 50 | //db.SetConnMaxIdleTime(time.Duration(info.Timeout) * time.Second) 51 | db.SetMaxIdleConns(0) 52 | defer db.Close() 53 | err = db.Ping() 54 | if err == nil { 55 | result := fmt.Sprintf("[+] mysql:%v:%v:%v %v", Host, Port, Username, Password) 56 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "mysql", Result: result, Host: info.Host, Passwd: pass, Username: user}}} 57 | common.LogSuccess(&res) 58 | global.Log.Warn("weak_passwd", zap.String("mysql", "mysql"), zap.String("host", info.Host), 59 | zap.String("password", pass), zap.String("username", user)) 60 | model.WeakPasswdList = append(model.WeakPasswdList, model.WeakPasswd{"mysql", result, info.Host, info.Ports, pass, user}) 61 | flag = true 62 | } 63 | } 64 | return flag, err 65 | } 66 | -------------------------------------------------------------------------------- /pkg/Plugins/mssql.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "strings" 7 | "time" 8 | 9 | "github.com/redtoolskobe/scaninfo/global" 10 | "go.uber.org/zap" 11 | 12 | "github.com/redtoolskobe/scaninfo/model" 13 | 14 | _ "github.com/denisenkom/go-mssqldb" 15 | "github.com/redtoolskobe/scaninfo/pkg/common" 16 | "github.com/redtoolskobe/scaninfo/pkg/options" 17 | ) 18 | 19 | func MssqlScan(info *options.HostInfo) (tmperr error) { 20 | starttime := time.Now().Unix() 21 | for _, user := range info.Userdict["mssql"] { 22 | for _, pass := range info.Passwords { 23 | pass = strings.Replace(pass, "{user}", user, -1) 24 | flag, err := MssqlConn(info, user, pass) 25 | if flag == true && err == nil { 26 | return err 27 | } else { 28 | errlog := fmt.Sprintf("[-] mssql %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) 29 | common.LogError(errlog) 30 | tmperr = err 31 | if common.CheckErrs(err) { 32 | return err 33 | } 34 | if time.Now().Unix()-starttime > (int64(len(info.Userdict["mssql"])*len(info.Passwords)) * info.Timeout) { 35 | return err 36 | } 37 | } 38 | } 39 | } 40 | return tmperr 41 | } 42 | 43 | func MssqlConn(info *options.HostInfo, user string, pass string) (flag bool, err error) { 44 | flag = false 45 | Host, Port, Username, Password := info.Host, info.Ports, user, pass 46 | dataSourceName := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%v;encrypt=disable;timeout=%v", Host, Username, Password, Port, time.Duration(info.Timeout)*time.Second) 47 | db, err := sql.Open("mssql", dataSourceName) 48 | if err == nil { 49 | db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second) 50 | //db.SetConnMaxIdleTime(time.Duration(info.Timeout) * time.Second) 51 | db.SetMaxIdleConns(0) 52 | defer db.Close() 53 | err = db.Ping() 54 | if err == nil { 55 | result := fmt.Sprintf("[+] mssql:%v:%v:%v %v", Host, Port, Username, Password) 56 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "mssql", Result: result, Host: info.Host, Passwd: pass, Username: user}}} 57 | common.LogSuccess(&res) 58 | global.Log.Warn("weak_passwd", zap.String("mssql", "mssql"), zap.String("host", info.Host), 59 | zap.String("password", pass), zap.String("username", user)) 60 | model.WeakPasswdList = append(model.WeakPasswdList, model.WeakPasswd{"mssql", result, info.Host, info.Ports, pass, user}) 61 | flag = true 62 | } 63 | } 64 | return flag, err 65 | } 66 | -------------------------------------------------------------------------------- /pkg/Plugins/findnet.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "fmt" 7 | "net" 8 | "strings" 9 | "time" 10 | 11 | "github.com/redtoolskobe/scaninfo/model" 12 | 13 | "github.com/redtoolskobe/scaninfo/global" 14 | "go.uber.org/zap" 15 | 16 | "github.com/redtoolskobe/scaninfo/pkg/options" 17 | 18 | "github.com/redtoolskobe/scaninfo/pkg/common" 19 | ) 20 | 21 | var ( 22 | bufferV1, _ = hex.DecodeString("05000b03100000004800000001000000b810b810000000000100000000000100c4fefc9960521b10bbcb00aa0021347a00000000045d888aeb1cc9119fe808002b10486002000000") 23 | bufferV2, _ = hex.DecodeString("050000031000000018000000010000000000000000000500") 24 | bufferV3, _ = hex.DecodeString("0900ffff0000") 25 | ) 26 | 27 | func Findnet(info *options.HostInfo) error { 28 | err := FindnetScan(info) 29 | return err 30 | } 31 | 32 | func FindnetScan(info *options.HostInfo) error { 33 | realhost := fmt.Sprintf("%s:%v", info.Host, 135) 34 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) 35 | if err != nil { 36 | return err 37 | } 38 | err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second)) 39 | if err != nil { 40 | return err 41 | } 42 | defer conn.Close() 43 | _, err = conn.Write(bufferV1) 44 | if err != nil { 45 | return err 46 | } 47 | reply := make([]byte, 4096) 48 | _, err = conn.Read(reply) 49 | if err != nil { 50 | return err 51 | } 52 | _, err = conn.Write(bufferV2) 53 | if err != nil { 54 | return err 55 | } 56 | if n, err := conn.Read(reply); err != nil || n < 42 { 57 | return err 58 | } 59 | text := reply[42:] 60 | flag := true 61 | for i := 0; i < len(text)-5; i++ { 62 | if bytes.Equal(text[i:i+6], bufferV3) { 63 | text = text[:i-4] 64 | flag = false 65 | break 66 | } 67 | } 68 | if flag { 69 | return err 70 | } 71 | err = read(text, info.Host, info) 72 | return err 73 | } 74 | func read(text []byte, host string, info *options.HostInfo) error { 75 | encodedStr := hex.EncodeToString(text) 76 | hostnames := strings.Replace(encodedStr, "0700", "", -1) 77 | hostname := strings.Split(hostnames, "000000") 78 | result := "NetInfo:\n[*]" + host 79 | for i := 0; i < len(hostname); i++ { 80 | hostname[i] = strings.Replace(hostname[i], "00", "", -1) 81 | host, err := hex.DecodeString(hostname[i]) 82 | if err != nil { 83 | return err 84 | } 85 | result += "\n [->]" + string(host) 86 | } 87 | res := common.VulInfo{"plugin", info.TaskID, map[string]interface{}{"type": "findnet", "result": result, "host": host}} 88 | common.LogSuccess(&res) 89 | global.Log.Warn("plugin", zap.String("findnet", "findnet"), zap.String("host", info.Host), 90 | zap.String("result", result)) 91 | model.PluginList = append(model.PluginList, model.Plugin{"findnet", result, host, info.Ports}) 92 | return nil 93 | } 94 | -------------------------------------------------------------------------------- /pkg/Plugins/mongodb.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | "time" 8 | 9 | "github.com/redtoolskobe/scaninfo/global" 10 | "go.uber.org/zap" 11 | 12 | "github.com/redtoolskobe/scaninfo/model" 13 | 14 | _ "github.com/denisenkom/go-mssqldb" 15 | "github.com/redtoolskobe/scaninfo/pkg/common" 16 | "github.com/redtoolskobe/scaninfo/pkg/options" 17 | ) 18 | 19 | func MongodbScan(info *options.HostInfo) error { 20 | _, err := MongodbUnauth(info) 21 | if err != nil { 22 | errlog := fmt.Sprintf("[-] Mongodb %v:%v %v", info.Host, info.Ports, err) 23 | common.LogError(errlog) 24 | } 25 | return err 26 | } 27 | 28 | func MongodbUnauth(info *options.HostInfo) (flag bool, err error) { 29 | flag = false 30 | senddata := []byte{58, 0, 0, 0, 167, 65, 0, 0, 0, 0, 0, 0, 212, 7, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 46, 36, 99, 109, 100, 0, 0, 0, 0, 0, 255, 255, 255, 255, 19, 0, 0, 0, 16, 105, 115, 109, 97, 115, 116, 101, 114, 0, 1, 0, 0, 0, 0} 31 | getlogdata := []byte{72, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 212, 7, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 46, 36, 99, 109, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 2, 103, 101, 116, 76, 111, 103, 0, 16, 0, 0, 0, 115, 116, 97, 114, 116, 117, 112, 87, 97, 114, 110, 105, 110, 103, 115, 0, 0} 32 | realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports) 33 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) 34 | if err != nil { 35 | return flag, err 36 | } 37 | defer conn.Close() 38 | err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second)) 39 | if err != nil { 40 | return flag, err 41 | } 42 | _, err = conn.Write(senddata) 43 | if err != nil { 44 | return flag, err 45 | } 46 | buf := make([]byte, 1024) 47 | count, err := conn.Read(buf) 48 | if err != nil { 49 | return flag, err 50 | } 51 | text := string(buf[0:count]) 52 | if strings.Contains(text, "ismaster") { 53 | _, err = conn.Write(getlogdata) 54 | if err != nil { 55 | return flag, err 56 | } 57 | count, err := conn.Read(buf) 58 | if err != nil { 59 | return flag, err 60 | } 61 | text := string(buf[0:count]) 62 | if strings.Contains(text, "totalLinesWritten") { 63 | flag = true 64 | result := fmt.Sprintf("[+] Mongodb:%v unauthorized", realhost) 65 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "mongodb", Result: result, Host: info.Host, Passwd: "", Username: ""}}} 66 | common.LogSuccess(&res) 67 | global.Log.Warn("weak_passwd", zap.String("mongodb", "mongodb"), zap.String("host", info.Host), 68 | zap.String("password", ""), zap.String("username", "")) 69 | model.WeakPasswdList = append(model.WeakPasswdList, model.WeakPasswd{"mongodb", result, info.Host, info.Ports, "", ""}) 70 | } 71 | } 72 | return flag, err 73 | } 74 | -------------------------------------------------------------------------------- /pkg/Plugins/smb.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | 8 | "github.com/redtoolskobe/scaninfo/global" 9 | "go.uber.org/zap" 10 | 11 | "github.com/redtoolskobe/scaninfo/model" 12 | 13 | "github.com/redtoolskobe/scaninfo/pkg/options" 14 | 15 | "github.com/redtoolskobe/scaninfo/pkg/common" 16 | "github.com/stacktitan/smb/smb" 17 | ) 18 | 19 | func SmbScan(info *options.HostInfo) (tmperr error) { 20 | starttime := time.Now().Unix() 21 | for _, user := range info.Userdict["smb"] { 22 | for _, pass := range info.Passwords { 23 | pass = strings.Replace(pass, "{user}", user, -1) 24 | flag, err := doWithTimeOut(info, user, pass) 25 | if flag == true && err == nil { 26 | var result string 27 | if info.Domain != "" { 28 | result = fmt.Sprintf("[+] SMB:%v:%v:%v\\%v %v", info.Host, info.Ports, info.Domain, user, pass) 29 | } else { 30 | result = fmt.Sprintf("[+] SMB:%v:%v:%v %v", info.Host, info.Ports, user, pass) 31 | } 32 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "smb", Result: result, Host: info.Host, Passwd: pass, Username: user}}} 33 | common.LogSuccess(&res) 34 | global.Log.Warn("weak_passwd", zap.String("smb", "smb"), zap.String("host", info.Host), 35 | zap.String("password", pass), zap.String("username", user)) 36 | return err 37 | } else { 38 | errlog := fmt.Sprintf("[-] smb %v:%v %v %v %v", info.Host, 445, user, pass, err) 39 | errlog = strings.Replace(errlog, "\n", "", -1) 40 | common.LogError(errlog) 41 | tmperr = err 42 | if common.CheckErrs(err) { 43 | return err 44 | } 45 | if time.Now().Unix()-starttime > (int64(len(info.Userdict["smb"])*len(info.Passwords)) * info.Timeout) { 46 | return err 47 | } 48 | } 49 | } 50 | } 51 | return tmperr 52 | } 53 | 54 | func SmblConn(info *options.HostInfo, user string, pass string, signal chan struct{}) (flag bool, err error) { 55 | flag = false 56 | Host, Username, Password := info.Host, user, pass 57 | options := smb.Options{ 58 | Host: Host, 59 | Port: 445, 60 | User: Username, 61 | Password: Password, 62 | Domain: info.Domain, 63 | Workstation: "", 64 | } 65 | 66 | session, err := smb.NewSession(options, false) 67 | if err == nil { 68 | session.Close() 69 | if session.IsAuthenticated { 70 | flag = true 71 | } 72 | } 73 | signal <- struct{}{} 74 | return flag, err 75 | } 76 | 77 | func doWithTimeOut(info *options.HostInfo, user string, pass string) (flag bool, err error) { 78 | signal := make(chan struct{}) 79 | go func() { 80 | flag, err = SmblConn(info, user, pass, signal) 81 | }() 82 | select { 83 | case <-signal: 84 | return flag, err 85 | case <-time.After(time.Duration(info.Timeout) * time.Second): 86 | return false, err 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /pkg/common/ipparser/ipprocess.go: -------------------------------------------------------------------------------- 1 | package ipparser 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "math/big" 7 | "net" 8 | "regexp" 9 | "strings" 10 | ) 11 | 12 | /** 13 | 这个文件主要是包含一些对ip地址进行处理的函数和对域名进行解析相关的函数 14 | */ 15 | 16 | // ValidIpv4 判断Ip地址是否合法 17 | func ValidIpv4(ip string) bool { 18 | if valid := net.ParseIP(ip); valid != nil { 19 | return true 20 | } 21 | 22 | return false 23 | } 24 | 25 | // 根据域名查找ip,一个域名可能对应多个ip 26 | func DomainToIp(domain string) ([]string, string, error) { 27 | var fields []string 28 | var mask string 29 | var host = domain 30 | 31 | if strings.Contains(domain, "/") { 32 | fields = strings.Split(domain, "/") 33 | host = fields[0] 34 | mask = fields[1] 35 | } 36 | 37 | //ips, err := net.LookupHost(host) 38 | ips, err := ipFilter(host) 39 | 40 | if err != nil { 41 | // TODO:: 记录日志 42 | fmt.Println(err) 43 | return nil, "", err 44 | } 45 | 46 | return ips, mask, nil 47 | } 48 | 49 | // ParseIPv4 把ipv4地址解析为整数 50 | func ParseIPv4(ipstr string) (uint64, error) { 51 | 52 | ip := big.NewInt(0) 53 | tmp := net.ParseIP(ipstr).To4() 54 | if tmp == nil { 55 | return 0, errors.New("Wrong ip addr") 56 | } 57 | ip.SetBytes(tmp) 58 | 59 | return ip.Uint64(), nil 60 | } 61 | 62 | // UnParseIPv4 把整数解析成ip地址 63 | func UnParseIPv4(ip uint64) string { 64 | return fmt.Sprintf("%d.%d.%d.%d", byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip)) 65 | } 66 | 67 | func IsIP(ip string) (b bool) { 68 | if m, _ := regexp.MatchString("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}/{0,1}[0-9]{0,2}$", ip); !m { 69 | return false 70 | } 71 | 72 | return true 73 | } 74 | 75 | func IsIPRange(ip string) (b bool) { 76 | if m, _ := regexp.MatchString("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}-[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$", ip); !m { 77 | return false 78 | } 79 | 80 | return true 81 | } 82 | 83 | func CidrParse(cidr string) ([]string, error) { 84 | ip, ipnet, err := net.ParseCIDR(cidr) 85 | if err != nil { 86 | return nil, err 87 | } 88 | 89 | var ips = make([]string, 0, 100) 90 | for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) { 91 | ips = append(ips, ip.String()) 92 | } 93 | // remove network address and broadcast address 94 | return ips[1 : len(ips)-1], nil 95 | } 96 | 97 | func inc(ip net.IP) { 98 | for j := len(ip) - 1; j >= 0; j-- { 99 | ip[j]++ 100 | if ip[j] > 0 { 101 | break 102 | } 103 | } 104 | } 105 | 106 | // exclude ipv6 addr 107 | func ipFilter(host string) ([]string, error) { 108 | tmp := make([]string, 0, 50) 109 | 110 | ips, err := net.LookupHost(host) 111 | if err != nil { 112 | return nil, err 113 | } 114 | 115 | for _, ip := range ips { 116 | if IsIP(ip) { 117 | tmp = append(tmp, ip) 118 | } 119 | } 120 | 121 | return tmp, nil 122 | } 123 | -------------------------------------------------------------------------------- /pkg/Plugins/ftp.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | 8 | "github.com/redtoolskobe/scaninfo/global" 9 | "go.uber.org/zap" 10 | 11 | "github.com/redtoolskobe/scaninfo/model" 12 | 13 | "github.com/jlaffaye/ftp" 14 | "github.com/redtoolskobe/scaninfo/pkg/common" 15 | "github.com/redtoolskobe/scaninfo/pkg/options" 16 | ) 17 | 18 | func FtpScan(info *options.HostInfo) (tmperr error) { 19 | starttime := time.Now().Unix() 20 | flag, err := FtpConn(info, "anonymous", "") 21 | if flag == true && err == nil { 22 | return err 23 | } else { 24 | errlog := fmt.Sprintf("[-] ftp://%v:%v %v %v", info.Host, info.Ports, "anonymous", err) 25 | common.LogError(errlog) 26 | tmperr = err 27 | if common.CheckErrs(err) { 28 | return err 29 | } 30 | } 31 | 32 | for _, user := range info.Userdict["ftp"] { 33 | for _, pass := range info.Passwords { 34 | pass = strings.Replace(pass, "{user}", user, -1) 35 | flag, err := FtpConn(info, user, pass) 36 | if flag == true && err == nil { 37 | return err 38 | } else { 39 | errlog := fmt.Sprintf("[-] ftp://%v:%v %v %v %v", info.Host, info.Ports, user, pass, err) 40 | common.LogError(errlog) 41 | tmperr = err 42 | if common.CheckErrs(err) { 43 | return err 44 | } 45 | if time.Now().Unix()-starttime > (int64(len(info.Userdict["ftp"])*len(info.Passwords)) * info.Timeout) { 46 | return err 47 | } 48 | } 49 | } 50 | } 51 | return tmperr 52 | } 53 | 54 | func FtpConn(info *options.HostInfo, user string, pass string) (flag bool, err error) { 55 | flag = false 56 | Host, Port, Username, Password := info.Host, info.Ports, user, pass 57 | conn, err := ftp.DialTimeout(fmt.Sprintf("%v:%v", Host, Port), time.Duration(info.Timeout)*time.Second) 58 | if err == nil { 59 | err = conn.Login(Username, Password) 60 | if err == nil { 61 | flag = true 62 | result := fmt.Sprintf("[+] ftp://%v:%v:%v %v", Host, Port, Username, Password) 63 | dirs, err := conn.List("") 64 | //defer conn.Logout() 65 | if err == nil { 66 | if len(dirs) > 0 { 67 | for i := 0; i < len(dirs); i++ { 68 | if len(dirs[i].Name) > 50 { 69 | result += "\n [->]" + dirs[i].Name[:50] 70 | } else { 71 | result += "\n [->]" + dirs[i].Name 72 | } 73 | if i == 5 { 74 | break 75 | } 76 | } 77 | } 78 | } 79 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "ftp", Result: result, Host: info.Host, Passwd: pass, Username: user}}} 80 | common.LogSuccess(&res) 81 | global.Log.Warn("weak_passwd", zap.String("ftp", "ftp"), zap.String("host", info.Host), 82 | zap.String("password", pass), zap.String("username", user)) 83 | model.WeakPasswdList = append(model.WeakPasswdList, model.WeakPasswd{"ftp", result, info.Host, info.Ports, pass, user}) 84 | } 85 | } 86 | return flag, err 87 | } 88 | -------------------------------------------------------------------------------- /finger/lib/chinese/chinese.go: -------------------------------------------------------------------------------- 1 | package chinese 2 | 3 | import ( 4 | "unicode/utf8" 5 | 6 | "golang.org/x/text/encoding/simplifiedchinese" 7 | ) 8 | 9 | func ByteToGBK(strBuf []byte) []byte { 10 | if isUtf8(strBuf) { 11 | if GBKBuf, err := simplifiedchinese.GBK.NewEncoder().Bytes(strBuf); err == nil { 12 | if isUtf8(GBKBuf) { 13 | return GBKBuf 14 | } 15 | } 16 | if GB18030Buf, err := simplifiedchinese.GB18030.NewEncoder().Bytes(strBuf); err == nil { 17 | if isUtf8(GB18030Buf) { 18 | return GB18030Buf 19 | } 20 | } 21 | //if HZGB2312Buf, err := simplifiedchinese.HZGB2312.NewEncoder().Bytes(strBuf); err == nil { 22 | // if isUtf8(HZGB2312Buf) { 23 | // return HZGB2312Buf 24 | // } 25 | //} 26 | return strBuf 27 | } else { 28 | return strBuf 29 | } 30 | } 31 | 32 | func ByteToUTF8(strBuf []byte) []byte { 33 | if isUtf8(strBuf) { 34 | return strBuf 35 | } else { 36 | if GBKBuf, err := simplifiedchinese.GBK.NewDecoder().Bytes(strBuf); err == nil { 37 | if isUtf8(GBKBuf) { 38 | return GBKBuf 39 | } 40 | } 41 | if GB18030Buf, err := simplifiedchinese.GB18030.NewDecoder().Bytes(strBuf); err == nil { 42 | if isUtf8(GB18030Buf) { 43 | return GB18030Buf 44 | } 45 | } 46 | //if HZGB2312Buf, err := simplifiedchinese.HZGB2312.NewDecoder().Bytes(strBuf); err == nil { 47 | // fmt.Println("3") 48 | // if isUtf8(HZGB2312Buf) { 49 | // return HZGB2312Buf 50 | // } 51 | //} 52 | return strBuf 53 | } 54 | } 55 | 56 | func ToGBK(str string) string { 57 | strBuf := []byte(str) 58 | GBKBuf := ByteToGBK(strBuf) 59 | return string(GBKBuf) 60 | 61 | } 62 | 63 | func ToUTF8(str string) string { 64 | strBuf := []byte(str) 65 | Utf8Buf := ByteToUTF8(strBuf) 66 | return string(Utf8Buf) 67 | } 68 | 69 | func isUtf8(buf []byte) bool { 70 | return utf8.Valid(buf) 71 | } 72 | 73 | //func isUtf8_old(data []byte) bool { 74 | // defer func() { 75 | // if e := recover(); e != nil { 76 | // } 77 | // }() 78 | // for i := 0; i < len(data); { 79 | // if data[i]&0x80 == 0x00 { 80 | // // 0XXX_XXXX 81 | // i++ 82 | // continue 83 | // } else if num := preNUm(data[i]); num > 2 { 84 | // // 110X_XXXX 10XX_XXXX 85 | // // 1110_XXXX 10XX_XXXX 10XX_XXXX 86 | // // 1111_0XXX 10XX_XXXX 10XX_XXXX 10XX_XXXX 87 | // // 1111_10XX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX 88 | // // 1111_110X 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX 89 | // // preNUm() 返回首个字节的8个bits中首个0bit前面1bit的个数,该数量也是该字符所使用的字节数 90 | // i++ 91 | // for j := 0; j < num-1; j++ { 92 | // //判断后面的 num - 1 个字节是不是都是10开头 93 | // if data[i]&0xc0 != 0x80 { 94 | // return false 95 | // } 96 | // i++ 97 | // } 98 | // } else { 99 | // //其他情况说明不是utf-8 100 | // return false 101 | // } 102 | // } 103 | // return true 104 | //} 105 | 106 | //func preNUm(data byte) int { 107 | // str := fmt.Sprintf("%b", data) 108 | // var i = 0 109 | // for i < len(str) { 110 | // if str[i] != '1' { 111 | // break 112 | // } 113 | // i++ 114 | // } 115 | // return i 116 | //} 117 | -------------------------------------------------------------------------------- /run/scan.go: -------------------------------------------------------------------------------- 1 | package run 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "os/signal" 8 | 9 | "github.com/redtoolskobe/scaninfo/imcp" 10 | 11 | "github.com/redtoolskobe/scaninfo/utils" 12 | 13 | "github.com/redtoolskobe/scaninfo/pkg/common" 14 | 15 | "github.com/redtoolskobe/scaninfo/model" 16 | 17 | "github.com/redtoolskobe/scaninfo/pkg/output" 18 | 19 | "github.com/redtoolskobe/scaninfo/pkg/report" 20 | 21 | "github.com/redtoolskobe/scaninfo/pkg/options" 22 | 23 | "github.com/pterm/pterm" 24 | ps "github.com/redtoolskobe/scaninfo/pkg/common/ipparser" 25 | "github.com/redtoolskobe/scaninfo/port/runner" 26 | "github.com/redtoolskobe/scaninfo/scanvul/cmd" 27 | ) 28 | 29 | func Start(ctx context.Context) { 30 | go Finderlist() 31 | option := common.NewDefaultOptions() 32 | engine := runner.CreateEngine(option) 33 | // 命令行参数错误 34 | if err := engine.Parser(); err != nil { 35 | fmt.Println(err) 36 | } 37 | //获得IP 38 | for _, ipnum := range engine.TaskIps { 39 | for ips := ipnum.Begin; ips <= ipnum.End; ips++ { 40 | ip := ps.UnParseIPv4(ips) 41 | engine.Options.IpList = append(engine.Options.IpList, ip) 42 | } 43 | } 44 | //判断端口扫描是否只针对icmp存活主机 45 | if common.Noping == false { 46 | engine.Options.IpList = imcp.ICMPRun(engine.Options.IpList, false) 47 | } 48 | report.IcmpReport(common.Rstfile+".xlsx", engine.Options.IpList) 49 | if common.Method == "ping" { 50 | return 51 | } 52 | engine.Ctx = ctx 53 | //端口扫描与服务识别 54 | pterm.Info.Println("正在进行端口探测... (请等待)") 55 | engine.Run() 56 | spinnerSuccess, _ := pterm.DefaultSpinner.Start("整理端口扫描结果") 57 | select { 58 | case <-ctx.Done(): 59 | pterm.Success.Println("父线程已经退去") 60 | default: 61 | engine.Wg.Wait() 62 | if engine.Writer != nil { 63 | } 64 | } 65 | spinnerSuccess.Success() 66 | //engine.Bar.Stop() 67 | pterm.Success.Println(fmt.Sprintf("端口服探测完成,发现端口数量为【%d】条", len(engine.PortServiceList))) 68 | if common.Method == "port" { 69 | report.Port(common.Rstfile+".xlsx", output.PortList) 70 | return 71 | } 72 | //漏洞扫描 73 | scanvul := options.NewDefaultScanVul(utils.GetUrlList(common.UrlFile)) 74 | pterm.Info.Println("开始进行漏洞和web指纹扫描") 75 | scanvul.ServicePortList = engine.PortServiceList 76 | VulEngine := cmd.NewScanEngine(scanvul) 77 | VulEngine.Scan() 78 | VulEngine.Bar.Stop() 79 | report.Port(common.Rstfile+".xlsx", output.PortList) 80 | report.WebFingerReport(common.Rstfile+".xlsx", model.WebFingerList) 81 | report.WeakPasswordReport(common.Rstfile+".xlsx", model.WeakPasswdList) 82 | report.PluginReport(common.Rstfile+".xlsx", model.PluginList) 83 | pterm.Success.Println("漏洞和指纹扫描已经结束") 84 | //指纹扫描 85 | } 86 | 87 | //control+c 退出的时候保存端口扫描结果和指纹扫描结果 88 | func Finderlist() { 89 | sigChan := make(chan os.Signal) 90 | signal.Notify(sigChan, os.Interrupt) 91 | select { 92 | case sig := <-sigChan: 93 | pterm.Warning.Println("退去之前将自动保存现有的结果:", sig) 94 | //fmt.Println(model.ResultReport) 95 | report.Port(common.Rstfile+".xlsx", output.PortList) 96 | report.WebFingerReport(common.Rstfile+".xlsx", model.WebFingerList) 97 | report.WeakPasswordReport(common.Rstfile+".xlsx", model.WeakPasswdList) 98 | report.PluginReport(common.Rstfile+".xlsx", model.PluginList) 99 | os.Exit(0) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /finger/gonmap/type-httpfinger.go: -------------------------------------------------------------------------------- 1 | package gonmap 2 | 3 | import ( 4 | "crypto/x509" 5 | "io" 6 | "io/ioutil" 7 | "net/http" 8 | 9 | "github.com/redtoolskobe/scaninfo/model" 10 | 11 | "github.com/redtoolskobe/scaninfo/finger/lib/httpfinger" 12 | "github.com/redtoolskobe/scaninfo/finger/lib/iconhash" 13 | "github.com/redtoolskobe/scaninfo/finger/lib/misc" 14 | "github.com/redtoolskobe/scaninfo/finger/lib/shttp" 15 | 16 | "github.com/PuerkitoBio/goquery" 17 | "github.com/redtoolskobe/scaninfo/finger/urlparse" 18 | ) 19 | 20 | type HttpFinger struct { 21 | URL *urlparse.URL 22 | StatusCode int 23 | Response string 24 | ResponseDigest string 25 | Title string 26 | Header string 27 | HeaderDigest string 28 | HashFinger string 29 | KeywordFinger string 30 | PeerCertificates *x509.Certificate 31 | Length int 32 | Websitle string 33 | Favicons *[]model.Fingers 34 | Keywords *[]model.Fingers 35 | } 36 | 37 | func NewHttpFinger(url *urlparse.URL, k *[]model.Fingers, f *[]model.Fingers) *HttpFinger { 38 | return &HttpFinger{ 39 | URL: url, 40 | Websitle: "", 41 | StatusCode: 0, 42 | Response: "", 43 | ResponseDigest: "", 44 | Title: "", 45 | Length: 0, 46 | Header: "", 47 | HashFinger: "", 48 | KeywordFinger: "", 49 | PeerCertificates: nil, 50 | Keywords: k, 51 | Favicons: f, 52 | } 53 | } 54 | func (h *HttpFinger) LoadHttpResponse(url *urlparse.URL, resp *http.Response) { 55 | h.Title = getTitle(shttp.GetBody(resp)) 56 | h.StatusCode = resp.StatusCode 57 | h.Header = getHeader(resp.Header.Clone()) 58 | h.Length = len(getResponse(shttp.GetBody(resp))) 59 | h.HeaderDigest = getHeaderDigest(resp.Header.Clone()) 60 | h.Response = getResponse(shttp.GetBody(resp)) 61 | h.HashFinger = GetFingerByHash(*url, *h.Favicons) 62 | h.KeywordFinger = GetFingerByKeyword(h.Header, h.Title, h.Response, *h.Keywords) 63 | _ = resp.Body.Close() 64 | } 65 | 66 | func getTitle(resp io.Reader) string { 67 | query, err := goquery.NewDocumentFromReader(resp) 68 | if err != nil { 69 | //fmt.Println(err.Error()) 70 | return "" 71 | } 72 | result := query.Find("title").Text() 73 | result = misc.FixLine(result) 74 | //Body.Close() 75 | return result 76 | } 77 | 78 | func getHeader(header http.Header) string { 79 | return shttp.Header2String(header) 80 | } 81 | 82 | func getResponse(resp io.Reader) string { 83 | body, err := ioutil.ReadAll(resp) 84 | if err != nil { 85 | //fmt.Println(err.Error()) 86 | return "" 87 | } 88 | bodyStr := string(body) 89 | return bodyStr 90 | } 91 | 92 | func getHeaderDigest(header http.Header) string { 93 | if header.Get("SERVER") != "" { 94 | return "server:" + header.Get("SERVER") 95 | } 96 | return "" 97 | } 98 | 99 | func GetFingerByKeyword(header string, title string, body string, k []model.Fingers) string { 100 | run := httpfinger.Keywords{k} 101 | return run.Match(header, title, body) 102 | } 103 | 104 | func GetFingerByHash(url urlparse.URL, f []model.Fingers) string { 105 | resp, err := shttp.GetFavicon(url) 106 | if err != nil { 107 | //fmt.Println(err.Error()) 108 | return "" 109 | } 110 | if resp.StatusCode != 200 { 111 | return "" 112 | } 113 | hash, err := iconhash.Get(resp.Body) 114 | if err != nil { 115 | return "" 116 | } 117 | _ = resp.Body.Close() 118 | run := httpfinger.Favicons{f} 119 | return run.Match(hash) 120 | } 121 | 122 | func (h *HttpFinger) LoadCert(resp *http.Response) { 123 | if resp.TLS != nil { 124 | h.PeerCertificates = resp.TLS.PeerCertificates[0] 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /scanvul/cmd/ScanVul.TXT: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "sync" 9 | 10 | "github.com/redtoolskobe/scaninfo/Plugins" 11 | "github.com/redtoolskobe/scaninfo/port/pkg/output" 12 | 13 | "github.com/redtoolskobe/scaninfo/scanvul/common" 14 | 15 | "github.com/redtoolskobe/scaninfo/options" 16 | ) 17 | 18 | type ScanEngine struct { 19 | ServiceList []string //要扫描的服务列表 20 | ScanService string //扫描的服务类型 21 | Options *options.ScanVul //扫描的一些选项 22 | } 23 | 24 | func NewScanEngine(options *options.ScanVul) *ScanEngine { 25 | return &ScanEngine{ 26 | ServiceList: common.ServiceList, 27 | Options: options, 28 | ScanService: "all", 29 | } 30 | } 31 | 32 | func (s *ScanEngine) Scan() { 33 | var ch = make(chan struct{}, 1000) 34 | var wg = sync.WaitGroup{} 35 | for _, service := range s.Options.ServicePortList { 36 | s.Options.Info.Ports = strconv.FormatUint(service.Port, 10) 37 | s.Options.Info.Host = service.Ip 38 | s.Options.Info.Url = service.Info.Url 39 | s.ScanService = "mysql" 40 | if s.ScanService == "all" { 41 | switch { 42 | case service.Info.Service == "smb": 43 | //AddScan(info.Ports, info, ch, &wg) //smb 44 | s.AddScan("1000001", s.Options.Info, ch, &wg) //ms17010 45 | s.AddScan("1000002", s.Options.Info, ch, &wg) //smbghost 46 | case service.Info.Url != "": 47 | s.AddScan("1000003", s.Options.Info, ch, &wg) //http 48 | case IsContain(s.ServiceList, service.Info.Service): 49 | s.AddScan(service.Info.Service, s.Options.Info, ch, &wg) //plugins scan 50 | default: 51 | } 52 | } else { 53 | s.AddScan(s.ScanService, s.Options.Info, ch, &wg) 54 | } 55 | } 56 | wg.Wait() 57 | common.LogWG.Wait() 58 | 59 | } 60 | 61 | func (s *ScanEngine) AddScan(service string, info options.HostInfo, ch chan struct{}, wg *sync.WaitGroup) { 62 | wg.Add(1) 63 | go func() { 64 | scanfun(Plugins.PluginList, service, &info) 65 | wg.Done() 66 | <-ch 67 | fmt.Println("一个扫描任务结束") 68 | }() 69 | ch <- struct{}{} 70 | } 71 | 72 | func scanfun(m map[string]interface{}, name string, infos ...interface{}) (result []reflect.Value, err error) { 73 | f := reflect.ValueOf(m[name]) 74 | if len(infos) != f.Type().NumIn() { 75 | err = errors.New("The number of infos is not adapted ") 76 | fmt.Println(err.Error()) 77 | return result, nil 78 | } 79 | in := make([]reflect.Value, len(infos)) 80 | for k, info := range infos { 81 | in[k] = reflect.ValueOf(info) 82 | } 83 | result = f.Call(in) 84 | return result, nil 85 | } 86 | 87 | func IsContain(items []string, item string) bool { 88 | for _, eachItem := range items { 89 | if eachItem == item { 90 | return true 91 | } 92 | } 93 | return false 94 | } 95 | 96 | func GetTaskList(servicelist []*output.ResultEvent) map[string][]options.HostInfo { 97 | task := map[string][]options.HostInfo{} 98 | for _, service := range servicelist { 99 | switch { 100 | case service.Port == 445: 101 | task["1000001"] = append(task["1000001"], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10)}) 102 | task["1000002"] = append(task["1000002"], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10)}) 103 | case service.Info.Url != "": 104 | task["1000003"] = append(task["1000003"], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10), Url: service.Info.Url}) 105 | case IsContain(common.ServiceList, service.Info.Service): 106 | task[service.Info.Service] = append(task[service.Info.Service], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10)}) 107 | default: 108 | } 109 | } 110 | return task 111 | } 112 | -------------------------------------------------------------------------------- /pkg/Plugins/ssh.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io/ioutil" 7 | "net" 8 | "strings" 9 | "time" 10 | 11 | "github.com/redtoolskobe/scaninfo/global" 12 | "go.uber.org/zap" 13 | 14 | "github.com/redtoolskobe/scaninfo/model" 15 | 16 | "github.com/redtoolskobe/scaninfo/pkg/common" 17 | "github.com/redtoolskobe/scaninfo/pkg/options" 18 | "golang.org/x/crypto/ssh" 19 | ) 20 | 21 | func SshScan(info *options.HostInfo) (tmperr error) { 22 | starttime := time.Now().Unix() 23 | for _, user := range info.Userdict["ssh"] { 24 | for _, pass := range info.Passwords { 25 | pass = strings.Replace(pass, "{user}", user, -1) 26 | flag, err := SshConn(info, user, pass) 27 | if flag == true && err == nil { 28 | return err 29 | } else { 30 | errlog := fmt.Sprintf("[-] ssh %v:%v %v %v %v", info.Host, info.Ports, user, pass, err) 31 | common.LogError(errlog) 32 | tmperr = err 33 | if common.CheckErrs(err) { 34 | return err 35 | } 36 | if time.Now().Unix()-starttime > (int64(len(info.Userdict["ssh"])*len(info.Passwords)) * info.Timeout) { 37 | return err 38 | } 39 | } 40 | if info.SshKey != "" { 41 | return err 42 | } 43 | } 44 | } 45 | return tmperr 46 | } 47 | 48 | func SshConn(info *options.HostInfo, user string, pass string) (flag bool, err error) { 49 | flag = false 50 | Host, Port, Username, Password := info.Host, info.Ports, user, pass 51 | Auth := []ssh.AuthMethod{} 52 | if info.SshKey != "" { 53 | pemBytes, err := ioutil.ReadFile(info.SshKey) 54 | if err != nil { 55 | return false, errors.New("read key failed" + err.Error()) 56 | } 57 | signer, err := ssh.ParsePrivateKey(pemBytes) 58 | if err != nil { 59 | return false, errors.New("parse key failed" + err.Error()) 60 | } 61 | Auth = []ssh.AuthMethod{ssh.PublicKeys(signer)} 62 | } else { 63 | Auth = []ssh.AuthMethod{ssh.Password(Password)} 64 | } 65 | 66 | config := &ssh.ClientConfig{ 67 | User: Username, 68 | Auth: Auth, 69 | Timeout: time.Duration(info.Timeout) * time.Second, 70 | HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { 71 | return nil 72 | }, 73 | } 74 | 75 | client, err := ssh.Dial("tcp", fmt.Sprintf("%v:%v", Host, Port), config) 76 | if err == nil { 77 | defer client.Close() 78 | session, err := client.NewSession() 79 | if err == nil { 80 | defer session.Close() 81 | flag = true 82 | var result string 83 | if info.Command != "" { 84 | combo, _ := session.CombinedOutput(info.Command) 85 | result = fmt.Sprintf("[+] SSH:%v:%v:%v %v \n %v", Host, Port, Username, Password, string(combo)) 86 | if info.SshKey != "" { 87 | result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct \n %v", Host, Port, string(combo)) 88 | } 89 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "ssh", Result: result, Host: info.Host, Passwd: pass, Username: user}}} 90 | common.LogSuccess(&res) 91 | } else { 92 | result = fmt.Sprintf("[+] SSH:%v:%v:%v %v", Host, Port, Username, Password) 93 | if info.SshKey != "" { 94 | result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct", Host, Port) 95 | } 96 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "ssh", Result: result, Host: info.Host, Passwd: pass, Username: user}}} 97 | common.LogSuccess(&res) 98 | global.Log.Warn("weak_passwd", zap.String("ssh", "ssh"), zap.String("host", info.Host), 99 | zap.String("password", pass), zap.String("username", Username)) 100 | model.WeakPasswdList = append(model.WeakPasswdList, model.WeakPasswd{"ssh", result, info.Host, info.Ports, pass, user}) 101 | } 102 | } 103 | } 104 | return flag, err 105 | 106 | } 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

scaninfo by 华东360安服团队

2 | 3 | 开源、轻量、快速、跨平台 的红队内外网打点扫描器 4 | 5 | ![](https://img.shields.io/badge/ReaTeam-%E6%AD%A6%E5%99%A8%E5%BA%93-red) ![](https://img.shields.io/badge/license-GPL--3.0-orange) ![](https://img.shields.io/badge/version-1.1.0-brightgreen) ![](https://img.shields.io/badge/author-kb24-blueviolet) 6 | 7 | 8 | ## 注意的点 9 | 10 | - 漏洞扫描的时候有时候最后几个任务会卡住,是因为ftp爆破模块,这个fscan也一样目前没有好的解决办法,后续更新.先阶段可以-eq 21跳过ftp,或者control+c 主动停止不影响结果保存。 11 | - 有时候扫外网的全端口会漏掉端口可以使用-n 指定线程为500,400,默认为900.网络好的话900-1000都是没有问题 12 | - 关于结果报告 xlsx 文件是当你control+c 主动停止或任务正常结束时才会写入。txt文件是实时写入。 13 | 14 | 15 | ## 项目说明 16 | 17 | > 为何有这个项目 18 | 19 | 在渗透测试的端口扫描阶段,相信很多人遇到的问题是nmap太慢,masscan不准确。难以在速度与准确度之间寻找一个平衡。 其实有个工具不错就是[TXPortMap](https://github.com/4dogs-cn/TXPortMap)。但是没有进度条当大量扫描的时候结果处理也太友好。 20 | 21 | 在内网这块[fscan](https://github.com/shadow1ng/fscan)算是一款很优秀的工具但也有一些问题,如端口扫描不支持服务识别等。 22 | 23 | 指纹这块[EHole](https://github.com/EdgeSecurityTeam/EHole)也算一款很优秀的工具 24 | 25 | ## 如何解决这个问题 26 | 27 | - scaninfo 专门解决上述问题并对上述项目代码进行了优化与重构,快速的端口扫描和服务识别比masscan更快。 28 | 29 | - 包含fscan的绝大部份功能除了poc扫描和自定义字典 30 | 31 | - 更好的web探测与指纹识别 32 | 33 | - 更好的报告输出 34 | 35 | ## 使用说明 36 | 37 | ![image-20211105132301924](./infoscan.assets/image-20211105132301924.png) 38 | 39 | > 常见的参数 40 | 41 | ```shell 42 | scaninfo -uf url.txt -m webfinger web指纹识别 43 | ``` 44 | 45 | ```shell 46 | scaninfo -i 192.168.0.0/24 -p 1-65535 -eq 53 -m port 端口扫描 47 | ``` 48 | 49 | ```shell 50 | scaninfo -i 192.168.0.0/24 -l ip.txt -uf url.txt -t1000 可以组合各种目标ip段ip文件url文件 51 | ``` 52 | 53 | ## 报告 54 | 55 | > 报告主要是直观的excel并对每一种类型进行分类。同时也会生成txt json格式的结果。 56 | 57 | ![image-20211105134827966](./infoscan.assets/image-20211105134827966.png) 58 | 59 | ![image-20211105134954709](./infoscan.assets/image-20211105134954709.png) 60 | 61 | ## 参数 62 | 63 | > 主要参数 64 | 65 | | 参数 | 说明 | 66 | | ----- | -------------------------------- | 67 | | -ei | 排除某IP | 68 | | -eq | 排除某端口 | 69 | | -l | 指定IP文件 | 70 | | -uf | 指定要web指纹识别的url文件 | 71 | | -ff | 指定指纹文件默认使用内置 | 72 | | -o | 指定保存的结果文件默认为result | 73 | | -p | 指定端口默认使用top100 | 74 | | -m | 指定扫描的模块默认为全部 | 75 | | -pt | 指定ping 探测存活的线程 | 76 | | -vt | 指定web指纹扫描的线程默认500 | 77 | | -n | 指定端口扫描的线程默认900 | 78 | | -show | 查看扫描支持的模块 | 79 | | -t | 端口扫描tcp连接的超时时间默认0.5 | 80 | | -np | 跳过存活探测 | 81 | 82 | > 模块说明 83 | 84 | | 模块 | 说明 | 85 | | --------- | ----------------------------------- | 86 | | ftp | ftp弱口令探测 | 87 | | ssh | ssh弱口令探测 | 88 | | smb | smb弱口令探测 | 89 | | mssql | mssql弱口令探测 | 90 | | mysql | mysql弱口令探测 | 91 | | mgo | mongodb弱口令探测 | 92 | | redis | redis弱口令探测 | 93 | | psql | psql弱口令探测 | 94 | | ms17010 | ms17010探测 | 95 | | smbghost | smbghost探测 | 96 | | webfinger | web指纹识别 | 97 | | netbios | netbios探测,可以识别主机名发现域控 | 98 | | findnet | oxid | 99 | | all | 所有 | 100 | | port | 端口扫描 | 101 | | ping | ping 存活 | 102 | | mem | memcached弱口令 | 103 | 104 | 105 | 106 | ## 感谢! 107 | 108 | 棱角团队 109 | 110 | https://github.com/EdgeSecurityTeam/EHole 111 | 112 | https://github.com/shadow1ng/fscan 113 | 114 | https://github.com/4dogs-cn/TXPortMap 115 | 116 | 117 | 118 | ## 最后 119 | 120 | 欢迎小伙伴们加入我们的知识星球。 121 | 122 | ![image-20211105140236732](./infoscan.assets/image-20211105140236732.png) 123 | -------------------------------------------------------------------------------- /pkg/report/report.go: -------------------------------------------------------------------------------- 1 | package report 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/redtoolskobe/scaninfo/model" 8 | 9 | "github.com/redtoolskobe/scaninfo/pkg/output" 10 | "github.com/xuri/excelize/v2" 11 | ) 12 | 13 | func IcmpReport(filename string, iplist []string) { 14 | categories := map[string]string{ 15 | "A1": "IP地址"} 16 | f := excelize.NewFile() 17 | index := f.NewSheet("IP地址") 18 | for k, v := range categories { 19 | f.SetCellValue("IP地址", k, v) 20 | } 21 | f.SetActiveSheet(index) 22 | for k, info := range iplist { 23 | f.SetSheetRow("IP地址", fmt.Sprint("A", k+2), &[]string{info}) 24 | } 25 | // Save spreadsheet by the given path. 26 | if err := f.SaveAs(filename); err != nil { 27 | fmt.Println(err) 28 | } 29 | } 30 | 31 | func Port(filename string, portlist []*output.ResultEvent) { 32 | categories := map[string]string{ 33 | "A1": "IP地址", "B1": "端口", "C1": "服务", "D1": "banner", "E1": "Url", "F1": "证书"} 34 | f, err := excelize.OpenFile(filename) 35 | if err != nil { 36 | fmt.Println("打开错误") 37 | return 38 | } 39 | index := f.NewSheet("端口服务") 40 | for k, v := range categories { 41 | f.SetCellValue("端口服务", k, v) 42 | } 43 | f.SetActiveSheet(index) 44 | for k, info := range portlist { 45 | f.SetSheetRow("端口服务", fmt.Sprint("A", k+2), &[]string{info.Ip, strconv.FormatUint(info.Port, 10), 46 | info.Info.Service, info.Info.Banner, info.Info.Url, info.Info.Cert}) 47 | } 48 | // Save spreadsheet by the given path. 49 | if err := f.SaveAs(filename); err != nil { 50 | fmt.Println(err) 51 | } 52 | } 53 | 54 | func WebFingerReport(filename string, webfingerlist []model.WebFinger) { 55 | categories := map[string]string{ 56 | "A1": "web地址", "B1": "状态码", "C1": "头部信息", "D1": "返回长度", "E1": "标题", "F1": "关键字指纹", "G1": "Hash指纹"} 57 | f, err := excelize.OpenFile(filename) 58 | if err != nil { 59 | fmt.Println("打开错误") 60 | return 61 | } 62 | index := f.NewSheet("web指纹") 63 | for k, v := range categories { 64 | f.SetCellValue("web指纹", k, v) 65 | } 66 | f.SetActiveSheet(index) 67 | for k, info := range webfingerlist { 68 | f.SetSheetRow("web指纹", fmt.Sprint("A", k+2), &[]string{info.Websitle, strconv.Itoa(info.StatusCode), 69 | info.HeaderDigest, strconv.Itoa(info.Length), info.Title, info.KeywordFinger, info.HashFinger}) 70 | } 71 | // Save spreadsheet by the given path. 72 | if err := f.SaveAs(filename); err != nil { 73 | fmt.Println(err) 74 | } 75 | } 76 | func PluginReport(filename string, plugin []model.Plugin) { 77 | categories := map[string]string{ 78 | "A1": "IP地址", "B1": "端口", "C1": "类型", "D1": "结果"} 79 | f, err := excelize.OpenFile(filename) 80 | if err != nil { 81 | fmt.Println("打开错误") 82 | return 83 | } 84 | index := f.NewSheet("插件漏洞") 85 | for k, v := range categories { 86 | f.SetCellValue("插件漏洞", k, v) 87 | } 88 | f.SetActiveSheet(index) 89 | for k, info := range plugin { 90 | f.SetSheetRow("插件漏洞", fmt.Sprint("A", k+2), &[]string{info.Host, info.Port, 91 | info.Type, info.Result}) 92 | } 93 | // Save spreadsheet by the given path. 94 | if err := f.SaveAs(filename); err != nil { 95 | fmt.Println(err) 96 | } 97 | } 98 | func WeakPasswordReport(filename string, weakpass []model.WeakPasswd) { 99 | categories := map[string]string{ 100 | "A1": "IP地址", "B1": "端口", "C1": "类型", "D1": "账号", "E1": "密码", "F1": "结果"} 101 | f, err := excelize.OpenFile(filename) 102 | if err != nil { 103 | fmt.Println("打开错误") 104 | return 105 | } 106 | index := f.NewSheet("弱口令") 107 | for k, v := range categories { 108 | f.SetCellValue("弱口令", k, v) 109 | } 110 | f.SetActiveSheet(index) 111 | for k, info := range weakpass { 112 | f.SetSheetRow("弱口令", fmt.Sprint("A", k+2), &[]string{info.Host, info.Port, 113 | info.Type, info.Username, info.Passwd, info.Result}) 114 | } 115 | // Save spreadsheet by the given path. 116 | if err := f.SaveAs(filename); err != nil { 117 | fmt.Println(err) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /pkg/Plugins/CVE-2020-0796.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "net" 7 | "time" 8 | 9 | "github.com/redtoolskobe/scaninfo/model" 10 | 11 | "github.com/redtoolskobe/scaninfo/global" 12 | "go.uber.org/zap" 13 | 14 | "github.com/redtoolskobe/scaninfo/pkg/options" 15 | 16 | "github.com/redtoolskobe/scaninfo/pkg/common" 17 | ) 18 | 19 | const ( 20 | pkt = "\x00" + // session 21 | "\x00\x00\xc0" + // legth 22 | 23 | "\xfeSMB@\x00" + // protocol 24 | 25 | //[MS-SMB2]: SMB2 NEGOTIATE Request 26 | //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e14db7ff-763a-4263-8b10-0c3944f52fc5 27 | 28 | "\x00\x00" + 29 | "\x00\x00" + 30 | "\x00\x00" + 31 | "\x00\x00" + 32 | "\x1f\x00" + 33 | "\x00\x00\x00\x00" + 34 | "\x00\x00\x00\x00" + 35 | "\x00\x00\x00\x00" + 36 | "\x00\x00\x00\x00" + 37 | "\x00\x00\x00\x00" + 38 | "\x00\x00\x00\x00" + 39 | "\x00\x00\x00\x00" + 40 | "\x00\x00\x00\x00" + 41 | "\x00\x00\x00\x00" + 42 | "\x00\x00\x00\x00" + 43 | "\x00\x00\x00\x00" + 44 | "\x00\x00\x00\x00" + 45 | 46 | // [MS-SMB2]: SMB2 NEGOTIATE_CONTEXT 47 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/15332256-522e-4a53-8cd7-0bd17678a2f7 48 | 49 | "$\x00" + 50 | "\x08\x00" + 51 | "\x01\x00" + 52 | "\x00\x00" + 53 | "\x7f\x00\x00\x00" + 54 | "\x00\x00\x00\x00" + 55 | "\x00\x00\x00\x00" + 56 | "\x00\x00\x00\x00" + 57 | "\x00\x00\x00\x00" + 58 | "x\x00" + 59 | "\x00\x00" + 60 | "\x02\x00" + 61 | "\x00\x00" + 62 | "\x02\x02" + 63 | "\x10\x02" + 64 | "\x22\x02" + 65 | "$\x02" + 66 | "\x00\x03" + 67 | "\x02\x03" + 68 | "\x10\x03" + 69 | "\x11\x03" + 70 | "\x00\x00\x00\x00" + 71 | 72 | // [MS-SMB2]: SMB2_PREAUTH_INTEGRITY_CAPABILITIES 73 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5a07bd66-4734-4af8-abcf-5a44ff7ee0e5 74 | 75 | "\x01\x00" + 76 | "&\x00" + 77 | "\x00\x00\x00\x00" + 78 | "\x01\x00" + 79 | "\x20\x00" + 80 | "\x01\x00" + 81 | "\x00\x00\x00\x00" + 82 | "\x00\x00\x00\x00" + 83 | "\x00\x00\x00\x00" + 84 | "\x00\x00\x00\x00" + 85 | "\x00\x00\x00\x00" + 86 | "\x00\x00\x00\x00" + 87 | "\x00\x00\x00\x00" + 88 | "\x00\x00\x00\x00" + 89 | "\x00\x00" + 90 | 91 | // [MS-SMB2]: SMB2_COMPRESSION_CAPABILITIES 92 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/78e0c942-ab41-472b-b117-4a95ebe88271 93 | 94 | "\x03\x00" + 95 | "\x0e\x00" + 96 | "\x00\x00\x00\x00" + 97 | "\x01\x00" + //CompressionAlgorithmCount 98 | "\x00\x00" + 99 | "\x01\x00\x00\x00" + 100 | "\x01\x00" + //LZNT1 101 | "\x00\x00" + 102 | "\x00\x00\x00\x00" 103 | ) 104 | 105 | func SmbGhost(info *options.HostInfo) error { 106 | err := SmbGhostScan(info) 107 | return err 108 | } 109 | 110 | func SmbGhostScan(info *options.HostInfo) error { 111 | ip, port, timeout := info.Host, 445, time.Duration(info.Timeout)*time.Second 112 | addr := fmt.Sprintf("%s:%v", info.Host, port) 113 | conn, err := net.DialTimeout("tcp", addr, timeout) 114 | if err != nil { 115 | return err 116 | } 117 | _, err = conn.Write([]byte(pkt)) 118 | if err != nil { 119 | return err 120 | } 121 | buff := make([]byte, 1024) 122 | err = conn.SetReadDeadline(time.Now().Add(timeout)) 123 | n, err := conn.Read(buff) 124 | if err != nil { 125 | return err 126 | } 127 | defer conn.Close() 128 | if bytes.Contains(buff[:n], []byte("Public")) == true { 129 | result := fmt.Sprintf("[+] %v CVE-2020-0796 SmbGhost Vulnerable", ip) 130 | res := common.VulInfo{"plugin", info.TaskID, map[string]interface{}{"type": "cve-2020-0796", "result": result, "host": info.Host, "port": port}} 131 | common.LogSuccess(&res) 132 | global.Log.Warn("plugin", zap.String("cve-2020-0796", "cve-2020-0796"), zap.String("host", info.Host), 133 | zap.Int("port", port), zap.String("result", result)) 134 | model.PluginList = append(model.PluginList, model.Plugin{"cve-2020-0796", result, info.Host, info.Ports}) 135 | } 136 | return err 137 | } 138 | -------------------------------------------------------------------------------- /pkg/Plugins/redis.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | "time" 8 | 9 | "github.com/redtoolskobe/scaninfo/global" 10 | "go.uber.org/zap" 11 | 12 | "github.com/redtoolskobe/scaninfo/model" 13 | 14 | "github.com/redtoolskobe/scaninfo/pkg/options" 15 | 16 | "github.com/redtoolskobe/scaninfo/pkg/common" 17 | ) 18 | 19 | func RedisScan(info *options.HostInfo) (tmperr error) { 20 | starttime := time.Now().Unix() 21 | flag, err := RedisUnauth(info) 22 | if flag == true && err == nil { 23 | return err 24 | } 25 | for _, pass := range info.Passwords { 26 | pass = strings.Replace(pass, "{user}", "redis", -1) 27 | flag, err := RedisConn(info, pass) 28 | if flag == true && err == nil { 29 | return err 30 | } else { 31 | errlog := fmt.Sprintf("[-] redis %v:%v %v %v", info.Host, info.Ports, pass, err) 32 | common.LogError(errlog) 33 | tmperr = err 34 | if common.CheckErrs(err) { 35 | return err 36 | } 37 | if time.Now().Unix()-starttime > (int64(len(info.Passwords)) * info.Timeout) { 38 | return err 39 | } 40 | } 41 | } 42 | return tmperr 43 | } 44 | 45 | func RedisConn(info *options.HostInfo, pass string) (flag bool, err error) { 46 | flag = false 47 | realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports) 48 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) 49 | if err != nil { 50 | return flag, err 51 | } 52 | defer conn.Close() 53 | err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second)) 54 | if err != nil { 55 | return flag, err 56 | } 57 | _, err = conn.Write([]byte(fmt.Sprintf("auth %s\r\n", pass))) 58 | if err != nil { 59 | return flag, err 60 | } 61 | reply, err := readreply(conn) 62 | if err != nil { 63 | return flag, err 64 | } 65 | if strings.Contains(reply, "+OK") { 66 | result := fmt.Sprintf("[+] Redis:%s %s", realhost, pass) 67 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "redis", Result: result, Host: info.Host, Passwd: pass, Username: ""}}} 68 | common.LogSuccess(&res) 69 | global.Log.Warn("weak_passwd", zap.String("redis", "redis"), zap.String("host", info.Host), 70 | zap.String("password", pass), zap.String("username", "")) 71 | model.WeakPasswdList = append(model.WeakPasswdList, model.WeakPasswd{"redis", result, info.Host, info.Ports, pass, ""}) 72 | flag = true 73 | } 74 | return flag, err 75 | } 76 | 77 | func RedisUnauth(info *options.HostInfo) (flag bool, err error) { 78 | flag = false 79 | realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports) 80 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) 81 | if err != nil { 82 | return flag, err 83 | } 84 | defer conn.Close() 85 | err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second)) 86 | if err != nil { 87 | return flag, err 88 | } 89 | _, err = conn.Write([]byte("info\r\n")) 90 | if err != nil { 91 | return flag, err 92 | } 93 | reply, err := readreply(conn) 94 | if err != nil { 95 | return flag, err 96 | } 97 | if strings.Contains(reply, "redis_version") { 98 | result := fmt.Sprintf("[+] Redis:%s unauthorized", realhost) 99 | res := common.VulInfo{"weak_passwd", info.TaskID, map[string]interface{}{"weak_passwd": model.WeakPasswd{Type: "redis", Result: result, Host: info.Host, Passwd: "", Username: ""}}} 100 | global.Log.Warn("weak_passwd", zap.String("redis", "redis"), zap.String("host", info.Host), 101 | zap.String("password", ""), zap.String("username", "")) 102 | common.LogSuccess(&res) 103 | model.WeakPasswdList = append(model.WeakPasswdList, model.WeakPasswd{"redis", result, info.Host, info.Ports, "", ""}) 104 | } 105 | return flag, err 106 | } 107 | 108 | func readreply(conn net.Conn) (result string, err error) { 109 | buf := make([]byte, 4096) 110 | for { 111 | count, err := conn.Read(buf) 112 | if err != nil { 113 | break 114 | } 115 | result += string(buf[0:count]) 116 | if count < 4096 { 117 | break 118 | } 119 | } 120 | return result, err 121 | } 122 | -------------------------------------------------------------------------------- /port/runner/scanner.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "strings" 8 | "sync/atomic" 9 | "time" 10 | 11 | "github.com/redtoolskobe/scaninfo/pkg/Ginfo/Ghttp" 12 | "github.com/redtoolskobe/scaninfo/pkg/common" 13 | "github.com/redtoolskobe/scaninfo/pkg/output" 14 | ) 15 | 16 | func (e *Engine) Scanner(ip string, port uint64) { 17 | atomic.AddInt64(&e.ComCount, 1) 18 | var dwSvc int 19 | var iRule = -1 20 | var bIsIdentification = false 21 | var resultEvent *output.ResultEvent 22 | var packet []byte 23 | //var iCntTimeOut = 0 24 | //fmt.Println(req, "/", Count) 25 | // 端口开放状态,发送报文,获取响应 26 | // 先判断端口是不是优先识别协议端口 27 | for _, svc := range common.St_Identification_Port { 28 | if port == svc.Port { 29 | bIsIdentification = true 30 | iRule = svc.Identification_RuleId 31 | data := common.St_Identification_Packet[iRule].Packet 32 | 33 | dwSvc, resultEvent = e.SendIdentificationPacketFunction(data, ip, port) 34 | break 35 | } 36 | } 37 | if (dwSvc > common.UNKNOWN_PORT && dwSvc <= common.SOCKET_CONNECT_FAILED) || dwSvc == common.SOCKET_READ_TIMEOUT { 38 | e.Writer.Write(resultEvent, &e.PortServiceList) 39 | return 40 | } 41 | 42 | // 发送其他协议查询包 43 | for i := 0; i < common.IPacketMask; i++ { 44 | // 超时2次,不再识别 45 | if bIsIdentification && iRule == i { 46 | continue 47 | } 48 | if i == 0 { 49 | // 说明是http,数据需要拼装一下 50 | var szOption string 51 | if port == 80 { 52 | szOption = fmt.Sprintf("%s%s\r\n\r\n", common.St_Identification_Packet[0].Packet, ip) 53 | } else { 54 | szOption = fmt.Sprintf("%s%s:%d\r\n\r\n", common.St_Identification_Packet[0].Packet, ip, port) 55 | } 56 | packet = []byte(szOption) 57 | } else { 58 | packet = common.St_Identification_Packet[i].Packet 59 | } 60 | 61 | dwSvc, resultEvent = e.SendIdentificationPacketFunction(packet, ip, port) 62 | if (dwSvc > common.UNKNOWN_PORT && dwSvc <= common.SOCKET_CONNECT_FAILED) || dwSvc == common.SOCKET_READ_TIMEOUT { 63 | e.Writer.Write(resultEvent, &e.PortServiceList) 64 | return 65 | } 66 | } 67 | // 没有识别到服务,也要输出当前开放端口状态 68 | e.Writer.Write(resultEvent, &e.PortServiceList) 69 | } 70 | 71 | func (e *Engine) SendIdentificationPacketFunction(data []byte, ip string, port uint64) (int, *output.ResultEvent) { 72 | addr := fmt.Sprintf("%s:%d", ip, port) 73 | even := &output.ResultEvent{ 74 | Target: addr, 75 | Info: &output.Info{}, 76 | Ip: ip, 77 | Port: port, 78 | } 79 | 80 | //fmt.Println(addr) 81 | var dwSvc int = common.UNKNOWN_PORT 82 | conn, err := net.DialTimeout("tcp", addr, time.Duration(e.Options.Tout*1000)*time.Millisecond) 83 | if err != nil { 84 | // 端口是closed状态 85 | return common.SOCKET_CONNECT_FAILED, nil 86 | } 87 | 88 | defer conn.Close() 89 | 90 | // Write方法是非阻塞的 91 | 92 | if _, err := conn.Write(data); err != nil { 93 | // 端口是开放的 94 | return dwSvc, even 95 | } 96 | 97 | // 直接开辟好空间,避免底层数组频繁申请内存 98 | var fingerprint = make([]byte, 0, 65535) 99 | var tmp = make([]byte, 256) 100 | // 存储读取的字节数 101 | var num int 102 | var szBan string 103 | var szSvcName string 104 | 105 | // 这里设置成6秒是因为超时的时候会重新尝试5次, 106 | 107 | readTimeout := 2 * time.Second 108 | 109 | // 设置读取的超时时间为6s 110 | conn.SetReadDeadline(time.Now().Add(readTimeout)) 111 | 112 | for { 113 | // Read是阻塞的 114 | n, err := conn.Read(tmp) 115 | if err != nil { 116 | // 虽然数据读取错误,但是端口仍然是open的 117 | // fmt.Println(err) 118 | if err != io.EOF { 119 | dwSvc = common.SOCKET_READ_TIMEOUT 120 | // fmt.Printf("Discovered open port\t%d\ton\t%s\n", port, ip) 121 | } 122 | break 123 | } 124 | 125 | if n > 0 { 126 | num += n 127 | fingerprint = append(fingerprint, tmp[:n]...) 128 | } else { 129 | // 虽然没有读取到数据,但是端口仍然是open的 130 | // fmt.Printf("Discovered open port\t%d\ton\t%s\n", port, ip) 131 | break 132 | } 133 | } 134 | // 服务识别 135 | if num > 0 { 136 | dwSvc = common.ComparePackets(fingerprint, num, &szBan, &szSvcName) 137 | //if len(szBan) > 15 { 138 | // szBan = szBan[:15] 139 | //} 140 | if dwSvc > common.UNKNOWN_PORT && dwSvc < common.SOCKET_CONNECT_FAILED { 141 | //even.WorkingEvent = "found" 142 | if szSvcName == "ssl/tls" || szSvcName == "http" { 143 | rst := Ghttp.GetHttpTitle(ip, Ghttp.HTTPorHTTPS, int(port)) 144 | even.WorkingEvent = rst 145 | even.Info.Url = rst.URL 146 | cert, err0 := Ghttp.GetCert(ip, int(port)) 147 | if err0 != nil { 148 | cert = "" 149 | } 150 | even.Info.Cert = cert 151 | } else { 152 | even.Info.Banner = strings.TrimSpace(szBan) 153 | } 154 | even.Info.Service = szSvcName 155 | even.Time = time.Now() 156 | // fmt.Printf("Discovered open port\t%d\ton\t%s\t\t%s\t\t%s\n", port, ip, szSvcName, strings.TrimSpace(szBan)) 157 | //Writer.Write(even) 158 | //return dwSvc, even 159 | } 160 | } 161 | 162 | return dwSvc, even 163 | } 164 | -------------------------------------------------------------------------------- /scanvul/cmd/ScanVul.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "sync" 9 | "sync/atomic" 10 | "time" 11 | 12 | "github.com/redtoolskobe/scaninfo/utils" 13 | 14 | "github.com/pterm/pterm" 15 | 16 | "github.com/redtoolskobe/scaninfo/pkg/Plugins" 17 | 18 | "github.com/redtoolskobe/scaninfo/pkg/common" 19 | "github.com/redtoolskobe/scaninfo/pkg/options" 20 | "github.com/redtoolskobe/scaninfo/pkg/output" 21 | ) 22 | 23 | type ScanEngine struct { 24 | ServiceList []string //要扫描的服务列表 25 | ScanType string //扫描的服务类型 26 | Options *options.ScanVul //扫描的一些选项 27 | Bar *pterm.ProgressbarPrinter 28 | Writer output.Writer 29 | Ticker *time.Ticker 30 | ComCount int64 31 | } 32 | 33 | func NewScanEngine(options *options.ScanVul) *ScanEngine { 34 | return &ScanEngine{ 35 | ServiceList: common.ScanTypeList, 36 | Options: options, 37 | ScanType: common.ScanMethodMap[common.Method], 38 | } 39 | } 40 | 41 | func (s *ScanEngine) Scan() { 42 | var Count int64 43 | var ch = make(chan struct{}, common.WebVulThreds) 44 | var wg = sync.WaitGroup{} 45 | tasklist := GetTaskList(s.Options.ServicePortList, s.ScanType, s.Options.UrlList) 46 | if tasklist == nil { 47 | return 48 | } 49 | for _, v := range tasklist { 50 | atomic.AddInt64(&Count, (int64(len(v)))) 51 | } 52 | pterm.NewRGB(15, 199, 209).Println("需要扫描的web指纹和漏洞数量为", Count) 53 | s.Bar, _ = pterm.DefaultProgressbar.WithTotal(int(Count)).WithTitle("[ScanInfo]").WithRemoveWhenDone(true).Start() 54 | for service, v := range tasklist { 55 | for _, info := range v { 56 | info.Userdict = s.Options.Info.Userdict 57 | info.Passwords = s.Options.Info.Passwords 58 | info.Timeout = s.Options.Info.Timeout 59 | s.AddScan(service, info, ch, &wg) 60 | } 61 | } 62 | 63 | wg.Wait() 64 | common.LogWG.Wait() 65 | s.Bar.Stop() 66 | } 67 | 68 | func (s *ScanEngine) AddScan(service string, info options.HostInfo, ch chan struct{}, wg *sync.WaitGroup) { 69 | wg.Add(1) 70 | go func() { 71 | scanplugin(Plugins.PluginList, service, &info) 72 | wg.Done() 73 | <-ch 74 | s.Bar.Add(1) 75 | }() 76 | ch <- struct{}{} 77 | } 78 | 79 | func scanplugin(m map[string]interface{}, name string, infos ...interface{}) (result []reflect.Value, err error) { 80 | f := reflect.ValueOf(m[name]) 81 | if len(infos) != f.Type().NumIn() { 82 | err = errors.New("The number of infos is not adapted ") 83 | //fmt.Println(err.Error()) 84 | return result, nil 85 | } 86 | in := make([]reflect.Value, len(infos)) 87 | for k, info := range infos { 88 | in[k] = reflect.ValueOf(info) 89 | } 90 | result = f.Call(in) 91 | return result, nil 92 | } 93 | 94 | func IsContain(items []string, item string) bool { 95 | for _, eachItem := range items { 96 | if eachItem == item { 97 | return true 98 | } 99 | } 100 | return false 101 | } 102 | 103 | func GetTaskList(servicelist []*output.ResultEvent, scantype string, urllist []string) map[string][]options.HostInfo { 104 | task := map[string][]options.HostInfo{} 105 | k, f, err := utils.GetFingerList(common.FingerFile) 106 | if err != nil { 107 | pterm.Warning.Println(fmt.Sprintf("指纹文件错误!已忽略web指纹扫描 %s", err.Error())) 108 | } 109 | for _, service := range servicelist { 110 | switch { 111 | case service.Port == 445: 112 | task["1000001"] = append(task["1000001"], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10)}) 113 | task["1000002"] = append(task["1000002"], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10)}) 114 | task["smb"] = append(task["smb"], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10)}) 115 | case service.Port == 135: 116 | task["findnet"] = append(task["findnet"], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10)}) 117 | case service.Port == 139: 118 | task["netbios"] = append(task["netbios"], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10)}) 119 | case service.Info.Url != "" && err == nil: 120 | task["1000003"] = append(task["1000003"], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10), Url: service.Info.Url, 121 | Favicons: &f, Keyword: &k}) 122 | case IsContain(common.ScanTypeList, service.Info.Service): 123 | task[service.Info.Service] = append(task[service.Info.Service], options.HostInfo{Host: service.Ip, Ports: strconv.FormatUint(service.Port, 10)}) 124 | default: 125 | 126 | } 127 | } 128 | //url列表 129 | for _, url := range urllist { 130 | if err == nil { 131 | task["1000003"] = append(task["1000003"], options.HostInfo{Url: url, Favicons: &f, Keyword: &k}) 132 | } 133 | } 134 | if scantype == "all" { 135 | return task 136 | } else { 137 | one := map[string][]options.HostInfo{} 138 | one[scantype] = task[scantype] 139 | return one 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /pkg/common/rangectl/range.go: -------------------------------------------------------------------------------- 1 | package rangectl 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "fmt" 7 | "os" 8 | "strconv" 9 | "strings" 10 | 11 | ps "github.com/redtoolskobe/scaninfo/pkg/common/ipparser" 12 | ) 13 | 14 | type Range struct { 15 | Begin uint64 16 | End uint64 17 | } 18 | 19 | /** 20 | RemoveExcFromTaskIps 从任务范围内移除需要排除的Ip或端口 21 | 返回值: 22 | 1. 表示任务列表范围,返回值2有效时才有意义 23 | 2. 表示返回值是否有效,只有排除范围把任务列表分成两段时才有效 24 | */ 25 | func (r *Range) RemoveExcFromTaskIps(exclude Range) (Range, bool) { 26 | var split Range 27 | var tmp = *r 28 | 29 | if r.Begin > exclude.End || r.End < exclude.Begin { 30 | return Range{}, false 31 | } 32 | 33 | if r.Begin >= exclude.Begin && r.End <= exclude.End { 34 | *r = Range{} 35 | return Range{}, false 36 | } 37 | 38 | if r.Begin >= exclude.Begin && r.End > exclude.End { 39 | r.Begin = exclude.End + 1 40 | return Range{}, false 41 | } 42 | 43 | if r.Begin < exclude.Begin && r.End <= exclude.End { 44 | r.End = exclude.Begin - 1 45 | return Range{}, false 46 | } 47 | 48 | if r.Begin < exclude.Begin && r.End > exclude.End { 49 | r.End = exclude.Begin - 1 50 | split.Begin = exclude.End + 1 51 | split.End = tmp.End 52 | 53 | return split, true 54 | } 55 | 56 | return Range{}, false 57 | } 58 | 59 | // ParsePortRange 解析自定义端口范围 60 | func ParsePortRange(port string) (Range, error) { 61 | var result Range 62 | port = strings.TrimSpace(port) 63 | if strings.Contains(port, "-") { 64 | prange := strings.Split(port, "-") 65 | start := prange[0] 66 | stop := prange[1] 67 | 68 | begin, err := strconv.Atoi(start) 69 | if err != nil { 70 | return Range{}, err 71 | } 72 | 73 | end, err := strconv.Atoi(stop) 74 | if err != nil { 75 | return Range{}, err 76 | } 77 | 78 | result.Begin = uint64(begin) 79 | result.End = uint64(end) 80 | } else { 81 | // 单个端口 82 | num, err := strconv.Atoi(port) 83 | if err != nil { 84 | return Range{}, err 85 | } 86 | 87 | result.Begin = uint64(num) 88 | result.End = uint64(num) 89 | } 90 | 91 | if result.Begin > result.End || result.Begin > 65536 || result.End > 65535 { 92 | return Range{}, errors.New("port range failed") 93 | } 94 | 95 | return result, nil 96 | } 97 | 98 | // ParseIpv4Range 解析Ip地址范围, 99 | func ParseIpv4Range(ip string) (Range, error) { 100 | var result Range 101 | 102 | index := strings.Index(ip, "/") 103 | if index != -1 { 104 | ips, err := ps.CidrParse(ip) 105 | if err != nil { 106 | fmt.Println(err) 107 | return Range{}, err 108 | } 109 | 110 | begin, err := ps.ParseIPv4(ips[0]) 111 | if err != nil { 112 | fmt.Println(err) 113 | return Range{}, err 114 | } 115 | 116 | result.Begin = begin 117 | 118 | end, err := ps.ParseIPv4(ips[len(ips)-1]) 119 | if err != nil { 120 | fmt.Println(err) 121 | return Range{}, err 122 | } 123 | 124 | result.End = end 125 | 126 | return result, nil 127 | 128 | } 129 | 130 | index = strings.Index(ip, "-") 131 | if index != -1 { 132 | ips := strings.Split(ip, "-") 133 | 134 | begin, err := ps.ParseIPv4(ips[0]) 135 | if err != nil { 136 | return Range{}, err 137 | } 138 | 139 | result.Begin = begin 140 | 141 | end, err := ps.ParseIPv4(ips[1]) 142 | if err != nil { 143 | return Range{}, err 144 | } 145 | 146 | result.End = end 147 | 148 | if end < begin { 149 | return Range{}, errors.New("End ip is large than start ip") 150 | } 151 | 152 | return result, nil 153 | } 154 | 155 | // 说明是单个的ip 156 | num, err := ps.ParseIPv4(ip) 157 | if err != nil { 158 | return Range{}, err 159 | } 160 | 161 | result.Begin = num 162 | result.End = num 163 | 164 | return result, nil 165 | } 166 | 167 | func ParseIPFromFile(path string) ([]Range, error) { 168 | var ips []Range 169 | p, err := os.Stat(path) 170 | if err != nil { 171 | return nil, err 172 | } 173 | if p.IsDir() { 174 | return nil, fmt.Errorf("could not input a dir: %s", path) 175 | } 176 | 177 | input, err := os.Open(path) 178 | 179 | if err != nil { 180 | return nil, fmt.Errorf("open file error: %s", path) 181 | } 182 | 183 | scanner := bufio.NewScanner(input) 184 | 185 | for scanner.Scan() { 186 | ip := strings.TrimSpace(scanner.Text()) 187 | if ip == "" { 188 | continue 189 | } 190 | if ps.IsIP(ip) || ps.IsIPRange(ip) { 191 | rst, err := ParseIpv4Range(ip) 192 | if err != nil { 193 | continue 194 | } 195 | ips = append(ips, rst) 196 | } else { 197 | tmp_ips, mask, err := ps.DomainToIp(ip) 198 | if err != nil { 199 | fmt.Println(err) 200 | continue 201 | } 202 | for _, ip := range tmp_ips { 203 | addr := ip 204 | if mask != "" { 205 | addr = ip + "/" + mask 206 | } 207 | result, err := ParseIpv4Range(addr) 208 | 209 | if err != nil { 210 | fmt.Println("Error occured while parse iprange") 211 | continue 212 | } 213 | ips = append(ips, result) 214 | } 215 | } 216 | } 217 | return ips, nil 218 | } 219 | -------------------------------------------------------------------------------- /finger/lib/slog/slog.go: -------------------------------------------------------------------------------- 1 | package slog 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | "runtime" 10 | "strings" 11 | 12 | "github.com/redtoolskobe/scaninfo/finger/lib/chinese" 13 | ) 14 | 15 | var this logger 16 | var splitStr = "> " 17 | 18 | type logger struct { 19 | info *log.Logger 20 | warning *log.Logger 21 | debug *log.Logger 22 | data *log.Logger 23 | error *log.Logger 24 | encoding string 25 | //fooLine *log.Logger 26 | } 27 | 28 | func Init(Debug bool, encoding string) { 29 | this.info = log.New(os.Stdout, "\r[+]", log.Ldate|log.Ltime) 30 | this.warning = log.New(os.Stdout, "\r[*]", log.Ldate|log.Ltime) 31 | this.error = log.New(io.MultiWriter(os.Stderr), "\rError:", 0) 32 | this.data = log.New(os.Stdout, "\r", 0) 33 | if Debug { 34 | this.debug = log.New(os.Stdout, "\r[-]", log.Ldate|log.Ltime) 35 | } else { 36 | this.debug = log.New(ioutil.Discard, "\r[-]", log.Ldate|log.Ltime) 37 | } 38 | 39 | this.encoding = encoding 40 | //this.fooline = log.New(os.Stdout, "[*]", 0) 41 | //infoFile,err:=os.OpenFile("/data/service_logs/info.log",os.O_CREATE|os.O_WRONLY|os.O_APPEND,0666) 42 | //warnFile,err:=os.OpenFile("/data/service_logs/warn.log",os.O_CREATE|os.O_WRONLY|os.O_APPEND,0666) 43 | //errFile,err:=os.OpenFile("/data/service_logs/errors.log",os.O_CREATE|os.O_WRONLY|os.O_APPEND,0666) 44 | // 45 | //if infoFile!=nil || warnFile != nil || err!=nil{ 46 | // log.Fatalln("打开日志文件失败:",err) 47 | //} 48 | //Info = log.New(os.Stdout, "[*]", log.Ldate|log.Ltime) 49 | //Warning = log.New(os.Stdout, "[*]", log.Ldate|log.Ltime) 50 | //Error = log.New(io.MultiWriter(os.Stderr,errFile),"Error:",log.Ldate | log.Ltime | log.Lshortfile) 51 | //Info = log.New(io.MultiWriter(os.Stderr,infoFile),"Info:",log.Ldate | log.Ltime | log.Lshortfile) 52 | //Warning = log.New(io.MultiWriter(os.Stderr,warnFile),"Warning:",log.Ldate | log.Ltime | log.Lshortfile) 53 | //Error = log.New(io.MultiWriter(os.Stderr,errFile),"Error:",log.Ldate | log.Ltime | log.Lshortfile) 54 | } 55 | 56 | func (t *logger) Data(s string) { 57 | t.data.Print(s) 58 | } 59 | 60 | func (t *logger) Info(s string) { 61 | t.info.Print(splitStr, s) 62 | } 63 | 64 | func (t *logger) Error(s string) { 65 | t.error.Print(s) 66 | os.Exit(0) 67 | } 68 | 69 | func (t *logger) Warning(s string) { 70 | t.warning.Print(splitStr, s) 71 | } 72 | 73 | func (t *logger) Debug(s string) { 74 | if debugFilter(s) { 75 | return 76 | } 77 | _, file, line, _ := runtime.Caller(3) 78 | file = file[strings.LastIndex(file, "/")+1:] 79 | t.debug.Printf("%s%s(%d) %s", splitStr, file, line, s) 80 | } 81 | 82 | func (t *logger) DoPrint(logType string, logStr string) { 83 | if this.encoding == "gb2312" { 84 | logStr = chinese.ToGBK(logStr) 85 | } else { 86 | logStr = chinese.ToUTF8(logStr) 87 | } 88 | switch logType { 89 | case "Debug": 90 | t.Debug(logStr) 91 | case "Info": 92 | t.Info(logStr) 93 | case "Data": 94 | t.Data(logStr) 95 | case "Warning": 96 | t.Warning(logStr) 97 | case "Error": 98 | t.Error(logStr) 99 | } 100 | 101 | } 102 | 103 | //func (t *logger) Error(s string) { 104 | // _, file, line, _ := runtime.Caller(2) 105 | // file = file[strings.LastIndex(file, "/")+1:] 106 | // t.error.Printf("%s%s(%d) %s", splitStr, file, line, s) 107 | // os.Exit(0) 108 | //} 109 | 110 | //func (t *logger) Errorf(format string, v ...interface{}) { 111 | // _, file, line, _ := runtime.Caller(2) 112 | // file = file[strings.LastIndex(file, "/")+1:] 113 | // format = fmt.Sprintf("%s%s(%d) %s", splitStr, file, line, format) 114 | // t.error.Printf(format, v...) 115 | // os.Exit(0) 116 | //} 117 | func Error(s ...interface{}) { 118 | this.DoPrint("Error", fmt.Sprint(s...)) 119 | } 120 | 121 | func Info(s ...interface{}) { 122 | this.DoPrint("Info", fmt.Sprint(s...)) 123 | } 124 | 125 | func Infof(format string, v ...interface{}) { 126 | this.DoPrint("Info", fmt.Sprintf(format, v...)) 127 | } 128 | 129 | func Warning(s ...interface{}) { 130 | this.DoPrint("Warning", fmt.Sprint(s...)) 131 | } 132 | 133 | func Warningf(format string, v ...interface{}) { 134 | this.DoPrint("Warning", fmt.Sprintf(format, v...)) 135 | } 136 | 137 | func Debug(s ...interface{}) { 138 | this.DoPrint("Debug", fmt.Sprint(s...)) 139 | } 140 | 141 | func Debugf(format string, v ...interface{}) { 142 | this.DoPrint("Debug", fmt.Sprintf(format, v...)) 143 | } 144 | 145 | func Data(v ...interface{}) { 146 | this.DoPrint("Data", fmt.Sprint(v...)) 147 | } 148 | 149 | //func Error(s string) { 150 | // this.Error(s) 151 | //} 152 | 153 | //func Errorf(format string, v ...interface{}) { 154 | // this.Errorf(format, v...) 155 | //} 156 | 157 | func debugFilter(s string) bool { 158 | //Debug 过滤器 159 | if strings.Contains(s, "too many") { //发现存在线程过高错误 160 | Error("当前线程过高,请降低线程!或者请执行\"ulimit -n 50000\"命令放开操作系统限制,MAC系统可能还需要执行:\"launchctl limit maxfiles 50000 50000\"") 161 | } 162 | if strings.Contains(s, "STEP1:CONNECT") { 163 | return true 164 | } 165 | return false 166 | } 167 | -------------------------------------------------------------------------------- /finger/lib/shttp/shttp.go: -------------------------------------------------------------------------------- 1 | package shttp 2 | 3 | import ( 4 | "bytes" 5 | "crypto/tls" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | 10 | "github.com/redtoolskobe/scaninfo/finger/lib/chinese" 11 | 12 | "github.com/redtoolskobe/scaninfo/finger/urlparse" 13 | 14 | "math/rand" 15 | "net/http" 16 | "strings" 17 | "time" 18 | ) 19 | 20 | func GetFavicon(url urlparse.URL) (*http.Response, error) { 21 | url.Path = url.Path + "/favicon.ico" 22 | return GetByHash(url.UnParse()) 23 | } 24 | 25 | func Get(Url string) (*http.Response, error) { 26 | request, err := http.NewRequest("GET", Url, nil) 27 | if err != nil { 28 | return nil, err 29 | } 30 | request.Header.Add("User-Agent", getUserAgent()) 31 | request.Header.Add("Cookie", "rememberMe=b63345edcb2b3c5084c02bd9690b6625") 32 | request.Close = true 33 | 34 | tr := &http.Transport{} 35 | (*tr).TLSClientConfig = &tls.Config{ 36 | InsecureSkipVerify: true, 37 | MinVersion: tls.VersionTLS10, 38 | } 39 | 40 | (*tr).DisableKeepAlives = false 41 | client := &http.Client{Timeout: 10 * time.Second} 42 | client.Transport = tr 43 | resp, err := client.Do(request) 44 | if err != nil { 45 | return resp, err 46 | } 47 | body2UTF8(resp) 48 | return resp, err 49 | } 50 | 51 | //中文编码导致Hash指纹出错重写了一个GET请求 52 | func GetByHash(Url string) (*http.Response, error) { 53 | request, err := http.NewRequest("GET", Url, nil) 54 | if err != nil { 55 | return nil, err 56 | } 57 | request.Header.Add("User-Agent", getUserAgent()) 58 | request.Close = true 59 | 60 | tr := &http.Transport{} 61 | (*tr).TLSClientConfig = &tls.Config{ 62 | InsecureSkipVerify: true, 63 | MinVersion: tls.VersionTLS10, 64 | } 65 | 66 | (*tr).DisableKeepAlives = false 67 | client := &http.Client{Timeout: 10 * time.Second} 68 | client.Transport = tr 69 | resp, err := client.Do(request) 70 | if err != nil { 71 | return resp, err 72 | } 73 | return resp, err 74 | } 75 | 76 | func Header2String(header http.Header) string { 77 | var result string 78 | for i := range header { 79 | result = strings.Join([]string{result, fmt.Sprintf("%s: %s\n", i, header.Get(i))}, "") 80 | } 81 | return result 82 | } 83 | 84 | func body2UTF8(resp *http.Response) { 85 | if strings.Contains(resp.Header.Get("Content-Type"), "utf-8") { 86 | return 87 | } 88 | bodyBuf, err := ioutil.ReadAll(resp.Body) 89 | if err != nil { 90 | //fmt.Println(err.Error()) 91 | } 92 | utf8Buf := chinese.ByteToUTF8(bodyBuf) 93 | resp.Body = ioutil.NopCloser(bytes.NewReader(utf8Buf)) 94 | return 95 | } 96 | 97 | func GetBody(resp *http.Response) io.Reader { 98 | bodyBuf, err := ioutil.ReadAll(resp.Body) 99 | if err != nil { 100 | fmt.Println(err.Error()) 101 | } 102 | resp.Body = ioutil.NopCloser(bytes.NewReader(bodyBuf)) 103 | return bytes.NewReader(bodyBuf) 104 | } 105 | 106 | func getUserAgent() string { 107 | var UserAgents = []string{ 108 | "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)", 109 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", 110 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)", 111 | "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", 112 | "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)", 113 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)", 114 | "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)", 115 | "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)", 116 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)", 117 | "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6", 118 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1", 119 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0", 120 | "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5", 121 | "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6", 122 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11", 123 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20", 124 | "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52", 125 | } 126 | rand.Seed(time.Now().UnixNano()) 127 | i := rand.Intn(len(UserAgents)) 128 | return UserAgents[i] 129 | } 130 | -------------------------------------------------------------------------------- /pkg/Ginfo/Ghttp/title.go: -------------------------------------------------------------------------------- 1 | package Ghttp 2 | 3 | import ( 4 | "net/http" 5 | "regexp" 6 | "strings" 7 | 8 | "golang.org/x/net/html" 9 | ) 10 | 11 | // ExtractTitle from a response 12 | func ExtractTitle(body string, r *http.Response) (title string) { 13 | var re = regexp.MustCompile(`(?im)<\s*title.*>(.*?)<\s*/\s*title>`) 14 | for _, match := range re.FindAllString(body, -1) { 15 | title = html.UnescapeString(trimTitleTags(match)) 16 | break 17 | } 18 | // Non UTF-8 19 | if contentTypes, ok := r.Header["Content-Type"]; ok { 20 | contentType := strings.ToLower(strings.Join(contentTypes, ";")) 21 | // special cases 22 | if strings.Contains(contentType, "charset=gb2312") || strings.Contains(contentType, "charset=gbk") { 23 | titleUtf8, err := Decodegbk([]byte(title)) 24 | if err != nil { 25 | return 26 | } 27 | 28 | return string(titleUtf8) 29 | } 30 | } 31 | 32 | return 33 | } 34 | 35 | func trimTitleTags(title string) string { 36 | // trim * 37 | titleBegin := strings.Index(title, ">") 38 | titleEnd := strings.Index(title, " stop { 146 | return nil 147 | } 148 | if step < 0 { 149 | return nil 150 | } 151 | 152 | for i := start; i <= stop; i += step { 153 | r = append(r, i) 154 | } 155 | return r 156 | } 157 | 158 | func FilterPrintStr(s string) string { 159 | // 将字符串转换为rune数组 160 | srcRunes := []rune(s) 161 | // 创建一个新的rune数组,用来存放过滤后的数据 162 | dstRunes := make([]rune, 0, len(srcRunes)) 163 | // 过滤不可见字符,根据上面的表的0-32和127都是不可见的字符 164 | for _, c := range srcRunes { 165 | if c >= 0 && c <= 31 { 166 | continue 167 | } 168 | if c == 127 { 169 | continue 170 | } 171 | dstRunes = append(dstRunes, c) 172 | } 173 | 174 | return string(dstRunes) 175 | } 176 | 177 | func SprintStringMap(stringMap map[string]string) string { 178 | var rArr []string 179 | var assistArr []string 180 | for key, value := range stringMap { 181 | if value == "" { 182 | continue 183 | } 184 | if IsInStrArr(assistArr, value) == false { 185 | assistArr = append(assistArr, value) 186 | rArr = append(rArr, fmt.Sprintf("%s:%s", key, value)) 187 | } 188 | } 189 | 190 | for index, value := range rArr { 191 | rArr[index] = chinese.ToUTF8(value) 192 | } 193 | 194 | return strings.Join(rArr, "、") 195 | } 196 | 197 | func MustLength(s string, i int) string { 198 | if len(s) > i { 199 | return s[:i] 200 | } 201 | return s 202 | } 203 | 204 | func Percent(int1 int, int2 int) string { 205 | float1 := float64(int1) 206 | float2 := float64(int2) 207 | f := 1 - float1/float2 208 | f = f * 100 209 | return strconv.FormatFloat(f, 'f', 2, 64) 210 | } 211 | 212 | func StrRandomCut(s string, length int) string { 213 | sRune := []rune(s) 214 | if len(sRune) > length { 215 | i := rand.Intn(len(sRune) - length) 216 | return string(sRune[i : i+length]) 217 | } else { 218 | return s 219 | } 220 | } 221 | 222 | func RemoveDuplicateElement(languages []string) []string { 223 | result := make([]string, 0, len(languages)) 224 | temp := map[string]struct{}{} 225 | for _, item := range languages { 226 | if _, ok := temp[item]; !ok { //如果字典中找不到元素,ok=false,!ok为true,就往切片中append元素。 227 | temp[item] = struct{}{} 228 | result = append(result, item) 229 | } 230 | } 231 | return result 232 | } 233 | 234 | func WriteLine(fileName string, byte []byte) error { 235 | //file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666) 236 | file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR, 0666) 237 | if err != nil { 238 | return err 239 | } 240 | //创建成功挂起关闭文件流,在函数结束前执行 241 | defer file.Close() 242 | //NewWriter创建一个以目标文件具有默认大小缓冲、写入w的*Writer。 243 | writer := bufio.NewWriter(file) 244 | //写入器将内容写入缓冲。返回写入的字节数。 245 | _, err = writer.Write(byte) 246 | //Flush方法将缓冲中的数据写入下层的io.Writer接口。缺少,数据将保留在缓冲区,并未写入io.Writer接口 247 | _ = writer.Flush() 248 | if err != nil { 249 | if err == io.EOF { 250 | return nil 251 | } 252 | return err 253 | } 254 | return err 255 | } 256 | -------------------------------------------------------------------------------- /pkg/common/parser.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bufio" 5 | "encoding/hex" 6 | "flag" 7 | "fmt" 8 | "os" 9 | "strings" 10 | 11 | "go.uber.org/ratelimit" 12 | ) 13 | 14 | type sliceValue []string 15 | 16 | func newSliceValue(vals []string, p *[]string) *sliceValue { 17 | *p = vals 18 | return (*sliceValue)(p) 19 | } 20 | 21 | func (s *sliceValue) Set(val string) error { 22 | *s = sliceValue(strings.Split(val, ",")) 23 | return nil 24 | } 25 | 26 | func (s *sliceValue) Get() interface{} { 27 | return []string(*s) 28 | } 29 | 30 | func (s *sliceValue) String() string { 31 | return strings.Join([]string(*s), ",") 32 | } 33 | 34 | var ( 35 | cmdIps []string 36 | // cmdExPath string 37 | cmdCofPath string 38 | cmdPorts []string 39 | cmdT1000 bool 40 | cmdRandom bool 41 | NumThreads int 42 | excPorts []string // 待排除端口 43 | excIps []string // 待排除Ip 44 | ipFile string 45 | WebVulThreds int 46 | UrlFile string 47 | Method string 48 | nocolor bool //彩色打印 49 | json bool 50 | tracelog string //请求日志 51 | Rstfile string //文件保存 52 | tout float64 //timeout 53 | nbtscan bool 54 | limit int 55 | Limiter ratelimit.Limiter 56 | IcmpThreds int 57 | ShowScanType bool 58 | FingerFile string 59 | Noping bool //是否为ping扫描默认为true 60 | ) 61 | 62 | type Options struct { 63 | CmdIps []string 64 | // cmdExPath string 65 | CmdCofPath string 66 | CmdPorts []string 67 | CmdT1000 bool 68 | CmdRandom bool 69 | NumThreads int 70 | IcmpThreads int 71 | ExcPorts []string // 待排除端口 72 | ExcIps []string // 待排除Ip 73 | IpFile string 74 | Rstfile string //文件保存 75 | Tout float64 //timeout 76 | Limit int 77 | Limiter ratelimit.Limiter 78 | IpList []string //要扫描的主机列表 79 | AliveHosts []string //存活的主机 80 | } 81 | 82 | var ScanMethodMap = map[string]string{ 83 | "ftp": "ftp", 84 | "ssh": "ssh", 85 | "findnet": "findnet", 86 | "netbios": "netbios", 87 | "smb": "smb", 88 | "mssql": "mssql", 89 | "mysql": "mysql", 90 | "psql": "postgresql", 91 | "redis": "redis", 92 | "mem": "memcached", 93 | "mgo": "mongodb", 94 | "all": "all", 95 | "port": "port", 96 | "ping": "ping", 97 | "ms17010": "1000001", 98 | "smbghost": "1000002", 99 | "webfinger": "1000003", 100 | } 101 | 102 | var ScanTypeList = []string{"ftp", "ssh", "findnet", "netbios", "smb", "mssql", "mysql", "psql", "redis", "mem", "mgo", "all", "port", "ping", "ms17010", "smbghost", "webfinger"} 103 | 104 | func NewDefaultOptions() *Options { 105 | return &Options{ 106 | CmdCofPath: "", 107 | CmdPorts: cmdPorts, 108 | CmdT1000: cmdT1000, 109 | NumThreads: NumThreads, 110 | ExcPorts: excPorts, 111 | ExcIps: excIps, 112 | CmdIps: cmdIps, 113 | IpFile: ipFile, 114 | Rstfile: Rstfile, 115 | Tout: tout, 116 | Limit: limit, 117 | Limiter: ratelimit.NewUnlimited(), 118 | IpList: []string{}, 119 | AliveHosts: []string{}, 120 | IcmpThreads: IcmpThreds, 121 | } 122 | } 123 | 124 | /** 125 | 命令行参数解析: 126 | -i: 输入的Ip地址或者域名,以逗号分隔. 例如192.168.1.1/24,scanme.nmap.org 127 | -e: 设置排除文件路径,排除文件内容为需要排除的ip地址列表 128 | -c: 配置文件路径,支持从配置文件中读取ip,地址列表 129 | -p: 需要扫描的端口列表,以逗号分隔,例如: 1-1000,3379,6379,和-p互斥 130 | -t1000: 布尔类型,默认是扫描top100,否则扫描top1000端口,和-p互斥 131 | -r: 布尔类型,表示扫描方式,随机扫描还是顺序扫描 132 | */ 133 | func init() { 134 | flag.Var(newSliceValue([]string{}, &cmdIps), "i", "set domain and ips") 135 | flag.StringVar(&ipFile, "l", "", "input ips file") 136 | flag.StringVar(&UrlFile, "uf", "", "input url file of webtitle scan") 137 | flag.StringVar(&FingerFile, "ff", "", "Custom specified file for finger") 138 | flag.Var(newSliceValue([]string{}, &cmdPorts), "p", "set port ranges to scan,default is top100") 139 | flag.BoolVar(&cmdT1000, "t1000", false, "scan top1000 ports") 140 | flag.BoolVar(&Noping, "np", false, "ping scan of host alive") 141 | flag.BoolVar(&ShowScanType, "show", false, "show scan type list") 142 | flag.StringVar(&Method, "m", "all", "Select scan type ,as: -m ssh (default al)") 143 | flag.IntVar(&NumThreads, "n", 900, "scan threads for port scan, between 1 and 2000") 144 | flag.IntVar(&IcmpThreds, "pt", 100, "imcp scan threds,default is 100 ") 145 | flag.IntVar(&WebVulThreds, "vt", 500, "web and vul scan threds,default is 500 ") 146 | flag.Var(newSliceValue([]string{}, &excPorts), "ep", "set port ranges to exclude") 147 | flag.Var(newSliceValue([]string{}, &excIps), "ei", "set ip ranges to exclude") 148 | flag.StringVar(&Rstfile, "o", "result", "save scan result file") 149 | flag.Float64Var(&tout, "t", 0.5, "scan port tcp connect time out default 0.5 second") 150 | } 151 | 152 | type Identification_Packet struct { 153 | Desc string 154 | Packet []byte 155 | } 156 | 157 | var St_Identification_Packet [100]Identification_Packet 158 | 159 | // 初始化IdentificationProtocol到内存中 160 | 161 | func init() { 162 | for i, packet := range IdentificationProtocol { 163 | szinfo := strings.Split(packet, "#") 164 | data, err := hex.DecodeString(szinfo[1]) 165 | if err != nil { 166 | fmt.Println(err) 167 | os.Exit(1) 168 | } 169 | 170 | St_Identification_Packet[i].Desc = szinfo[0] 171 | St_Identification_Packet[i].Packet = data 172 | } 173 | } 174 | 175 | func ArgsPrint() { 176 | fmt.Println(cmdIps) 177 | fmt.Println(cmdRandom) 178 | fmt.Println(cmdPorts) 179 | fmt.Println(excPorts) 180 | } 181 | 182 | /** 183 | configeFileParse 配置文件解析函数 184 | 配置文件每行一条数据,可以是单个ip,域名,也可以是带掩码的ip和域名 185 | */ 186 | func ConfigeFileParse(path string) ([]string, error) { 187 | var err error 188 | var ips = make([]string, 0, 100) 189 | 190 | file, err := os.Open(path) 191 | if err != nil { 192 | fmt.Println(err) 193 | os.Exit(1) 194 | } 195 | 196 | defer file.Close() 197 | 198 | reader := bufio.NewReader(file) 199 | 200 | for { 201 | line, err := reader.ReadString('\n') 202 | if err != nil { 203 | break 204 | } 205 | 206 | // 去除空行 207 | if len(line) == 0 || line == "\r\n" { 208 | continue 209 | } 210 | 211 | // 以#开头的为注释内容 212 | if strings.Index(line, "#") == 0 { 213 | continue 214 | } 215 | 216 | ips = append(ips, line) 217 | } 218 | 219 | return ips, err 220 | } 221 | -------------------------------------------------------------------------------- /imcp/icmp.go: -------------------------------------------------------------------------------- 1 | package imcp 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "net" 7 | "os/exec" 8 | "runtime" 9 | "strings" 10 | "sync" 11 | "time" 12 | 13 | "github.com/redtoolskobe/scaninfo/pkg/common" 14 | 15 | "github.com/pterm/pterm" 16 | 17 | "github.com/redtoolskobe/scaninfo/utils" 18 | "golang.org/x/net/icmp" 19 | ) 20 | 21 | var ( 22 | AliveHosts []string 23 | OS = runtime.GOOS 24 | ExistHosts = make(map[string]struct{}) 25 | livewg sync.WaitGroup 26 | ) 27 | 28 | func ICMPRun(hostslist []string, Ping bool) []string { 29 | spinnerSuccess, _ := pterm.DefaultSpinner.Start("正在进行IMCP存活主机探测... (请等待)") 30 | chanHosts := make(chan string, common.IcmpThreds) 31 | go func() { 32 | for ip := range chanHosts { 33 | if _, ok := ExistHosts[ip]; !ok && utils.IsContain(hostslist, ip) { 34 | ExistHosts[ip] = struct{}{} 35 | AliveHosts = append(AliveHosts, ip) 36 | } 37 | livewg.Done() 38 | } 39 | }() 40 | 41 | if Ping == true { 42 | //使用ping探测 43 | RunPing(hostslist, chanHosts) 44 | } else { 45 | //优先尝试监听本地icmp,批量探测 46 | conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") 47 | if err == nil { 48 | RunIcmp1(hostslist, conn, chanHosts) 49 | } else { 50 | //尝试无监听icmp探测 51 | conn, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second) 52 | if err == nil { 53 | go conn.Close() 54 | RunIcmp2(hostslist, chanHosts) 55 | } else { 56 | pterm.Warning.Println("使用ICMP扫描请确认是否为sudo权限,已切换成PING扫描") 57 | //使用ping探测 58 | //global.GVA_LOG_fscan.Warn(fmt.Sprintf("使用ICMP扫描请确认是否为sudo权限,已切换成PING扫描"), zap.String("scan", "FSCAN")) 59 | RunPing(hostslist, chanHosts) 60 | } 61 | } 62 | } 63 | 64 | livewg.Wait() 65 | close(chanHosts) 66 | spinnerSuccess.Success(fmt.Sprintf("imcp存活主机扫描结束,存活主机数量为【%d】台", len(AliveHosts))) 67 | return AliveHosts 68 | } 69 | 70 | func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) { 71 | endflag := false 72 | go func() { 73 | for { 74 | if endflag == true { 75 | return 76 | } 77 | msg := make([]byte, 100) 78 | _, sourceIP, _ := conn.ReadFrom(msg) 79 | if sourceIP != nil { 80 | livewg.Add(1) 81 | chanHosts <- sourceIP.String() 82 | } 83 | } 84 | }() 85 | 86 | for _, host := range hostslist { 87 | dst, _ := net.ResolveIPAddr("ip", host) 88 | IcmpByte := makemsg(host) 89 | conn.WriteTo(IcmpByte, dst) 90 | } 91 | //根据hosts数量修改icmp监听时间 92 | start := time.Now() 93 | for { 94 | if len(AliveHosts) == len(hostslist) { 95 | break 96 | } 97 | since := time.Now().Sub(start) 98 | var wait time.Duration 99 | switch { 100 | case len(hostslist) <= 256: 101 | wait = time.Second * 3 102 | default: 103 | wait = time.Second * 6 104 | } 105 | if since > wait { 106 | break 107 | } 108 | } 109 | endflag = true 110 | conn.Close() 111 | } 112 | 113 | func RunIcmp2(hostslist []string, chanHosts chan string) { 114 | num := 1000 115 | if len(hostslist) < num { 116 | num = len(hostslist) 117 | } 118 | var wg sync.WaitGroup 119 | limiter := make(chan struct{}, num) 120 | for _, host := range hostslist { 121 | wg.Add(1) 122 | limiter <- struct{}{} 123 | go func(host string) { 124 | if icmpalive(host) { 125 | livewg.Add(1) 126 | chanHosts <- host 127 | } 128 | <-limiter 129 | wg.Done() 130 | }(host) 131 | } 132 | wg.Wait() 133 | close(limiter) 134 | } 135 | 136 | func icmpalive(host string) bool { 137 | startTime := time.Now() 138 | conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second) 139 | if err != nil { 140 | return false 141 | } 142 | defer conn.Close() 143 | if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil { 144 | return false 145 | } 146 | msg := makemsg(host) 147 | if _, err := conn.Write(msg); err != nil { 148 | return false 149 | } 150 | 151 | receive := make([]byte, 60) 152 | if _, err := conn.Read(receive); err != nil { 153 | return false 154 | } 155 | 156 | return true 157 | } 158 | 159 | func RunPing(hostslist []string, chanHosts chan string) { 160 | var bsenv = "" 161 | if OS != "windows" { 162 | bsenv = "/bin/bash" 163 | } 164 | var wg sync.WaitGroup 165 | limiter := make(chan struct{}, 50) 166 | for _, host := range hostslist { 167 | wg.Add(1) 168 | limiter <- struct{}{} 169 | go func(host string) { 170 | if ExecCommandPing(host, bsenv) { 171 | livewg.Add(1) 172 | chanHosts <- host 173 | } 174 | <-limiter 175 | wg.Done() 176 | }(host) 177 | } 178 | wg.Wait() 179 | } 180 | 181 | func ExecCommandPing(ip string, bsenv string) bool { 182 | var command *exec.Cmd 183 | if OS == "windows" { 184 | command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" 185 | } else if OS == "linux" { 186 | command = exec.Command(bsenv, "-c", "ping -c 1 -w 1 "+ip+" >/dev/null && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" 187 | } else if OS == "darwin" { 188 | command = exec.Command(bsenv, "-c", "ping -c 1 -W 1 "+ip+" >/dev/null && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" 189 | } 190 | outinfo := bytes.Buffer{} 191 | command.Stdout = &outinfo 192 | err := command.Start() 193 | if err != nil { 194 | return false 195 | } 196 | if err = command.Wait(); err != nil { 197 | return false 198 | } else { 199 | if strings.Contains(outinfo.String(), "true") { 200 | return true 201 | } else { 202 | return false 203 | } 204 | } 205 | } 206 | 207 | func makemsg(host string) []byte { 208 | msg := make([]byte, 40) 209 | id0, id1 := genIdentifier(host) 210 | msg[0] = 8 211 | msg[1] = 0 212 | msg[2] = 0 213 | msg[3] = 0 214 | msg[4], msg[5] = id0, id1 215 | msg[6], msg[7] = genSequence(1) 216 | check := checkSum(msg[0:40]) 217 | msg[2] = byte(check >> 8) 218 | msg[3] = byte(check & 255) 219 | return msg 220 | } 221 | 222 | func checkSum(msg []byte) uint16 { 223 | sum := 0 224 | length := len(msg) 225 | for i := 0; i < length-1; i += 2 { 226 | sum += int(msg[i])*256 + int(msg[i+1]) 227 | } 228 | if length%2 == 1 { 229 | sum += int(msg[length-1]) * 256 230 | } 231 | sum = (sum >> 16) + (sum & 0xffff) 232 | sum = sum + (sum >> 16) 233 | answer := uint16(^sum) 234 | return answer 235 | } 236 | 237 | func genSequence(v int16) (byte, byte) { 238 | ret1 := byte(v >> 8) 239 | ret2 := byte(v & 255) 240 | return ret1, ret2 241 | } 242 | 243 | func genIdentifier(host string) (byte, byte) { 244 | return host[0], host[1] 245 | } 246 | -------------------------------------------------------------------------------- /pkg/Plugins/ms17017.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "encoding/binary" 5 | "encoding/hex" 6 | "errors" 7 | "fmt" 8 | "net" 9 | "strings" 10 | "time" 11 | 12 | "github.com/redtoolskobe/scaninfo/model" 13 | 14 | "github.com/redtoolskobe/scaninfo/global" 15 | "go.uber.org/zap" 16 | 17 | "github.com/redtoolskobe/scaninfo/pkg/common" 18 | "github.com/redtoolskobe/scaninfo/pkg/options" 19 | ) 20 | 21 | var ( 22 | negotiateProtocolRequest, _ = hex.DecodeString("00000085ff534d4272000000001853c00000000000000000000000000000fffe00004000006200025043204e4554574f524b2050524f4752414d20312e3000024c414e4d414e312e30000257696e646f777320666f7220576f726b67726f75707320332e316100024c4d312e325830303200024c414e4d414e322e3100024e54204c4d20302e313200") 23 | sessionSetupRequest, _ = hex.DecodeString("00000088ff534d4273000000001807c00000000000000000000000000000fffe000040000dff00880004110a000000000000000100000000000000d40000004b000000000000570069006e0064006f007700730020003200300030003000200032003100390035000000570069006e0064006f007700730020003200300030003000200035002e0030000000") 24 | treeConnectRequest, _ = hex.DecodeString("00000060ff534d4275000000001807c00000000000000000000000000000fffe0008400004ff006000080001003500005c005c003100390032002e003100360038002e003100370035002e003100320038005c00490050004300240000003f3f3f3f3f00") 25 | transNamedPipeRequest, _ = hex.DecodeString("0000004aff534d42250000000018012800000000000000000000000000088ea3010852981000000000ffffffff0000000000000000000000004a0000004a0002002300000007005c504950455c00") 26 | trans2SessionSetupRequest, _ = hex.DecodeString("0000004eff534d4232000000001807c00000000000000000000000000008fffe000841000f0c0000000100000000000000a6d9a40000000c00420000004e0001000e000d0000000000000000000000000000") 27 | ) 28 | 29 | func MS17010(info *options.HostInfo) error { 30 | err := MS17010Scan(info) 31 | if err != nil { 32 | errlog := fmt.Sprintf("[-] Ms17010 %v %v", info.Host, err) 33 | common.LogError(errlog) 34 | } 35 | return err 36 | } 37 | 38 | func MS17010Scan(info *options.HostInfo) error { 39 | ip := info.Host 40 | // connecting to a host in LAN if reachable should be very quick 41 | conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(info.Timeout)*time.Second) 42 | if err != nil { 43 | //fmt.Printf("failed to connect to %s\n", ip) 44 | return err 45 | } 46 | defer conn.Close() 47 | err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second)) 48 | if err != nil { 49 | //fmt.Printf("failed to connect to %s\n", ip) 50 | return err 51 | } 52 | _, err = conn.Write(negotiateProtocolRequest) 53 | if err != nil { 54 | return err 55 | } 56 | reply := make([]byte, 1024) 57 | // let alone half packet 58 | if n, err := conn.Read(reply); err != nil || n < 36 { 59 | return err 60 | } 61 | 62 | if binary.LittleEndian.Uint32(reply[9:13]) != 0 { 63 | // status != 0 64 | return err 65 | } 66 | 67 | _, err = conn.Write(sessionSetupRequest) 68 | if err != nil { 69 | return err 70 | } 71 | n, err := conn.Read(reply) 72 | if err != nil || n < 36 { 73 | return err 74 | } 75 | 76 | if binary.LittleEndian.Uint32(reply[9:13]) != 0 { 77 | // status != 0 78 | //fmt.Printf("can't determine whether %s is vulnerable or not\n", ip) 79 | var Err = errors.New("can't determine whether target is vulnerable or not") 80 | return Err 81 | } 82 | 83 | // extract OS info 84 | var os string 85 | sessionSetupResponse := reply[36:n] 86 | if wordCount := sessionSetupResponse[0]; wordCount != 0 { 87 | // find byte count 88 | byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9]) 89 | if n != int(byteCount)+45 { 90 | fmt.Println("[-]", ip+":445", "ms17010 invalid session setup AndX response") 91 | } else { 92 | // two continous null bytes indicates end of a unicode string 93 | for i := 10; i < len(sessionSetupResponse)-1; i++ { 94 | if sessionSetupResponse[i] == 0 && sessionSetupResponse[i+1] == 0 { 95 | os = string(sessionSetupResponse[10:i]) 96 | os = strings.Replace(os, string([]byte{0x00}), "", -1) 97 | break 98 | } 99 | } 100 | } 101 | 102 | } 103 | userID := reply[32:34] 104 | treeConnectRequest[32] = userID[0] 105 | treeConnectRequest[33] = userID[1] 106 | // TODO change the ip in tree path though it doesn't matter 107 | _, err = conn.Write(treeConnectRequest) 108 | if err != nil { 109 | return err 110 | } 111 | if n, err := conn.Read(reply); err != nil || n < 36 { 112 | return err 113 | } 114 | 115 | treeID := reply[28:30] 116 | transNamedPipeRequest[28] = treeID[0] 117 | transNamedPipeRequest[29] = treeID[1] 118 | transNamedPipeRequest[32] = userID[0] 119 | transNamedPipeRequest[33] = userID[1] 120 | 121 | _, err = conn.Write(transNamedPipeRequest) 122 | if err != nil { 123 | return err 124 | } 125 | if n, err := conn.Read(reply); err != nil || n < 36 { 126 | return err 127 | } 128 | 129 | if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 { 130 | //fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os) 131 | //if runtime.GOOS=="windows" {fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os) 132 | //} else{fmt.Printf("\033[33m%s\tMS17-010\t(%s)\033[0m\n", ip, os)} 133 | result := fmt.Sprintf("[+] %s\tMS17-010\t(%s)", ip, os) 134 | fmt.Println(result) 135 | // detect present of DOUBLEPULSAR SMB implant 136 | trans2SessionSetupRequest[28] = treeID[0] 137 | trans2SessionSetupRequest[29] = treeID[1] 138 | trans2SessionSetupRequest[32] = userID[0] 139 | trans2SessionSetupRequest[33] = userID[1] 140 | 141 | _, err = conn.Write(trans2SessionSetupRequest) 142 | if err != nil { 143 | return err 144 | } 145 | if n, err := conn.Read(reply); err != nil || n < 36 { 146 | return err 147 | } 148 | 149 | if reply[34] == 0x51 { 150 | result := fmt.Sprintf("[+] %s has DOUBLEPULSAR SMB IMPLANT", ip) 151 | res := common.VulInfo{"plugin", info.TaskID, map[string]interface{}{"type": "ms17010", "result": result}} 152 | common.LogSuccess(&res) 153 | global.Log.Warn("plugin", zap.String("ms-17-010", "ms-17-010"), zap.String("host", info.Host), 154 | zap.String("result", result)) 155 | model.PluginList = append(model.PluginList, model.Plugin{"ms-17-010", result, info.Host, info.Ports}) 156 | } 157 | 158 | } else { 159 | result := fmt.Sprintf("[*] %s (%s)", ip, os) 160 | res := common.VulInfo{"plugin", info.TaskID, map[string]interface{}{"type": "ms17010", "result": result, "host": info.Host, "port": 445}} 161 | common.LogSuccess(&res) 162 | global.Log.Warn("plugin", zap.String("ms-17-010", "ms-17-010"), zap.String("host", info.Host), 163 | zap.String("result", result)) 164 | model.PluginList = append(model.PluginList, model.Plugin{"ms-17-010", result, info.Host, info.Ports}) 165 | } 166 | return err 167 | 168 | } 169 | -------------------------------------------------------------------------------- /port/runner/engine.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "sync" 7 | "time" 8 | 9 | "github.com/pterm/pterm" 10 | 11 | "github.com/redtoolskobe/scaninfo/pkg/common" 12 | 13 | "go.uber.org/ratelimit" 14 | 15 | ps "github.com/redtoolskobe/scaninfo/pkg/common/ipparser" 16 | 17 | rc "github.com/redtoolskobe/scaninfo/pkg/common/rangectl" 18 | 19 | "github.com/redtoolskobe/scaninfo/pkg/output" 20 | ) 21 | 22 | type Addr struct { 23 | ip string 24 | port uint64 25 | } 26 | 27 | type Engine struct { 28 | TaskIps []rc.Range //IP列表 29 | TaskPorts []rc.Range //端口列表 30 | ExcdPorts []rc.Range // 待排除端口 31 | ExcdIps []rc.Range // 待排除的Ip 32 | WorkerCount int //协程数据 33 | TaskChan chan Addr // 传递待扫描的ip端口对 34 | //DoneChan chan struct{} // 任务完成通知 35 | Wg *sync.WaitGroup 36 | Options *common.Options 37 | Count int 38 | ComCount int64 39 | Writer output.Writer 40 | Ctx context.Context 41 | Bar *pterm.ProgressbarPrinter 42 | Ticker *time.Ticker 43 | PortServiceList []*output.ResultEvent 44 | } 45 | 46 | //创建引擎 47 | func CreateEngine(option *common.Options) *Engine { 48 | 49 | if option.Limit > 1 { 50 | option.Limiter = ratelimit.New(option.Limit) 51 | } else { 52 | option.Limiter = ratelimit.NewUnlimited() 53 | } 54 | 55 | return &Engine{ 56 | TaskChan: make(chan Addr, option.NumThreads), 57 | WorkerCount: option.NumThreads, 58 | Wg: &sync.WaitGroup{}, 59 | Options: option, 60 | } 61 | } 62 | 63 | // 扫描任务创建 64 | func (e *Engine) Scheduler() { 65 | for i := 0; i < e.WorkerCount; i++ { 66 | e.worker(e.TaskChan, e.Wg) 67 | } 68 | } 69 | 70 | func (e *Engine) Run() { 71 | e.Wg.Add(e.WorkerCount) 72 | e.Ticker = time.NewTicker(time.Second * 1) 73 | go func(t *time.Ticker) { 74 | for { 75 | <-t.C 76 | e.Bar.Current = int(e.ComCount) 77 | e.Bar.Add(0) 78 | } 79 | }(e.Ticker) 80 | go e.Scheduler() 81 | e.randomScan() 82 | // 扫描任务发送完成,关闭通道 83 | //fmt.Println("Task Add done") 84 | //pterm.Success.Println("已关闭TaskChan,Bar进度条") 85 | //e.Ticker.Stop() 86 | e.Bar.Stop() 87 | close(e.TaskChan) 88 | e.Ticker.Stop() 89 | return 90 | } 91 | 92 | func (e *Engine) randomScan() { 93 | // 投机取巧,打乱端口顺序,遍历ip扫描 94 | var portlist = make(map[int]uint64) 95 | var index int 96 | var addr Addr 97 | 98 | //得到端口IPLIST 99 | for _, ports := range e.TaskPorts { 100 | for port := ports.Begin; port <= ports.End; port++ { 101 | portlist[index] = port 102 | index++ 103 | } 104 | } 105 | 106 | e.Count = len(e.Options.IpList) * len(portlist) 107 | e.Bar, _ = pterm.DefaultProgressbar.WithTotal(e.Count).WithTitle("[Port Scan]").WithRemoveWhenDone(true).Start() 108 | for _, ip := range e.Options.IpList { 109 | for _, po := range portlist { 110 | addr.ip = ip 111 | addr.port = po 112 | select { 113 | case <-e.Ctx.Done(): 114 | pterm.Success.Println("子线程Scan扫描已经结束停止任务列表Chan") 115 | e.Ticker.Stop() 116 | for len(e.TaskChan) > 0 { 117 | <-e.TaskChan 118 | } 119 | return 120 | default: 121 | e.TaskChan <- addr 122 | } 123 | } 124 | } 125 | 126 | } 127 | 128 | //初始化引擎 129 | func (e *Engine) Parser() error { 130 | var err error 131 | e.Writer, err = output.NewStandardWriter() 132 | if err != nil { 133 | return err 134 | } 135 | var ports []string 136 | // TODO:: 待增加排除ip和排除端口流程 137 | 138 | for _, ipstr := range e.Options.CmdIps { 139 | if ps.IsIP(ipstr) || ps.IsIPRange(ipstr) { 140 | result, err := rc.ParseIpv4Range(ipstr) 141 | if err != nil { 142 | fmt.Println("Error occured while parse iprange") 143 | return err 144 | } 145 | 146 | e.TaskIps = append(e.TaskIps, result) 147 | } else { 148 | // 说明是域名,需要对域名进行解析 149 | ips, mask, err := ps.DomainToIp(ipstr) 150 | if err != nil { 151 | fmt.Println(err) 152 | return err 153 | } 154 | for _, ip := range ips { 155 | addr := ip 156 | if mask != "" { 157 | addr = ip + "/" + mask 158 | } 159 | 160 | result, err := rc.ParseIpv4Range(addr) 161 | 162 | if err != nil { 163 | fmt.Println("Error occured while parse iprange") 164 | return err 165 | } 166 | 167 | e.TaskIps = append(e.TaskIps, result) 168 | } 169 | } 170 | } 171 | 172 | if e.Options.IpFile != "" { 173 | rst, err := rc.ParseIPFromFile(e.Options.IpFile) 174 | if err == nil { 175 | for _, r := range rst { 176 | e.TaskIps = append(e.TaskIps, r) 177 | } 178 | } 179 | } 180 | 181 | if len(e.Options.ExcIps) != 0 { 182 | for _, ipstr := range e.Options.ExcIps { 183 | if ps.IsIP(ipstr) || ps.IsIPRange(ipstr) { 184 | result, err := rc.ParseIpv4Range(ipstr) 185 | if err != nil { 186 | fmt.Println("Error occured while parse iprange") 187 | return err 188 | } 189 | 190 | e.ExcdIps = append(e.ExcdIps, result) 191 | } else { 192 | // 说明是域名,需要对域名进行解析 193 | ips, mask, err := ps.DomainToIp(ipstr) 194 | if err != nil { 195 | fmt.Println(err) 196 | return err 197 | } 198 | for _, ip := range ips { 199 | addr := ip 200 | if mask != "" { 201 | addr = ip + "/" + mask 202 | } 203 | 204 | result, err := rc.ParseIpv4Range(addr) 205 | 206 | if err != nil { 207 | fmt.Println("Error occured while parse iprange") 208 | return err 209 | } 210 | 211 | e.ExcdIps = append(e.ExcdIps, result) 212 | } 213 | } 214 | } 215 | 216 | for _, ipe := range e.ExcdIps { 217 | for i := 0; i < len(e.TaskIps); i++ { 218 | if res, ok := (e.TaskIps[i]).RemoveExcFromTaskIps(ipe); ok { 219 | e.TaskIps = append(e.TaskIps, res) 220 | } 221 | } 222 | } 223 | } 224 | 225 | // 说明有自定义端口 226 | if len(e.Options.CmdPorts) != 0 { 227 | ports = e.Options.CmdPorts 228 | } else { 229 | if !e.Options.CmdT1000 { 230 | // Top100端口扫描 231 | ports = common.Top100Ports 232 | 233 | } else { 234 | // Top1000端口扫描 235 | ports = common.Top1000Ports 236 | } 237 | } 238 | 239 | // 解析命令行端口范围 240 | for _, portstr := range ports { 241 | result, err := rc.ParsePortRange(portstr) 242 | if err != nil { 243 | fmt.Println(err) 244 | return err 245 | } 246 | 247 | e.TaskPorts = append(e.TaskPorts, result) 248 | } 249 | 250 | // 解析待排除端口范围 251 | if len(e.Options.ExcPorts) != 0 { 252 | for _, portstr := range e.Options.ExcPorts { 253 | result, err := rc.ParsePortRange(portstr) 254 | if err != nil { 255 | fmt.Println(err) 256 | return err 257 | } 258 | 259 | e.ExcdPorts = append(e.ExcdPorts, result) 260 | } 261 | 262 | // range出来的其实是原始值的拷贝,因此,这里需要对原始值进行修改时,不能使用range 263 | for _, exp := range e.ExcdPorts { 264 | for i := 0; i < len(e.TaskPorts); i++ { 265 | if res, ok := (e.TaskPorts[i]).RemoveExcFromTaskIps(exp); ok { 266 | e.TaskPorts = append(e.TaskPorts, res) 267 | } 268 | } 269 | } 270 | } 271 | 272 | // fmt.Println(e.TaskPorts) 273 | // fmt.Println(e.ExcdPorts) 274 | return nil 275 | } 276 | -------------------------------------------------------------------------------- /pkg/Ginfo/Ghttp/Ghttp.go: -------------------------------------------------------------------------------- 1 | package Ghttp 2 | 3 | import ( 4 | "bytes" 5 | "crypto/tls" 6 | "crypto/x509" 7 | "encoding/json" 8 | "errors" 9 | "fmt" 10 | "io/ioutil" 11 | "net" 12 | "net/http" 13 | "net/url" 14 | "strconv" 15 | "strings" 16 | "time" 17 | 18 | "github.com/redtoolskobe/scaninfo/pkg/conversion" 19 | ) 20 | 21 | const ( 22 | // HTTP defines the plain http scheme 23 | HTTP = "http" 24 | // HTTPS defines the secure http scheme 25 | HTTPS = "https" 26 | // HTTPorHTTPS defines the both http and https scheme 27 | HTTPorHTTPS = "http|https" 28 | ) 29 | 30 | type ScanOptions struct { 31 | Methods []string 32 | StoreResponseDirectory string 33 | RequestURI string 34 | RequestBody string 35 | VHost bool 36 | OutputTitle bool 37 | OutputStatusCode bool 38 | OutputLocation bool 39 | OutputContentLength bool 40 | StoreResponse bool 41 | OutputServerHeader bool 42 | OutputWebSocket bool 43 | OutputWithNoColor bool 44 | OutputMethod bool 45 | ResponseInStdout bool 46 | TLSProbe bool 47 | CSPProbe bool 48 | OutputContentType bool 49 | Unsafe bool 50 | Pipeline bool 51 | HTTP2Probe bool 52 | OutputIP bool 53 | OutputCName bool 54 | OutputCDN bool 55 | OutputResponseTime bool 56 | PreferHTTPS bool 57 | NoFallback bool 58 | } 59 | 60 | func Analyze(protocol, domain string, port int, method string, scanopts *ScanOptions) Result { 61 | origProtocol := protocol 62 | if protocol == "http" { 63 | protocol = HTTP 64 | } else { 65 | protocol = HTTPS 66 | } 67 | retried := false 68 | retry: 69 | URL := fmt.Sprintf("%s://%s", protocol, domain) 70 | if port > 0 { 71 | URL = fmt.Sprintf("%s://%s:%d", protocol, domain, port) 72 | } 73 | 74 | var client *http.Client 75 | tr := &http.Transport{ 76 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 77 | } 78 | client = &http.Client{ 79 | Timeout: time.Second * 10, //timeout 80 | Transport: tr, 81 | } 82 | 83 | req, err := http.NewRequest(method, URL, nil) 84 | if err != nil { 85 | return Result{URL: URL, err: err} 86 | } 87 | req.Header.Set("Connection", "keep-alive") 88 | req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") 89 | 90 | resp, err := client.Do(req) 91 | 92 | if err != nil { 93 | if !retried && origProtocol == HTTPorHTTPS { 94 | if protocol == HTTPS { 95 | protocol = HTTP 96 | } else { 97 | protocol = HTTPS 98 | } 99 | retried = true 100 | goto retry 101 | } 102 | return Result{URL: URL, err: err} 103 | } 104 | 105 | var fullURL string 106 | 107 | if resp.StatusCode >= 0 { 108 | if port > 0 { 109 | fullURL = fmt.Sprintf("%s://%s:%d", protocol, domain, port) 110 | } else { 111 | fullURL = fmt.Sprintf("%s://%s", protocol, domain) 112 | } 113 | } 114 | 115 | builder := &strings.Builder{} 116 | builder.WriteString(fullURL) 117 | 118 | if scanopts.OutputStatusCode { 119 | builder.WriteString(" [") 120 | builder.WriteString(strconv.Itoa(resp.StatusCode)) 121 | builder.WriteRune(']') 122 | } 123 | 124 | if scanopts.OutputContentLength { 125 | builder.WriteString(" [") 126 | builder.WriteString(strconv.FormatInt(resp.ContentLength, 10)) 127 | builder.WriteRune(']') 128 | } 129 | 130 | if scanopts.OutputContentType { 131 | builder.WriteString(" [") 132 | builder.WriteString(resp.Header.Get("Content-Type")) 133 | builder.WriteRune(']') 134 | } 135 | 136 | defer resp.Body.Close() 137 | var titles []string 138 | body, err := ioutil.ReadAll(resp.Body) 139 | if err == nil { 140 | title1 := ExtractTitle(string(body), resp) 141 | finger := ExtractFinger(string(body), resp) 142 | if title1 != "" { 143 | titles = append(titles, title1) 144 | } 145 | if finger != "" { 146 | titles = append(titles, finger) 147 | } 148 | if scanopts.OutputTitle { 149 | builder.WriteString(" [") 150 | builder.WriteString(strings.Join(titles, "|")) 151 | builder.WriteRune(']') 152 | } 153 | } 154 | title := strings.Join(titles, "|") 155 | 156 | serverHeader1 := resp.Header.Get("Server") 157 | serverHeader2 := resp.Header.Get("X-Powered-By") 158 | var serverHeaders []string 159 | if serverHeader1 != "" { 160 | serverHeaders = append(serverHeaders, serverHeader1) 161 | } 162 | if serverHeader2 != "" { 163 | serverHeaders = append(serverHeaders, serverHeader2) 164 | } 165 | serverHeader := strings.Join(serverHeaders, "|") 166 | 167 | if scanopts.OutputServerHeader { 168 | builder.WriteString(fmt.Sprintf(" [%s]", serverHeader)) 169 | } 170 | 171 | // web socket 172 | isWebSocket := resp.StatusCode == 101 173 | if scanopts.OutputWebSocket && isWebSocket { 174 | builder.WriteString(" [websocket]") 175 | } 176 | 177 | return Result{ 178 | URL: fullURL, 179 | ContentLength: len(body), 180 | StatusCode: resp.StatusCode, 181 | ContentType: resp.Header.Get("Content-Type"), 182 | Title: title, 183 | WebServer: serverHeader, 184 | str: builder.String(), 185 | } 186 | } 187 | 188 | // Result of a scan 189 | type Result struct { 190 | URL string `json:"url"` 191 | Title string `json:"title"` 192 | WebServer string `json:"webserver"` 193 | ContentType string `json:"content-type,omitempty"` 194 | ContentLength int `json:"content-length"` 195 | StatusCode int `json:"status-code"` 196 | err error 197 | str string 198 | } 199 | 200 | // JSON the result 201 | func (r *Result) JSON() string { 202 | if js, err := json.Marshal(r); err == nil { 203 | return string(js) 204 | } 205 | 206 | return "" 207 | } 208 | 209 | func GetHttpTitle(target, proc string, port int) Result { 210 | var scanopts = new(ScanOptions) 211 | scanopts.OutputTitle = true 212 | scanopts.OutputServerHeader = true 213 | result := Analyze(proc, target, port, "GET", scanopts) 214 | return result 215 | } 216 | 217 | func (r *Result) ToString() string { 218 | 219 | builder := &bytes.Buffer{} 220 | if r.err == nil { 221 | builder.WriteString("[") 222 | builder.WriteString(conversion.ToString(r.StatusCode)) 223 | builder.WriteString("] ") 224 | if r.WebServer != "" { 225 | builder.WriteString("[") 226 | builder.WriteString(r.WebServer) 227 | builder.WriteString("] ") 228 | } 229 | if r.Title != "" { 230 | builder.WriteString("[") 231 | builder.WriteString(r.Title) 232 | builder.WriteString("] ") 233 | } 234 | } 235 | 236 | return builder.String() 237 | } 238 | 239 | func hostsFrom(ss []string) []string { 240 | for i, s := range ss { 241 | u, _ := url.Parse(s) 242 | if host := u.Hostname(); host != "" { 243 | ss[i] = host 244 | } 245 | } 246 | return ss 247 | } 248 | 249 | type hostinfo struct { 250 | Host string 251 | Port int 252 | Certs []*x509.Certificate 253 | } 254 | 255 | func (h *hostinfo) getCerts(timeout time.Duration) error { 256 | //log.Printf("connecting to %s:%d", h.Host, h.Port) 257 | dialer := &net.Dialer{Timeout: timeout} 258 | conn, err := tls.DialWithDialer( 259 | dialer, 260 | "tcp", 261 | h.Host+":"+strconv.Itoa(h.Port), 262 | &tls.Config{ 263 | InsecureSkipVerify: true, 264 | }) 265 | if err != nil { 266 | return err 267 | } 268 | 269 | defer conn.Close() 270 | 271 | if err := conn.Handshake(); err != nil { 272 | return err 273 | } 274 | 275 | pc := conn.ConnectionState().PeerCertificates 276 | h.Certs = make([]*x509.Certificate, 0, len(pc)) 277 | for _, cert := range pc { 278 | if cert.IsCA { 279 | continue 280 | } 281 | h.Certs = append(h.Certs, cert) 282 | } 283 | 284 | return nil 285 | } 286 | 287 | func CertInfo(host string, port string, timeout time.Duration) (commonName string, dnsNames []string, err error) { 288 | port_int, err := strconv.Atoi(port) 289 | if err != nil { 290 | return commonName, dnsNames, err 291 | } 292 | info := hostinfo{Host: host, Port: port_int} 293 | err = info.getCerts(timeout) 294 | if err != nil { 295 | return commonName, dnsNames, err 296 | } 297 | for _, cert := range info.Certs { 298 | if cert != nil && cert.Subject.CommonName != "" { 299 | return cert.Subject.CommonName, cert.DNSNames, err 300 | } 301 | } 302 | return commonName, dnsNames, errors.New("not found") 303 | } 304 | 305 | func GetCert(domain string, port int) (string, error) { 306 | var CN string 307 | var DN []string 308 | var ret string 309 | var err error 310 | if port > 0 { 311 | CN, DN, err = CertInfo(domain, strconv.Itoa(port), 5*time.Second) 312 | } else { 313 | CN, DN, err = CertInfo(domain, "443", 5*time.Second) 314 | } 315 | ret = "CommonName:" + CN + "; " 316 | if len(DN) > 0 { 317 | ret = ret + "DNSName:" 318 | ret = ret + DN[0] 319 | } 320 | return ret, err 321 | } 322 | -------------------------------------------------------------------------------- /pkg/Ginfo/Gnbtscan/GNetBIOS.go: -------------------------------------------------------------------------------- 1 | package Gnbtscan 2 | 3 | //forked from https://github.com/shadow1ng/fscan/blob/main/Plugins/NetBIOS.go 4 | 5 | import ( 6 | "bytes" 7 | "fmt" 8 | "net" 9 | "strconv" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | var ( 15 | UNIQUE_NAMES = map[string]string{ 16 | "\x00": "Workstation Service", 17 | "\x03": "Messenger Service", 18 | "\x06": "RAS Server Service", 19 | "\x1F": "NetDDE Service", 20 | "\x20": "Server Service", 21 | "\x21": "RAS Client Service", 22 | "\xBE": "Network Monitor Agent", 23 | "\xBF": "Network Monitor Application", 24 | "\x1D": "Master Browser", 25 | "\x1B": "Domain Master Browser", 26 | } 27 | 28 | GROUP_NAMES = map[string]string{ 29 | "\x00": "Domain Name", 30 | "\x1C": "Domain Controllers", 31 | "\x1E": "Browser Service Elections", 32 | } 33 | 34 | NetBIOS_ITEM_TYPE = map[string]string{ 35 | "\x01\x00": "NetBIOS computer name", 36 | "\x02\x00": "NetBIOS domain name", 37 | "\x03\x00": "DNS computer name", 38 | "\x04\x00": "DNS domain name", 39 | "\x05\x00": "DNS tree name", 40 | "\x07\x00": "Time stamp", 41 | } 42 | ) 43 | 44 | type NbnsName struct { 45 | unique string 46 | group string 47 | msg string 48 | osversion string 49 | } 50 | 51 | //Scan get netbios stat information by udp137 52 | func Scan(ip string) (string, error) { 53 | nbname, err := GetNbnsname(ip) 54 | var msg, isdc string 55 | 56 | if strings.Contains(nbname.msg, "Domain Controllers") { 57 | isdc = "[DC]" 58 | } 59 | msg = fmt.Sprintf("%s%s\\%s %s", isdc, nbname.group, nbname.unique, nbname.osversion) 60 | 61 | if len(nbname.group) > 0 || len(nbname.unique) > 0 { 62 | return msg, nil 63 | } 64 | return "", err 65 | } 66 | 67 | //NetBIOS1 get netbios name, group and os version by udp137 and tcp139 port 68 | func NetBIOS1(ip string) (nbname NbnsName, err error) { 69 | nbname, err = GetNbnsname(ip) 70 | var payload0 []byte 71 | if err == nil { 72 | name := netbiosEncode(nbname.unique) 73 | payload0 = append(payload0, []byte("\x81\x00\x00D ")...) 74 | payload0 = append(payload0, name...) 75 | payload0 = append(payload0, []byte("\x00 EOENEBFACACACACACACACACACACACACA\x00")...) 76 | } 77 | realhost := fmt.Sprintf("%s:%v", ip, 139) 78 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(3)*time.Second) 79 | if err != nil { 80 | return 81 | } 82 | err = conn.SetDeadline(time.Now().Add(time.Duration(3) * time.Second)) 83 | if err != nil { 84 | return 85 | } 86 | defer conn.Close() 87 | 88 | if len(payload0) > 0 { 89 | _, err1 := conn.Write(payload0) 90 | if err1 != nil { 91 | return 92 | } 93 | _, err1 = readbytes(conn) 94 | if err1 != nil { 95 | return 96 | } 97 | } 98 | 99 | payload1 := []byte("\x00\x00\x00\x85\xff\x53\x4d\x42\x72\x00\x00\x00\x00\x18\x53\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x00\x00\x00\x62\x00\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00") 100 | payload2 := []byte("\x00\x00\x01\x0a\xff\x53\x4d\x42\x73\x00\x00\x00\x00\x18\x07\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x40\x00\x0c\xff\x00\x0a\x01\x04\x41\x32\x00\x00\x00\x00\x00\x00\x00\x4a\x00\x00\x00\x00\x00\xd4\x00\x00\xa0\xcf\x00\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x02\xce\x0e\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x33\x00\x37\x00\x39\x00\x30\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x32\x00\x00\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x35\x00\x2e\x00\x32\x00\x00\x00\x00\x00") 101 | _, err = conn.Write(payload1) 102 | if err != nil { 103 | return 104 | } 105 | _, err = readbytes(conn) 106 | if err != nil { 107 | return 108 | } 109 | 110 | _, err = conn.Write(payload2) 111 | if err != nil { 112 | return 113 | } 114 | ret, err := readbytes(conn) 115 | if err != nil || len(ret) < 45 { 116 | return 117 | } 118 | 119 | num1, err := bytetoint(ret[43:44][0]) 120 | if err != nil { 121 | return 122 | } 123 | num2, err := bytetoint(ret[44:45][0]) 124 | if err != nil { 125 | return 126 | } 127 | length := num1 + num2*256 128 | os_version := ret[47+length:] 129 | tmp1 := bytes.ReplaceAll(os_version, []byte{0x00, 0x00}, []byte{124}) 130 | tmp1 = bytes.ReplaceAll(tmp1, []byte{0x00}, []byte{}) 131 | msg1 := string(tmp1[:len(tmp1)-1]) 132 | nbname.osversion = msg1 133 | index1 := strings.Index(msg1, "|") 134 | if index1 > 0 { 135 | nbname.osversion = nbname.osversion[:index1] 136 | } 137 | nbname.msg += "-------------------------------------------\n" 138 | nbname.msg += msg1 + "\n" 139 | start := bytes.Index(ret, []byte("NTLMSSP")) 140 | if len(ret) < start+45 { 141 | return 142 | } 143 | num1, err = bytetoint(ret[start+40 : start+41][0]) 144 | if err != nil { 145 | return 146 | } 147 | num2, err = bytetoint(ret[start+41 : start+42][0]) 148 | if err != nil { 149 | return 150 | } 151 | length = num1 + num2*256 152 | num1, err = bytetoint(ret[start+44 : start+45][0]) 153 | if err != nil { 154 | return 155 | } 156 | offset, err := bytetoint(ret[start+44 : start+45][0]) 157 | if err != nil || len(ret) < start+offset+length { 158 | return 159 | } 160 | index := start + offset 161 | for index < start+offset+length { 162 | item_type := ret[index : index+2] 163 | num1, err = bytetoint(ret[index+2 : index+3][0]) 164 | if err != nil { 165 | return 166 | } 167 | num2, err = bytetoint(ret[index+3 : index+4][0]) 168 | if err != nil { 169 | return 170 | } 171 | item_length := num1 + num2*256 172 | item_content := bytes.ReplaceAll(ret[index+4:index+4+item_length], []byte{0x00}, []byte{}) 173 | index += 4 + item_length 174 | if string(item_type) == "\x07\x00" { 175 | //Time stamp, 暂时不想处理 176 | } else if NetBIOS_ITEM_TYPE[string(item_type)] != "" { 177 | nbname.msg += fmt.Sprintf("%-22s: %s\n", NetBIOS_ITEM_TYPE[string(item_type)], string(item_content)) 178 | } else if string(item_type) == "\x00\x00" { 179 | break 180 | } else { 181 | nbname.msg += fmt.Sprintf("Unknown: %s\n", string(item_content)) 182 | } 183 | } 184 | return nbname, err 185 | } 186 | 187 | func GetNbnsname(ip string) (nbname NbnsName, err error) { 188 | senddata1 := []byte{102, 102, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 32, 67, 75, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0, 0, 33, 0, 1} 189 | realhost := fmt.Sprintf("%s:%v", ip, 137) 190 | conn, err := net.DialTimeout("udp", realhost, time.Duration(3)*time.Second) 191 | if err != nil { 192 | return 193 | } 194 | err = conn.SetDeadline(time.Now().Add(time.Duration(3) * time.Second)) 195 | if err != nil { 196 | return 197 | } 198 | defer conn.Close() 199 | _, err = conn.Write(senddata1) 200 | if err != nil { 201 | return 202 | } 203 | text, err := readbytes(conn) 204 | if err != nil { 205 | return 206 | } 207 | if len(text) < 57 { 208 | return nbname, fmt.Errorf("no names available") 209 | } 210 | num, err := bytetoint(text[56:57][0]) 211 | if err != nil { 212 | return 213 | } 214 | data := text[57:] 215 | var msg string 216 | for i := 0; i < num; i++ { 217 | if len(data) < 18*i+16 { 218 | break 219 | } 220 | name := string(data[18*i : 18*i+15]) 221 | flag_bit := data[18*i+15 : 18*i+16] 222 | if GROUP_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" { 223 | msg += fmt.Sprintf("%s G %s\n", name, GROUP_NAMES[string(flag_bit)]) 224 | } else if UNIQUE_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" { 225 | msg += fmt.Sprintf("%s U %s\n", name, UNIQUE_NAMES[string(flag_bit)]) 226 | } else if string(flag_bit) == "\x00" || len(data) >= 18*i+18 { 227 | name_flags := data[18*i+16 : 18*i+18][0] 228 | if name_flags >= 128 { 229 | nbname.group = strings.Replace(name, " ", "", -1) 230 | msg += fmt.Sprintf("%s G %s\n", name, GROUP_NAMES[string(flag_bit)]) 231 | } else { 232 | nbname.unique = strings.Replace(name, " ", "", -1) 233 | msg += fmt.Sprintf("%s U %s\n", name, UNIQUE_NAMES[string(flag_bit)]) 234 | } 235 | } else { 236 | msg += fmt.Sprintf("%s \n", name) 237 | } 238 | } 239 | nbname.msg += msg 240 | return 241 | } 242 | 243 | func readbytes(conn net.Conn) (result []byte, err error) { 244 | buf := make([]byte, 4096) 245 | for { 246 | count, err := conn.Read(buf) 247 | if err != nil { 248 | break 249 | } 250 | result = append(result, buf[0:count]...) 251 | if count < 4096 { 252 | break 253 | } 254 | } 255 | return result, err 256 | } 257 | 258 | func bytetoint(text byte) (int, error) { 259 | num1 := fmt.Sprintf("%v", text) 260 | num, err := strconv.Atoi(num1) 261 | return num, err 262 | } 263 | 264 | func netbiosEncode(name string) (output []byte) { 265 | var names []int 266 | src := fmt.Sprintf("%-16s", name) 267 | for _, a := range src { 268 | char_ord := int(a) 269 | high_4_bits := char_ord >> 4 270 | low_4_bits := char_ord & 0x0f 271 | names = append(names, high_4_bits, low_4_bits) 272 | } 273 | for _, one := range names { 274 | out := (one + 0x41) 275 | output = append(output, byte(out)) 276 | } 277 | return 278 | } 279 | -------------------------------------------------------------------------------- /pkg/Plugins/NetBIOS.go: -------------------------------------------------------------------------------- 1 | package Plugins 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "net" 7 | "strconv" 8 | "strings" 9 | "time" 10 | 11 | "github.com/redtoolskobe/scaninfo/model" 12 | 13 | "github.com/redtoolskobe/scaninfo/global" 14 | "go.uber.org/zap" 15 | 16 | "github.com/redtoolskobe/scaninfo/pkg/options" 17 | 18 | "github.com/redtoolskobe/scaninfo/pkg/common" 19 | ) 20 | 21 | var ( 22 | UNIQUE_NAMES = map[string]string{ 23 | "\x00": "Workstation Service", 24 | "\x03": "Messenger Service", 25 | "\x06": "RAS Server Service", 26 | "\x1F": "NetDDE Service", 27 | "\x20": "Server Service", 28 | "\x21": "RAS Client Service", 29 | "\xBE": "Network Monitor Agent", 30 | "\xBF": "Network Monitor Application", 31 | "\x1D": "Master Browser", 32 | "\x1B": "Domain Master Browser", 33 | } 34 | 35 | GROUP_NAMES = map[string]string{ 36 | "\x00": "Domain Name", 37 | "\x1C": "Domain Controllers", 38 | "\x1E": "Browser Service Elections", 39 | } 40 | 41 | NetBIOS_ITEM_TYPE = map[string]string{ 42 | "\x01\x00": "NetBIOS computer name", 43 | "\x02\x00": "NetBIOS domain name", 44 | "\x03\x00": "DNS computer name", 45 | "\x04\x00": "DNS domain name", 46 | "\x05\x00": "DNS tree name", 47 | "\x07\x00": "Time stamp", 48 | } 49 | ) 50 | 51 | type NbnsName struct { 52 | unique string 53 | group string 54 | msg string 55 | osversion string 56 | } 57 | 58 | func NetBIOS(info *options.HostInfo) error { 59 | nbname, err := NetBIOS1(info) 60 | var msg, isdc string 61 | 62 | if strings.Contains(nbname.msg, "Domain Controllers") { 63 | isdc = "[+]DC" 64 | } 65 | msg += fmt.Sprintf("[*] %-15s%-5s %s\\%-15s %s", info.Host, isdc, nbname.group, nbname.unique, nbname.osversion) 66 | 67 | if info.Scantype == "netbios" { 68 | msg += "\n-------------------------------------------\n" + nbname.msg 69 | } 70 | if len(nbname.group) > 0 || len(nbname.unique) > 0 { 71 | res := common.VulInfo{"plugin", info.TaskID, map[string]interface{}{"type": "NetBIOS", "result": msg, "host": info.Host}} 72 | common.LogSuccess(&res) 73 | global.Log.Warn("plugin", zap.String("NetBIOS", "NetBIOS"), zap.String("host", info.Host), 74 | zap.String("result", msg)) 75 | model.PluginList = append(model.PluginList, model.Plugin{"NetBIOS", msg, info.Host, info.Ports}) 76 | } 77 | return err 78 | } 79 | 80 | func NetBIOS1(info *options.HostInfo) (nbname NbnsName, err error) { 81 | nbname, err = GetNbnsname(info) 82 | var payload0 []byte 83 | if err == nil { 84 | name := netbiosEncode(nbname.unique) 85 | payload0 = append(payload0, []byte("\x81\x00\x00D ")...) 86 | payload0 = append(payload0, name...) 87 | payload0 = append(payload0, []byte("\x00 EOENEBFACACACACACACACACACACACACA\x00")...) 88 | } 89 | realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports) 90 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) 91 | if err != nil { 92 | return 93 | } 94 | err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second)) 95 | if err != nil { 96 | return 97 | } 98 | defer conn.Close() 99 | 100 | if info.Ports == "139" && len(payload0) > 0 { 101 | _, err1 := conn.Write(payload0) 102 | if err1 != nil { 103 | return 104 | } 105 | _, err1 = readbytes(conn) 106 | if err1 != nil { 107 | return 108 | } 109 | } 110 | 111 | payload1 := []byte("\x00\x00\x00\x85\xff\x53\x4d\x42\x72\x00\x00\x00\x00\x18\x53\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x00\x00\x00\x62\x00\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00") 112 | payload2 := []byte("\x00\x00\x01\x0a\xff\x53\x4d\x42\x73\x00\x00\x00\x00\x18\x07\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x40\x00\x0c\xff\x00\x0a\x01\x04\x41\x32\x00\x00\x00\x00\x00\x00\x00\x4a\x00\x00\x00\x00\x00\xd4\x00\x00\xa0\xcf\x00\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x02\xce\x0e\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x33\x00\x37\x00\x39\x00\x30\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x32\x00\x00\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x35\x00\x2e\x00\x32\x00\x00\x00\x00\x00") 113 | _, err = conn.Write(payload1) 114 | if err != nil { 115 | return 116 | } 117 | _, err = readbytes(conn) 118 | if err != nil { 119 | return 120 | } 121 | 122 | _, err = conn.Write(payload2) 123 | if err != nil { 124 | return 125 | } 126 | ret, err := readbytes(conn) 127 | if err != nil || len(ret) < 45 { 128 | return 129 | } 130 | 131 | num1, err := bytetoint(ret[43:44][0]) 132 | if err != nil { 133 | return 134 | } 135 | num2, err := bytetoint(ret[44:45][0]) 136 | if err != nil { 137 | return 138 | } 139 | length := num1 + num2*256 140 | if len(ret) < 48+length { 141 | return 142 | } 143 | os_version := ret[47+length:] 144 | tmp1 := bytes.ReplaceAll(os_version, []byte{0x00, 0x00}, []byte{124}) 145 | tmp1 = bytes.ReplaceAll(tmp1, []byte{0x00}, []byte{}) 146 | msg1 := string(tmp1[:len(tmp1)-1]) 147 | nbname.osversion = msg1 148 | index1 := strings.Index(msg1, "|") 149 | if index1 > 0 { 150 | nbname.osversion = nbname.osversion[:index1] 151 | } 152 | nbname.msg += "-------------------------------------------\n" 153 | nbname.msg += msg1 + "\n" 154 | start := bytes.Index(ret, []byte("NTLMSSP")) 155 | if len(ret) < start+45 { 156 | return 157 | } 158 | num1, err = bytetoint(ret[start+40 : start+41][0]) 159 | if err != nil { 160 | return 161 | } 162 | num2, err = bytetoint(ret[start+41 : start+42][0]) 163 | if err != nil { 164 | return 165 | } 166 | length = num1 + num2*256 167 | num1, err = bytetoint(ret[start+44 : start+45][0]) 168 | if err != nil { 169 | return 170 | } 171 | offset, err := bytetoint(ret[start+44 : start+45][0]) 172 | if err != nil || len(ret) < start+offset+length { 173 | return 174 | } 175 | index := start + offset 176 | for index < start+offset+length { 177 | item_type := ret[index : index+2] 178 | num1, err = bytetoint(ret[index+2 : index+3][0]) 179 | if err != nil { 180 | return 181 | } 182 | num2, err = bytetoint(ret[index+3 : index+4][0]) 183 | if err != nil { 184 | return 185 | } 186 | item_length := num1 + num2*256 187 | item_content := bytes.ReplaceAll(ret[index+4:index+4+item_length], []byte{0x00}, []byte{}) 188 | index += 4 + item_length 189 | if string(item_type) == "\x07\x00" { 190 | //Time stamp, 暂时不想处理 191 | } else if NetBIOS_ITEM_TYPE[string(item_type)] != "" { 192 | nbname.msg += fmt.Sprintf("%-22s: %s\n", NetBIOS_ITEM_TYPE[string(item_type)], string(item_content)) 193 | } else if string(item_type) == "\x00\x00" { 194 | break 195 | } else { 196 | nbname.msg += fmt.Sprintf("Unknown: %s\n", string(item_content)) 197 | } 198 | } 199 | return nbname, err 200 | } 201 | 202 | func GetNbnsname(info *options.HostInfo) (nbname NbnsName, err error) { 203 | senddata1 := []byte{102, 102, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 32, 67, 75, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0, 0, 33, 0, 1} 204 | realhost := fmt.Sprintf("%s:%v", info.Host, 137) 205 | conn, err := net.DialTimeout("udp", realhost, time.Duration(info.Timeout)*time.Second) 206 | if err != nil { 207 | return 208 | } 209 | err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second)) 210 | if err != nil { 211 | return 212 | } 213 | defer conn.Close() 214 | _, err = conn.Write(senddata1) 215 | if err != nil { 216 | return 217 | } 218 | text, err := readbytes(conn) 219 | if err != nil { 220 | return 221 | } 222 | if len(text) < 57 { 223 | return nbname, fmt.Errorf("no names available") 224 | } 225 | num, err := bytetoint(text[56:57][0]) 226 | if err != nil { 227 | return 228 | } 229 | data := text[57:] 230 | var msg string 231 | for i := 0; i < num; i++ { 232 | if len(data) < 18*i+16 { 233 | break 234 | } 235 | name := string(data[18*i : 18*i+15]) 236 | flag_bit := data[18*i+15 : 18*i+16] 237 | if GROUP_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" { 238 | msg += fmt.Sprintf("%s G %s\n", name, GROUP_NAMES[string(flag_bit)]) 239 | } else if UNIQUE_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" { 240 | msg += fmt.Sprintf("%s U %s\n", name, UNIQUE_NAMES[string(flag_bit)]) 241 | } else if string(flag_bit) == "\x00" || len(data) >= 18*i+18 { 242 | name_flags := data[18*i+16 : 18*i+18][0] 243 | if name_flags >= 128 { 244 | nbname.group = strings.Replace(name, " ", "", -1) 245 | msg += fmt.Sprintf("%s G %s\n", name, GROUP_NAMES[string(flag_bit)]) 246 | } else { 247 | nbname.unique = strings.Replace(name, " ", "", -1) 248 | msg += fmt.Sprintf("%s U %s\n", name, UNIQUE_NAMES[string(flag_bit)]) 249 | } 250 | } else { 251 | msg += fmt.Sprintf("%s \n", name) 252 | } 253 | } 254 | nbname.msg += msg 255 | return 256 | } 257 | 258 | func readbytes(conn net.Conn) (result []byte, err error) { 259 | buf := make([]byte, 4096) 260 | for { 261 | count, err := conn.Read(buf) 262 | if err != nil { 263 | break 264 | } 265 | result = append(result, buf[0:count]...) 266 | if count < 4096 { 267 | break 268 | } 269 | } 270 | return result, err 271 | } 272 | 273 | func bytetoint(text byte) (int, error) { 274 | num1 := fmt.Sprintf("%v", text) 275 | num, err := strconv.Atoi(num1) 276 | return num, err 277 | } 278 | 279 | func netbiosEncode(name string) (output []byte) { 280 | var names []int 281 | src := fmt.Sprintf("%-16s", name) 282 | for _, a := range src { 283 | char_ord := int(a) 284 | high_4_bits := char_ord >> 4 285 | low_4_bits := char_ord & 0x0f 286 | names = append(names, high_4_bits, low_4_bits) 287 | } 288 | for _, one := range names { 289 | out := (one + 0x41) 290 | output = append(output, byte(out)) 291 | } 292 | return 293 | } 294 | -------------------------------------------------------------------------------- /pkg/common/engine.TXT: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "strings" 8 | "sync" 9 | "time" 10 | 11 | "github.com/pterm/pterm" 12 | 13 | "github.com/4dogs-cn/TXPortMap/pkg/Ginfo/Ghttp" 14 | "github.com/4dogs-cn/TXPortMap/pkg/Ginfo/Gnbtscan" 15 | ps "github.com/4dogs-cn/TXPortMap/pkg/common/ipparser" 16 | rc "github.com/4dogs-cn/TXPortMap/pkg/common/rangectl" 17 | "github.com/4dogs-cn/TXPortMap/pkg/conversion" 18 | "github.com/4dogs-cn/TXPortMap/pkg/output" 19 | "go.uber.org/ratelimit" 20 | ) 21 | 22 | type Addr struct { 23 | ip string 24 | port uint64 25 | } 26 | 27 | type NBTScanIPMap struct { 28 | sync.Mutex 29 | IPS map[string]struct{} 30 | } 31 | 32 | // type Range struct { 33 | // Begin uint64 34 | // End uint64 35 | // } 36 | 37 | var ( 38 | mutex sync.Mutex 39 | Writer output.Writer 40 | NBTScanIPs = NBTScanIPMap{IPS: make(map[string]struct{})} 41 | totoal int64 42 | req int64 43 | Count int 44 | Bar *pterm.ProgressbarPrinter 45 | progressErr error 46 | Progre Progress 47 | ) 48 | 49 | type Engine struct { 50 | TaskIps []rc.Range 51 | TaskPorts []rc.Range 52 | ExcdPorts []rc.Range // 待排除端口 53 | ExcdIps []rc.Range // 待排除的Ip 54 | RandomFlag bool 55 | WorkerCount int 56 | TaskChan chan Addr // 传递待扫描的ip端口对 57 | //DoneChan chan struct{} // 任务完成通知 58 | Wg *sync.WaitGroup 59 | } 60 | 61 | // SetIP as seen 62 | func (r *NBTScanIPMap) SetIP(ip string) { 63 | r.Lock() 64 | defer r.Unlock() 65 | 66 | r.IPS[ip] = struct{}{} 67 | } 68 | 69 | // HasIP checks if an ip has been seen 70 | func (r *NBTScanIPMap) HasIP(ip string) bool { 71 | r.Lock() 72 | defer r.Unlock() 73 | 74 | _, ok := r.IPS[ip] 75 | return ok 76 | } 77 | 78 | // 扫描目标建立,ip:port发送到任务通道 79 | func (e *Engine) Run() { 80 | var addr Addr 81 | e.Wg.Add(e.WorkerCount) 82 | go e.Scheduler() 83 | 84 | // fmt.Println(e.TaskPorts) 85 | 86 | // TODO:: if !e.RandomFlag 87 | if !e.RandomFlag { 88 | // 随机扫描,向任务通道随机发送addr 89 | e.randomScan() 90 | 91 | } else { 92 | // 顺序扫描,向任务通道顺序发送addr 93 | for _, ipnum := range e.TaskIps { 94 | for ips := ipnum.Begin; ips <= ipnum.End; ips++ { 95 | ip := ps.UnParseIPv4(ips) 96 | 97 | for _, ports := range e.TaskPorts { 98 | for port := ports.Begin; port <= ports.End; port++ { 99 | addr.ip = ip 100 | addr.port = port 101 | 102 | //e.SubmitTask(addr) 103 | //fmt.Println("ip:",ip,":port",port) 104 | e.TaskChan <- addr 105 | } 106 | } 107 | } 108 | } 109 | } 110 | 111 | // 扫描任务发送完成,关闭通道 112 | //fmt.Println("Task Add done") 113 | close(e.TaskChan) 114 | } 115 | 116 | func (e *Engine) SubmitTask(addr Addr) { 117 | //fmt.Printf("submit# %s:%d\n", addr.ip, addr.port) 118 | go func() { 119 | e.TaskChan <- addr 120 | }() 121 | } 122 | 123 | // 扫描任务创建 124 | func (e *Engine) Scheduler() { 125 | for i := 0; i < e.WorkerCount; i++ { 126 | worker(e.TaskChan, e.Wg) 127 | } 128 | } 129 | 130 | // 参数解析,对命令行中传递的参数进行格式化存储 131 | func (e *Engine) Parser() error { 132 | var err error 133 | Writer, err = output.NewStandardWriter(nocolor, json, rstfile, tracelog) 134 | if err != nil { 135 | return err 136 | } 137 | var ports []string 138 | // TODO:: 待增加排除ip和排除端口流程 139 | 140 | for _, ipstr := range cmdIps { 141 | if ps.IsIP(ipstr) || ps.IsIPRange(ipstr) { 142 | result, err := rc.ParseIpv4Range(ipstr) 143 | if err != nil { 144 | fmt.Println("Error occured while parse iprange") 145 | return err 146 | } 147 | 148 | e.TaskIps = append(e.TaskIps, result) 149 | } else { 150 | // 说明是域名,需要对域名进行解析 151 | ips, mask, err := ps.DomainToIp(ipstr) 152 | if err != nil { 153 | fmt.Println(err) 154 | return err 155 | } 156 | for _, ip := range ips { 157 | addr := ip 158 | if mask != "" { 159 | addr = ip + "/" + mask 160 | } 161 | 162 | result, err := rc.ParseIpv4Range(addr) 163 | 164 | if err != nil { 165 | fmt.Println("Error occured while parse iprange") 166 | return err 167 | } 168 | 169 | e.TaskIps = append(e.TaskIps, result) 170 | } 171 | } 172 | } 173 | 174 | if ipFile != "" { 175 | rst, err := rc.ParseIPFromFile(ipFile) 176 | if err == nil { 177 | for _, r := range rst { 178 | e.TaskIps = append(e.TaskIps, r) 179 | } 180 | } 181 | } 182 | 183 | if len(excIps) != 0 { 184 | for _, ipstr := range excIps { 185 | if ps.IsIP(ipstr) || ps.IsIPRange(ipstr) { 186 | result, err := rc.ParseIpv4Range(ipstr) 187 | if err != nil { 188 | fmt.Println("Error occured while parse iprange") 189 | return err 190 | } 191 | 192 | e.ExcdIps = append(e.ExcdIps, result) 193 | } else { 194 | // 说明是域名,需要对域名进行解析 195 | ips, mask, err := ps.DomainToIp(ipstr) 196 | if err != nil { 197 | fmt.Println(err) 198 | return err 199 | } 200 | for _, ip := range ips { 201 | addr := ip 202 | if mask != "" { 203 | addr = ip + "/" + mask 204 | } 205 | 206 | result, err := rc.ParseIpv4Range(addr) 207 | 208 | if err != nil { 209 | fmt.Println("Error occured while parse iprange") 210 | return err 211 | } 212 | 213 | e.ExcdIps = append(e.ExcdIps, result) 214 | } 215 | } 216 | } 217 | 218 | for _, ipe := range e.ExcdIps { 219 | for i := 0; i < len(e.TaskIps); i++ { 220 | if res, ok := (e.TaskIps[i]).RemoveExcFromTaskIps(ipe); ok { 221 | e.TaskIps = append(e.TaskIps, res) 222 | } 223 | } 224 | } 225 | } 226 | 227 | // 说明有自定义端口 228 | if len(cmdPorts) != 0 { 229 | ports = cmdPorts 230 | } else { 231 | if !cmdT1000 { 232 | // Top100端口扫描 233 | ports = Top100Ports 234 | 235 | } else { 236 | // Top1000端口扫描 237 | ports = Top1000Ports 238 | } 239 | } 240 | 241 | // 解析命令行端口范围 242 | for _, portstr := range ports { 243 | result, err := rc.ParsePortRange(portstr) 244 | if err != nil { 245 | fmt.Println(err) 246 | return err 247 | } 248 | 249 | e.TaskPorts = append(e.TaskPorts, result) 250 | } 251 | 252 | // 解析待排除端口范围 253 | if len(excPorts) != 0 { 254 | for _, portstr := range excPorts { 255 | result, err := rc.ParsePortRange(portstr) 256 | if err != nil { 257 | fmt.Println(err) 258 | return err 259 | } 260 | 261 | e.ExcdPorts = append(e.ExcdPorts, result) 262 | } 263 | 264 | // range出来的其实是原始值的拷贝,因此,这里需要对原始值进行修改时,不能使用range 265 | for _, exp := range e.ExcdPorts { 266 | for i := 0; i < len(e.TaskPorts); i++ { 267 | if res, ok := (e.TaskPorts[i]).RemoveExcFromTaskIps(exp); ok { 268 | e.TaskPorts = append(e.TaskPorts, res) 269 | } 270 | } 271 | } 272 | } 273 | 274 | // fmt.Println(e.TaskPorts) 275 | // fmt.Println(e.ExcdPorts) 276 | 277 | return nil 278 | } 279 | 280 | func CreateEngine() *Engine { 281 | 282 | if limit > 1 { 283 | Limiter = ratelimit.New(limit) 284 | } else { 285 | Limiter = ratelimit.NewUnlimited() 286 | } 287 | 288 | return &Engine{ 289 | RandomFlag: cmdRandom, 290 | TaskChan: make(chan Addr, 1000), 291 | WorkerCount: NumThreads, 292 | Wg: &sync.WaitGroup{}, 293 | } 294 | } 295 | 296 | func nbtscaner(ip string) { 297 | resultEvent := output.ResultEvent{Target: ip, Info: &output.Info{}} 298 | nbInfo, err := Gnbtscan.Scan(ip) 299 | if err == nil && len(nbInfo) > 0 { 300 | resultEvent.Info.Service = "nbstat" 301 | resultEvent.Info.Banner = nbInfo 302 | Writer.Write(&resultEvent) 303 | } 304 | } 305 | 306 | func scanner(ip string, port uint64) { 307 | Progre.IncrementRequests() 308 | var dwSvc int 309 | var iRule = -1 310 | var bIsIdentification = false 311 | var resultEvent *output.ResultEvent 312 | var packet []byte 313 | //var iCntTimeOut = 0 314 | //fmt.Println(req, "/", Count) 315 | // 端口开放状态,发送报文,获取响应 316 | // 先判断端口是不是优先识别协议端口 317 | for _, svc := range St_Identification_Port { 318 | if port == svc.Port { 319 | bIsIdentification = true 320 | iRule = svc.Identification_RuleId 321 | data := st_Identification_Packet[iRule].Packet 322 | 323 | dwSvc, resultEvent = SendIdentificationPacketFunction(data, ip, port) 324 | break 325 | } 326 | } 327 | if (dwSvc > UNKNOWN_PORT && dwSvc <= SOCKET_CONNECT_FAILED) || dwSvc == SOCKET_READ_TIMEOUT { 328 | Writer.Write(resultEvent) 329 | return 330 | } 331 | 332 | // 发送其他协议查询包 333 | for i := 0; i < iPacketMask; i++ { 334 | // 超时2次,不再识别 335 | if bIsIdentification && iRule == i { 336 | continue 337 | } 338 | if i == 0 { 339 | // 说明是http,数据需要拼装一下 340 | var szOption string 341 | if port == 80 { 342 | szOption = fmt.Sprintf("%s%s\r\n\r\n", st_Identification_Packet[0].Packet, ip) 343 | } else { 344 | szOption = fmt.Sprintf("%s%s:%d\r\n\r\n", st_Identification_Packet[0].Packet, ip, port) 345 | } 346 | packet = []byte(szOption) 347 | } else { 348 | packet = st_Identification_Packet[i].Packet 349 | } 350 | 351 | dwSvc, resultEvent = SendIdentificationPacketFunction(packet, ip, port) 352 | if (dwSvc > UNKNOWN_PORT && dwSvc <= SOCKET_CONNECT_FAILED) || dwSvc == SOCKET_READ_TIMEOUT { 353 | Writer.Write(resultEvent) 354 | return 355 | } 356 | } 357 | // 没有识别到服务,也要输出当前开放端口状态 358 | Writer.Write(resultEvent) 359 | } 360 | 361 | func worker(res chan Addr, wg *sync.WaitGroup) { 362 | go func() { 363 | defer wg.Done() 364 | 365 | for addr := range res { 366 | //do netbios stat scan 367 | if nbtscan && NBTScanIPs.HasIP(addr.ip) == false { 368 | NBTScanIPs.SetIP(addr.ip) 369 | nbtscaner(addr.ip) 370 | } 371 | Limiter.Take() 372 | scanner(addr.ip, addr.port) 373 | } 374 | 375 | }() 376 | } 377 | 378 | func SendIdentificationPacketFunction(data []byte, ip string, port uint64) (int, *output.ResultEvent) { 379 | addr := fmt.Sprintf("%s:%d", ip, port) 380 | even := &output.ResultEvent{ 381 | Target: addr, 382 | Info: &output.Info{}, 383 | } 384 | 385 | //fmt.Println(addr) 386 | var dwSvc int = UNKNOWN_PORT 387 | conn, err := net.DialTimeout("tcp", addr, time.Duration(tout*1000)*time.Millisecond) 388 | if err != nil { 389 | // 端口是closed状态 390 | Writer.Request(ip, conversion.ToString(port), "tcp", fmt.Errorf("time out")) 391 | return SOCKET_CONNECT_FAILED, nil 392 | } 393 | 394 | defer conn.Close() 395 | 396 | // Write方法是非阻塞的 397 | 398 | if _, err := conn.Write(data); err != nil { 399 | // 端口是开放的 400 | Writer.Request(ip, conversion.ToString(port), "tcp", err) 401 | return dwSvc, even 402 | } 403 | 404 | // 直接开辟好空间,避免底层数组频繁申请内存 405 | var fingerprint = make([]byte, 0, 65535) 406 | var tmp = make([]byte, 256) 407 | // 存储读取的字节数 408 | var num int 409 | var szBan string 410 | var szSvcName string 411 | 412 | // 这里设置成6秒是因为超时的时候会重新尝试5次, 413 | 414 | readTimeout := 2 * time.Second 415 | 416 | // 设置读取的超时时间为6s 417 | conn.SetReadDeadline(time.Now().Add(readTimeout)) 418 | 419 | for { 420 | // Read是阻塞的 421 | n, err := conn.Read(tmp) 422 | if err != nil { 423 | // 虽然数据读取错误,但是端口仍然是open的 424 | // fmt.Println(err) 425 | if err != io.EOF { 426 | dwSvc = SOCKET_READ_TIMEOUT 427 | // fmt.Printf("Discovered open port\t%d\ton\t%s\n", port, ip) 428 | } 429 | break 430 | } 431 | 432 | if n > 0 { 433 | num += n 434 | fingerprint = append(fingerprint, tmp[:n]...) 435 | } else { 436 | // 虽然没有读取到数据,但是端口仍然是open的 437 | // fmt.Printf("Discovered open port\t%d\ton\t%s\n", port, ip) 438 | break 439 | } 440 | } 441 | Writer.Request(ip, conversion.ToString(port), "tcp", err) 442 | // 服务识别 443 | if num > 0 { 444 | dwSvc = ComparePackets(fingerprint, num, &szBan, &szSvcName) 445 | //if len(szBan) > 15 { 446 | // szBan = szBan[:15] 447 | //} 448 | if dwSvc > UNKNOWN_PORT && dwSvc < SOCKET_CONNECT_FAILED { 449 | //even.WorkingEvent = "found" 450 | if szSvcName == "ssl/tls" || szSvcName == "http" { 451 | rst := Ghttp.GetHttpTitle(ip, Ghttp.HTTPorHTTPS, int(port)) 452 | even.WorkingEvent = rst 453 | cert, err0 := Ghttp.GetCert(ip, int(port)) 454 | if err0 != nil { 455 | cert = "" 456 | } 457 | even.Info.Cert = cert 458 | } else { 459 | even.Info.Banner = strings.TrimSpace(szBan) 460 | } 461 | even.Info.Service = szSvcName 462 | even.Time = time.Now() 463 | // fmt.Printf("Discovered open port\t%d\ton\t%s\t\t%s\t\t%s\n", port, ip, szSvcName, strings.TrimSpace(szBan)) 464 | //Writer.Write(even) 465 | //return dwSvc, even 466 | } 467 | } 468 | 469 | return dwSvc, even 470 | } 471 | 472 | // randomScan 随机扫描, 有问题,扫描C段时扫描不到, 473 | // TODO::尝试遍历ip,端口顺序打乱扫描 474 | func (e *Engine) randomScan() { 475 | // 投机取巧,打乱端口顺序,遍历ip扫描 476 | var portlist = make(map[int]uint64) 477 | var iplist = []string{} 478 | var index int 479 | var addr Addr 480 | 481 | //得到端口IPLIST 482 | for _, ports := range e.TaskPorts { 483 | for port := ports.Begin; port <= ports.End; port++ { 484 | portlist[index] = port 485 | index++ 486 | } 487 | } 488 | //得到IPlist 489 | for _, ipnum := range e.TaskIps { 490 | for ips := ipnum.Begin; ips <= ipnum.End; ips++ { 491 | ip := ps.UnParseIPv4(ips) 492 | iplist = append(iplist, ip) 493 | } 494 | } 495 | 496 | Count = len(iplist) * len(portlist) 497 | Bar, _ = pterm.DefaultProgressbar.WithTotal(Count).WithTitle("[Port Scan]").Start() 498 | Progre, progressErr = NewStatsTicker(1, true) 499 | if progressErr != nil { 500 | fmt.Println(progressErr) 501 | } 502 | Progre.Init(int64(Count)) 503 | for _, ip := range iplist { 504 | for _, po := range portlist { 505 | addr.ip = ip 506 | addr.port = po 507 | e.TaskChan <- addr 508 | } 509 | } 510 | 511 | } 512 | 513 | // 统计待扫描的ip数目 514 | func (e *Engine) ipRangeCount() uint64 { 515 | var count uint64 516 | for _, ipnum := range e.TaskIps { 517 | count += ipnum.End - ipnum.Begin + 1 518 | } 519 | 520 | return count 521 | } 522 | 523 | // 统计待扫描的端口数目 524 | func (e *Engine) portRangeCount() uint64 { 525 | var count uint64 526 | for _, ports := range e.TaskPorts { 527 | count += ports.End - ports.Begin + 1 528 | } 529 | 530 | return count 531 | } 532 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= 2 | github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= 3 | github.com/MarvinJWendt/testza v0.2.8 h1:wADjxMxaIeasMStYq3AFsVyKR0B+1nkFfiRfnz2NEtI= 4 | github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= 5 | github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= 6 | github.com/PuerkitoBio/goquery v1.7.1 h1:oE+T06D+1T7LNrn91B4aERsRIeCLJ/oPSa6xB9FPnz4= 7 | github.com/PuerkitoBio/goquery v1.7.1/go.mod h1:XY0pP4kfraEmmV1O7Uf6XyjoslwsneBbgeDjLYuN8xY= 8 | github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= 9 | github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= 10 | github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE= 11 | github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= 12 | github.com/atomicgo/cursor v0.0.1 h1:xdogsqa6YYlLfM+GyClC/Lchf7aiMerFiZQn7soTOoU= 13 | github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= 14 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 15 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 16 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 18 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 19 | github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI= 20 | github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= 21 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= 22 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 23 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 24 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 25 | github.com/goinggo/mapstructure v0.0.0-20140717182941-194205d9b4a9 h1:wqckanyE9qc/XnvnybC6SHOb8Nyd62QXAZOzA8twFig= 26 | github.com/goinggo/mapstructure v0.0.0-20140717182941-194205d9b4a9/go.mod h1:64ikIrMv84B+raz7akXOqbF7cK3/OQQ/6cClY10oy7A= 27 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= 28 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 29 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 30 | github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk= 31 | github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= 32 | github.com/jlaffaye/ftp v0.0.0-20210307004419-5d4190119067 h1:P2S26PMwXl8+ZGuOG3C69LG4be5vHafUayZm9VPw3tU= 33 | github.com/jlaffaye/ftp v0.0.0-20210307004419-5d4190119067/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU= 34 | github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= 35 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 36 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 37 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 38 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 39 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 40 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 41 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 42 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 43 | github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg= 44 | github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 45 | github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 46 | github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 47 | github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= 48 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 49 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 50 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 51 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 52 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 53 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 54 | github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= 55 | github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 56 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 57 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 58 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 59 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 60 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 61 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 62 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 63 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= 64 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= 65 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 66 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 67 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 68 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 69 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 70 | github.com/projectdiscovery/clistats v0.0.8 h1:tjmWb15mqsPf/yrQXVHLe2ThZX/5+mgKSfZBKWWLh20= 71 | github.com/projectdiscovery/clistats v0.0.8/go.mod h1:lV6jUHAv2bYWqrQstqW8iVIydKJhWlVaLl3Xo9ioVGg= 72 | github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI= 73 | github.com/projectdiscovery/gologger v1.1.4/go.mod h1:Bhb6Bdx2PV1nMaFLoXNBmHIU85iROS9y1tBuv7T5pMY= 74 | github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= 75 | github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= 76 | github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= 77 | github.com/pterm/pterm v0.12.31 h1:+UFxhtv9Kuz0nIBH7Aqc2AF0QeOlNChb38L2sYPtXiU= 78 | github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= 79 | github.com/pterm/pterm v0.12.33 h1:XiT50Pvdqn5O8FAiIqZMpXP6NkVEcmlUa+mkA1yWVCg= 80 | github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= 81 | github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj3nKI= 82 | github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= 83 | github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o= 84 | github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= 85 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 86 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 87 | github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik= 88 | github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= 89 | github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8 h1:GVFkBBJAEO3CpzIYcDDBdpUObzKwVW9okNWcLYL/nnU= 90 | github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8/go.mod h1:phLSETqH/UJsBtwDVBxSfJKwwkbJcGyy2Q/h4k+bmww= 91 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 92 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 93 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 94 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 95 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 96 | github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= 97 | github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= 98 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= 99 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= 100 | github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 h1:EpI0bqf/eX9SdZDwlMmahKM+CDBgNbsXMhsN28XrM8o= 101 | github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= 102 | github.com/xuri/excelize/v2 v2.4.1 h1:veeeFLAJwsNEBPBlDepzPIYS1eLyBVcXNZUW79exZ1E= 103 | github.com/xuri/excelize/v2 v2.4.1/go.mod h1:rSu0C3papjzxQA3sdK8cU544TebhrPUoTOaGPIh0Q1A= 104 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 105 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= 106 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 107 | go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= 108 | go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= 109 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 110 | go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= 111 | go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= 112 | go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= 113 | go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= 114 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 115 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 116 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 117 | golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 118 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 119 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= 120 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 121 | golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk= 122 | golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 123 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 124 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 125 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 126 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 127 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 128 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 129 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 130 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 131 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 132 | golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 133 | golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b h1:eB48h3HiRycXNy8E0Gf5e0hv7YT6Kt14L/D73G1fuwo= 134 | golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 135 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 136 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 137 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 138 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 139 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 140 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 141 | golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 142 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 143 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 144 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 145 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 146 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 147 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= 148 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 149 | golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= 150 | golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 151 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 152 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 153 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= 154 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 155 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= 156 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 157 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 158 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 159 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 160 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 161 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 162 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 163 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 164 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 165 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 166 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 167 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 168 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 169 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 170 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 171 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 172 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 173 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 174 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 175 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 176 | --------------------------------------------------------------------------------