├── pkg ├── output │ ├── out_file.go │ ├── format_json.go │ ├── output_test.go │ ├── format_file.go │ ├── format_screen.go │ └── output.go ├── common │ ├── ipparser │ │ ├── ipprocess_test.go │ │ └── ipprocess.go │ ├── rangectl │ │ ├── range_test.go │ │ └── range.go │ ├── parser_test.go │ ├── service_test.go │ ├── parser.go │ ├── engine.go │ ├── constant.go │ └── service.go ├── Ginfo │ ├── Gnbtscan │ │ ├── Gnbtscan_test.go │ │ └── GNetBIOS.go │ └── Ghttp │ │ ├── encodings.go │ │ ├── title.go │ │ └── Ghttp.go └── conversion │ └── conversion.go ├── .gitignore ├── img ├── sucre.jpg ├── TxPortMap.jpg ├── image-20210329112056656.png ├── image-20210329113123457.png ├── image-20210329113409985.png ├── image-20210329114458453.png ├── image-20210329114524449.png ├── image-20210329210749167.png ├── image-20210329211016678.png └── image-20210329211309482.png ├── go.mod ├── cmd └── TxPortMap │ └── TxPortMap.go ├── README.md ├── .github └── workflows │ └── go.yml └── go.sum /pkg/output/out_file.go: -------------------------------------------------------------------------------- 1 | package output 2 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /img/sucre.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/sucre.jpg -------------------------------------------------------------------------------- /img/TxPortMap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/TxPortMap.jpg -------------------------------------------------------------------------------- /img/image-20210329112056656.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/image-20210329112056656.png -------------------------------------------------------------------------------- /img/image-20210329113123457.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/image-20210329113123457.png -------------------------------------------------------------------------------- /img/image-20210329113409985.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/image-20210329113409985.png -------------------------------------------------------------------------------- /img/image-20210329114458453.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/image-20210329114458453.png -------------------------------------------------------------------------------- /img/image-20210329114524449.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/image-20210329114524449.png -------------------------------------------------------------------------------- /img/image-20210329210749167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/image-20210329210749167.png -------------------------------------------------------------------------------- /img/image-20210329211016678.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/image-20210329211016678.png -------------------------------------------------------------------------------- /img/image-20210329211309482.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4dogs-cn/TXPortMap/HEAD/img/image-20210329211309482.png -------------------------------------------------------------------------------- /pkg/output/format_json.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | jsoniter "github.com/json-iterator/go" 5 | ) 6 | // TODO 7 | 8 | func (w *StandardWriter) formatJSON(output *ResultEvent)([]byte,error){ 9 | return jsoniter.Marshal(output) 10 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/4dogs-cn/TXPortMap 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/fatih/color v1.10.0 7 | github.com/json-iterator/go v1.1.10 8 | github.com/pkg/errors v0.9.1 9 | github.com/projectdiscovery/fdmax v0.0.3 10 | github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 11 | go.uber.org/ratelimit v0.2.0 12 | golang.org/x/net v0.0.0-20210326220855-61e056675ecf 13 | golang.org/x/text v0.3.5 14 | ) 15 | -------------------------------------------------------------------------------- /pkg/output/output_test.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestNewStandardWriter(t *testing.T) { 9 | writer, err := NewStandardWriter(false, "scan.txt", "trace.log") 10 | if err !=nil{ 11 | t.Logf("new writer error :%s\n",err.Error()) 12 | } 13 | even := &ResultEvent{ 14 | Target: "192.168.0.53", 15 | Time: time.Now(), 16 | WorkingEvent: "time out", 17 | } 18 | writer.Write(even) 19 | } 20 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /pkg/output/format_file.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | 4 | import ( 5 | "os" 6 | ) 7 | 8 | type fileWriter struct { 9 | file *os.File 10 | } 11 | 12 | // NewFileOutputWriter creates a new buffered writer for a file 13 | func newFileOutputWriter(file string) (*fileWriter, error) { 14 | output, err := os.Create(file) 15 | if err != nil { 16 | return nil, err 17 | } 18 | return &fileWriter{file: output}, nil 19 | } 20 | 21 | // WriteString writes an output to the underlying file 22 | func (w *fileWriter) Write(data []byte) error { 23 | _, err := w.file.Write(data) 24 | if err != nil { 25 | return err 26 | } 27 | _, err = w.file.Write([]byte("\n")) 28 | return err 29 | } 30 | 31 | // Close closes the underlying writer flushing everything to disk 32 | func (w *fileWriter) Close() error { 33 | //nolint:errcheck // we don't care whether sync failed or succeeded. 34 | w.file.Sync() 35 | return w.file.Close() 36 | } 37 | -------------------------------------------------------------------------------- /cmd/TxPortMap/TxPortMap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | _ "github.com/projectdiscovery/fdmax/autofdmax" //Add automatic increase of file descriptors in linux 7 | "github.com/4dogs-cn/TXPortMap/pkg/common" 8 | "os" 9 | ) 10 | 11 | func init() { 12 | flag.Parse() 13 | 14 | // fmt.Println("threadnum: ", common.NumThreads) 15 | 16 | if common.NumThreads < 1 || common.NumThreads > 2000 { 17 | fmt.Println("number of goroutine must between 1 and 2000") 18 | os.Exit(-1) 19 | } 20 | } 21 | 22 | // 建议扫描top100或者top1000端口时使用顺序扫描,其它情况使用随机扫描 23 | func main() { 24 | 25 | // trace追踪文件生产,调试时打开注释即可 26 | /* 27 | f1, err := os.Create("scan.trace") 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | trace.Start(f1) 32 | defer trace.Stop() 33 | */ 34 | //common.ArgsPrint() 35 | engine := common.CreateEngine() 36 | 37 | // 命令行参数错误 38 | if err := engine.Parser(); err != nil { 39 | fmt.Println(err) 40 | os.Exit(1) 41 | } 42 | 43 | 44 | // common.ArgsPrint() 45 | //engine.Wg.Add(engine.WorkerCount) 46 | //go engine.Scheduler() 47 | engine.Run() 48 | 49 | // 等待扫描任务完成 50 | engine.Wg.Wait() 51 | if common.Writer !=nil{ 52 | common.Writer.Close() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TXPortMap 2 | 3 | Port Scanner & Banner Identify From TianXiang 4 | 5 | ``` 6 | ./TxPortMap -h 7 | ``` 8 | 9 | ![image-20210329210749167](./img/image-20210329210749167.png) 10 | 11 | ``` 12 | 新增加彩色文字输出格式 对http/https协议进行title以及报文长度打印,获取title失败打印报文前20字节 13 | ``` 14 | 15 | ![image-20210329211309482](./img/image-20210329211309482.png) 16 | 17 | ``` 18 | 新增日志文件以及扫描结果文件 19 | ``` 20 | 21 | ![image-20210329211016678](./img/image-20210329211016678.png) 22 | 23 | ``` 24 | TxPortMap 会直接扫描top100 加上t1000参数会扫描top1000 可以通过-p 指定端口,分号指定多个 25 | ``` 26 | 27 | ![image-20210329113123457](./img/image-20210329113123457.png) 28 | 29 | ![image-20210329113409985](./img/image-20210329113409985.png) 30 | 31 | 32 | 33 | # 项目说明 34 | 在渗透测试的端口扫描阶段,相信很多人遇到的问题是nmap太慢,masscan不准确。 35 | 本项目为天象渗透测试平台后端使用的端口扫描和指纹识别模块,采用Golang编写,以期在速度与准确度之间寻找一个平衡。 36 | 开源后希望大家可以一起完善指纹和提交优化建议。 37 | 38 | TxPortMap时间:20.171秒 39 | 40 | nmap 2分51.89秒 41 | 42 | ![image-20210329114458453](./img/image-20210329114458453.png) 43 | 44 | ![image-20210329114524449](./img/image-20210329114524449.png) 45 | 46 | 47 | 本项目 暂不进行更新 新项目为黑客语言yak开发 具有更多黑客功能 可移步官网 https://www.yaklang.io/ 48 | 并用yak语言实现有国产burp suite替代工具 yakit 单兵平台 https://github.com/yaklang/yakit 49 | 50 | 交流群 51 | 52 | ![TxPortMap](./img/TxPortMap.jpg) 53 | 54 | 群满可加微信 55 | 56 | ![sucre](./img/sucre.jpg) 57 | 58 | -------------------------------------------------------------------------------- /pkg/output/format_screen.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/4dogs-cn/TXPortMap/pkg/Ginfo/Ghttp" 7 | "github.com/4dogs-cn/TXPortMap/pkg/conversion" 8 | "github.com/fatih/color" 9 | "strings" 10 | ) 11 | 12 | // formatScreen formats the output for showing on screen. 13 | func (w *StandardWriter) formatScreen(output *ResultEvent) []byte { 14 | builder := &bytes.Buffer{} 15 | builder.WriteString(color.RedString(fmt.Sprintf("%-20s",output.Target))) 16 | builder.WriteString(" ") 17 | if output.Info.Service != "unknown" { 18 | builder.WriteString(color.YellowString(output.Info.Service)) 19 | } 20 | 21 | if output.Info.Service == "ssl/tls" || output.Info.Service == "http" { 22 | if len(output.Info.Cert) > 0 { 23 | builder.WriteString(" [") 24 | builder.WriteString(color.YellowString(output.Info.Cert)) 25 | builder.WriteString("]") 26 | } 27 | } 28 | if output.WorkingEvent != nil { 29 | switch tmp := output.WorkingEvent.(type) { 30 | case Ghttp.Result: 31 | httpBanner := tmp.ToString() 32 | if len(httpBanner) > 0 { 33 | builder.WriteString(" | ") 34 | builder.WriteString(color.GreenString(httpBanner)) 35 | } 36 | default: 37 | result := conversion.ToString(tmp) 38 | if strings.HasPrefix(result, "\\x") == false && len(result) > 0 { 39 | builder.WriteString(" | ") 40 | builder.WriteString(color.GreenString(result)) 41 | } 42 | } 43 | } else { 44 | if strings.HasPrefix(output.Info.Banner, "\\x") == false && len(output.Info.Banner) > 0 { 45 | r := strings.Split(output.Info.Banner, "\\x0d\\x0a") 46 | builder.WriteString(" | ") 47 | builder.WriteString(color.GreenString(r[0])) 48 | } 49 | } 50 | return builder.Bytes() 51 | } 52 | -------------------------------------------------------------------------------- /pkg/conversion/conversion.go: -------------------------------------------------------------------------------- 1 | package conversion 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | "fmt" 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/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/output/output.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "github.com/fatih/color" 5 | jsoniter "github.com/json-iterator/go" 6 | "github.com/pkg/errors" 7 | "github.com/shiena/ansicolor" 8 | "io" 9 | "os" 10 | "regexp" 11 | "sync" 12 | "time" 13 | ) 14 | 15 | // Writer is an interface which writes output to somewhere for nuclei events. 16 | type Writer interface { 17 | // Close closes the output writer interface 18 | Close() 19 | // Write writes the event to file and/or screen. 20 | Write(*ResultEvent) error 21 | // Request logs a request in the trace log 22 | Request(ip, port, requestType string, err error) 23 | } 24 | 25 | type Info struct { 26 | Banner string 27 | Service string 28 | Cert string 29 | } 30 | type ResultEvent struct { 31 | WorkingEvent interface{} `json:"WorkingEvent"` 32 | Info *Info `json:"info,inline"` 33 | Time time.Time `json:"time"` 34 | Target string `json:"Target"` 35 | } 36 | 37 | type StandardWriter struct { 38 | w io.Writer 39 | json bool 40 | outputFile *fileWriter 41 | outputMutex *sync.Mutex 42 | traceFile *fileWriter 43 | traceMutex *sync.Mutex 44 | } 45 | 46 | var decolorizerRegex = regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) 47 | 48 | func NewStandardWriter(nocolor, json bool, file, traceFile string) (*StandardWriter, error) { 49 | w := ansicolor.NewAnsiColorWriter(os.Stdout) 50 | if nocolor { 51 | color.NoColor = true 52 | } 53 | var outputFile *fileWriter 54 | if file != "" { 55 | output, err := newFileOutputWriter(file) 56 | if err != nil { 57 | return nil, errors.Wrap(err, "could not create output file") 58 | 59 | } 60 | outputFile = output 61 | } 62 | var traceOutput *fileWriter 63 | if traceFile != "" { 64 | output, err := newFileOutputWriter(traceFile) 65 | if err != nil { 66 | return nil, errors.Wrap(err, "could not create output file") 67 | } 68 | traceOutput = output 69 | } 70 | writer := &StandardWriter{ 71 | w: w, 72 | json: json, 73 | outputFile: outputFile, 74 | outputMutex: &sync.Mutex{}, 75 | traceFile: traceOutput, 76 | traceMutex: &sync.Mutex{}, 77 | } 78 | return writer, nil 79 | } 80 | 81 | // Write writes the event to file and/or screen. 82 | func (w *StandardWriter) Write(event *ResultEvent) error { 83 | if event == nil{ 84 | return nil 85 | } 86 | event.Time = time.Now() 87 | 88 | var data []byte 89 | var err error 90 | if w.json { 91 | data, err = w.formatJSON(event) 92 | } else { 93 | data = w.formatScreen(event) 94 | } 95 | 96 | if err != nil { 97 | return errors.Wrap(err, "could not format output") 98 | } 99 | if len(data) == 0 { 100 | return nil 101 | } 102 | 103 | w.outputMutex.Lock() 104 | defer w.outputMutex.Unlock() 105 | 106 | _, _ = w.w.Write(data) 107 | _, _ = w.w.Write([]byte("\n")) 108 | 109 | if w.outputFile != nil { 110 | if !w.json { 111 | data = decolorizerRegex.ReplaceAll(data, []byte("")) 112 | } 113 | if writeErr := w.outputFile.Write(data); writeErr != nil { 114 | return errors.Wrap(err, "could not write to output") 115 | } 116 | } 117 | 118 | 119 | return nil 120 | } 121 | 122 | func (w *StandardWriter) Close() { 123 | if w.outputFile != nil { 124 | w.outputFile.Close() 125 | } 126 | if w.traceFile != nil { 127 | w.traceFile.Close() 128 | } 129 | } 130 | 131 | type JSONTraceRequest struct { 132 | IP string `json:"ip"` 133 | Port string `json:"port"` 134 | Error string `json:"error"` 135 | Type string `json:"type"` 136 | } 137 | 138 | // Request writes a log the requests trace log 139 | func (w *StandardWriter) Request(ip, port, requestType string, err error) { 140 | if w.traceFile == nil { 141 | return 142 | } 143 | request := &JSONTraceRequest{ 144 | IP: ip, 145 | Port: port, 146 | Type: requestType, 147 | } 148 | if err != nil { 149 | request.Error = err.Error() 150 | } else { 151 | request.Error = "none" 152 | } 153 | 154 | data, err := jsoniter.Marshal(request) 155 | if err != nil { 156 | return 157 | } 158 | w.traceMutex.Lock() 159 | _ = w.traceFile.Write(data) 160 | w.traceMutex.Unlock() 161 | } 162 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | build_and_release: 9 | strategy: 10 | matrix: 11 | os: 12 | - windows-latest 13 | - macos-latest 14 | - ubuntu-latest 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Set up Go 20 | uses: actions/setup-go@v2 21 | with: 22 | go-version: 1.15 23 | 24 | - name: Build For Linux and MacOS and windows 25 | run: go build -o "./TxPortMap_$(go env GOOS)_$(go env GOARCH)" -v cmd/TxPortMap/TxPortMap.go 26 | 27 | - name: Upload Artifacts Windows 28 | uses: actions/upload-artifact@v2 29 | if: runner.os == 'Windows' 30 | with: 31 | name: TxPortMap_windows_amd64 32 | path: ./TxPortMap_windows_amd64 33 | - name: Upload Artifacts MacOS 34 | uses: actions/upload-artifact@v2 35 | if: runner.os == 'macOS' 36 | with: 37 | name: TxPortMap_darwin_amd64 38 | path: ./TxPortMap_darwin_amd64 39 | 40 | 41 | - name: Upload Artifacts Linux 42 | uses: actions/upload-artifact@v2 43 | if: runner.os == 'Linux' 44 | with: 45 | name: TxPortMap_linux_amd64 46 | path: ./TxPortMap_linux_amd64 47 | 48 | download_artifacts_and_release: 49 | needs: build_and_release 50 | runs-on: ubuntu-latest 51 | steps: 52 | - name: Download Windows TxPortMap 53 | uses: actions/download-artifact@v2 54 | with: 55 | name: TxPortMap_windows_amd64 56 | - name: Download macOS TxPortMap 57 | uses: actions/download-artifact@v2 58 | with: 59 | name: TxPortMap_darwin_amd64 60 | - name: Download Linux TxPortMap 61 | uses: actions/download-artifact@v2 62 | with: 63 | name: TxPortMap_linux_amd64 64 | - name: Create Release 65 | id: create_release 66 | uses: actions/create-release@v1 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 69 | with: 70 | tag_name: ${{ github.ref }} 71 | release_name: Release ${{ github.ref }} 72 | draft: false 73 | prerelease: false 74 | 75 | - name: Upload Release Asset Linux 76 | uses: actions/upload-release-asset@v1 77 | env: 78 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 79 | with: 80 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 81 | asset_path: ./TxPortMap_linux_amd64 82 | asset_name: TxPortMap_linux_amd64 83 | asset_content_type: application/octet-stream 84 | 85 | - name: Upload Release Asset macOS 86 | uses: actions/upload-release-asset@v1 87 | env: 88 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 89 | with: 90 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 91 | asset_path: ./TxPortMap_darwin_amd64 92 | asset_name: TxPortMap_darwin_amd64 93 | asset_content_type: application/octet-stream 94 | 95 | - name: Upload Release Asset Windows 96 | uses: actions/upload-release-asset@v1 97 | env: 98 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 99 | with: 100 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 101 | asset_path: ./TxPortMap_windows_amd64 102 | asset_name: TxPortMap_windows_amd64 103 | asset_content_type: application/octet-stream 104 | -------------------------------------------------------------------------------- /pkg/common/parser.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bufio" 5 | "encoding/hex" 6 | "flag" 7 | "fmt" 8 | "os" 9 | "strings" 10 | "go.uber.org/ratelimit" 11 | ) 12 | 13 | type sliceValue []string 14 | 15 | func newSliceValue(vals []string, p *[]string) *sliceValue { 16 | *p = vals 17 | return (*sliceValue)(p) 18 | } 19 | 20 | func (s *sliceValue) Set(val string) error { 21 | *s = sliceValue(strings.Split(val, ",")) 22 | return nil 23 | } 24 | 25 | func (s *sliceValue) Get() interface{} { 26 | return []string(*s) 27 | } 28 | 29 | func (s *sliceValue) String() string { 30 | return strings.Join([]string(*s), ",") 31 | } 32 | 33 | var ( 34 | cmdIps []string 35 | // cmdExPath string 36 | cmdCofPath string 37 | cmdPorts []string 38 | cmdT1000 bool 39 | cmdRandom bool 40 | NumThreads int 41 | excPorts []string // 待排除端口 42 | excIps []string // 待排除Ip 43 | ipFile string 44 | nocolor bool //彩色打印 45 | json bool 46 | tracelog string //请求日志 47 | rstfile string //文件保存 48 | tout float64 //timeout 49 | nbtscan bool 50 | limit int 51 | Limiter ratelimit.Limiter 52 | ) 53 | 54 | /** 55 | 命令行参数解析: 56 | -i: 输入的Ip地址或者域名,以逗号分隔. 例如192.168.1.1/24,scanme.nmap.org 57 | -e: 设置排除文件路径,排除文件内容为需要排除的ip地址列表 58 | -c: 配置文件路径,支持从配置文件中读取ip,地址列表 59 | -p: 需要扫描的端口列表,以逗号分隔,例如: 1-1000,3379,6379,和-p互斥 60 | -t1000: 布尔类型,默认是扫描top100,否则扫描top1000端口,和-p互斥 61 | -r: 布尔类型,表示扫描方式,随机扫描还是顺序扫描 62 | -nbtscan: 布尔类型,是否进行netbios扫描,默认为否 63 | */ 64 | func init() { 65 | flag.Var(newSliceValue([]string{}, &cmdIps), "i", "set domain and ips") 66 | //flag.StringVar(&cmdExPath, "e", "", "set exclude file path") 67 | // flag.StringVar(&cmdCofPath, "c", "", "set config file path") 68 | flag.Var(newSliceValue([]string{}, &cmdPorts), "p", "set port ranges to scan,default is top100") 69 | 70 | flag.BoolVar(&cmdT1000, "t1000", false, "scan top1000 ports") 71 | flag.BoolVar(&cmdRandom, "r", false, "random scan flag") 72 | flag.IntVar(&NumThreads, "n", 800, "number of goroutines, between 1 and 2000") 73 | flag.IntVar(&limit, "limit", 0, "number of goroutines, between 1 and 2000") 74 | flag.Var(newSliceValue([]string{}, &excPorts), "ep", "set port ranges to exclude") 75 | flag.Var(newSliceValue([]string{}, &excIps), "ei", "set ip ranges to exclude") 76 | flag.StringVar(&ipFile, "l", "", "input ips file") 77 | flag.BoolVar(&nocolor, "nocolor", false, "using color ascii to screen") 78 | flag.BoolVar(&json, "json", false, "output json format") 79 | flag.StringVar(&tracelog, "tracefile", "", "request log") 80 | flag.StringVar(&rstfile, "o", "rst.txt", "success log") 81 | flag.Float64Var(&tout,"t",0.5,"tcp connect time out default 0.5 second") 82 | flag.BoolVar(&nbtscan, "nbtscan", false, "get netbios stat by UDP137 in local network") 83 | } 84 | 85 | type Identification_Packet struct { 86 | Desc string 87 | Packet []byte 88 | } 89 | 90 | var st_Identification_Packet [100]Identification_Packet 91 | 92 | // 初始化IdentificationProtocol到内存中 93 | 94 | func init() { 95 | for i, packet := range IdentificationProtocol { 96 | szinfo := strings.Split(packet, "#") 97 | data, err := hex.DecodeString(szinfo[1]) 98 | if err != nil { 99 | fmt.Println(err) 100 | os.Exit(1) 101 | } 102 | 103 | st_Identification_Packet[i].Desc = szinfo[0] 104 | st_Identification_Packet[i].Packet = data 105 | } 106 | } 107 | 108 | func ArgsPrint() { 109 | fmt.Println(cmdIps) 110 | fmt.Println(cmdRandom) 111 | fmt.Println(cmdPorts) 112 | fmt.Println(excPorts) 113 | } 114 | 115 | /** 116 | configeFileParse 配置文件解析函数 117 | 配置文件每行一条数据,可以是单个ip,域名,也可以是带掩码的ip和域名 118 | */ 119 | func ConfigeFileParse(path string) ([]string, error) { 120 | var err error 121 | var ips = make([]string, 0, 100) 122 | 123 | file, err := os.Open(path) 124 | if err != nil { 125 | fmt.Println(err) 126 | os.Exit(1) 127 | } 128 | 129 | defer file.Close() 130 | 131 | reader := bufio.NewReader(file) 132 | 133 | for { 134 | line, err := reader.ReadString('\n') 135 | if err != nil { 136 | break 137 | } 138 | 139 | // 去除空行 140 | if len(line) == 0 || line == "\r\n" { 141 | continue 142 | } 143 | 144 | // 以#开头的为注释内容 145 | if strings.Index(line, "#") == 0 { 146 | continue 147 | } 148 | 149 | ips = append(ips, line) 150 | } 151 | 152 | return ips, err 153 | } 154 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= 2 | github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= 7 | github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 8 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 9 | github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= 10 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 11 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= 12 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 13 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 14 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 15 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 16 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 17 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 18 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 19 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 20 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 21 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 22 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 23 | github.com/projectdiscovery/fdmax v0.0.3 h1:FM6lv9expZ/rEEBI9tkRh6tx3DV0gtpwzdc0h7bGPqg= 24 | github.com/projectdiscovery/fdmax v0.0.3/go.mod h1:NWRcaR7JTO7fC27H4jCl9n7Z+KIredwpgw1fV+4KrKI= 25 | github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik= 26 | github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= 27 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 28 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 29 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 30 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 31 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= 32 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 33 | go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= 34 | go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= 35 | golang.org/x/net v0.0.0-20210326220855-61e056675ecf h1:WUcCxqQqDT0aXO4VnQbfMvp4zh7m1Gb2clVuHUAGGRE= 36 | golang.org/x/net v0.0.0-20210326220855-61e056675ecf/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= 37 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 38 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 39 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 40 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 41 | golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg= 42 | golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 43 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 44 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 45 | golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= 46 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 47 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 48 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 49 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 50 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 51 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 52 | -------------------------------------------------------------------------------- /pkg/common/rangectl/range.go: -------------------------------------------------------------------------------- 1 | package rangectl 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "fmt" 7 | ps "github.com/4dogs-cn/TXPortMap/pkg/common/ipparser" 8 | "os" 9 | "strconv" 10 | "strings" 11 | ) 12 | 13 | type Range struct { 14 | Begin uint64 15 | End uint64 16 | } 17 | 18 | /** 19 | RemoveExcFromTaskIps 从任务范围内移除需要排除的Ip或端口 20 | 返回值: 21 | 1. 表示任务列表范围,返回值2有效时才有意义 22 | 2. 表示返回值是否有效,只有排除范围把任务列表分成两段时才有效 23 | */ 24 | func (r *Range) RemoveExcFromTaskIps(exclude Range) (Range, bool) { 25 | var split Range 26 | var tmp = *r 27 | 28 | if r.Begin > exclude.End || r.End < exclude.Begin { 29 | return Range{}, false 30 | } 31 | 32 | if r.Begin >= exclude.Begin && r.End <= exclude.End { 33 | *r = Range{} 34 | return Range{}, false 35 | } 36 | 37 | if r.Begin >= exclude.Begin && r.End > exclude.End { 38 | r.Begin = exclude.End + 1 39 | return Range{}, false 40 | } 41 | 42 | if r.Begin < exclude.Begin && r.End <= exclude.End { 43 | r.End = exclude.Begin - 1 44 | return Range{}, false 45 | } 46 | 47 | if r.Begin < exclude.Begin && r.End > exclude.End { 48 | r.End = exclude.Begin - 1 49 | split.Begin = exclude.End + 1 50 | split.End = tmp.End 51 | 52 | return split, true 53 | } 54 | 55 | return Range{}, false 56 | } 57 | 58 | // ParsePortRange 解析自定义端口范围 59 | func ParsePortRange(port string) (Range, error) { 60 | var result Range 61 | port = strings.TrimSpace(port) 62 | if strings.Contains(port, "-") { 63 | prange := strings.Split(port, "-") 64 | start := prange[0] 65 | stop := prange[1] 66 | 67 | begin, err := strconv.Atoi(start) 68 | if err != nil { 69 | return Range{}, err 70 | } 71 | 72 | end, err := strconv.Atoi(stop) 73 | if err != nil { 74 | return Range{}, err 75 | } 76 | 77 | result.Begin = uint64(begin) 78 | result.End = uint64(end) 79 | } else { 80 | // 单个端口 81 | num, err := strconv.Atoi(port) 82 | if err != nil { 83 | return Range{}, err 84 | } 85 | 86 | result.Begin = uint64(num) 87 | result.End = uint64(num) 88 | } 89 | 90 | if result.Begin > result.End || result.Begin > 65536 || result.End > 65535 { 91 | return Range{}, errors.New("port range failed") 92 | } 93 | 94 | return result, nil 95 | } 96 | 97 | // ParseIpv4Range 解析Ip地址范围, 98 | func ParseIpv4Range(ip string) (Range, error) { 99 | var result Range 100 | 101 | index := strings.Index(ip, "/") 102 | if index != -1 { 103 | ips, err := ps.CidrParse(ip) 104 | if err != nil { 105 | fmt.Println(err) 106 | return Range{}, err 107 | } 108 | 109 | begin, err := ps.ParseIPv4(ips[0]) 110 | if err != nil { 111 | fmt.Println(err) 112 | return Range{}, err 113 | } 114 | 115 | result.Begin = begin 116 | 117 | end, err := ps.ParseIPv4(ips[len(ips)-1]) 118 | if err != nil { 119 | fmt.Println(err) 120 | return Range{}, err 121 | } 122 | 123 | result.End = end 124 | 125 | return result, nil 126 | 127 | } 128 | 129 | index = strings.Index(ip, "-") 130 | if index != -1 { 131 | ips := strings.Split(ip, "-") 132 | 133 | begin, err := ps.ParseIPv4(ips[0]) 134 | if err != nil { 135 | return Range{}, err 136 | } 137 | 138 | result.Begin = begin 139 | 140 | end, err := ps.ParseIPv4(ips[1]) 141 | if err != nil { 142 | return Range{}, err 143 | } 144 | 145 | result.End = end 146 | 147 | if end < begin { 148 | return Range{}, errors.New("End ip is large than start ip") 149 | } 150 | 151 | return result, nil 152 | } 153 | 154 | // 说明是单个的ip 155 | num, err := ps.ParseIPv4(ip) 156 | if err != nil { 157 | return Range{}, err 158 | } 159 | 160 | result.Begin = num 161 | result.End = num 162 | 163 | return result, nil 164 | } 165 | 166 | func ParseIPFromFile(path string) ([]Range, error) { 167 | var ips []Range 168 | p, err := os.Stat(path) 169 | if err != nil { 170 | return nil, err 171 | } 172 | if p.IsDir() { 173 | return nil, fmt.Errorf("could not input a dir: %s", path) 174 | } 175 | 176 | input, err := os.Open(path) 177 | 178 | if err != nil { 179 | return nil, fmt.Errorf("open file error: %s", path) 180 | } 181 | 182 | scanner := bufio.NewScanner(input) 183 | 184 | for scanner.Scan() { 185 | ip := strings.TrimSpace(scanner.Text()) 186 | if ip == "" { 187 | continue 188 | } 189 | if ps.IsIP(ip) || ps.IsIPRange(ip) { 190 | rst, err := ParseIpv4Range(ip) 191 | if err != nil { 192 | continue 193 | } 194 | ips = append(ips, rst) 195 | }else{ 196 | tmp_ips, mask, err := ps.DomainToIp(ip) 197 | if err != nil { 198 | fmt.Println(err) 199 | continue 200 | } 201 | for _, ip := range tmp_ips { 202 | addr := ip 203 | if mask != "" { 204 | addr = ip + "/" + mask 205 | } 206 | result, err := ParseIpv4Range(addr) 207 | 208 | if err != nil { 209 | fmt.Println("Error occured while parse iprange") 210 | continue 211 | } 212 | ips = append(ips,result) 213 | } 214 | } 215 | } 216 | return ips, nil 217 | } 218 | -------------------------------------------------------------------------------- /pkg/Ginfo/Ghttp/title.go: -------------------------------------------------------------------------------- 1 | package Ghttp 2 | 3 | import ( 4 | "golang.org/x/net/html" 5 | "net/http" 6 | "regexp" 7 | "strings" 8 | ) 9 | 10 | // ExtractTitle from a response 11 | func ExtractTitle(body string, r *http.Response) (title string) { 12 | var re = regexp.MustCompile(`(?im)<\s*title.*>(.*?)<\s*/\s*title>`) 13 | for _, match := range re.FindAllString(body, -1) { 14 | title = html.UnescapeString(trimTitleTags(match)) 15 | break 16 | } 17 | // Non UTF-8 18 | if contentTypes, ok := r.Header["Content-Type"]; ok { 19 | contentType := strings.ToLower(strings.Join(contentTypes, ";")) 20 | // special cases 21 | if strings.Contains(contentType, "charset=gb2312") || strings.Contains(contentType, "charset=gbk") { 22 | titleUtf8, err := Decodegbk([]byte(title)) 23 | if err != nil { 24 | return 25 | } 26 | 27 | return string(titleUtf8) 28 | } 29 | } 30 | 31 | return 32 | } 33 | 34 | func trimTitleTags(title string) string { 35 | // trim * 36 | titleBegin := strings.Index(title, ">") 37 | titleEnd := strings.Index(title, " 0 { 70 | URL = fmt.Sprintf("%s://%s:%d", protocol, domain, port) 71 | } 72 | 73 | var client *http.Client 74 | tr := &http.Transport{ 75 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 76 | } 77 | client = &http.Client{ 78 | Timeout: time.Second * 10, //timeout 79 | Transport: tr, 80 | } 81 | 82 | req, err := http.NewRequest(method, URL, nil) 83 | if err != nil { 84 | return Result{URL: URL, err: err} 85 | } 86 | req.Header.Set("Connection", "keep-alive") 87 | 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") 88 | 89 | resp, err := client.Do(req) 90 | 91 | if err != nil { 92 | if !retried && origProtocol == HTTPorHTTPS { 93 | if protocol == HTTPS { 94 | protocol = HTTP 95 | } else { 96 | protocol = HTTPS 97 | } 98 | retried = true 99 | goto retry 100 | } 101 | return Result{URL: URL, err: err} 102 | } 103 | 104 | var fullURL string 105 | 106 | if resp.StatusCode >= 0 { 107 | if port > 0 { 108 | fullURL = fmt.Sprintf("%s://%s:%d", protocol, domain, port) 109 | } else { 110 | fullURL = fmt.Sprintf("%s://%s", protocol, domain) 111 | } 112 | } 113 | 114 | builder := &strings.Builder{} 115 | builder.WriteString(fullURL) 116 | 117 | if scanopts.OutputStatusCode { 118 | builder.WriteString(" [") 119 | builder.WriteString(strconv.Itoa(resp.StatusCode)) 120 | builder.WriteRune(']') 121 | } 122 | 123 | if scanopts.OutputContentLength { 124 | builder.WriteString(" [") 125 | builder.WriteString(strconv.FormatInt(resp.ContentLength, 10)) 126 | builder.WriteRune(']') 127 | } 128 | 129 | if scanopts.OutputContentType { 130 | builder.WriteString(" [") 131 | builder.WriteString(resp.Header.Get("Content-Type")) 132 | builder.WriteRune(']') 133 | } 134 | 135 | defer resp.Body.Close() 136 | var titles []string 137 | body, err := ioutil.ReadAll(resp.Body) 138 | if err == nil { 139 | title1 := ExtractTitle(string(body), resp) 140 | finger := ExtractFinger(string(body), resp) 141 | if title1 != "" { 142 | titles = append(titles, title1) 143 | } 144 | if finger != "" { 145 | titles = append(titles, finger) 146 | } 147 | if scanopts.OutputTitle { 148 | builder.WriteString(" [") 149 | builder.WriteString(strings.Join(titles, "|")) 150 | builder.WriteRune(']') 151 | } 152 | } 153 | title := strings.Join(titles, "|") 154 | 155 | serverHeader1 := resp.Header.Get("Server") 156 | serverHeader2 := resp.Header.Get("X-Powered-By") 157 | var serverHeaders []string 158 | if serverHeader1 != "" { 159 | serverHeaders = append(serverHeaders, serverHeader1) 160 | } 161 | if serverHeader2 != "" { 162 | serverHeaders = append(serverHeaders, serverHeader2) 163 | } 164 | serverHeader := strings.Join(serverHeaders, "|") 165 | 166 | if scanopts.OutputServerHeader { 167 | builder.WriteString(fmt.Sprintf(" [%s]", serverHeader)) 168 | } 169 | 170 | // web socket 171 | isWebSocket := resp.StatusCode == 101 172 | if scanopts.OutputWebSocket && isWebSocket { 173 | builder.WriteString(" [websocket]") 174 | } 175 | 176 | return Result{ 177 | URL: fullURL, 178 | ContentLength: len(body), 179 | StatusCode: resp.StatusCode, 180 | ContentType: resp.Header.Get("Content-Type"), 181 | Title: title, 182 | WebServer: serverHeader, 183 | str: builder.String(), 184 | } 185 | } 186 | 187 | // Result of a scan 188 | type Result struct { 189 | URL string `json:"url"` 190 | Title string `json:"title"` 191 | WebServer string `json:"webserver"` 192 | ContentType string `json:"content-type,omitempty"` 193 | ContentLength int `json:"content-length"` 194 | StatusCode int `json:"status-code"` 195 | err error 196 | str string 197 | } 198 | 199 | // JSON the result 200 | func (r *Result) JSON() string { 201 | if js, err := json.Marshal(r); err == nil { 202 | return string(js) 203 | } 204 | 205 | return "" 206 | } 207 | 208 | func GetHttpTitle(target, proc string, port int) Result { 209 | var scanopts = new(ScanOptions) 210 | scanopts.OutputTitle = true 211 | scanopts.OutputServerHeader = true 212 | result := Analyze(proc, target, port, "GET", scanopts) 213 | return result 214 | } 215 | 216 | func (r *Result) ToString() string { 217 | 218 | builder := &bytes.Buffer{} 219 | if r.err == nil { 220 | builder.WriteString("[") 221 | builder.WriteString(conversion.ToString(r.StatusCode)) 222 | builder.WriteString("] ") 223 | if r.WebServer != "" { 224 | builder.WriteString("[") 225 | builder.WriteString(r.WebServer) 226 | builder.WriteString("] ") 227 | } 228 | if r.Title != "" { 229 | builder.WriteString("[") 230 | builder.WriteString(r.Title) 231 | builder.WriteString("] ") 232 | } 233 | } 234 | 235 | return builder.String() 236 | } 237 | 238 | func hostsFrom(ss []string) []string { 239 | for i, s := range ss { 240 | u, _ := url.Parse(s) 241 | if host := u.Hostname(); host != "" { 242 | ss[i] = host 243 | } 244 | } 245 | return ss 246 | } 247 | 248 | type hostinfo struct { 249 | Host string 250 | Port int 251 | Certs []*x509.Certificate 252 | } 253 | 254 | func (h *hostinfo) getCerts(timeout time.Duration) error { 255 | //log.Printf("connecting to %s:%d", h.Host, h.Port) 256 | dialer := &net.Dialer{Timeout: timeout} 257 | conn, err := tls.DialWithDialer( 258 | dialer, 259 | "tcp", 260 | h.Host+":"+strconv.Itoa(h.Port), 261 | &tls.Config{ 262 | InsecureSkipVerify: true, 263 | }) 264 | if err != nil { 265 | return err 266 | } 267 | 268 | defer conn.Close() 269 | 270 | if err := conn.Handshake(); err != nil { 271 | return err 272 | } 273 | 274 | pc := conn.ConnectionState().PeerCertificates 275 | h.Certs = make([]*x509.Certificate, 0, len(pc)) 276 | for _, cert := range pc { 277 | if cert.IsCA { 278 | continue 279 | } 280 | h.Certs = append(h.Certs, cert) 281 | } 282 | 283 | return nil 284 | } 285 | 286 | func CertInfo(host string, port string, timeout time.Duration) (commonName string, dnsNames []string, err error) { 287 | port_int, err := strconv.Atoi(port) 288 | if err != nil { 289 | return commonName, dnsNames, err 290 | } 291 | info := hostinfo{Host: host, Port: port_int} 292 | err = info.getCerts(timeout) 293 | if err != nil { 294 | return commonName, dnsNames, err 295 | } 296 | for _, cert := range info.Certs { 297 | if cert != nil && cert.Subject.CommonName != "" { 298 | return cert.Subject.CommonName, cert.DNSNames, err 299 | } 300 | } 301 | return commonName, dnsNames, errors.New("not found") 302 | } 303 | 304 | func GetCert(domain string, port int) (string, error) { 305 | var CN string 306 | var DN []string 307 | var ret string 308 | var err error 309 | if port > 0 { 310 | CN, DN, err = CertInfo(domain, strconv.Itoa(port), 5*time.Second) 311 | } else { 312 | CN, DN, err = CertInfo(domain, "443", 5*time.Second) 313 | } 314 | ret = "CommonName:" + CN + "; " 315 | if len(DN) > 0 { 316 | ret = ret + "DNSName:" 317 | ret = ret + DN[0] 318 | } 319 | return ret, err 320 | } 321 | -------------------------------------------------------------------------------- /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/common/engine.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "github.com/4dogs-cn/TXPortMap/pkg/Ginfo/Ghttp" 6 | "github.com/4dogs-cn/TXPortMap/pkg/Ginfo/Gnbtscan" 7 | ps "github.com/4dogs-cn/TXPortMap/pkg/common/ipparser" 8 | rc "github.com/4dogs-cn/TXPortMap/pkg/common/rangectl" 9 | "github.com/4dogs-cn/TXPortMap/pkg/conversion" 10 | "github.com/4dogs-cn/TXPortMap/pkg/output" 11 | "go.uber.org/ratelimit" 12 | "io" 13 | "net" 14 | "strings" 15 | "sync" 16 | "time" 17 | ) 18 | 19 | type Addr struct { 20 | ip string 21 | port uint64 22 | } 23 | 24 | type NBTScanIPMap struct{ 25 | sync.Mutex 26 | IPS map[string]struct{} 27 | } 28 | // type Range struct { 29 | // Begin uint64 30 | // End uint64 31 | // } 32 | 33 | var ( 34 | Writer output.Writer 35 | NBTScanIPs = NBTScanIPMap{IPS:make(map[string]struct{})} 36 | ) 37 | 38 | type Engine struct { 39 | TaskIps []rc.Range 40 | TaskPorts []rc.Range 41 | ExcdPorts []rc.Range // 待排除端口 42 | ExcdIps []rc.Range // 待排除的Ip 43 | RandomFlag bool 44 | WorkerCount int 45 | TaskChan chan Addr // 传递待扫描的ip端口对 46 | //DoneChan chan struct{} // 任务完成通知 47 | Wg *sync.WaitGroup 48 | } 49 | 50 | // SetIP as seen 51 | func (r *NBTScanIPMap) SetIP(ip string) { 52 | r.Lock() 53 | defer r.Unlock() 54 | 55 | r.IPS[ip] = struct{}{} 56 | } 57 | 58 | // HasIP checks if an ip has been seen 59 | func (r *NBTScanIPMap) HasIP(ip string) bool { 60 | r.Lock() 61 | defer r.Unlock() 62 | 63 | _, ok := r.IPS[ip] 64 | return ok 65 | } 66 | 67 | // 扫描目标建立,ip:port发送到任务通道 68 | func (e *Engine) Run() { 69 | var addr Addr 70 | e.Wg.Add(e.WorkerCount) 71 | go e.Scheduler() 72 | 73 | // fmt.Println(e.TaskPorts) 74 | 75 | // TODO:: if !e.RandomFlag 76 | if !e.RandomFlag { 77 | // 随机扫描,向任务通道随机发送addr 78 | e.randomScan() 79 | 80 | } else { 81 | // 顺序扫描,向任务通道顺序发送addr 82 | for _, ipnum := range e.TaskIps { 83 | for ips := ipnum.Begin; ips <= ipnum.End; ips++ { 84 | ip := ps.UnParseIPv4(ips) 85 | 86 | for _, ports := range e.TaskPorts { 87 | for port := ports.Begin; port <= ports.End; port++ { 88 | addr.ip = ip 89 | addr.port = port 90 | 91 | //e.SubmitTask(addr) 92 | //fmt.Println("ip:",ip,":port",port) 93 | e.TaskChan <- addr 94 | } 95 | } 96 | } 97 | } 98 | } 99 | 100 | // 扫描任务发送完成,关闭通道 101 | //fmt.Println("Task Add done") 102 | close(e.TaskChan) 103 | } 104 | 105 | func (e *Engine) SubmitTask(addr Addr) { 106 | //fmt.Printf("submit# %s:%d\n", addr.ip, addr.port) 107 | go func() { 108 | e.TaskChan <- addr 109 | }() 110 | } 111 | 112 | // 扫描任务创建 113 | func (e *Engine) Scheduler() { 114 | for i := 0; i < e.WorkerCount; i++ { 115 | worker(e.TaskChan, e.Wg) 116 | } 117 | } 118 | 119 | // 参数解析,对命令行中传递的参数进行格式化存储 120 | func (e *Engine) Parser() error { 121 | var err error 122 | Writer, err = output.NewStandardWriter(nocolor, json, rstfile, tracelog) 123 | if err != nil { 124 | return err 125 | } 126 | var ports []string 127 | // TODO:: 待增加排除ip和排除端口流程 128 | 129 | for _, ipstr := range cmdIps { 130 | if ps.IsIP(ipstr) || ps.IsIPRange(ipstr) { 131 | result, err := rc.ParseIpv4Range(ipstr) 132 | if err != nil { 133 | fmt.Println("Error occured while parse iprange") 134 | return err 135 | } 136 | 137 | e.TaskIps = append(e.TaskIps, result) 138 | } else { 139 | // 说明是域名,需要对域名进行解析 140 | ips, mask, err := ps.DomainToIp(ipstr) 141 | if err != nil { 142 | fmt.Println(err) 143 | return err 144 | } 145 | for _, ip := range ips { 146 | addr := ip 147 | if mask != "" { 148 | addr = ip + "/" + mask 149 | } 150 | 151 | result, err := rc.ParseIpv4Range(addr) 152 | 153 | if err != nil { 154 | fmt.Println("Error occured while parse iprange") 155 | return err 156 | } 157 | 158 | e.TaskIps = append(e.TaskIps, result) 159 | } 160 | } 161 | } 162 | 163 | if ipFile != "" { 164 | rst, err := rc.ParseIPFromFile(ipFile) 165 | if err == nil { 166 | for _, r := range rst { 167 | e.TaskIps = append(e.TaskIps, r) 168 | } 169 | } 170 | } 171 | 172 | if len(excIps) != 0 { 173 | for _, ipstr := range excIps { 174 | if ps.IsIP(ipstr) || ps.IsIPRange(ipstr) { 175 | result, err := rc.ParseIpv4Range(ipstr) 176 | if err != nil { 177 | fmt.Println("Error occured while parse iprange") 178 | return err 179 | } 180 | 181 | e.ExcdIps = append(e.ExcdIps, result) 182 | } else { 183 | // 说明是域名,需要对域名进行解析 184 | ips, mask, err := ps.DomainToIp(ipstr) 185 | if err != nil { 186 | fmt.Println(err) 187 | return err 188 | } 189 | for _, ip := range ips { 190 | addr := ip 191 | if mask != "" { 192 | addr = ip + "/" + mask 193 | } 194 | 195 | result, err := rc.ParseIpv4Range(addr) 196 | 197 | if err != nil { 198 | fmt.Println("Error occured while parse iprange") 199 | return err 200 | } 201 | 202 | e.ExcdIps = append(e.ExcdIps, result) 203 | } 204 | } 205 | } 206 | 207 | for _, ipe := range e.ExcdIps { 208 | for i := 0; i < len(e.TaskIps); i++ { 209 | if res, ok := (e.TaskIps[i]).RemoveExcFromTaskIps(ipe); ok { 210 | e.TaskIps = append(e.TaskIps, res) 211 | } 212 | } 213 | } 214 | } 215 | 216 | // 说明有自定义端口 217 | if len(cmdPorts) != 0 { 218 | ports = cmdPorts 219 | } else { 220 | if !cmdT1000 { 221 | // Top100端口扫描 222 | ports = Top100Ports 223 | 224 | } else { 225 | // Top1000端口扫描 226 | ports = Top1000Ports 227 | } 228 | } 229 | 230 | // 解析命令行端口范围 231 | for _, portstr := range ports { 232 | result, err := rc.ParsePortRange(portstr) 233 | if err != nil { 234 | fmt.Println(err) 235 | return err 236 | } 237 | 238 | e.TaskPorts = append(e.TaskPorts, result) 239 | } 240 | 241 | // 解析待排除端口范围 242 | if len(excPorts) != 0 { 243 | for _, portstr := range excPorts { 244 | result, err := rc.ParsePortRange(portstr) 245 | if err != nil { 246 | fmt.Println(err) 247 | return err 248 | } 249 | 250 | e.ExcdPorts = append(e.ExcdPorts, result) 251 | } 252 | 253 | // range出来的其实是原始值的拷贝,因此,这里需要对原始值进行修改时,不能使用range 254 | for _, exp := range e.ExcdPorts { 255 | for i := 0; i < len(e.TaskPorts); i++ { 256 | if res, ok := (e.TaskPorts[i]).RemoveExcFromTaskIps(exp); ok { 257 | e.TaskPorts = append(e.TaskPorts, res) 258 | } 259 | } 260 | } 261 | } 262 | 263 | // fmt.Println(e.TaskPorts) 264 | // fmt.Println(e.ExcdPorts) 265 | 266 | return nil 267 | } 268 | 269 | func CreateEngine() *Engine { 270 | 271 | if limit > 1{ 272 | Limiter = ratelimit.New(limit) 273 | }else{ 274 | Limiter = ratelimit.NewUnlimited() 275 | } 276 | 277 | return &Engine{ 278 | RandomFlag: cmdRandom, 279 | TaskChan: make(chan Addr, 1000), 280 | WorkerCount: NumThreads, 281 | Wg: &sync.WaitGroup{}, 282 | } 283 | } 284 | 285 | func nbtscaner(ip string) { 286 | resultEvent := output.ResultEvent{Target: ip, Info: &output.Info{}} 287 | nbInfo, err := Gnbtscan.Scan(ip) 288 | if err == nil && len(nbInfo) > 0 { 289 | resultEvent.Info.Service = "nbstat" 290 | resultEvent.Info.Banner = nbInfo 291 | Writer.Write(&resultEvent) 292 | } 293 | } 294 | 295 | func scanner(ip string, port uint64) { 296 | var dwSvc int 297 | var iRule = -1 298 | var bIsIdentification = false 299 | var resultEvent *output.ResultEvent 300 | var packet []byte 301 | //var iCntTimeOut = 0 302 | 303 | // 端口开放状态,发送报文,获取响应 304 | // 先判断端口是不是优先识别协议端口 305 | for _, svc := range St_Identification_Port { 306 | if port == svc.Port { 307 | bIsIdentification = true 308 | iRule = svc.Identification_RuleId 309 | data := st_Identification_Packet[iRule].Packet 310 | 311 | dwSvc, resultEvent = SendIdentificationPacketFunction(data, ip, port) 312 | break 313 | } 314 | } 315 | if (dwSvc > UNKNOWN_PORT && dwSvc <= SOCKET_CONNECT_FAILED) || dwSvc == SOCKET_READ_TIMEOUT { 316 | Writer.Write(resultEvent) 317 | return 318 | } 319 | 320 | // 发送其他协议查询包 321 | for i := 0; i < iPacketMask; i++ { 322 | // 超时2次,不再识别 323 | if bIsIdentification && iRule == i { 324 | continue 325 | } 326 | if i == 0 { 327 | // 说明是http,数据需要拼装一下 328 | var szOption string 329 | if port == 80 { 330 | szOption = fmt.Sprintf("%s%s\r\n\r\n", st_Identification_Packet[0].Packet, ip) 331 | } else { 332 | szOption = fmt.Sprintf("%s%s:%d\r\n\r\n", st_Identification_Packet[0].Packet, ip, port) 333 | } 334 | packet = []byte(szOption) 335 | }else{ 336 | packet = st_Identification_Packet[i].Packet 337 | } 338 | 339 | dwSvc, resultEvent = SendIdentificationPacketFunction(packet, ip, port) 340 | if (dwSvc > UNKNOWN_PORT && dwSvc <= SOCKET_CONNECT_FAILED) || dwSvc == SOCKET_READ_TIMEOUT { 341 | Writer.Write(resultEvent) 342 | return 343 | } 344 | } 345 | // 没有识别到服务,也要输出当前开放端口状态 346 | Writer.Write(resultEvent) 347 | } 348 | 349 | func worker(res chan Addr, wg *sync.WaitGroup) { 350 | go func() { 351 | defer wg.Done() 352 | 353 | 354 | for addr := range res { 355 | //do netbios stat scan 356 | if nbtscan && NBTScanIPs.HasIP(addr.ip) == false{ 357 | NBTScanIPs.SetIP(addr.ip) 358 | nbtscaner(addr.ip) 359 | } 360 | Limiter.Take() 361 | scanner(addr.ip, addr.port) 362 | } 363 | 364 | }() 365 | } 366 | 367 | func SendIdentificationPacketFunction(data []byte, ip string, port uint64) (int, *output.ResultEvent) { 368 | addr := fmt.Sprintf("%s:%d", ip, port) 369 | even := &output.ResultEvent{ 370 | Target: addr, 371 | Info: &output.Info{}, 372 | } 373 | 374 | //fmt.Println(addr) 375 | var dwSvc int = UNKNOWN_PORT 376 | conn, err := net.DialTimeout("tcp", addr, time.Duration(tout * 1000) * time.Millisecond) 377 | if err != nil { 378 | // 端口是closed状态 379 | Writer.Request(ip, conversion.ToString(port), "tcp", fmt.Errorf("time out")) 380 | return SOCKET_CONNECT_FAILED, nil 381 | } 382 | 383 | defer conn.Close() 384 | 385 | // Write方法是非阻塞的 386 | 387 | if _, err := conn.Write(data); err != nil { 388 | // 端口是开放的 389 | Writer.Request(ip, conversion.ToString(port), "tcp", err) 390 | return dwSvc, even 391 | } 392 | 393 | // 直接开辟好空间,避免底层数组频繁申请内存 394 | var fingerprint = make([]byte, 0, 65535) 395 | var tmp = make([]byte, 256) 396 | // 存储读取的字节数 397 | var num int 398 | var szBan string 399 | var szSvcName string 400 | 401 | // 这里设置成6秒是因为超时的时候会重新尝试5次, 402 | 403 | readTimeout := 2 * time.Second 404 | 405 | // 设置读取的超时时间为6s 406 | conn.SetReadDeadline(time.Now().Add(readTimeout)) 407 | 408 | for { 409 | // Read是阻塞的 410 | n, err := conn.Read(tmp) 411 | if err != nil { 412 | // 虽然数据读取错误,但是端口仍然是open的 413 | // fmt.Println(err) 414 | if err != io.EOF { 415 | dwSvc = SOCKET_READ_TIMEOUT 416 | // fmt.Printf("Discovered open port\t%d\ton\t%s\n", port, ip) 417 | } 418 | break 419 | } 420 | 421 | if n > 0 { 422 | num += n 423 | fingerprint = append(fingerprint, tmp[:n]...) 424 | } else { 425 | // 虽然没有读取到数据,但是端口仍然是open的 426 | // fmt.Printf("Discovered open port\t%d\ton\t%s\n", port, ip) 427 | break 428 | } 429 | } 430 | Writer.Request(ip, conversion.ToString(port), "tcp", err) 431 | // 服务识别 432 | if num > 0 { 433 | dwSvc = ComparePackets(fingerprint, num, &szBan, &szSvcName) 434 | //if len(szBan) > 15 { 435 | // szBan = szBan[:15] 436 | //} 437 | if dwSvc > UNKNOWN_PORT && dwSvc < SOCKET_CONNECT_FAILED { 438 | //even.WorkingEvent = "found" 439 | if szSvcName == "ssl/tls" || szSvcName == "http" { 440 | rst := Ghttp.GetHttpTitle(ip, Ghttp.HTTPorHTTPS, int(port)) 441 | even.WorkingEvent = rst 442 | cert, err0 := Ghttp.GetCert(ip, int(port)) 443 | if err0 != nil { 444 | cert = "" 445 | } 446 | even.Info.Cert = cert 447 | } else { 448 | even.Info.Banner = strings.TrimSpace(szBan) 449 | } 450 | even.Info.Service = szSvcName 451 | even.Time = time.Now() 452 | // fmt.Printf("Discovered open port\t%d\ton\t%s\t\t%s\t\t%s\n", port, ip, szSvcName, strings.TrimSpace(szBan)) 453 | //Writer.Write(even) 454 | //return dwSvc, even 455 | } 456 | } 457 | 458 | return dwSvc, even 459 | } 460 | 461 | // randomScan 随机扫描, 有问题,扫描C段时扫描不到, 462 | // TODO::尝试遍历ip,端口顺序打乱扫描 463 | func (e *Engine) randomScan() { 464 | // 投机取巧,打乱端口顺序,遍历ip扫描 465 | var portlist = make(map[int]uint64) 466 | var index int 467 | var addr Addr 468 | 469 | for _, ports := range e.TaskPorts { 470 | for port := ports.Begin; port <= ports.End; port++ { 471 | portlist[index] = port 472 | index++ 473 | } 474 | } 475 | 476 | for _, ipnum := range e.TaskIps { 477 | for ips := ipnum.Begin; ips <= ipnum.End; ips++ { 478 | ip := ps.UnParseIPv4(ips) 479 | for _, po := range portlist { 480 | addr.ip = ip 481 | addr.port = po 482 | 483 | e.TaskChan <- addr 484 | } 485 | // fmt.Printf("%d ", po) 486 | } 487 | } 488 | 489 | } 490 | 491 | // 统计待扫描的ip数目 492 | func (e *Engine) ipRangeCount() uint64 { 493 | var count uint64 494 | for _, ipnum := range e.TaskIps { 495 | count += ipnum.End - ipnum.Begin + 1 496 | } 497 | 498 | return count 499 | } 500 | 501 | // 统计待扫描的端口数目 502 | func (e *Engine) portRangeCount() uint64 { 503 | var count uint64 504 | for _, ports := range e.TaskPorts { 505 | count += ports.End - ports.Begin + 1 506 | } 507 | 508 | return count 509 | } 510 | -------------------------------------------------------------------------------- /pkg/common/constant.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | const ( 4 | UNKNOWN_PORT = iota 5 | UNKNOWN_SVC 6 | MySQL 7 | MySQL_NOT_ALLOWED 8 | MySQL_BLOCKED 9 | SSH 10 | FTP 11 | FTP_NOT_ALLOWED_OR_NOT_AVAILABLE // {服务不可用或者拒绝访问} 12 | SMTP 13 | SMTP_NOT_ALLOWED_OR_NOT_AVAILABLE // {服务不可用或者拒绝访问} 14 | FTP_OR_SMTP 15 | FTP_OR_SMTP_SERVICE_NOT_AVAILABLE // 服务不可用 16 | VM_AUTH_DAEMON 17 | POP3 // port : 110 18 | POPPASSD // port : 110 19 | IMAP4 20 | VNC // port : 5900 21 | RDP // port : 3389 22 | SSL_TLS // port : 443 23 | MSSQL // port : 1433 24 | ORACLE // port : 1521 25 | REDIS // port : 6379 26 | REDIS_AUTH 27 | REDIS_DENIED 28 | MEMCACHED // port : 11211 29 | TELNET // port : 23 30 | HTTP // port : 80 31 | PCANYWHERE // port : 5631 32 | VPN_PPTP // port : 1723 33 | RSYNC // port : 873 34 | MSRPC // port : 135 35 | NETBIOS_SSN // port : 139 36 | MICROSOFT_DS // port : 445 37 | DECRPC 38 | POSTGRESQL // port : 5432 39 | IBMDB2 40 | MONGODB // port : 27017 41 | MONGODB_AUTH 42 | LDAP // port : 389 43 | DNS // port : 53 44 | DNS_NOBANNER 45 | ROUTEROS // port : 8291 46 | RADMIN // port : 4899 47 | JAVARMI 48 | JAVARMI_CRASHPLAN 49 | JABBER 50 | JDWP 51 | MMS // port : 1755 52 | DTSPCD // port : 6112 53 | SVNSERVE 54 | WEBLOGIC // port : 7001 55 | SIP 56 | SVRLOC // port : 427 57 | AJP13 // port : 8009 58 | NFS // port : 2049 59 | ELASTICSEARCH // port : 9300 60 | RTSP // port : 554 61 | LOTUSNOTES // port : 1352 62 | ) 63 | 64 | const ( 65 | SOCKET_CONNECT_FAILED = iota + 10000001 // 连接失败 66 | SOCKET_READ_TIMEOUT // 读取超时错误 67 | ) 68 | 69 | // IdentificationProtocol 用于服务识别时发送的报文 70 | var IdentificationProtocol = []string{ 71 | "Ghttp#474554202f20485454502f312e310d0a557365722d4167656e743a204d6f7a696c6c612f352e30202857696e646f7773204e5420362e313b20574f57363429204170706c655765624b69742f3533372e333620284b48544d4c2c206c696b65204765636b6f29204368726f6d652f35312e302e323730342e313036205361666172692f3533372e33360d0a4163636570743a202a2f2a0d0a486f73743a20", 72 | "rdp#030000130ee000000000000100080003000000", 73 | "ssl/tls(1)#16030100ae010000aa030355d1668dc7272d1242aaf6e9666fbbe21e5acc601d572b39e45a5f13609dec1600001c5a5ac02bc02fc02cc030cca9cca8c013c014009c009d002f0035000a010000656a6a0000ff010001000017000000230000000d00140012040308040401050308050501080606010201000500050100000000001200000010000e000c02683208687474702f312e3175500000000b00020100000a000a0008dada001d001700188a8a000100", 74 | "ssl/tls(2)#1603000069010000650303551ca7e472616e646f6d3172616e646f6d3272616e646f6d3372616e646f6d3400000c002f000a00130039000400ff01000030000d002c002a000100030002060106030602020102030202030103030302040104030402010101030102050105030502", 75 | "ssl/tls(3)#809e01030100750000002000006600006500006400006300006200003a00003900003800003500003400003300003200002f00001b00001a00001900001800001700001600001500001400001300001200001100000a0000090000080000060000050000040000030700c0060040040080030080020080010080000002000001e4693c2bf6d69bbbd3819fbf15c140a56f142c4d20c4c7e0b6b0b21ff929e898", 76 | "mssql#1201003400000000000015000601001b000102001c000c0300280004ff080001550000004d5353514c536572766572004e53464f", 77 | "dns#001E0006010000010000000000000776657273696F6E0462696E640000100003", 78 | "oracle#005a0000010000000136012c000008007fff7f08000000010020003a0000000000000000000000000000000034e600000001000000000000000028434f4e4e4543545f444154413d28434f4d4d414e443d76657273696f6e2929", 79 | "nfs#80000028106c8eb90000000000000002000186a3000000040000000000000000000000000000000000000000", 80 | "redis#2a310d0a24340d0a70696e670d0a696e666f0d0a717569740d0a", 81 | "weblogic#74332031322e312e320a41533a323034380a484c3a31390a0a", 82 | "vpn-pptp#009c00011a2b3c4d00010000010000000000000100000001ffff00016e6f6e650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004d6963726f736f667400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 83 | "rsync#405253594e43443a2032392e0a0a", 84 | "memcached#73746174730d0a717569740d0a", 85 | "msrpc/netbios-ssn/microsoft-ds/postgresql#000000a4ff534d4272000000000801400000000000000000000000000000400600000100008100025043204e4554574f524b2050524f4752414d20312e3000024d4943524f534f4654204e4554574f524b5320312e303300024d4943524f534f4654204e4554574f524b5320332e3000024c414e4d414e312e3000024c4d312e3258303032000253616d626100024e54204c414e4d414e20312e3000024e54204c4d20302e313200", 86 | "ibm-db2#00000000444232444153202020202020010400000010397a000100000000000000000000010c0000000000000c0000000c00000004", 87 | "mongodb#410000004d095000ffffffffd407000000000000746573742e24636d640000000000ffffffff1b0000000173657276657253746174757300000000000000f03f00", 88 | "ldap#300c020101600702010204008000", 89 | "mikrotik#12026c6973740000000000000000000100000000", 90 | "ajp13#123400010a", 91 | "wms#01000000cefa0bb0a00000004d4d5320140000000000000000000000000000001200000001000300f0f0f0f00b0004001c0003004e00530050006c0061007900650072002f00310030002e0030002e0030002e0033003600340036003b0020007b00330033003000300041004400350030002d0032004300330039002d0034003600630030002d0041004500300041002d004200410033004500450030004300380031003300360045007d0000000000", 92 | "dtspcd#3030303030303032303430303064303030312020342000726f6f74000031300000", 93 | "jabber#3c3f786d6c2076657273696f6e3d27312e30273f3e3c73747265616d3a73747265616d20786d6c6e733a73747265616d3d27687474703a2f2f6574686572782e6a61626265722e6f72672f73747265616d732720786d6c6e733d276a61626265723a636c69656e742720786d6c3a6c616e673d2772752d52552720746f3d272e272076657273696f6e3d27312e30273e", 94 | "jdwp#4a4457502d48616e647368616b65", 95 | "sip#4f5054494f4e53207369703a6e6d205349502f322e300d0a5669613a205349502f322e302f544350206e6d3b6272616e63683d666f6f0d0a46726f6d3a203c7369703a6e6d406e6d3e3b7461673d726f6f740d0a546f3a203c7369703a6e6d32406e6d323e0d0a43616c6c2d49443a2035303030300d0a435365713a203432204f5054494f4e530d0a4d61782d466f7277617264733a2037300d0a436f6e74656e742d4c656e6774683a20300d0a436f6e746163743a203c7369703a6e6d406e6d3e0d0a4163636570743a206170706c69636174696f6e2f7364700d0a0d0a", 96 | "svrloc#0201000036200000000000010002656e00000015736572766963653a736572766963652d6167656e74000764656661756c7400000000", 97 | "pcanywhere#00000000", 98 | "radmin#01000000010000000808", 99 | "postgresql#00000042000300007573657200706f73746772657300646174616261736500706f737467726573006170706c69636174696f6e5f6e616d65004e6176696361740000", 100 | "rtsp/sip#4f5054494f4e53207369703a6e6d205349502f322e300d0a5669613a205349502f322e302f544350206e6d3b6272616e63683d666f6f0d0a46726f6d3a203c7369703a6e6d406e6d3e3b7461673d726f6f740d0a546f3a203c7369703a6e6d32406e6d323e0d0a43616c6c2d49443a2035303030300d0a435365713a203432204f5054494f4e530d0a4d61782d466f7277617264733a2037300d0a436f6e74656e742d4c656e6774683a20300d0a436f6e746163743a203c7369703a6e6d406e6d3e0d0a4163636570743a206170706c69636174696f6e2f7364700d0a0d0a", 101 | "lotusnotes#3a0000002f00000002000040020f0001003d050000000000000000000000002f000000000000000000401f0000000000000000000000000000000000", 102 | "onvif(1)#3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d227574662d38223f3e3c456e76656c6f706520786d6c6e733a646e3d22687474703a2f2f7777772e6f6e7669662e6f72672f76657231302f6e6574776f726b2f7773646c2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030332f30352f736f61702d656e76656c6f7065223e3c4865616465723e3c7773613a4d657373616765494420786d6c6e733a7773613d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030342f30382f61646472657373696e67223e757569643a37653266353530352d393765352d343934312d613732362d3938376137656265616136303c2f7773613a4d65737361676549443e3c7773613a546f20786d6c6e733a7773613d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030342f30382f61646472657373696e67223e75726e3a736368656d61732d786d6c736f61702d6f72673a77733a323030353a30343a646973636f766572793c2f7773613a546f3e3c7773613a416374696f6e20786d6c6e733a7773613d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030342f30382f61646472657373696e67223e687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030352f30342f646973636f766572792f50726f62653c2f7773613a416374696f6e3e3c2f4865616465723e3c426f64793e3c50726f626520786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030352f30342f646973636f76657279223e3c54797065733e646e3a4e6574776f726b566964656f5472616e736d69747465723c2f54797065733e3c53636f706573202f3e3c2f50726f62653e3c2f426f64793e3c2f456e76656c6f70653e", 103 | "onvif(2)#3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d227574662d38223f3e3c456e76656c6f706520786d6c6e733a7464733d22687474703a2f2f7777772e6f6e7669662e6f72672f76657231302f6465766963652f7773646c2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030332f30352f736f61702d656e76656c6f7065223e3c4865616465723e3c7773613a4d657373616765494420786d6c6e733a7773613d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030342f30382f61646472657373696e67223e757569643a31613737653736312d396361302d343939612d613835332d3463346236633935323864643c2f7773613a4d65737361676549443e3c7773613a546f20786d6c6e733a7773613d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030342f30382f61646472657373696e67223e75726e3a736368656d61732d786d6c736f61702d6f72673a77733a323030353a30343a646973636f766572793c2f7773613a546f3e3c7773613a416374696f6e20786d6c6e733a7773613d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030342f30382f61646472657373696e67223e687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030352f30342f646973636f766572792f50726f62653c3b2f7773613a416374696f6e3e3c2f4865616465723e3c426f64793e3c50726f626520786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f77732f323030352f30342f646973636f76657279223e3c54797065733e7464733a4465766963653c2f54797065733e3c53636f706573202f3e3c2f50726f62653e3c2f426f64793e3c2f456e76656c6f70653e", 104 | } 105 | 106 | // Top 100常见端口 107 | var Top100Ports = []string{ 108 | "21-23", "25", "53", "69", "79", "80-89", "110-111", "135", "139", "143", "161", "322", "389", "443", "445", "465", "512-515", "524", "587", "873", "993", "995", "999", 109 | "1080", "1158", "1352", "1433", "1521", "1863", "2049", "2100", "2181", "2222", "2323", "3128", "3306", "3389", "4848", "4899", "5000", "5061", "5432", "5631-5632", "5800", "5900", "6379", "7001", "7080", "7090", "8000", "8008", 110 | "8009", "8069", "8080-8090", "8141", "8161", "8291", "8443", "8888", "8899", "8880", "9001", "9080", "9090", "9200", "9300", "9443", "9898", "9900", 111 | "17001-17003", "11211", "20080", "27017", 112 | } 113 | 114 | // Top 1000常见端口 115 | var Top1000Ports = []string{ 116 | "1", "3-4", "6-7", "9", "13", "17", "19-26", "30", "32-33", "37", "42-43", "49", "53", "70", "79-85", "88-90", "99-100", "106", "109-111", "113", "119", "125", "135", "139", "143-144", "146", "161", "163", "179", "199", "211-212", "222", "254-256", "259", "264", "280", "301", "306", "311", "340", "366", "389", "406-407", "416-417", "425", "427", "443-445", "458", "464-465", "481", "497", "500", "512-515", "524", "541", "543-545", "548", "554-555", "563", "587", "593", "616-617", "625", "631", "636", "646", "648", "666-668", "683", "687", "691", "700", "705", "711", "714", "720", "722", "726", "749", "765", "777", "783", "787", "800-801", "808", "843", "873", "880", "888", "898", "900-903", "911-912", "981", "987", "990", "992-993", "995", "999-1002", 117 | "1007", "1009-1011", "1021-1100", "1102", "1104-1108", "1110-1114", "1117", "1119", "1121-1124", "1126", "1130-1132", "1137-1138", "1141", "1145", "1147", "1148-1149", "1151-1152", "1154", "1163-1166", "1169", "1174-1175", "1183", "1185-1187", "1192", "1198-1199", "1201", "1213", "1216-1218", "1233-1234", "1236", "1244", "1247-1248", "1259", "1271-1272", "1277", "1287", "1296", "1300-1301", "1309-1311", "1322", "1328", "1334", "1352", "1417", "1433-1434", "1443", "1455", "1461", "1494", "1500-1501", "1503", "1521", "1524", "1533", "1556", "1580", "1583", "1594", "1600", "1641", "1658", "1666", "1687-1688", "1700", "1717-1721", "1723", "1755", "1761", "1782-1783", "1801", "1805", "1812", "1839-1840", "1862-1864", "1875", "1900", "1914", "1935", "1947", "1971-1972", "1974", "1984", "1998-2010", 118 | "2013", "2020-2022", "2030", "2033-2035", "2038", "2040-2043", "2045-2049", "2065", "2068", "2099-2100", "2103", "2105-2107", "2111", "2119", "2121", "2126", "2135", "2144", "2160-2161", "2170", "2179", "2190", "2191", "2196", "2200", "2222", "2251", "2260", "2288", "2301", "2323", "2366", "2381-2383", "2393-2394", "2399", "2401", "2492", "2500", "2522", "2525", "2557", "2601-2602", "2604-2605", "2607-2608", "2638", "2701-2702", "2710", "2717-2718", "2725", "2800", "2809", "2811", "2869", "2875", "2909-2910", "2920", "2967-2968", "2998", "3000-3001", "3003", "3005-3007", "3011", "3013", "3017", "3030-3031", "3050", "3052", "3071", "3077", "3128", "3168", "3211", "3221", "3260-3261", "3268-3269", "3283", "3300-3301", "3306", "3322-3325", "3333", "3351", "3367", "3369-3372", "3389-3390", "3404", "3476", "3493", "3517", "3527", "3546", "3551", "3580", "3659", "3689", "3690", "3703", "3737", "3766", "3784", "3800-3801", "3809", "3814", "3826-3828", "3851", "3869", "3871", "3878", "3880", "3889", "3905", "3914", "3918", "3920", "3945", "3971", "3986", "3995", "3998", "4000-4006", "4045", "4111", "4125-4126", "4129", "4224", "4242", "4279", "4321", "4343", "4443-4446", "4449-4550", "4567", "4662", "4848", "4899-4900", "4998", 119 | "5000-5004", "5009", "5030", "5033", "5050-5051", "5054", "5060-5061", "5080", "5087", "5100-5102", "5120", "5190", "5200", "5214", "5221-5222", "5225-5226", "5269", "5280", "5298", "5357", "5405", "5414", "5431-5432", "5440", "5500", "5510", "5544", "5550", "5555", "5560", "5566", "5631", "5633", "5666", "5678-5679", "5718", "5730", "5800-5802", "5810-5811", "5815", "5822", "5825", "5850", "5859", "5862", "5877", "5900-5904", "5906-5907", "5910-5911", "5915", "5922", "5925", "5950", "5952", "5959-5963", "5987-5989", "5998-6007", "6009", "6025", "6059", "6100-6101", "6106", "6112", "6123", "6129", "6156", "6346", "6389", "6502", "6510", "6543", "6547", "6565-6567", "6580", "6646", "6666-6669", "6689", "6692", "6699", "6779", "6788-6789", "6792", "6839", "6881", "6901", "6969", "7000-7002", "7004", "7007", "7019", "7025", "7070", "7100", "7103", "7106", "7200-7201", "7402", "7435", "7443", "7496", "7512", "7625", "7627", "7676", "7741", "7777-7778", "7800", "7911", "7920-7921", "7937-7938", "7999-8002", "8007-8011", "8021-8022", "8031", "8042", "8045", "8080-8090", "8093", "8099-8100", "8180-8181", "8192-8194", "8200", "8222", "8254", "8290-8292", "8300", "8333", "8383", "8400", "8402", "8443", "8500", "8600", "8649", "8651-8652", "8654", "8701", "8800", "8873", "8888", "8899", "8880", "8994", 120 | "9000-9003", "9009-9011", "9040", "9050", "9060", "9043", "9071", "9080-9081", "9090-9091", "9099-9103", "9110-9111", "9200", "9207", "9220", "9290", "9415", "9418", "9485", "9500", "9443", "9502-9503", "9535", "9575", "9593-9595", "9618", "9666", "9876-9878", "9898", "9900", "9917", "9943-9944", "9968", "9998-10004", "10009-10010", "10012", "10024-10025", "10082", "10180", "10215", "10243", "10566", "10616-10617", "10621", "10626", "10628-10629", "10778", "11110-11111", "11967", "12000", "12174", "12265", "12345", "13456", "13722", "13782-13783", "14000", "14238", "14441-14442", "15000", "15002-15004", "15660", "15742", "16000-16001", "16012", "16016", "16018", "16080", "16113", "16992-16993", "17877", "17988", "18040", "18101", "18988", "19101", "19283", "19315", "19350", "19780", "19801", "19842", "20000", "20005", "20031", "20221-20222", "20828", "21571", "22939", "23502", "24444", "24800", "25734-25735", "26214", "27000", "27352-27353", "27355-27356", "27715", "28201", "30000", "30718", "30951", "31038", "31337", "32768-32785", "33354", "33899", "34571-34573", "35500", "38292", "40193", "40911", "41511", "42510", "44176", "44442-44443", "44501", "45100", "48080", "49152-49161", "49163", "49165", "49167", "49175-49176", "49400", "49999-50003", "50006", "50300", "50389", "50500", "50636", "50800", "51103", "51493", "52673", "52822", "52848", "52869", "54045", "54328", "55055-55056", "55555", "55600", "56737-56738", "57294", "57797", "58080", "60020", "60443", "61532", "61900", "62078", "63331", "64623", "64680", "65000", "65129", "65389", 121 | } 122 | 123 | type Identification_Port struct { 124 | SzSvcName string // 服务名 125 | Port uint64 // 端口 126 | Identification_RuleId int // 针对规则条目序号 127 | } 128 | 129 | var St_Identification_Port = []Identification_Port{ 130 | {"rdp", 3389, 1}, 131 | {"mssql", 1433, 5}, 132 | {"dns", 53, 6}, 133 | {"oracle", 1521, 7}, 134 | {"nfs", 2049, 8}, 135 | {"redis", 6379, 9}, 136 | {"weblogic", 7001, 10}, 137 | {"weblogic", 7002, 10}, 138 | {"vpn", 1723, 11}, 139 | {"rsync", 873, 12}, 140 | {"memcached", 11211, 13}, 141 | {"msrcp", 135, 14}, 142 | {"netbios-ssn", 139, 14}, 143 | {"microsoft-ds", 445, 14}, 144 | {"mongodb", 27017, 16}, 145 | {"ldap", 389, 17}, 146 | {"mikrotik", 8291, 18}, 147 | {"ajp13", 8009, 19}, 148 | {"wms", 1755, 20}, 149 | {"dtspcd", 6112, 21}, 150 | {"svrloc", 427, 25}, 151 | {"pcanywhere", 5631, 26}, 152 | {"pcanywhere", 5632, 26}, 153 | {"radmin", 4899, 27}, 154 | {"postgresql", 5432, 28}, // 模拟Navicat登陆 155 | {"postgresql", 5432, 14}, // 通过rpc包判断 156 | {"rtsp", 554, 29}, 157 | {"sip", 5060, 29}, 158 | {"lotusnotes", 1352, 30}, 159 | {"onvif",3702,31}, 160 | {"onvif",3702,32}, 161 | } 162 | 163 | // rdp_receive_packet 164 | var os___xrdp_1 = []byte{0x03, 0x00, 0x00, 0x09, 0x02, 0xf0, 0x80, 0x21, 0x80} // xrdp 165 | var os___xrdp_2 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x02, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00} // xrdp 166 | var os___xrdp_3 = []byte{0x03, 0x00, 0x00, 0x0b, 0x06, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00} // xrdp 167 | var os___xrdp_4 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x02, 0x01, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00} // xrdp 168 | 169 | var os______old = []byte{0x03, 0x00, 0x00, 0x0b, 0x06, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00} // Windows 2000 Advanced Server || Windoes XP Professional || Windows Embedded POSReady 2009 || Windows Embedded Standard 170 | 171 | var os___2008_1 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00} // Windows Server 2008 R2 Datacenter 172 | var os___2008_2 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x02, 0x01, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00} // Windows Server 2008 R2 Datacenter 173 | var os___2008_3 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x02, 0x09, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00} // Windows Server 2008 R2 Standard 174 | 175 | var os___2012_1 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00} // Windows Server 2012 R2 176 | var os___2012_2 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x02, 0x07, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00} // Windows Server 2012 177 | var os__2012_r2 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x02, 0x0f, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00} // Windows Server 2012 R2 178 | 179 | var os__Vista_1 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x02, 0x1f, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00} // Vista以后的操作系统 180 | 181 | var os_Multiple_1 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00} // Windows 2003 / 2008 / 2012 182 | var os_Multiple_2 = []byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xd0, 0x00, 0x00, 0x12, 0x34, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00} // Windows 2003 / 2008 / 2012 183 | 184 | var iPacketMask = len(IdentificationProtocol) 185 | -------------------------------------------------------------------------------- /pkg/common/service.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | /** 12 | 服务识别相关处理函数 13 | rcv: 通过对比banner信息,解析服务信息 14 | 15 | */ 16 | 17 | func ComparePackets(rcv []byte, rcvSize int, szBan *string, szSvcName *string) int { 18 | 19 | var dwRecognition = UNKNOWN_PORT 20 | var buf = rcv[:] 21 | //var buf = rcv[:rcvSize] 22 | //var bufUp = bytes.ToUpper(buf) 23 | // DNS 24 | // 将缓存数据转换成可打印字符 25 | 26 | var printBuf string 27 | var cHex string 28 | var szFlagDns = []byte{0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x04, 0x62, 0x69, 0x6E, 0x64} 29 | var MagicCookie = []byte{0x1a, 0x2b, 0x3c, 0x4d} 30 | var PcAnyWhereMark_Low = []byte{0x00, 0x58, 0x08} // PcAnyWhere服务标识(低版本) 31 | var PcAnyWhereMark_High = []byte{0x1b, 0x59, 0x32} // PcAnyWhere服务标识(高版本) 32 | var szFlag_LDAP = []byte{0x02, 0x01, 0x01, 0x61} 33 | var szFlag_RADMIN = []byte{0x01, 0x00, 0x00, 0x00} 34 | 35 | for i := 0; i < rcvSize; i++ { 36 | if !strconv.IsPrint(rune(buf[i])) { 37 | cHex = fmt.Sprintf("\\x%02x", buf[i]) // 不可打印字符 38 | } else { 39 | cHex = fmt.Sprintf("%c", buf[i]) // 可打印字符 40 | } 41 | 42 | printBuf += cHex 43 | } 44 | 45 | var bufUp = bytes.ToUpper([]byte(printBuf)) 46 | 47 | var cFlag_MongoDB = []byte{0x4d, 0x09, 0x50, 0x00} 48 | var cBit_MongoDB []byte 49 | 50 | if len(buf) <4 { 51 | goto Return 52 | } 53 | 54 | if rcvSize <4{ 55 | goto Return 56 | } 57 | if bytes.Equal(buf[:3], []byte("220")) { 58 | *szBan = printBuf 59 | if bytes.Contains(bufUp, []byte("FTP")) || bytes.Contains(bufUp, []byte("FILEZILLA")) || bytes.Contains(bufUp, []byte("SERVICE READY FOR NEW USER")) { 60 | *szSvcName = "ftp" 61 | dwRecognition = FTP 62 | } else if bytes.Contains(bufUp, []byte("SMTP")) { 63 | // 这里比较的是原始字符串还是大写的字符串? 64 | *szSvcName = "smtp" 65 | dwRecognition = SMTP 66 | } else if bytes.Contains(buf, []byte("VMware Authentication Daemon Version")) { 67 | *szSvcName = "vmware-auth" 68 | dwRecognition = VM_AUTH_DAEMON 69 | } else { 70 | *szSvcName = "ftp|smtp" 71 | dwRecognition = FTP_OR_SMTP 72 | } 73 | goto Return 74 | } 75 | 76 | if bytes.Equal(buf[:4], []byte("421 ")) || bytes.Equal(buf[:4], []byte("550 ")) { 77 | *szBan = printBuf 78 | 79 | if bytes.Contains(bufUp, []byte("NO CONNECTIONS ALLOWED FROM YOUR IP")) || bytes.Contains(bufUp, []byte("UNABLE TO OPEN CONFIGURATION FILE")) { 80 | *szSvcName = "ftp" 81 | dwRecognition = FTP_NOT_ALLOWED_OR_NOT_AVAILABLE 82 | } else if bytes.Contains(bufUp, []byte("SMTP")) || bytes.Contains(bufUp, []byte(" SPAM")) || bytes.Equal(bufUp[:len("421 4.3.2 SERVICE NOT AVAILABLE")], []byte("421 4.3.2 SERVICE NOT AVAILABLE")) { 83 | *szSvcName = "smtp" 84 | dwRecognition = SMTP_NOT_ALLOWED_OR_NOT_AVAILABLE 85 | } else { 86 | *szSvcName = "ftp|smtp" 87 | dwRecognition = FTP_OR_SMTP_SERVICE_NOT_AVAILABLE 88 | } 89 | goto Return 90 | } 91 | 92 | if bytes.Equal(buf[:3], []byte("554")) { 93 | // 554 表示SMTP服务器拒绝当前主机访问 94 | *szBan = printBuf 95 | *szSvcName = "smtp" 96 | 97 | dwRecognition = SMTP_NOT_ALLOWED_OR_NOT_AVAILABLE 98 | 99 | goto Return 100 | } 101 | 102 | if bytes.Equal(buf[:9], []byte("rblsmtpd:")) { 103 | // 反垃圾邮件 104 | *szBan = printBuf 105 | *szSvcName = "smtp" 106 | dwRecognition = SMTP 107 | 108 | goto Return 109 | } 110 | 111 | // POP 112 | if bytes.Equal(buf[:4], []byte("+OK ")) { 113 | *szBan = printBuf 114 | *szSvcName = "pop" 115 | dwRecognition = POP3 116 | 117 | goto Return 118 | } 119 | 120 | if bytes.Equal(buf[:12], []byte("200 poppassd")) { 121 | *szBan = printBuf 122 | *szSvcName = "pop" 123 | dwRecognition = POPPASSD 124 | 125 | goto Return 126 | } 127 | 128 | // IMAP4 129 | if bytes.Equal(buf[:5], []byte("* OK ")) { 130 | *szBan = printBuf 131 | *szSvcName = "imap" 132 | 133 | dwRecognition = IMAP4 134 | 135 | goto Return 136 | } 137 | 138 | // VNC 139 | if bytes.Equal(buf[:4], []byte("\x52\x46\x42\x20")) { 140 | *szSvcName = "vnc" 141 | if len(buf) > 10 { 142 | *szBan = fmt.Sprintf("RFB %c.%c", buf[6], buf[10]) 143 | 144 | } else { 145 | *szBan = fmt.Sprintf("RFB *.*") 146 | } 147 | 148 | dwRecognition = VNC 149 | goto Return 150 | } 151 | 152 | // SSH 153 | if bytes.Equal(bufUp[:4], []byte("SSH-")) { 154 | *szBan = printBuf 155 | *szSvcName = "ssh" 156 | dwRecognition = SSH 157 | 158 | goto Return 159 | } 160 | 161 | // MYSQL TODO:: 默认使用了小端序,需要考虑大端序的情况 162 | if rcvSize > 7 && buf[4] == 0xff && buf[0] == uint8(rcvSize-4) { 163 | *szSvcName = "mysql" 164 | //var uErr uint16 165 | 166 | uErr := binary.LittleEndian.Uint16([]byte(buf[5:7])) 167 | 168 | if uErr == 1129 { 169 | *szBan = "BLOCKED" 170 | dwRecognition = MySQL_BLOCKED 171 | } else { 172 | *szBan = "NOT ALLOWED" 173 | dwRecognition = MySQL_NOT_ALLOWED 174 | } 175 | 176 | goto Return 177 | 178 | 179 | } 180 | 181 | if rcvSize > 5 && buf[4] >= 10 { 182 | // TODO:: 183 | index := strings.Index(printBuf, "\\x00\\x00\\x00\\x0a") 184 | 185 | if index != -1 { 186 | right := printBuf[len("\\x00\\x00\\x00\\x0a")+index:] 187 | iFind := strings.Index(right, "\\x00") 188 | if iFind != -1 { 189 | left := right[:iFind] 190 | *szBan = left 191 | *szSvcName = "mysql" 192 | dwRecognition = MySQL 193 | 194 | goto Return 195 | } 196 | } 197 | } 198 | 199 | // ROS TODO:: 200 | if strings.Contains(printBuf, "\\x13\\x02list") { 201 | *szSvcName = "MikroTik" 202 | dwRecognition = ROUTEROS 203 | 204 | goto Return 205 | } 206 | 207 | // Java-RMI TODO:: 208 | if strings.Contains(printBuf, "|com.code42.messaging.security.") { 209 | *szSvcName = "JavaRMI" 210 | *szBan = "CrashPlan online backup" 211 | 212 | dwRecognition = JAVARMI_CRASHPLAN 213 | 214 | goto Return 215 | } 216 | 217 | if strings.Index(printBuf, "\\xac\\xed\\x00\\x05") == 0 { 218 | *szSvcName = "JavaRMI" 219 | *szBan = printBuf 220 | 221 | dwRecognition = JAVARMI 222 | 223 | goto Return 224 | } 225 | 226 | // JDWP 227 | if bytes.Equal(buf[:len("JDWP-Handshake")], []byte("JDWP-Handshake")) { 228 | *szSvcName = "jdwp" 229 | dwRecognition = JDWP 230 | 231 | goto Return 232 | } 233 | 234 | // jabber 235 | if bytes.Contains(buf, []byte("jabber.org")) && 236 | (bytes.EqualFold(buf[:len(" 0 { 309 | dwRecognition = DNS 310 | *szBan = string(buftmp[13 : 13+buftmp[12]]) 311 | } 312 | } else { 313 | szSOAFlag := []byte{0xc0, 0x0c, 0x00, 0x06} 314 | n := bytes.Index(buf, szSOAFlag) 315 | if n != -1 { 316 | buftmp := buf[n:] 317 | dwRecognition = DNS 318 | *szBan = string(buftmp[15 : buf[11]-4*5-2-1-2]) 319 | } 320 | } 321 | 322 | if len(*szBan) == 0 { 323 | *szBan = "-NOBANNER-" 324 | } 325 | 326 | goto Return 327 | } 328 | 329 | if buf[1] == byte(rcvSize-2) && buf[3] == 0x06 { 330 | dwRecognition = DNS_NOBANNER 331 | *szSvcName = "dns" 332 | *szBan = "-NOBANNER-" 333 | 334 | goto Return 335 | } 336 | 337 | // WEBLOGIC-t3 338 | if rcvSize > 5 && bytes.Equal(buf[:5], []byte("HELO:")) { 339 | *szSvcName = "WebLogic-t3" 340 | dwRecognition = WEBLOGIC 341 | 342 | // TODO:: 343 | //*szBan = printBuf 344 | n := strings.Index(printBuf, "\\x0a") 345 | if n != -1 { 346 | bantmp := printBuf[:n] 347 | 348 | *szBan = strings.ReplaceAll(bantmp, "HELO:", "") 349 | } else { 350 | *szBan = printBuf 351 | } 352 | goto Return 353 | } 354 | 355 | if bytes.Contains(buf, []byte("filter blocked Socket, weblogic.security.net.FilterException")) { 356 | *szSvcName = "WebLogic-t3" 357 | dwRecognition = WEBLOGIC 358 | 359 | *szBan = "Weblogic Filter Blocked t3/t3s" 360 | 361 | goto Return 362 | } 363 | 364 | // HTTP | RTSP TODO:: szBan 365 | if bytes.Index(bufUp, []byte("HTTP/")) == 0 || bytes.Index(bufUp, []byte("RTSP/1")) == 0 { 366 | if bytes.Index(bufUp, []byte("HTTP/")) == 0 { 367 | dwRecognition = HTTP 368 | *szSvcName = "http" 369 | } else { 370 | dwRecognition = RTSP 371 | *szSvcName = "rtsp" 372 | } 373 | 374 | //*szBan = printBuf 375 | n := strings.Index(printBuf, "\\x0d\\x0aServer:") 376 | if n != -1 { 377 | bantmp := printBuf[len("\\x0d\\x0aServer:")+n:] 378 | idx := strings.Index(bantmp, "\\x0d\\x0a") 379 | if idx != -1 { 380 | *szBan = string(bantmp[:idx]) 381 | goto Return 382 | } 383 | 384 | } 385 | // HTTP 打印100个字符就够了,不然整个网页太长 386 | if len(printBuf) > 100 { 387 | *szBan = printBuf[:100] 388 | } else { 389 | *szBan = printBuf 390 | } 391 | goto Return 392 | } 393 | 394 | // bandwidth-test TODO:: 395 | if strings.EqualFold(printBuf, "\\x01\\x00\\x00\\x00") { 396 | dwRecognition = UNKNOWN_SVC 397 | *szSvcName = "bandwidth-test" 398 | *szBan = "MikroTik bandwidth-test server" 399 | 400 | goto Return 401 | } 402 | 403 | // // h.239 TODO:: 404 | if strings.EqualFold(printBuf, "BadRecord") { 405 | dwRecognition = UNKNOWN_SVC 406 | *szSvcName = "h.239" 407 | *szBan = "Polycom People+Content IP H.239" 408 | 409 | goto Return 410 | } 411 | 412 | // h323q931 TODO:: 413 | if strings.EqualFold(printBuf, "\\x03\\x00\\x000\\x08\\x02\\x00\\x00}\\x08\\x02\\x80\\xe2\\x14\\x01\\x00~\\x00\\x1d\\x05\\x08 \\x19\\x00\\x06\\x00\\x08\\x91J\\x00\\x05\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") { 414 | dwRecognition = UNKNOWN_SVC 415 | *szSvcName = "h323q931" 416 | *szBan = "Polycom ViewStation H.323" 417 | 418 | goto Return 419 | } 420 | 421 | // RDP 422 | if buf[0] == 0x03 && buf[1] == 0x00 && buf[2] == 0x00 { 423 | dwRecognition = RDP 424 | *szSvcName = "rdp" 425 | 426 | if bytes.Equal(buf[:len(os______old)], os______old) { 427 | *szBan = "Windows Server 2003 or before" 428 | } else if bytes.Equal(buf[:len(os___xrdp_1)], os___xrdp_1) || 429 | bytes.Equal(buf[:len(os___xrdp_2)], os___xrdp_2) || 430 | bytes.Equal(buf[:len(os___xrdp_3)], os___xrdp_3) || 431 | bytes.Equal(buf[:len(os___xrdp_4)], os___xrdp_4) { 432 | // xrdp 433 | *szBan = "xrdp" 434 | } else if bytes.Equal(buf[:len(os___2008_1)], os___2008_1) || 435 | bytes.Equal(buf[:len(os___2008_2)], os___2008_2) || 436 | bytes.Equal(buf[:len(os___2008_3)], os___2008_3) { 437 | *szBan = "Windows Server 2008 [R2] [Standard/Enterprise/Datacenter]" 438 | } else if bytes.Equal(buf[:len(os___2012_1)], os___2012_1) || 439 | bytes.Equal(buf[:len(os___2012_2)], os___2012_2) || 440 | bytes.Equal(buf[:len(os__2012_r2)], os__2012_r2) { 441 | *szBan = "Windows Server 2012 [R2]" 442 | } else if bytes.Equal(buf[:len(os__Vista_1)], os__Vista_1) { 443 | *szBan = "Windows Vista or later" 444 | } else if bytes.Equal(buf[:len(os_Multiple_1)], os_Multiple_1) || 445 | bytes.Equal(buf[:len(os_Multiple_2)], os_Multiple_2) { 446 | *szBan = "Windows [7/8/10/Server] 2003/2008/2012 [R2] [Standard/Enterprise] [x64] Edition" 447 | } else { 448 | *szBan = printBuf 449 | } 450 | 451 | goto Return 452 | } 453 | 454 | // ssl / tls 455 | if (buf[0] == 0x15 || buf[0] == 0x16) && buf[1] == 0x03 { 456 | // TODO:: 457 | cBit_SSL, err := IntToBytes(rcvSize-5, 2) 458 | if err != nil { 459 | //fmt.Println(err) 460 | dwRecognition = UNKNOWN_PORT 461 | goto Return 462 | } 463 | 464 | if buf[3] == 0x00 || (buf[3] == cBit_SSL[1] && buf[4] == cBit_SSL[0]) { 465 | // 这里仅做服务识别 466 | dwRecognition = SSL_TLS 467 | *szSvcName = "ssl/tls" 468 | *szBan = "--" 469 | goto Return 470 | } 471 | } 472 | 473 | // MSSQL 474 | 475 | if buf[3] == byte(rcvSize) && buf[0] == 0x04 { 476 | *szSvcName = "mssql" 477 | dwRecognition = MSSQL 478 | 479 | // http://blogs.sqlsentry.com/team-posts/latest-builds-sql-server-2016/ 480 | var szSQLVer string 481 | dwMajorVersion := buf[29] 482 | dwMinorVersion := buf[30] 483 | dwBuildNumber := uint16(buf[31])*256 + uint16(buf[32]) 484 | 485 | if dwMajorVersion < 5 || dwMajorVersion > 14 { 486 | dwRecognition = UNKNOWN_SVC // 版本不存在 487 | } 488 | 489 | switch dwMajorVersion { 490 | case 6: 491 | if dwMinorVersion == 50 { 492 | szSQLVer += " 6.5" 493 | } 494 | case 7: 495 | szSQLVer += " 7" 496 | case 8, 80: 497 | szSQLVer += " 2000" 498 | case 9: 499 | szSQLVer += " 2005" 500 | case 10: 501 | szSQLVer += " 2008" 502 | case 11: 503 | szSQLVer += " 2012" 504 | case 12: 505 | szSQLVer += " 2014" 506 | case 13: 507 | szSQLVer += " 2016" 508 | } 509 | 510 | if dwMajorVersion < 6 { 511 | szSQLVer += " [earlier than 6.5]" 512 | } 513 | 514 | if dwMajorVersion == 10 { 515 | if dwMinorVersion == 50 { 516 | szSQLVer += " R2" 517 | } 518 | } 519 | 520 | if dwMajorVersion > 12 { 521 | szSQLVer += " [Later than 2014]" 522 | } 523 | 524 | switch dwMinorVersion { 525 | case 50: 526 | if dwBuildNumber == 2500 { 527 | szSQLVer += " SP1" 528 | } else if dwBuildNumber == 4000 { 529 | szSQLVer += " SP2" 530 | } 531 | case 194: 532 | szSQLVer += " RTM" 533 | //case 384: 534 | // szSQLVer += " SP1" 535 | //case 534: 536 | // szSQLVer += " SP2" 537 | //case 760: 538 | // szSQLVer += " SP3" 539 | case 0: 540 | if dwMajorVersion == 8 && dwBuildNumber == 2039 { 541 | szSQLVer += " SP4" 542 | } else if dwMajorVersion == 9 && dwBuildNumber == 1399 { 543 | szSQLVer += " RTM" 544 | } else if dwMajorVersion == 9 && dwBuildNumber == 2047 { 545 | szSQLVer += " SP1" 546 | } else if dwMajorVersion == 9 && (dwBuildNumber == 3042 || dwBuildNumber == 3073) { 547 | szSQLVer += " SP2" 548 | } else if dwMajorVersion == 9 && dwBuildNumber == 4035 { 549 | szSQLVer += " SP3" 550 | } else if dwMajorVersion == 10 && dwBuildNumber == 1600 { 551 | szSQLVer += " RTM" 552 | } else if dwMajorVersion == 10 && dwBuildNumber == 2531 { 553 | szSQLVer += " SP1" 554 | } else if dwMajorVersion == 10 && dwBuildNumber == 4000 { 555 | szSQLVer += " SP2" 556 | } 557 | } 558 | 559 | szSQLNum := fmt.Sprintf("%d.%d.%d", dwMajorVersion, dwMinorVersion, dwBuildNumber) 560 | *szBan = fmt.Sprintf("MSSQL Server%s %s", szSQLVer, szSQLNum) 561 | 562 | if dwRecognition != UNKNOWN_SVC { 563 | goto Return 564 | } 565 | } 566 | 567 | // Oracle 判断是否允许TNSLSNR 568 | if bytes.Contains(buf, []byte("Y(DESCRIPTION=(TMP=)(VSNNUM=")) || bytes.Contains(buf, []byte(")(ERROR_STACK=(ERROR=(CODE=")) { 569 | // TODO 570 | if n := strings.Index(printBuf, "(VSNNUM="); n != -1 { 571 | buftmp := printBuf[n+8:] 572 | if idx := strings.Index(buftmp, ")(ERR="); idx != -1 { 573 | tmp := buftmp[:idx] 574 | if i, err := strconv.Atoi(tmp); err == nil { 575 | i = i << 4 576 | ver, err := IntToBytes(i, 4) 577 | if err == nil { 578 | h := ver[3] >> 4 579 | l := ver[3] << 4 580 | l = l >> 4 581 | p := ver[1] >> 4 582 | q := ver[0] >> 4 583 | 584 | *szBan = fmt.Sprintf("%d.%d.%d.%d.%d", h, l, ver[2], p, q) 585 | *szSvcName = "oracle" 586 | dwRecognition = ORACLE 587 | 588 | goto Return 589 | } 590 | } 591 | 592 | } 593 | } 594 | } 595 | 596 | if n := strings.Index(printBuf, "TNSLSNR"); n != -1 { 597 | // 允许TNSLSNR查询 598 | // TODO:: 599 | buftmp := printBuf[len(printBuf)-n:] 600 | *szBan = strings.ReplaceAll(buftmp, "\\x0a\\x09", " / ") 601 | *szSvcName = "oracle" 602 | dwRecognition = ORACLE 603 | 604 | goto Return 605 | } 606 | 607 | // Redis 608 | if bytes.Equal(buf[:len("+PONG")], []byte("+PONG")) { 609 | // 可以获取到版本信息 610 | dwRecognition = REDIS 611 | *szSvcName = "redis" 612 | // TODO:: 613 | //*szBan = printBuf 614 | if n := strings.Index(printBuf, "redis_version:"); n != -1 { 615 | buftmp := printBuf[len(printBuf)-n-14:] 616 | if idx := strings.Index(buftmp, "\\x0d\\x0a"); idx != -1 { 617 | bleft := buftmp[:idx] 618 | *szBan = bleft 619 | } else { 620 | *szBan = printBuf 621 | } 622 | 623 | } else { 624 | *szBan = printBuf 625 | } 626 | 627 | goto Return 628 | } 629 | 630 | if bytes.Contains(buf, []byte("-NOAUTH Authentication required")) || 631 | bytes.Contains(buf, []byte("-ERR operation not permitted")) || 632 | bytes.Contains(buf, []byte("-ERR wrong number of arguments for '")) || 633 | bytes.Contains(buf, []byte("-ERR unknown command '")) || 634 | bytes.Contains(buf, []byte("-ERR unknown command `")) { 635 | dwRecognition = REDIS_AUTH 636 | *szSvcName = "redis" 637 | *szBan = "NOAUTH, Authentication required" 638 | 639 | goto Return 640 | } 641 | 642 | if bytes.Contains(buf, []byte("-DENIED Redis is running in protected mode because protected mode is enabled")) { 643 | *szSvcName = "redis" 644 | *szBan = "DENIED, Redis is running in protected mode" 645 | dwRecognition = REDIS_DENIED 646 | 647 | goto Return 648 | } 649 | 650 | // vpn-pptp 651 | if uint8(rcvSize) == buf[1] && bytes.Equal(buf[4:8], MagicCookie) { 652 | *szSvcName = "vpn-pptp" 653 | dwRecognition = VPN_PPTP 654 | 655 | szHostName := buf[28:92] 656 | szVendorName := buf[92:156] 657 | 658 | *szBan = fmt.Sprintf("%s|%s", szHostName, szVendorName) 659 | 660 | goto Return 661 | } 662 | 663 | // RSYNC 664 | if bytes.EqualFold(buf[:9], []byte("@RSYNCD: ")) { 665 | //csbuf := fmt.Sprintf("%s", buf) 666 | //csbuf = strings.ReplaceAll(csbuf, "\r", "\\x0d") 667 | //csbuf = strings.ReplaceAll(csbuf, "\n", "\\x0a") 668 | 669 | *szBan = printBuf 670 | dwRecognition = RSYNC 671 | *szSvcName = "rsync" 672 | 673 | goto Return 674 | } 675 | 676 | // PCANYWHERE 677 | if bytes.Equal(buf[:3], PcAnyWhereMark_Low) { 678 | *szSvcName = "pcanywhere" 679 | dwRecognition = PCANYWHERE 680 | 681 | goto Return 682 | } 683 | 684 | if bytes.Equal(buf[:3], PcAnyWhereMark_High) { 685 | *szSvcName = "pcanywhere" 686 | dwRecognition = PCANYWHERE 687 | *szBan = "高版本" 688 | 689 | goto Return 690 | } 691 | 692 | // memcached 693 | if bytes.Equal(buf[:len("STAT pid ")], []byte("STAT pid ")) { 694 | *szSvcName = "memcached" 695 | dwRecognition = MEMCACHED 696 | // TODO: 获取版本号 697 | if n := strings.Index(printBuf, "STAT version "); n != -1 { 698 | buftmp := printBuf[len(printBuf)-n-13:] 699 | if idx := strings.Index(buftmp, "\\x0d\\x0a"); n != -1 { 700 | *szBan = buftmp[:idx] 701 | goto Return 702 | } 703 | } 704 | *szBan = "Memcached" 705 | 706 | goto Return 707 | } 708 | 709 | if bytes.Index(buf, []byte("SERVER_ERROR unauthorized, null bucket")) == 0 { 710 | *szSvcName = "memcached" 711 | dwRecognition = MEMCACHED 712 | *szBan = "SERVER_ERROR unauthorized" 713 | 714 | goto Return 715 | } 716 | 717 | // Mongodb TODO:: 718 | //fmt.Println(cBit_MongoDB) 719 | cBit_MongoDB, _ = IntToBytes(rcvSize, 4) 720 | if bytes.Equal(buf[:4], cBit_MongoDB) && bytes.Equal(buf[8:12], cFlag_MongoDB) { 721 | if bytes.Contains(buf, []byte("host")) && bytes.Contains(buf, []byte("version")) && 722 | bytes.Contains(buf, []byte("uptime")) && bytes.Contains(buf, []byte("ok")) { 723 | *szSvcName = "mongodb" 724 | dwRecognition = MONGODB 725 | 726 | var szVer, szHost string 727 | 728 | if k := bytes.Index(buf, []byte("version")); k != -1 { 729 | szVer = fmt.Sprintf("%s", buf[k+len("version")+1+4:k+len("version")+1+4+6]) 730 | } 731 | 732 | if n := bytes.Index(buf, []byte("host")); n != -1 { 733 | szHost = fmt.Sprintf("%s", buf[n+len("host")+1+4:n+len("host")+1+4+6]) 734 | } 735 | 736 | *szBan = fmt.Sprintf("%s|%s", szVer, szHost) 737 | } else if bytes.Contains(buf, []byte("errmsg")) { 738 | dwRecognition = MONGODB_AUTH 739 | *szSvcName = "mongodb" 740 | *szBan = "unauthorized" 741 | } 742 | 743 | if dwRecognition != UNKNOWN_SVC { 744 | goto Return 745 | } 746 | } 747 | 748 | // LDAP 749 | if bytes.Contains(buf, szFlag_LDAP) { 750 | *szSvcName = "ldap" 751 | dwRecognition = LDAP 752 | 753 | goto Return 754 | } 755 | 756 | // SIP 757 | if bytes.EqualFold(buf[:4], []byte("SIP/")) { 758 | *szSvcName = "sip" 759 | dwRecognition = SIP 760 | 761 | // TODO 获取szBan 762 | mark := "\\x0d\\x0aServer:" 763 | n := strings.Index(printBuf, "\\x0d\\x0aServer:") 764 | if n == -1 { 765 | mark = "\\x0d\\x0aUser-Agent:" 766 | n = strings.Index(printBuf, "\\x0d\\x0aUser-Agent:") 767 | } 768 | 769 | if n != -1 { 770 | buftmp := printBuf[len(printBuf)-n-len(mark):] 771 | if idx := strings.Index(buftmp, "\\x0d\\x0a"); idx != -1 { 772 | *szBan = buftmp[:idx] 773 | goto Return 774 | } 775 | } 776 | 777 | *szBan = printBuf 778 | 779 | goto Return 780 | } 781 | 782 | // RAdmin 783 | if bytes.Equal(buf[:4], szFlag_RADMIN) && (buf[4] == 0x25 || buf[4] == 0x09) { 784 | *szSvcName = "radmin" 785 | dwRecognition = RADMIN 786 | *szBan = printBuf 787 | 788 | goto Return 789 | } 790 | 791 | // POSTGRESQL 792 | if buf[0] == 0x45 && buf[4] == byte(rcvSize-1) && 793 | (bytes.Contains(buf, []byte("FATAL")) || bytes.Contains(buf, []byte("Fpostmaster.c"))) { 794 | *szSvcName = "postgresql" 795 | dwRecognition = POSTGRESQL 796 | 797 | goto Return 798 | } 799 | 800 | if buf[0] == 0x52 && (buf[4] == byte(rcvSize-1) || bytes.Contains(buf, []byte("server_version\x00")) || 801 | bytes.EqualFold(buf[:len("R\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x00")], []byte("R\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x00"))) { 802 | *szSvcName = "postgresql" 803 | dwRecognition = POSTGRESQL 804 | 805 | goto Return 806 | } 807 | 808 | // NETBIOS(445) 809 | if buf[0] == 0 && buf[3] == byte(rcvSize-4) && buf[5] == 0x53 && buf[6] == 0x4d && buf[7] == 0x42 { 810 | *szSvcName = "microsoft-ds" 811 | dwRecognition = MICROSOFT_DS 812 | 813 | //iLen := 4 + 32 + 45 814 | //szDomainName := buf[iLen:rcvSize] 815 | //szHostName := buf[iLen+(len(szDomainName)+1)*2:rcvSize] 816 | 817 | // TODO:: 818 | *szBan = printBuf 819 | 820 | goto Return 821 | } 822 | 823 | // msrcp(135) 824 | if buf[0] == 0x05 && buf[8] == byte(rcvSize) { 825 | *szSvcName = "msrcp" 826 | dwRecognition = DECRPC 827 | 828 | if !bytes.EqualFold(buf, []byte("\\x05\\x00\\x0d\\x03\\x10\\x00\\x00\\x00\\x18\\x00\\x00\\x00\\x00\\x08\\x01@\\x04\\x00\\x01\\x05\\x00\\x00\\x00\\x00")) { 829 | *szBan = printBuf 830 | } 831 | 832 | goto Return 833 | } 834 | 835 | // netbios-ssn 139 836 | if buf[0] == 0x83 && buf[1] == 0x00 && buf[4] == 0x8f { 837 | *szSvcName = "netbios-ssn" 838 | dwRecognition = NETBIOS_SSN 839 | 840 | goto Return 841 | } 842 | 843 | // MMS (Microsoft Media Server Protocol) 844 | if rcvSize > 15 && buf[12] == 0x4d && buf[13] == 0x4d && buf[14] == 0x53 && buf[15] == 0x20 { 845 | *szSvcName = "mms" 846 | dwRecognition = MMS 847 | 848 | goto Return 849 | } 850 | 851 | // SVRLOC 852 | if bytes.Contains(buf, []byte("service:service-agent://")) || 853 | (buf[0] == 0x02 && buf[1] == 0x0b && buf[13] == 0x02 && buf[14] == 0x65 && buf[15] == 0x6e) { 854 | *szSvcName = "svrloc" 855 | dwRecognition = SVRLOC 856 | 857 | goto Return 858 | } 859 | 860 | // AJP13 861 | if strings.EqualFold(printBuf, "AB\\x00\\x01\\x09") { 862 | *szSvcName = "ajp13" 863 | dwRecognition = AJP13 864 | *szBan = "Apache Jserv (Protocol v1.3)" 865 | 866 | goto Return 867 | } 868 | 869 | //fmt.Println(rcvSize) 870 | if strings.EqualFold(printBuf, "AB\\x00") { 871 | *szSvcName = "ajp13" 872 | dwRecognition = AJP13 873 | *szBan = "Apache Jserv" 874 | 875 | goto Return 876 | } 877 | 878 | // nfs TODO:: 879 | if strings.Index(printBuf, "\\x80\\x00\\x00") == 0 && 880 | strings.Contains(printBuf, "\\x10l\\x8e") { 881 | *szSvcName = "nfs" 882 | dwRecognition = NFS 883 | 884 | goto Return 885 | } 886 | 887 | // lotusnotes (1352) TODO:: 888 | if strings.Index(printBuf, "\\x84\\x00\\x00\\x00") == 0 { 889 | *szSvcName = "lotusnotes" 890 | dwRecognition = LOTUSNOTES 891 | 892 | goto Return 893 | } 894 | 895 | // TELNET 896 | if bytes.Contains(buf, []byte("ogin:")) || bytes.Contains(buf, []byte("ccount:")) || 897 | bytes.Contains(buf, []byte("ser:")) || bytes.Contains(buf, []byte("ame:")) || 898 | bytes.Contains(buf, []byte("assword:")) || bytes.Contains(buf, []byte("telnet")) || 899 | bytes.Contains(buf, []byte("System administrator")) || bytes.Contains(buf, []byte("%connection closed by remote host!")) || 900 | bytes.Contains(buf, []byte("not allowed now, you may try")) || bytes.Contains(buf, []byte("All user interfaces are used, please try later")) || 901 | (buf[0] == 0xff && buf[1] == 0xfd) || (buf[0] == 0xff && buf[1] == 0xfb) { 902 | dwRecognition = TELNET 903 | *szSvcName = "telnet" 904 | *szBan = printBuf 905 | 906 | goto Return 907 | } 908 | 909 | // subversion 910 | if rcvSize > 5 && bytes.Equal(buf[:len("( success ( ")], []byte("( success ( ")) { 911 | dwRecognition = SVNSERVE 912 | *szSvcName = "svn" 913 | 914 | goto Return 915 | } 916 | 917 | // elasticsearch 918 | if strings.EqualFold(printBuf, "This is not a HTTP port") { 919 | *szSvcName = "elasticsearch" 920 | dwRecognition = ELASTICSEARCH 921 | *szBan = "Elasticsearch binary API" 922 | 923 | goto Return 924 | } 925 | 926 | // bgp 927 | if strings.Index(printBuf, "\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff") == 0 { 928 | *szSvcName = "bgp" 929 | dwRecognition = UNKNOWN_SVC 930 | 931 | goto Return 932 | } 933 | 934 | // ldp 935 | if strings.Index(printBuf, "\\x00\\x01\\x00\\x1c\\x00\\x00\\x00\\x00\\x00\\x00") == 0 { 936 | *szSvcName = "ldp" 937 | dwRecognition = UNKNOWN_SVC 938 | 939 | goto Return 940 | } 941 | 942 | // xmpp 943 | if strings.EqualFold(printBuf, "") { 944 | *szSvcName = "xmpp" 945 | dwRecognition = UNKNOWN_SVC 946 | *szBan = printBuf 947 | 948 | goto Return 949 | } 950 | 951 | // Hikvision IPCam control port 952 | if strings.Index(printBuf, "\\x00\\x00\\x00\\x10\\x00\\x00\\x00") == 0 { 953 | dwRecognition = UNKNOWN_SVC 954 | *szSvcName = "ipcam" 955 | *szBan = printBuf 956 | 957 | goto Return 958 | } 959 | 960 | // shoutcast 961 | if strings.EqualFold(printBuf, "invalid password\\x0d\\x0a") { 962 | dwRecognition = UNKNOWN_SVC 963 | *szSvcName = "shoutcast" 964 | *szBan = "SHOUTcast server" 965 | 966 | goto Return 967 | } 968 | 969 | // zebra 970 | if strings.EqualFold(printBuf, "Vty password is not set.\\x0d\\x0a") { 971 | dwRecognition = UNKNOWN_SVC 972 | *szSvcName = "zebra" 973 | *szBan = "Quagga routing software" 974 | 975 | goto Return 976 | } 977 | 978 | // 判断是HTTP或者HTTPS, 979 | // if bytes.Contains(bufUp, []byte("You're speaking plain HTTP to an SSL-enabled server port")) { 980 | // dwRecognition = SSL_TLS 981 | // *szSvcName = "ssl" 982 | 983 | // // HTTP/HTTPS 打印100个字符就够了,不然整个网页太长 984 | // *szBan = printBuf[:100] 985 | // goto Return 986 | // } 987 | 988 | // 未知服务,返回数据修改成16进制保存(数据包大于0) 989 | if rcvSize > 0 { 990 | dwRecognition = UNKNOWN_SVC 991 | *szSvcName = "unknown" 992 | *szBan = printBuf 993 | //*szBan = string(buf) 994 | } 995 | 996 | Return: 997 | return dwRecognition 998 | } 999 | 1000 | // 整形向字符切片转换 1001 | func IntToBytes(n int, b byte) ([]byte, error) { 1002 | switch b { 1003 | case 1: 1004 | tmp := int8(n) 1005 | bytesBuffer := bytes.NewBuffer([]byte{}) 1006 | err := binary.Write(bytesBuffer, binary.BigEndian, &tmp) 1007 | return bytesBuffer.Bytes(), err 1008 | case 2: 1009 | tmp := int16(n) 1010 | bytesBuffer := bytes.NewBuffer([]byte{}) 1011 | //err := binary.Write(bytesBuffer, binary.BigEndian, &tmp) 1012 | err := binary.Write(bytesBuffer, binary.LittleEndian, &tmp) 1013 | return bytesBuffer.Bytes(), err 1014 | case 3, 4: 1015 | tmp := int32(n) 1016 | bytesBuffer := bytes.NewBuffer([]byte{}) 1017 | //err := binary.Write(bytesBuffer, binary.BigEndian, &tmp) 1018 | err := binary.Write(bytesBuffer, binary.LittleEndian, &tmp) 1019 | return bytesBuffer.Bytes(), err 1020 | } 1021 | return nil, fmt.Errorf("IntToBytes b param is invaild") 1022 | } 1023 | 1024 | //func bytesToUint16(buf []byte) uint16 { 1025 | // return binary.LittleEndian.Uint16(buf) 1026 | //} 1027 | --------------------------------------------------------------------------------