dddd/lib/ddfinger/parse.go

615 lines
15 KiB
Go
Raw Normal View History

2023-08-18 08:55:46 +02:00
package ddfinger
import (
"container/list"
2024-04-03 06:32:26 +02:00
"dddd/ddout"
2023-08-18 08:55:46 +02:00
"dddd/structs"
"dddd/utils"
"fmt"
"github.com/projectdiscovery/gologger"
"net/url"
"regexp"
2024-04-03 06:32:26 +02:00
"runtime"
2023-08-18 08:55:46 +02:00
"strconv"
"strings"
"sync"
)
// 判断优先级 非运算符返回0
func advance(ch int) int {
// !
if ch == 33 {
return 3
}
// &
if ch == 38 {
return 2
}
// |
if ch == 124 {
return 1
}
return 0
}
// 计算纯bool表达式支持 ! && & || | ( )
func boolEval(expression string) bool {
2024-04-27 18:55:20 +02:00
// 左右括号数量相等
2023-08-18 08:55:46 +02:00
if strings.Count(expression, "(") != strings.Count(expression, ")") {
gologger.Fatal().Msg(fmt.Sprintf("[-] 纯布尔表达式 [%s] 左右括号不匹配", expression))
}
// 去除空格
for strings.Contains(expression, " ") {
expression = strings.ReplaceAll(expression, " ", "")
}
// 去除空表达式
for strings.Contains(expression, "()") {
expression = strings.ReplaceAll(expression, "()", "")
}
for strings.Contains(expression, "&&") {
expression = strings.ReplaceAll(expression, "&&", "&")
}
for strings.Contains(expression, "||") {
expression = strings.ReplaceAll(expression, "||", "|")
}
if !strings.Contains(expression, "T") && !strings.Contains(expression, "F") {
return false
// panic("纯布尔表达式错误没有包含T/F")
}
expr := list.New()
operator_stack := list.New()
for _, ch := range expression {
// ch 为 T或者F
if ch == 84 || ch == 70 {
expr.PushBack(int(ch))
} else if advance(int(ch)) > 0 {
if operator_stack.Len() == 0 {
operator_stack.PushBack(int(ch))
continue
}
// 两个!抵消
if ch == 33 && operator_stack.Back().Value.(int) == 33 {
operator_stack.Remove(operator_stack.Back())
continue
}
for operator_stack.Len() != 0 && operator_stack.Back().Value.(int) != 40 && advance(operator_stack.Back().Value.(int)) >= advance(int(ch)) {
e := operator_stack.Back()
expr.PushBack(e.Value.(int))
operator_stack.Remove(e)
}
operator_stack.PushBack(int(ch))
} else if ch == 40 {
operator_stack.PushBack(int(ch))
2024-04-27 18:55:20 +02:00
} else if ch == 41 {
2023-08-18 08:55:46 +02:00
for operator_stack.Back().Value.(int) != 40 {
e := operator_stack.Back()
expr.PushBack(e.Value.(int))
operator_stack.Remove(e)
}
operator_stack.Remove(operator_stack.Back())
}
}
for operator_stack.Len() != 0 {
e := operator_stack.Back()
expr.PushBack(e.Value.(int))
operator_stack.Remove(e)
}
tf_stack := list.New()
for expr.Len() != 0 {
e := expr.Front()
ch := e.Value.(int)
expr.Remove(e)
if ch == 84 || ch == 70 {
tf_stack.PushBack(int(ch))
}
if ch == 38 { // &
em := tf_stack.Back()
a := em.Value.(int)
tf_stack.Remove(em)
em = tf_stack.Back()
b := em.Value.(int)
tf_stack.Remove(em)
if a == 84 && b == 84 {
tf_stack.PushBack(84)
} else {
tf_stack.PushBack(70)
}
}
if ch == 124 { // |
em := tf_stack.Back()
a := em.Value.(int)
tf_stack.Remove(em)
em = tf_stack.Back()
b := em.Value.(int)
tf_stack.Remove(em)
if a == 70 && b == 70 {
tf_stack.PushBack(70)
} else {
tf_stack.PushBack(84)
}
}
if ch == 33 { // !
em := tf_stack.Back()
a := em.Value.(int)
tf_stack.Remove(em)
if a == 70 {
tf_stack.PushBack(84)
} else if a == 84 {
tf_stack.PushBack(70)
}
}
}
if tf_stack.Front().Value.(int) == 84 {
return true
} else {
return false
}
}
func getRuleData(rule string) structs.RuleData {
if !strings.Contains(rule, "=\"") {
return structs.RuleData{}
}
pos := strings.Index(rule, "=\"")
op := 0
if rule[pos-1] == 33 {
op = 1
} else if rule[pos-1] == 61 {
op = 2
} else if rule[pos-1] == 62 {
op = 3
} else if rule[pos-1] == 60 {
op = 4
} else if rule[pos-1] == 126 {
op = 5
}
start := 0
ti := 0
if op > 0 {
ti = 1
}
for i := pos - 1 - ti; i >= 0; i-- {
2023-11-13 10:21:19 +01:00
if (rule[i] > 122 || rule[i] < 97) && rule[i] != 95 {
2023-08-18 08:55:46 +02:00
start = i + 1
break
}
}
key := rule[start : pos-ti]
end := pos + 2
for i := pos + 2; i < len(rule)-1; i++ {
if rule[i] != 92 && rule[i+1] == 34 {
end = i + 2
break
}
}
value := rule[pos+2 : end-1]
all := rule[start:end]
return structs.RuleData{Start: start, End: end, Op: int16(op), Key: key, Value: value, All: all}
}
2024-04-03 06:32:26 +02:00
func ParseRule(rule string) []structs.RuleData {
2023-08-18 08:55:46 +02:00
var result []structs.RuleData
empty := structs.RuleData{}
for {
data := getRuleData(rule)
if data == empty {
break
}
result = append(result, data)
rule = rule[:data.Start] + "T" + rule[data.End:]
}
return result
}
func regexMatch(pattern string, s string) (bool, error) {
matched, err := regexp.MatchString(pattern, s)
if err != nil {
return false, err
}
return matched, nil
}
// body="123" op=0 dataSource为http.body dataRule=123
func dataCheckString(op int16, dataSource string, dataRule string) bool {
dataSource = strings.ToLower(dataSource)
dataRule = strings.ToLower(dataRule)
dataRule = strings.ReplaceAll(dataRule, "\\\"", "\"")
if op == 0 {
if strings.Contains(dataSource, dataRule) {
return true
}
} else if op == 1 {
if !strings.Contains(dataSource, dataRule) {
return true
}
} else if op == 2 {
if dataSource == dataRule {
return true
}
} else if op == 5 {
rs, err := regexMatch(dataRule, dataSource)
if err == nil && rs {
return true
}
}
return false
}
func dataCheckInt(op int16, dataSource int, dataRule int) bool {
if op == 0 { // 数字相等
if dataSource == dataRule {
return true
}
} else if op == 1 { // 数字不相等
if dataSource != dataRule {
return true
}
} else if op == 3 { // 大于等于
if dataSource >= dataRule {
return true
}
} else if op == 4 {
if dataSource <= dataRule {
return true
}
}
return false
}
func checkPath(Path string,
webPath structs.UrlPathEntity,
Port int, // 所开放的端口
Protocol string, // 协议
Banner string, // 响应
Cert string, // TLS证书
) []string {
var fingerPrintResults []string
isWeb := Path != "no#web" && webPath.Hash != ""
hashString := webPath.Hash
body := ""
bodyBytes, ok := structs.GlobalHttpBodyHMap.Get(hashString)
if !ok {
body = ""
} else {
body = string(bodyBytes)
}
headerString := ""
headerBytes, ok := structs.GlobalHttpHeaderHMap.Get(webPath.HeaderHashString)
if !ok {
headerString = ""
} else {
headerString = string(headerBytes)
}
2024-04-03 06:32:26 +02:00
workers := runtime.NumCPU() * 2
2023-08-18 08:55:46 +02:00
inputChan := make(chan structs.FingerPEntity, len(structs.FingerprintDB))
defer close(inputChan)
results := make(chan string, len(structs.FingerprintDB))
defer close(results)
var wg sync.WaitGroup
//接收结果
go func() {
for found := range results {
if found != "" {
fingerPrintResults = append(fingerPrintResults, found)
}
wg.Done()
}
}()
//多线程扫描
for i := 0; i < workers; i++ {
go func() {
for finger := range inputChan {
rules := finger.Rule
product := finger.ProductName
expr := finger.AllString
for _, singleRule := range rules {
singleRuleResult := false
if singleRule.Key == "header" {
if isWeb && dataCheckString(singleRule.Op, headerString, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "body" {
if isWeb && dataCheckString(singleRule.Op, body, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "server" {
if isWeb && dataCheckString(singleRule.Op, webPath.Server, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "title" {
if isWeb && dataCheckString(singleRule.Op, webPath.Title, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "cert" {
if dataCheckString(singleRule.Op, Cert, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "port" {
value, err := strconv.Atoi(singleRule.Value)
if err == nil && dataCheckInt(singleRule.Op, Port, value) {
singleRuleResult = true
}
} else if singleRule.Key == "protocol" {
if singleRule.Op == 0 {
if Protocol == singleRule.Value {
singleRuleResult = true
}
} else if singleRule.Op == 1 {
if Protocol != singleRule.Value {
singleRuleResult = true
}
}
} else if singleRule.Key == "path" {
if isWeb && dataCheckString(singleRule.Op, Path, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "body_hash" {
if isWeb && dataCheckString(singleRule.Op, webPath.Hash, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "icon_hash" {
value, err := strconv.Atoi(singleRule.Value)
hashIcon, errHash := strconv.Atoi(webPath.IconHash)
if isWeb && err == nil && errHash == nil && dataCheckInt(singleRule.Op, hashIcon, value) {
singleRuleResult = true
}
} else if singleRule.Key == "status" {
value, err := strconv.Atoi(singleRule.Value)
if isWeb && err == nil && dataCheckInt(singleRule.Op, webPath.StatusCode, value) {
singleRuleResult = true
}
} else if singleRule.Key == "content_type" {
if isWeb && dataCheckString(singleRule.Op, webPath.ContentType, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "banner" {
if dataCheckString(singleRule.Op, Banner, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "type" {
if singleRule.Value == "service" {
singleRuleResult = true
}
}
if singleRuleResult {
expr = expr[:singleRule.Start] + "T" + expr[singleRule.End:]
} else {
expr = expr[:singleRule.Start] + "F" + expr[singleRule.End:]
}
}
r := boolEval(expr)
if r {
results <- product
} else {
results <- ""
}
}
}()
}
//添加扫描目标
for _, input := range structs.FingerprintDB {
wg.Add(1)
inputChan <- input
}
wg.Wait()
return utils.RemoveDuplicateElement(fingerPrintResults)
}
func FingerprintIdentification() {
gologger.Info().Msg("指纹识别中")
// 先识别非Web
for hostPort, protocol := range structs.GlobalIPPortMap {
if protocol == "http" || protocol == "https" || protocol == "" {
continue
}
t := strings.Split(hostPort, ":")
if len(t) != 2 {
continue
}
// host := t[0]
port, err := strconv.Atoi(t[1])
if err != nil {
continue
}
banner := ""
bodyBytes, ok := structs.GlobalBannerHMap.Get(hostPort)
if !ok {
banner = ""
} else {
banner = string(bodyBytes)
}
results := checkPath("no#web", structs.UrlPathEntity{}, port, protocol, banner, "")
if len(results) > 0 {
Url := fmt.Sprintf("%s://%s", protocol, hostPort)
structs.GlobalResultMap[Url] = results
2024-04-03 06:32:26 +02:00
//msg := "[Finger] " + Url + " ["
//for _, r := range results {
// msg += aurora.Cyan(r).String() + ","
//}
//msg = msg[:len(msg)-1] + "]"
//gologger.Silent().Msg(msg)
ddout.FormatOutput(ddout.OutputMessage{
Type: "Finger",
IP: "",
IPs: nil,
Port: "",
Protocol: "",
Web: ddout.WebInfo{},
Finger: results,
Domain: "",
GoPoc: ddout.GoPocsResultType{},
URI: Url,
AdditionalMsg: "",
})
2023-08-18 08:55:46 +02:00
}
}
for rootURL, urlEntity := range structs.GlobalURLMap {
banner := ""
if urlEntity.IP != "" {
hostPort := fmt.Sprintf("%s:%d", urlEntity.IP, urlEntity.Port)
bodyBytes, ok := structs.GlobalBannerHMap.Get(hostPort)
if !ok {
banner = ""
} else {
banner = string(bodyBytes)
}
}
URL, _ := url.Parse(rootURL)
for path, pathEntity := range urlEntity.WebPaths {
results := checkPath(path, pathEntity, urlEntity.Port, URL.Scheme, banner, urlEntity.Cert)
fullURL := rootURL + path
if len(results) > 0 {
structs.GlobalResultMap[fullURL] = results
2024-04-03 06:32:26 +02:00
//msg := "[Finger] " + fullURL + " "
//msg += fmt.Sprintf("[%d] [", pathEntity.StatusCode)
//for _, r := range results {
// msg += aurora.Cyan(r).String() + ","
//}
//msg = msg[:len(msg)-1] + "]"
//if pathEntity.Title != "" {
// msg += fmt.Sprintf(" [%s]", pathEntity.Title)
//}
//gologger.Silent().Msg(msg)
ddout.FormatOutput(ddout.OutputMessage{
Type: "Finger",
IP: "",
IPs: nil,
Port: "",
Protocol: "",
Web: ddout.WebInfo{
Status: strconv.Itoa(pathEntity.StatusCode),
Title: pathEntity.Title,
},
Finger: results,
Domain: "",
GoPoc: ddout.GoPocsResultType{},
URI: fullURL,
AdditionalMsg: "",
})
2023-08-18 08:55:46 +02:00
} else {
structs.GlobalResultMap[fullURL] = []string{}
}
}
}
2024-01-02 14:50:55 +01:00
gologger.AuditTimeLogger("指纹识别结束")
2023-08-18 08:55:46 +02:00
}
func SingleCheck(finger structs.FingerPEntity, Protocol string, headerString string, body string,
Server string, Title string, Cert string, Port int, Path string, Hash string, IconHash string, StatusCode int,
ContentType string, Banner string) bool {
rules := finger.Rule
expr := finger.AllString
for _, singleRule := range rules {
singleRuleResult := false
if singleRule.Key == "header" {
if dataCheckString(singleRule.Op, headerString, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "body" {
if dataCheckString(singleRule.Op, body, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "server" {
if dataCheckString(singleRule.Op, Server, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "title" {
if dataCheckString(singleRule.Op, Title, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "cert" {
if dataCheckString(singleRule.Op, Cert, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "port" {
value, err := strconv.Atoi(singleRule.Value)
if err == nil && dataCheckInt(singleRule.Op, Port, value) {
singleRuleResult = true
}
} else if singleRule.Key == "protocol" {
if singleRule.Op == 0 {
if Protocol == singleRule.Value {
singleRuleResult = true
}
} else if singleRule.Op == 1 {
if Protocol != singleRule.Value {
singleRuleResult = true
}
}
} else if singleRule.Key == "path" {
if dataCheckString(singleRule.Op, Path, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "body_hash" {
if dataCheckString(singleRule.Op, Hash, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "icon_hash" {
value, err := strconv.Atoi(singleRule.Value)
hashIcon, errHash := strconv.Atoi(IconHash)
if err == nil && errHash == nil && dataCheckInt(singleRule.Op, hashIcon, value) {
singleRuleResult = true
}
} else if singleRule.Key == "status" {
value, err := strconv.Atoi(singleRule.Value)
if err == nil && dataCheckInt(singleRule.Op, StatusCode, value) {
singleRuleResult = true
}
} else if singleRule.Key == "content_type" {
if dataCheckString(singleRule.Op, ContentType, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "banner" {
if dataCheckString(singleRule.Op, Banner, singleRule.Value) {
singleRuleResult = true
}
} else if singleRule.Key == "type" {
if singleRule.Value == "service" {
singleRuleResult = true
}
}
if singleRuleResult {
expr = expr[:singleRule.Start] + "T" + expr[singleRule.End:]
} else {
expr = expr[:singleRule.Start] + "F" + expr[singleRule.End:]
}
}
return boolEval(expr)
}