├── 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 | 
10 |
11 | ```
12 | 新增加彩色文字输出格式 对http/https协议进行title以及报文长度打印,获取title失败打印报文前20字节
13 | ```
14 |
15 | 
16 |
17 | ```
18 | 新增日志文件以及扫描结果文件
19 | ```
20 |
21 | 
22 |
23 | ```
24 | TxPortMap 会直接扫描top100 加上t1000参数会扫描top1000 可以通过-p 指定端口,分号指定多个
25 | ```
26 |
27 | 
28 |
29 | 
30 |
31 |
32 |
33 | # 项目说明
34 | 在渗透测试的端口扫描阶段,相信很多人遇到的问题是nmap太慢,masscan不准确。
35 | 本项目为天象渗透测试平台后端使用的端口扫描和指纹识别模块,采用Golang编写,以期在速度与准确度之间寻找一个平衡。
36 | 开源后希望大家可以一起完善指纹和提交优化建议。
37 |
38 | TxPortMap时间:20.171秒
39 |
40 | nmap 2分51.89秒
41 |
42 | 
43 |
44 | 
45 |
46 |
47 | 本项目 暂不进行更新 新项目为黑客语言yak开发 具有更多黑客功能 可移步官网 https://www.yaklang.io/
48 | 并用yak语言实现有国产burp suite替代工具 yakit 单兵平台 https://github.com/yaklang/yakit
49 |
50 | 交流群
51 |
52 | 
53 |
54 | 群满可加微信
55 |
56 | 
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, "")
38 | return title[titleBegin+1 : titleEnd]
39 | }
40 |
41 | func ExtractFinger(body string, r *http.Response) (string) {
42 | var fingers []string
43 |
44 | if r.Header.Get("Set-Cookie") != "" && strings.Contains(r.Header.Get("Set-Cookie"), "rememberMe=deleteMe") {
45 | fingers = append(fingers, "Shiro!!")
46 | }
47 | if body != "" {
48 | if strings.Contains(body, "servletContextInitParams") {
49 | fingers = append(fingers, "Spring env!!")
50 | } else if strings.Contains(body, "logback") {
51 | fingers = append(fingers, "Spring env!!")
52 | } else if strings.Contains(body, "Error 404--Not Found") || strings.Contains(body, "Error 403--") {
53 | fingers = append(fingers, "Weblogic!!")
54 | } else if strings.Contains(body, "/por/login_psw.csp") {
55 | fingers = append(fingers, "Sangfor SSL VPN!!")
56 | } else if strings.Contains(body, "weaver,e-mobile") {
57 | fingers = append(fingers, "e-mobile!!")
58 | } else if strings.Contains(body, "ecology") {
59 | fingers = append(fingers, "ecology!!")
60 | } else if strings.Contains(body, "e-Bridge") || strings.Contains(body, "wx.weaver") {
61 | fingers = append(fingers, "e-Bridge!!")
62 | } else if strings.Contains(body, "Swagger UI") {
63 | fingers = append(fingers, "Swagger UI!!")
64 | } else if strings.Contains(body, "4008 111 000") {
65 | fingers = append(fingers, "Ruijie")
66 | } else if strings.Contains(body, "Script/SmcScript.js?version=") {
67 | fingers = append(fingers, "Huawei SMC")
68 | } else if strings.Contains(body, "/wnm/ssl/web/frame/login.html") {
69 | fingers = append(fingers, "H3C Router")
70 | } else if strings.Contains(body, "/+CSCOE+/logon.html") {
71 | fingers = append(fingers, "Cisco SSLVPN!!")
72 | } else if strings.Contains(body, "Huawei") || strings.Contains(body, "huawei") || strings.Contains(body, "Hicloud") || strings.Contains(body, "hicloud") || strings.Contains(body, "Vmall") || strings.Contains(body, "vmall") {
73 | fingers = append(fingers, "Huawei!!")
74 | } else if strings.Contains(body, "../zentao/theme/zui/css/min.css") {
75 | fingers = append(fingers, "Zentao!!")
76 | } else if strings.Contains(body, "UI_component/commonDefine/UI_regex_define.js") {
77 | fingers = append(fingers, "Huawei Firewall")
78 | } else if strings.Contains(body, "CDGServer3") {
79 | fingers = append(fingers, "亿赛通电子文档!!")
80 | } else if strings.Contains(body, "/zcms/") || strings.Contains(body, "App=ZCMS(ZCMS内容管理系统)") {
81 | fingers = append(fingers, "ZCMS!!")
82 | } else if strings.Contains(body, "3F367B74-92D9-4C5E-AB93-234F8A91D5E6") {
83 | fingers = append(fingers, "云匣子!!")
84 | } else if strings.Contains(body, "\x2Findex.zul") {
85 | fingers = append(fingers, "Old 云匣子!!")
86 | } else if strings.Contains(body, "gHasSecureMail") {
87 | fingers = append(fingers, "亿邮!!")
88 | } else if strings.Contains(body, "any_rsa_pas") || strings.Contains(body, "https://sec.anymacro.com") {
89 | fingers = append(fingers, "Anymail!!")
90 | } else if strings.Contains(body, "action=\"/coremail/index.jsp?cus=1\"") || strings.Contains(body, "/coremail/common/") {
91 | fingers = append(fingers, "Coremail!!")
92 | } else if strings.Contains(body, "\"/r/cms/") {
93 | fingers = append(fingers, "JEECMS!!")
94 | } else if strings.Contains(body, "CN/volumn/") {
95 | fingers = append(fingers, "网刊系统!!")
96 | } else if strings.Contains(body, "journalx") {
97 | fingers = append(fingers, "玛格泰克JournalX!!")
98 | } else if strings.Contains(body, "href=\"/seeyon/skin/dist") || strings.Contains(body, "/seeyon/main.do") {
99 | fingers = append(fingers, "致远OA!!")
100 | } else if strings.Contains(body, "StylePath:\"/resource/style") {
101 | fingers = append(fingers, "蓝凌ekp!!")
102 | } else if strings.Contains(body, "Office Anywhere") || strings.Contains(body, "general/login_code.php") {
103 | fingers = append(fingers, "通达OA!!")
104 | } else if strings.Contains(body, "webmail/se/account/download.do") || strings.Contains(body, "url=/webmail/\"") {
105 | fingers = append(fingers, "Easysite!!")
106 | } else if strings.Contains(body, "Zabbix SIA") {
107 | fingers = append(fingers, "Zabbix!!")
108 | } else if strings.Contains(body, "Powered by Discuz!") || strings.Contains(body, "content=\"Discuz!") {
109 | fingers = append(fingers, "Discuz!!")
110 | }
111 | }
112 |
113 | return strings.Join(fingers,"|")
114 | }
115 |
--------------------------------------------------------------------------------
/pkg/Ginfo/Ghttp/Ghttp.go:
--------------------------------------------------------------------------------
1 | package Ghttp
2 |
3 | import (
4 | "bytes"
5 | "crypto/tls"
6 | "crypto/x509"
7 | "encoding/json"
8 | "errors"
9 | "fmt"
10 | "github.com/4dogs-cn/TXPortMap/pkg/conversion"
11 | "io/ioutil"
12 | "net"
13 | "net/http"
14 | "net/url"
15 | "strconv"
16 | "strings"
17 | "time"
18 | )
19 |
20 | const (
21 | // HTTP defines the plain http scheme
22 | HTTP = "http"
23 | // HTTPS defines the secure http scheme
24 | HTTPS = "https"
25 | // HTTPorHTTPS defines the both http and https scheme
26 | HTTPorHTTPS = "http|https"
27 | )
28 |
29 | type ScanOptions struct {
30 | Methods []string
31 | StoreResponseDirectory string
32 | RequestURI string
33 | RequestBody string
34 | VHost bool
35 | OutputTitle bool
36 | OutputStatusCode bool
37 | OutputLocation bool
38 | OutputContentLength bool
39 | StoreResponse bool
40 | OutputServerHeader bool
41 | OutputWebSocket bool
42 | OutputWithNoColor bool
43 | OutputMethod bool
44 | ResponseInStdout bool
45 | TLSProbe bool
46 | CSPProbe bool
47 | OutputContentType bool
48 | Unsafe bool
49 | Pipeline bool
50 | HTTP2Probe bool
51 | OutputIP bool
52 | OutputCName bool
53 | OutputCDN bool
54 | OutputResponseTime bool
55 | PreferHTTPS bool
56 | NoFallback bool
57 | }
58 |
59 | func Analyze(protocol, domain string, port int, method string, scanopts *ScanOptions) Result {
60 | origProtocol := protocol
61 | if protocol == "http" {
62 | protocol = HTTP
63 | } else {
64 | protocol = HTTPS
65 | }
66 | retried := false
67 | retry:
68 | URL := fmt.Sprintf("%s://%s", protocol, domain)
69 | if port > 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 |
--------------------------------------------------------------------------------