github.com/chainreactors/fingers@v1.2.1/common/framework.go (about)

     1  package common
     2  
     3  import (
     4  	"github.com/chainreactors/utils/iutils"
     5  	"strings"
     6  )
     7  
     8  // 指纹类型定义
     9  type FingerprintType int
    10  
    11  const (
    12  	WebFingerprint     FingerprintType = iota // Web应用指纹
    13  	ServiceFingerprint                        // 服务指纹
    14  )
    15  
    16  // 引擎能力定义
    17  type EngineCapability struct {
    18  	SupportWeb     bool // 支持Web指纹
    19  	SupportService bool // 支持Service指纹
    20  }
    21  
    22  // Service指纹检测结果
    23  type ServiceResult struct {
    24  	Framework *Framework
    25  	Vuln      *Vuln // 可选,只有部分引擎(如fingers)会返回漏洞信息
    26  }
    27  
    28  var NoGuess bool
    29  
    30  type From int
    31  
    32  const (
    33  	FrameFromDefault From = iota
    34  	FrameFromACTIVE
    35  	FrameFromICO
    36  	FrameFromNOTFOUND
    37  	FrameFromGUESS
    38  	FrameFromRedirect
    39  	FrameFromFingers
    40  	FrameFromFingerprintHub
    41  	FrameFromWappalyzer
    42  	FrameFromEhole
    43  	FrameFromGoby
    44  	FrameFromNmap
    45  )
    46  
    47  func (f From) String() string {
    48  	return FrameFromMap[f]
    49  }
    50  
    51  var FrameFromMap = map[From]string{
    52  	FrameFromDefault:        "default",
    53  	FrameFromACTIVE:         "active",
    54  	FrameFromICO:            "ico",
    55  	FrameFromNOTFOUND:       "404",
    56  	FrameFromGUESS:          "guess",
    57  	FrameFromRedirect:       "redirect",
    58  	FrameFromFingers:        "fingers",
    59  	FrameFromFingerprintHub: "fingerprinthub",
    60  	FrameFromWappalyzer:     "wappalyzer",
    61  	FrameFromEhole:          "ehole",
    62  	FrameFromGoby:           "goby",
    63  	FrameFromNmap:           "nmap",
    64  }
    65  
    66  func GetFrameFrom(s string) From {
    67  	switch s {
    68  	case "active":
    69  		return FrameFromACTIVE
    70  	case "404":
    71  		return FrameFromNOTFOUND
    72  	case "ico":
    73  		return FrameFromICO
    74  	case "guess":
    75  		return FrameFromGUESS
    76  	case "redirect":
    77  		return FrameFromRedirect
    78  	case "fingerprinthub", "fingerprinthub_v4": // fingerprinthub_v4 保留用于向后兼容
    79  		return FrameFromFingerprintHub
    80  	case "wappalyzer":
    81  		return FrameFromWappalyzer
    82  	case "ehole":
    83  		return FrameFromEhole
    84  	case "goby":
    85  		return FrameFromGoby
    86  	case "fingers":
    87  		return FrameFromFingers
    88  	case "nmap":
    89  		return FrameFromNmap
    90  
    91  	default:
    92  		return FrameFromDefault
    93  	}
    94  }
    95  
    96  func NewFramework(name string, from From) *Framework {
    97  	frame := &Framework{
    98  		Name:       name,
    99  		From:       from,
   100  		Froms:      map[From]bool{from: true},
   101  		Tags:       make([]string, 0),
   102  		Attributes: NewAttributesWithAny(),
   103  	}
   104  	frame.Attributes.Product = name
   105  	frame.Attributes.Part = "a"
   106  	if from >= FrameFromFingers {
   107  		frame.AddTag(from.String())
   108  	}
   109  	return frame
   110  }
   111  
   112  func NewFrameworkWithVersion(name string, from From, version string) *Framework {
   113  	frame := NewFramework(name, from)
   114  	frame.Attributes.Version = version
   115  	//frame.Version = version
   116  	return frame
   117  }
   118  
   119  type Framework struct {
   120  	Name        string        `json:"name"`
   121  	From        From          `json:"-"` // 指纹可能会有多个来源, 指纹合并时会将多个来源记录到froms中
   122  	Froms       map[From]bool `json:"froms,omitempty"`
   123  	Tags        []string      `json:"tags,omitempty"`
   124  	IsFocus     bool          `json:"is_focus,omitempty"`
   125  	MatchDetail *MatchDetail  `json:"matcher,omitempty"`
   126  	*Attributes `json:"attributes,omitempty"`
   127  }
   128  
   129  // MatchDetail describes which rule and matcher produced a hit.
   130  type MatchDetail struct {
   131  	RuleIndex    int    `json:"rule_index,omitempty"`
   132  	MatcherType  string `json:"matcher_type,omitempty"`
   133  	MatcherIndex int    `json:"matcher_index,omitempty"`
   134  	MatcherValue string `json:"matcher_value,omitempty"`
   135  	SendData     string `json:"send_data,omitempty"`
   136  }
   137  
   138  func (f *Framework) String() string {
   139  	var s strings.Builder
   140  	if f.IsFocus {
   141  		s.WriteString("focus:")
   142  	}
   143  	s.WriteString(f.Name)
   144  
   145  	if f.Version != "" {
   146  		s.WriteString(":" + strings.Replace(f.Version, ":", "_", -1))
   147  	}
   148  
   149  	if len(f.Froms) > 1 {
   150  		s.WriteString(":(")
   151  		var froms []string
   152  		for from, _ := range f.Froms {
   153  			froms = append(froms, FrameFromMap[from])
   154  		}
   155  		s.WriteString(strings.Join(froms, " "))
   156  		s.WriteString(")")
   157  	} else {
   158  		for from, _ := range f.Froms {
   159  			if from != FrameFromFingers {
   160  				s.WriteString(":")
   161  				s.WriteString(FrameFromMap[from])
   162  			}
   163  		}
   164  	}
   165  	return strings.TrimSpace(s.String())
   166  }
   167  
   168  func (f *Framework) UpdateAttributes(attrs *Attributes) {
   169  	if f.Version != "" {
   170  		attrs.Version = f.Version
   171  	}
   172  	f.Attributes = attrs
   173  }
   174  
   175  func (f *Framework) CPE() string {
   176  	return f.Attributes.String()
   177  }
   178  
   179  func (f *Framework) URI() string {
   180  	return f.Attributes.URI()
   181  }
   182  
   183  func (f *Framework) WFN() string {
   184  	return f.Attributes.WFNString()
   185  }
   186  
   187  func (f *Framework) IsGuess() bool {
   188  	var is bool
   189  	for from, _ := range f.Froms {
   190  		if from == FrameFromGUESS {
   191  			is = true
   192  		} else {
   193  			return false
   194  		}
   195  	}
   196  	return is
   197  }
   198  
   199  func (f *Framework) AddTag(tag string) {
   200  	if !f.HasTag(tag) {
   201  		f.Tags = append(f.Tags, tag)
   202  	}
   203  }
   204  
   205  func (f *Framework) HasTag(tag string) bool {
   206  	for _, t := range f.Tags {
   207  		if t == tag {
   208  			return true
   209  		}
   210  	}
   211  	return false
   212  }
   213  
   214  type Frameworks map[string]*Framework
   215  
   216  func (fs Frameworks) One() *Framework {
   217  	for _, f := range fs {
   218  		return f
   219  	}
   220  	return nil
   221  }
   222  
   223  func (fs Frameworks) List() []*Framework {
   224  	var frameworks []*Framework
   225  	for _, f := range fs {
   226  		frameworks = append(frameworks, f)
   227  	}
   228  	return frameworks
   229  }
   230  
   231  func (fs Frameworks) Add(other *Framework) bool {
   232  	if other == nil {
   233  		return false
   234  	}
   235  	other.Name = strings.ToLower(other.Name)
   236  	if frame, ok := fs[other.Name]; ok {
   237  		for from, _ := range other.Froms {
   238  			frame.Froms[from] = true
   239  		}
   240  		frame.Tags = iutils.StringsUnique(append(frame.Tags, other.Tags...))
   241  		frame.UpdateAttributes(other.Attributes)
   242  		return false
   243  	} else {
   244  		fs[other.Name] = other
   245  		return true
   246  	}
   247  }
   248  
   249  func (fs Frameworks) Merge(other Frameworks) int {
   250  	// name, tag 统一小写, 减少指纹库之间的差异
   251  	var n int
   252  	for _, f := range other {
   253  		f.Name = strings.ToLower(f.Name)
   254  		if fs.Add(f) {
   255  			n += 1
   256  		}
   257  	}
   258  	return n
   259  }
   260  
   261  func (fs Frameworks) String() string {
   262  	if fs == nil {
   263  		return ""
   264  	}
   265  	frameworkStrs := make([]string, len(fs))
   266  	i := 0
   267  	for _, f := range fs {
   268  		if NoGuess && f.IsGuess() {
   269  			continue
   270  		}
   271  		frameworkStrs[i] = f.String()
   272  		i++
   273  	}
   274  	return strings.Join(frameworkStrs, "||")
   275  }
   276  
   277  func (fs Frameworks) GetNames() []string {
   278  	if fs == nil {
   279  		return nil
   280  	}
   281  	var titles []string
   282  	for _, f := range fs {
   283  		if !f.IsGuess() {
   284  			titles = append(titles, f.Name)
   285  		}
   286  	}
   287  	return titles
   288  }
   289  
   290  func (fs Frameworks) URI() []string {
   291  	if fs == nil {
   292  		return nil
   293  	}
   294  	var uris []string
   295  	for _, f := range fs {
   296  		uris = append(uris, f.URI())
   297  	}
   298  	return uris
   299  }
   300  
   301  func (fs Frameworks) CPE() []string {
   302  	if fs == nil {
   303  		return nil
   304  	}
   305  	var cpes []string
   306  	for _, f := range fs {
   307  		cpes = append(cpes, f.CPE())
   308  	}
   309  	return cpes
   310  }
   311  
   312  func (fs Frameworks) WFN() []string {
   313  	if fs == nil {
   314  		return nil
   315  	}
   316  	var wfns []string
   317  	for _, f := range fs {
   318  		wfns = append(wfns, f.WFN())
   319  	}
   320  	return wfns
   321  }
   322  
   323  func (fs Frameworks) IsFocus() bool {
   324  	if fs == nil {
   325  		return false
   326  	}
   327  	for _, f := range fs {
   328  		if f.IsFocus {
   329  			return true
   330  		}
   331  	}
   332  	return false
   333  }
   334  
   335  func (fs Frameworks) HasTag(tag string) bool {
   336  	for _, f := range fs {
   337  		if f.HasTag(tag) {
   338  			return true
   339  		}
   340  	}
   341  	return false
   342  }
   343  
   344  func (fs Frameworks) HasFrom(from string) bool {
   345  	for _, f := range fs {
   346  		if f.Froms[GetFrameFrom(from)] {
   347  			return true
   348  		}
   349  	}
   350  	return false
   351  }