├── 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 |    
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 | 
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 | 
58 |
59 | 
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 | 
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, "")
39 | return title[titleBegin+1 : titleEnd]
40 | }
41 |
42 | func ExtractFinger(body string, r *http.Response) string {
43 | var fingers []string
44 |
45 | if r.Header.Get("Set-Cookie") != "" && strings.Contains(r.Header.Get("Set-Cookie"), "rememberMe=deleteMe") {
46 | fingers = append(fingers, "Shiro!!")
47 | }
48 | if body != "" {
49 | if strings.Contains(body, "servletContextInitParams") {
50 | fingers = append(fingers, "Spring env!!")
51 | } else if strings.Contains(body, "logback") {
52 | fingers = append(fingers, "Spring env!!")
53 | } else if strings.Contains(body, "Error 404--Not Found") || strings.Contains(body, "Error 403--") {
54 | fingers = append(fingers, "Weblogic!!")
55 | } else if strings.Contains(body, "/por/login_psw.csp") {
56 | fingers = append(fingers, "Sangfor SSL VPN!!")
57 | } else if strings.Contains(body, "weaver,e-mobile") {
58 | fingers = append(fingers, "e-mobile!!")
59 | } else if strings.Contains(body, "ecology") {
60 | fingers = append(fingers, "ecology!!")
61 | } else if strings.Contains(body, "e-Bridge") || strings.Contains(body, "wx.weaver") {
62 | fingers = append(fingers, "e-Bridge!!")
63 | } else if strings.Contains(body, "Swagger UI") {
64 | fingers = append(fingers, "Swagger UI!!")
65 | } else if strings.Contains(body, "4008 111 000") {
66 | fingers = append(fingers, "Ruijie")
67 | } else if strings.Contains(body, "Script/SmcScript.js?version=") {
68 | fingers = append(fingers, "Huawei SMC")
69 | } else if strings.Contains(body, "/wnm/ssl/web/frame/login.html") {
70 | fingers = append(fingers, "H3C Router")
71 | } else if strings.Contains(body, "/+CSCOE+/logon.html") {
72 | fingers = append(fingers, "Cisco SSLVPN!!")
73 | } else if strings.Contains(body, "Huawei") || strings.Contains(body, "huawei") || strings.Contains(body, "Hicloud") || strings.Contains(body, "hicloud") || strings.Contains(body, "Vmall") || strings.Contains(body, "vmall") {
74 | fingers = append(fingers, "Huawei!!")
75 | } else if strings.Contains(body, "../zentao/theme/zui/css/min.css") {
76 | fingers = append(fingers, "Zentao!!")
77 | } else if strings.Contains(body, "UI_component/commonDefine/UI_regex_define.js") {
78 | fingers = append(fingers, "Huawei Firewall")
79 | } else if strings.Contains(body, "CDGServer3") {
80 | fingers = append(fingers, "亿赛通电子文档!!")
81 | } else if strings.Contains(body, "/zcms/") || strings.Contains(body, "App=ZCMS(ZCMS内容管理系统)") {
82 | fingers = append(fingers, "ZCMS!!")
83 | } else if strings.Contains(body, "3F367B74-92D9-4C5E-AB93-234F8A91D5E6") {
84 | fingers = append(fingers, "云匣子!!")
85 | } else if strings.Contains(body, "\x2Findex.zul") {
86 | fingers = append(fingers, "Old 云匣子!!")
87 | } else if strings.Contains(body, "gHasSecureMail") {
88 | fingers = append(fingers, "亿邮!!")
89 | } else if strings.Contains(body, "any_rsa_pas") || strings.Contains(body, "https://sec.anymacro.com") {
90 | fingers = append(fingers, "Anymail!!")
91 | } else if strings.Contains(body, "action=\"/coremail/index.jsp?cus=1\"") || strings.Contains(body, "/coremail/common/") {
92 | fingers = append(fingers, "Coremail!!")
93 | } else if strings.Contains(body, "\"/r/cms/") {
94 | fingers = append(fingers, "JEECMS!!")
95 | } else if strings.Contains(body, "CN/volumn/") {
96 | fingers = append(fingers, "网刊系统!!")
97 | } else if strings.Contains(body, "journalx") {
98 | fingers = append(fingers, "玛格泰克JournalX!!")
99 | } else if strings.Contains(body, "href=\"/seeyon/skin/dist") || strings.Contains(body, "/seeyon/main.do") {
100 | fingers = append(fingers, "致远OA!!")
101 | } else if strings.Contains(body, "StylePath:\"/resource/style") {
102 | fingers = append(fingers, "蓝凌ekp!!")
103 | } else if strings.Contains(body, "Office Anywhere") || strings.Contains(body, "general/login_code.php") {
104 | fingers = append(fingers, "通达OA!!")
105 | } else if strings.Contains(body, "webmail/se/account/download.do") || strings.Contains(body, "url=/webmail/\"") {
106 | fingers = append(fingers, "Easysite!!")
107 | } else if strings.Contains(body, "Zabbix SIA") {
108 | fingers = append(fingers, "Zabbix!!")
109 | } else if strings.Contains(body, "Powered by Discuz!") || strings.Contains(body, "content=\"Discuz!") {
110 | fingers = append(fingers, "Discuz!!")
111 | }
112 | }
113 |
114 | return strings.Join(fingers, "|")
115 | }
116 |
--------------------------------------------------------------------------------
/finger/lib/misc/misc.go:
--------------------------------------------------------------------------------
1 | package misc
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "io"
7 | "math/rand"
8 | "os"
9 | "strconv"
10 | "strings"
11 |
12 | "github.com/redtoolskobe/scaninfo/finger/lib/chinese"
13 | )
14 |
15 | func StrArr2IntArr(strArr []string) ([]int, error) {
16 | var intArr []int
17 | for _, value := range strArr {
18 | intValue, err := strconv.Atoi(value)
19 | if err != nil {
20 | return nil, err
21 | }
22 | intArr = append(intArr, intValue)
23 | }
24 | return intArr, nil
25 | }
26 |
27 | func Str2Int(str string) int {
28 | intValue, err := strconv.Atoi(str)
29 | if err != nil {
30 | return 0
31 | }
32 | return intValue
33 | }
34 |
35 | //func IntArr2StrArr(intArr []int) []string {
36 | // var strArr []string
37 | // for _, value := range intArr {
38 | // strValue := strconv.Itoa(value)
39 | // strArr = append(strArr, strValue)
40 | // }
41 | // return strArr
42 | //}
43 |
44 | func Int2Str(Int int) string {
45 | return strconv.Itoa(Int)
46 | }
47 |
48 | func IsInStrArr(slice []string, val string) bool {
49 | for _, item := range slice {
50 | if item == val {
51 | return true
52 | }
53 | }
54 | return false
55 | }
56 |
57 | func IsInIntArr(slice []int, val int) bool {
58 | for _, item := range slice {
59 | if item == val {
60 | return true
61 | }
62 | }
63 | return false
64 | }
65 |
66 | func ReadLine(fileName string, handler func(string, bool)) error {
67 | f, err := os.Open(fileName)
68 | if err != nil {
69 | return err
70 | }
71 | buf := bufio.NewReader(f)
72 | for {
73 | line, err := buf.ReadString('\n')
74 | line = FixLine(line)
75 | handler(line, true)
76 | if err != nil {
77 | if err == io.EOF {
78 | return nil
79 | }
80 | return err
81 | }
82 | }
83 | }
84 |
85 | func ReadLineAll(fileName string) []string {
86 | var strArr []string
87 | f, err := os.Open(fileName)
88 | if err != nil {
89 | return strArr
90 | }
91 | buf := bufio.NewReader(f)
92 | for {
93 | line, err := buf.ReadString('\n')
94 | line = FixLine(line)
95 | strArr = append(strArr, line)
96 | if err != nil {
97 | if err == io.EOF {
98 | return strArr
99 | }
100 | return strArr
101 | }
102 | }
103 | }
104 |
105 | func FixLine(line string) string {
106 | line = strings.Replace(line, "\r", "", -1)
107 | line = strings.Replace(line, " ", "", -1)
108 | line = strings.Replace(line, "\t", "", -1)
109 | line = strings.Replace(line, "\r", "", -1)
110 | line = strings.Replace(line, "\n", "", -1)
111 | return line
112 | }
113 |
114 | func UniStrAppend(slice []string, elems ...string) []string {
115 | for _, elem := range elems {
116 | if IsInStrArr(slice, elem) {
117 | continue
118 | } else {
119 | slice = append(slice, elem)
120 | }
121 | }
122 | return slice
123 | }
124 |
125 | func FileIsExist(path string) bool {
126 | _, err := os.Lstat(path)
127 | return !os.IsNotExist(err)
128 | }
129 |
130 | func Xrange(args ...int) []int {
131 | var start, stop int
132 | var step = 1
133 | var r []int
134 | switch len(args) {
135 | case 1:
136 | stop = args[0]
137 | start = 0
138 | case 2:
139 | start, stop = args[0], args[1]
140 | case 3:
141 | start, stop, step = args[0], args[1], args[2]
142 | default:
143 | return nil
144 | }
145 | if start > 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 |
--------------------------------------------------------------------------------