From 5a06f7175d9f4d58892a86b5bbd83ffd4fbd42d3 Mon Sep 17 00:00:00 2001 From: ariary Date: Fri, 29 Jul 2022 21:50:07 +0200 Subject: [PATCH] print special character --- .gitignore | 4 +++ Makefile | 5 ++- README.md | 7 +++-- cmd/httpclient/main.go | 7 ++--- cmd/httpcustomhouse/main.go | 61 +++++++++++++++++++++++++++++-------- pkg/parser/parser.go | 8 +++++ pkg/utils/utils.go | 50 ------------------------------ 7 files changed, 71 insertions(+), 71 deletions(-) create mode 100644 .gitignore delete mode 100755 pkg/utils/utils.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2355d80 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +go.sum +httpclient +httpcustomhouse +httpoverride \ No newline at end of file diff --git a/Makefile b/Makefile index bd27dfb..fab8332 100755 --- a/Makefile +++ b/Makefile @@ -8,4 +8,7 @@ build.httpoverride: @echo "build in ${PWD}";go build -o httpoverride cmd/httpoverride/main.go build.httpclient: - @echo "build in ${PWD}";go build -o httpclient cmd/httpclient/main.go \ No newline at end of file + @echo "build in ${PWD}";go build -o httpclient cmd/httpclient/main.go + +all: + @echo "build in ${PWD}";go build -o httpclient cmd/httpclient/main.go;go build -o httpoverride cmd/httpoverride/main.go;go build -o httpcustomhouse cmd/httpcustomhouse/main.go \ No newline at end of file diff --git a/README.md b/README.md index 70e3940..b5bcc09 100755 --- a/README.md +++ b/README.md @@ -27,9 +27,10 @@ HTTP request smuggling is a technique for interfering with the way a web site pr * `curl`, go http client, `ncat`, `openssl s_client` aren't fully satisfying especially when dealing with "malformed http request" **Real examples:** -* [Forge `TE.CL` request smuggling attack](https://github.com/ariary/HTTPCustomHouse/blob/main/EXAMPLES.md#analyze-tecl-request-treatment) -* [Forge `CL.TE` request smuggling attack](https://github.com/ariary/HTTPCustomHouse/blob/main/EXAMPLES.md#analyze-clte-request-treatment) -* [Exploit `CL.TE`](https://github.com/ariary/HTTPCustomHouse/blob/main/EXAMPLES.md#exploiting-http-request-smuggling-to-reveal-front-end-request-rewriting) +* [Forge `TE.CL` request smuggling attack](./EXAMPLES.md#analyze-tecl-request-treatment) +* [Forge `CL.TE` request smuggling attack](./EXAMPLES.md#analyze-clte-request-treatment) +* [Exploit `CL.TE`](./EXAMPLES.md#exploiting-http-request-smuggling-to-reveal-front-end-request-rewriting) [[2](./EXAMPLES.md#exploiting-http-request-smuggling-to-bypass-front-end-security-controls-clte-vulnerability)] [[3](./EXAMPLES.md#exploiting-http-request-smuggling-to-deliver-reflected-xss-clte)] +* [Exploit `TE.CL`](./EXAMPLES.md#exploiting-http-request-smuggling-to-bypass-front-end-security-controls-tecl-vulnerability) ## Usage diff --git a/cmd/httpclient/main.go b/cmd/httpclient/main.go index 2a937f0..2379abc 100644 --- a/cmd/httpclient/main.go +++ b/cmd/httpclient/main.go @@ -8,7 +8,6 @@ import ( "io/ioutil" "log" "os" - "strings" "github.com/ariary/HTTPCustomHouse/pkg/client" "github.com/ariary/HTTPCustomHouse/pkg/config" @@ -87,8 +86,7 @@ func main() { if cfg.Verbose { fmt.Println(color.MagentaForeground("------------------------ SEND:")) if cfg.Debug { - reqDebug := strings.ReplaceAll(string(rawRequest), "\r", color.Green("\\r")) - reqDebug = strings.ReplaceAll(reqDebug, "\n", color.Green("\\n\n")) + reqDebug := parser.ReplaceSpecialCharacters(rawRequest) fmt.Println(reqDebug) } else { fmt.Println(string(rawRequest)) // raw request ~ request.GetRawRequest(cfg.Request) @@ -117,8 +115,7 @@ func main() { if cfg.Verbose { fmt.Println("--------------------- SEND:") if cfg.Debug { - reqDebug := strings.ReplaceAll(string(rawRequest), "\r", color.Green("\\r")) - reqDebug = strings.ReplaceAll(reqDebug, "\n", color.Green("\\n\n")) + reqDebug := parser.ReplaceSpecialCharacters(rawRequest) fmt.Println(reqDebug) } else { fmt.Println(string(rawRequest)) // raw request ~ request.GetRawRequest(cfg.Request) diff --git a/cmd/httpcustomhouse/main.go b/cmd/httpcustomhouse/main.go index 7f12f63..6c1801b 100755 --- a/cmd/httpcustomhouse/main.go +++ b/cmd/httpcustomhouse/main.go @@ -13,10 +13,11 @@ import ( ) const usage = `Usage of httpcustomhouse: - -r, --residues display residues of the request not treated by the custom officer - -cl, --Content-Length stop request treatment according to Content-Length header value - -te, --Transfer-Encoding stop request treatment according to chunked encoding - -h, --help prints help information + -r, --residues display residues of the request not treated by the custom officer + -cl, --Content-Length stop request treatment according to Content-Length header value + -te, --Transfer-Encoding stop request treatment according to chunked encoding + -d, --debug display special characters (\r and \n) + -h, --help prints help information ` // /!\ request contain \r\n\r\n characters, when editing w/ vscode for example this character are @@ -35,6 +36,10 @@ func main() { var isTE bool flag.BoolVar(&isTE, "Transfer-Encoding", false, "stop request treatment according to chunked encoding") flag.BoolVar(&isTE, "te", false, "stop request treatment according to chunked encoding") + //-d + var debug bool + flag.BoolVar(&debug, "debug", false, "Display with special character") + flag.BoolVar(&debug, "d", false, "Display request with special character") flag.Usage = func() { fmt.Print(usage) } flag.Parse() @@ -54,11 +59,19 @@ func main() { // Print header for h, v := range httpHeader { - fmt.Printf("%s: %s\n", h, v[0]) //TODO handle where multiple value are found for a specific header + headerLine := h + ": " + v[0] + "\n" + if debug { + headerLine = parser.ReplaceSpecialCharacters([]byte(headerLine)) + } + fmt.Printf(headerLine) //TODO handle where multiple value are found for a specific header } // /!\ bodyB include \r\n to end headers section - fmt.Print("\r\n") + separeHeaderAndBody := "\r\n" + if debug { + separeHeaderAndBody = parser.ReplaceSpecialCharacters([]byte(separeHeaderAndBody)) + } + fmt.Print(separeHeaderAndBody) bodyB = bodyB[2:] if isTE { //TE custom house @@ -67,19 +80,35 @@ func main() { sTransferEncoding := httpHeader.Get("Transfer-encoding") if sTransferEncoding == "chunked" { bodyTE, residueB := parser.FilterWithChunkEncoding(bodyB) - fmt.Print(string(bodyTE)) + bodyTEStr := string(bodyTE) + if debug { + bodyTEStr = parser.ReplaceSpecialCharacters(bodyTE) + } + fmt.Print(bodyTEStr) if residue { - fmt.Fprintf(os.Stderr, color.Magenta(string(residueB))) + residueStr := string(residueB) + if debug { + residueStr = parser.ReplaceSpecialCharacters(residueB) + } + fmt.Fprintf(os.Stderr, color.Magenta(residueStr)) } } else { - fmt.Print(string(bodyB)) + bodyStr := string(bodyB) + if debug { + bodyStr = parser.ReplaceSpecialCharacters(bodyB) + } + fmt.Print(bodyStr) } } else { //CL custom house // Get Content-Length value sContentLength := httpHeader.Get("Content-Length") if sContentLength == "" { + bodyStr := string(bodyB) + if debug { + bodyStr = parser.ReplaceSpecialCharacters(bodyB) + } //fmt.Fprintf(os.Stderr, "Content-Length not found") - fmt.Print(string(bodyB)) //Print whole request + fmt.Print(bodyStr) //Print whole request } else { contentLength, err := strconv.Atoi(sContentLength) if err != nil { @@ -87,11 +116,19 @@ func main() { } bodyCL, residueB, difference := parser.FilterWithContentLength(contentLength, bodyB) - fmt.Print(string(bodyCL)) + bodyCLStr := string(bodyCL) + if debug { + bodyCLStr = parser.ReplaceSpecialCharacters(bodyCL) + } + fmt.Print(bodyCLStr) if difference > 0 { fmt.Fprintln(os.Stderr, color.Yellow("\nMissing ", difference, " bytes in body")) } else if residue { - fmt.Fprintf(os.Stderr, color.Magenta(string(residueB))) + residueStr := string(residueB) + if debug { + residueStr = parser.ReplaceSpecialCharacters(residueB) + } + fmt.Fprintf(os.Stderr, color.Magenta(residueStr)) } } diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index 774875f..e1a7373 100755 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -12,6 +12,7 @@ import ( "github.com/ariary/HTTPCustomHouse/pkg/request" "github.com/ariary/HTTPCustomHouse/pkg/response" + "github.com/ariary/go-utils/pkg/color" ) //Parse a request to retrieve headers and body @@ -175,3 +176,10 @@ func ParseResponse(reqMethod string, url string, resp string) (response response return response, err } + +//ReplaceSpecialCharacters: replace special characters in a given string (bytes) to make them visible +func ReplaceSpecialCharacters(rawWithSpecial []byte) (strWithoutSpecial string) { + strWithoutSpecial = strings.ReplaceAll(string(rawWithSpecial), "\r", color.Green("\\r")) + strWithoutSpecial = strings.ReplaceAll(strWithoutSpecial, "\n", color.Green("\\n\n")) + return strWithoutSpecial +} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go deleted file mode 100755 index 9bdee87..0000000 --- a/pkg/utils/utils.go +++ /dev/null @@ -1,50 +0,0 @@ -package utils - -import ( - "fmt" - "math/rand" - "time" -) - -var ( - Info = Teal - Warn = Yellow - Evil = Red - Good = Green - Code = Cyan -) - -var ( - Black = Color("\033[1;30m%s\033[0m") - Red = Color("\033[1;31m%s\033[0m") - Green = Color("\033[1;32m%s\033[0m") - Yellow = Color("\033[1;33m%s\033[0m") - Purple = Color("\033[1;34m%s\033[0m") - Magenta = Color("\033[1;35m%s\033[0m") - Teal = Color("\033[1;36m%s\033[0m") - White = Color("\033[1;37m%s\033[0m") - Cyan = Color("\033[1;96m%s\033[0m") - Underlined = Color("\033[4m%s\033[24m") - Bold = Color("\033[1m%s\033[0m") - Italic = Color("\033[3m%s\033[0m") - RedForeground = Color("\033[1;41m%s\033[0m") -) - -func Color(colorString string) func(...interface{}) string { - sprint := func(args ...interface{}) string { - return fmt.Sprintf(colorString, - fmt.Sprint(args...)) - } - return sprint -} - -//GenerateRandom: generate a "random" string of 6 alphanumeric charcaters -func GenerateRandom() string { - rand.Seed(time.Now().UnixNano()) - var characters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789") - b := make([]rune, 6) - for i := range b { - b[i] = characters[rand.Intn(len(characters))] - } - return string(b) -}