Path: blob/dev/pkg/protocols/common/helpers/responsehighlighter/hexdump.go
2073 views
package responsehighlighter12import (3"errors"4"fmt"5"regexp"6"strings"7"unicode"89"github.com/projectdiscovery/gologger"10)1112// [0-9a-fA-F]{8} {2} - hexdump indexes (8 character hex value followed by two spaces)13// [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)14// \x1b\[(\d;?)+m - ASCII color code pattern15// \x1b\[0m - ASCII color code reset16// \|(.*)\|\n - ASCII representation of the input delimited by pipe characters17var hexDumpParsePattern = regexp.MustCompile(`([0-9a-fA-F]{8} {2})((?:(?:\x1b\[(?:\d;?)+m)?[0-9a-fA-F]{2}(?:\x1b\[0m)? +)+)\|(.*)\|\n`)18var hexValuePattern = regexp.MustCompile(`([a-fA-F0-9]{2})`)1920type HighlightableHexDump struct {21index []string22hex []string23ascii []string24}2526func NewHighlightableHexDump(rowSize int) HighlightableHexDump {27return HighlightableHexDump{index: make([]string, 0, rowSize), hex: make([]string, 0, rowSize), ascii: make([]string, 0, rowSize)}28}2930func (hexDump HighlightableHexDump) len() int {31return len(hexDump.index)32}3334func (hexDump HighlightableHexDump) String() string {35var result string36for i := 0; i < hexDump.len(); i++ {37result += hexDump.index[i] + hexDump.hex[i] + "|" + hexDump.ascii[i] + "|\n"38}39return result40}4142func toHighLightedHexDump(hexDump, snippetToHighlight string) (HighlightableHexDump, error) {43hexDumpRowValues := hexDumpParsePattern.FindAllStringSubmatch(hexDump, -1)44if hexDumpRowValues == nil || len(hexDumpRowValues) != strings.Count(hexDump, "\n") {45message := "could not parse hexdump"46gologger.Warning().Msg(message)4748return HighlightableHexDump{}, errors.New(message)49}5051result := NewHighlightableHexDump(len(hexDumpRowValues))52for _, currentHexDumpRowValues := range hexDumpRowValues {53result.index = append(result.index, currentHexDumpRowValues[1])54result.hex = append(result.hex, currentHexDumpRowValues[2])55result.ascii = append(result.ascii, currentHexDumpRowValues[3])56}57return result.highlight(snippetToHighlight), nil58}5960func (hexDump HighlightableHexDump) highlight(snippetToColor string) HighlightableHexDump {61return highlightAsciiSection(highlightHexSection(hexDump, snippetToColor), snippetToColor)62}6364func highlightHexSection(hexDump HighlightableHexDump, snippetToColor string) HighlightableHexDump {65var snippetHexCharactersMatchPattern string66for _, char := range snippetToColor {67snippetHexCharactersMatchPattern += fmt.Sprintf(`(%02x[ \n]+)`, char)68}6970hexDump.hex = highlight(hexDump.hex, snippetHexCharactersMatchPattern, func(v string) string {71return hexValuePattern.ReplaceAllString(v, addColor("$1"))72})7374return hexDump75}7677func highlightAsciiSection(hexDump HighlightableHexDump, snippetToColor string) HighlightableHexDump {78var snippetCharactersMatchPattern string79for _, v := range snippetToColor {80var value string81if IsASCIIPrintable(v) {82value = regexp.QuoteMeta(string(v))83} else {84value = "."85}86snippetCharactersMatchPattern += fmt.Sprintf(`(%s\n*)`, value)87}8889hexDump.ascii = highlight(hexDump.ascii, snippetCharactersMatchPattern, func(v string) string {90if len(v) > 1 {91return addColor(string(v[0])) + v[1:] // do not color new line characters92}93return addColor(v)94})9596return hexDump97}9899func highlight(values []string, snippetCharactersMatchPattern string, replaceToFunc func(v string) string) []string {100rows := strings.Join(values, "\n")101compiledPattern := regexp.MustCompile(snippetCharactersMatchPattern)102for _, submatch := range compiledPattern.FindAllStringSubmatch(rows, -1) {103var replaceTo string104var replaceFrom string105for _, matchedValueWithSuffix := range submatch[1:] {106replaceFrom += matchedValueWithSuffix107replaceTo += replaceToFunc(matchedValueWithSuffix)108}109rows = strings.ReplaceAll(rows, replaceFrom, replaceTo)110}111return strings.Split(rows, "\n")112}113114func HasBinaryContent(input string) bool {115return !IsASCII(input)116}117118// IsASCII tests whether a string consists only of ASCII characters or not119func IsASCII(input string) bool {120for i := 0; i < len(input); i++ {121if input[i] > unicode.MaxASCII {122return false123}124}125return true126}127128func IsASCIIPrintable(input rune) bool {129return input > 32 && input < unicode.MaxASCII130}131132133