Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/protocols/common/helpers/responsehighlighter/hexdump.go
2073 views
1
package responsehighlighter
2
3
import (
4
"errors"
5
"fmt"
6
"regexp"
7
"strings"
8
"unicode"
9
10
"github.com/projectdiscovery/gologger"
11
)
12
13
// [0-9a-fA-F]{8} {2} - hexdump indexes (8 character hex value followed by two spaces)
14
// [0-9a-fA-F]{2} + - 2 character long hex values followed by one or two space (potentially wrapped with an ASCII color code, see below)
15
// \x1b\[(\d;?)+m - ASCII color code pattern
16
// \x1b\[0m - ASCII color code reset
17
// \|(.*)\|\n - ASCII representation of the input delimited by pipe characters
18
var hexDumpParsePattern = regexp.MustCompile(`([0-9a-fA-F]{8} {2})((?:(?:\x1b\[(?:\d;?)+m)?[0-9a-fA-F]{2}(?:\x1b\[0m)? +)+)\|(.*)\|\n`)
19
var hexValuePattern = regexp.MustCompile(`([a-fA-F0-9]{2})`)
20
21
type HighlightableHexDump struct {
22
index []string
23
hex []string
24
ascii []string
25
}
26
27
func NewHighlightableHexDump(rowSize int) HighlightableHexDump {
28
return HighlightableHexDump{index: make([]string, 0, rowSize), hex: make([]string, 0, rowSize), ascii: make([]string, 0, rowSize)}
29
}
30
31
func (hexDump HighlightableHexDump) len() int {
32
return len(hexDump.index)
33
}
34
35
func (hexDump HighlightableHexDump) String() string {
36
var result string
37
for i := 0; i < hexDump.len(); i++ {
38
result += hexDump.index[i] + hexDump.hex[i] + "|" + hexDump.ascii[i] + "|\n"
39
}
40
return result
41
}
42
43
func toHighLightedHexDump(hexDump, snippetToHighlight string) (HighlightableHexDump, error) {
44
hexDumpRowValues := hexDumpParsePattern.FindAllStringSubmatch(hexDump, -1)
45
if hexDumpRowValues == nil || len(hexDumpRowValues) != strings.Count(hexDump, "\n") {
46
message := "could not parse hexdump"
47
gologger.Warning().Msg(message)
48
49
return HighlightableHexDump{}, errors.New(message)
50
}
51
52
result := NewHighlightableHexDump(len(hexDumpRowValues))
53
for _, currentHexDumpRowValues := range hexDumpRowValues {
54
result.index = append(result.index, currentHexDumpRowValues[1])
55
result.hex = append(result.hex, currentHexDumpRowValues[2])
56
result.ascii = append(result.ascii, currentHexDumpRowValues[3])
57
}
58
return result.highlight(snippetToHighlight), nil
59
}
60
61
func (hexDump HighlightableHexDump) highlight(snippetToColor string) HighlightableHexDump {
62
return highlightAsciiSection(highlightHexSection(hexDump, snippetToColor), snippetToColor)
63
}
64
65
func highlightHexSection(hexDump HighlightableHexDump, snippetToColor string) HighlightableHexDump {
66
var snippetHexCharactersMatchPattern string
67
for _, char := range snippetToColor {
68
snippetHexCharactersMatchPattern += fmt.Sprintf(`(%02x[ \n]+)`, char)
69
}
70
71
hexDump.hex = highlight(hexDump.hex, snippetHexCharactersMatchPattern, func(v string) string {
72
return hexValuePattern.ReplaceAllString(v, addColor("$1"))
73
})
74
75
return hexDump
76
}
77
78
func highlightAsciiSection(hexDump HighlightableHexDump, snippetToColor string) HighlightableHexDump {
79
var snippetCharactersMatchPattern string
80
for _, v := range snippetToColor {
81
var value string
82
if IsASCIIPrintable(v) {
83
value = regexp.QuoteMeta(string(v))
84
} else {
85
value = "."
86
}
87
snippetCharactersMatchPattern += fmt.Sprintf(`(%s\n*)`, value)
88
}
89
90
hexDump.ascii = highlight(hexDump.ascii, snippetCharactersMatchPattern, func(v string) string {
91
if len(v) > 1 {
92
return addColor(string(v[0])) + v[1:] // do not color new line characters
93
}
94
return addColor(v)
95
})
96
97
return hexDump
98
}
99
100
func highlight(values []string, snippetCharactersMatchPattern string, replaceToFunc func(v string) string) []string {
101
rows := strings.Join(values, "\n")
102
compiledPattern := regexp.MustCompile(snippetCharactersMatchPattern)
103
for _, submatch := range compiledPattern.FindAllStringSubmatch(rows, -1) {
104
var replaceTo string
105
var replaceFrom string
106
for _, matchedValueWithSuffix := range submatch[1:] {
107
replaceFrom += matchedValueWithSuffix
108
replaceTo += replaceToFunc(matchedValueWithSuffix)
109
}
110
rows = strings.ReplaceAll(rows, replaceFrom, replaceTo)
111
}
112
return strings.Split(rows, "\n")
113
}
114
115
func HasBinaryContent(input string) bool {
116
return !IsASCII(input)
117
}
118
119
// IsASCII tests whether a string consists only of ASCII characters or not
120
func IsASCII(input string) bool {
121
for i := 0; i < len(input); i++ {
122
if input[i] > unicode.MaxASCII {
123
return false
124
}
125
}
126
return true
127
}
128
129
func IsASCIIPrintable(input rune) bool {
130
return input > 32 && input < unicode.MaxASCII
131
}
132
133