Reputation: 1172
I have a question, for security purposes, it is sometimes very useful to make HTTP requests with illegal paths, such as: http://localhost/%x
, in Golang it does not seem to be a way to do that, could anyone give some light to this issue?
What I have tried so far:
- .Get() function
response, err := http.DefaultClient.Get("http://localhost/%x")
if err != nil{
panic(err) // net/url.EscapeError
}
requestObject, err := http.NewRequest("GET", "http://localhost/%x", nil)
if err != nil {
panic(err) // panics!
}
And
requestObject, err := http.NewRequest("GET", "http://localhost", nil)
if err != nil {
panic(err) // Not panic
}
requestObject.URL.Path = "/%x"
response, err = netClient.goHttpClient.Do(requestObject)
if err != nil {
panic(err) // Not panic
}
This last one looks promising, but request is made to %25x
instead of %x
, can someone give some help please?
UPDATE: Go can send %x in the request, in the query section though, not in the path, I want to send %x in the path, so my issue is not solved:
requestObject, err := http.NewRequest("GET", "http://localhost", nil)
if err != nil {
panic(err) // Not panic
}
requestObject.URL.Path = "/%x"
requestObject.URL.RawQuery = "%x"
Request is made to http://localhost/%25x?%x
The %x in the path is encoded, in the query it is not.
UPDATE:
The answer given @Cerise is the one I use, and it works fine, but there are edge cases to take into account.
1 - Proxy: If you have to forward the requests to a proxy, for some reason, the HTTP framework does not know how to send HTTP requests that your proxy can understand, to fix this, in Burp suite, you have to enable invisible proxy as documented here: https://portswigger.net/support/using-burp-suites-invisible-proxy-settings-to-test-a-non-proxy-aware-thick-client-application
This still has an issue, I noticed it when I had to debug some HTTP requests, I could not make sense, of what Burp Suite was telling me, then inspecting the requests in Wireshark I knew there was something wrong, if you use .Opaque + BurpSuite, BurpSuite will modify some requests, this is where the second issue comes into play, keep reading.
2 - Opaque does not handle well the paths starting with "//", I don't think it is a bug though, it is well known that https://stackoverflow.com can also be rewritten as //stackoverflow.com, I think this the logic taken into account by go, anyway, if you do:
requestObject, err := http.NewRequest(methodStr, "http://localhost", nil)
requestObject.URL.Opaque = "//something"
This is what the HTTP request looks like with Wireshark:
GET http://something HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Language: en-US,en;q=0.9,ca;q=0.8
Cache-Control: no-cache
Connection: close
Pragma: no-cache
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
Accept-Encoding: gzip
notice the first line, it is not what we may have though first, right?
I used to debug HTTP requests with Burp Suite, but let's use the same code, and forward the requests to Burp using:
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyURL("http://localhost:8080")
Don't forget to enable invisible proxy on BurpSuite, otherwise it will reject the request. What Burp Suite shows is:
GET / HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Language: en-US,en;q=0.9,ca;q=0.8
Cache-Control: no-cache
Connection: close
Pragma: no-cache
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
Accept-Encoding: gzip, deflate
outch!!, Burp has changed our request completely!!! Takeaways: - Do not use Your HTTP proxy to debug requests made with Opaque - Do not use .Opaque with paths starting with double slashes, use the following:
if strings.HasPrefix(yourPath, "//") {
requestObject.URL.Path = fmt.Sprintf("%s", yourPath)
} else {
requestObject.URL.Opaque = fmt.Sprintf("%s", yourPath)
}
Upvotes: 1
Views: 662
Reputation: 121099
Set Request.URL.Opaque to the invalid path. The Opaque data is written to the network as is.
requestObject, err := http.NewRequest("GET", "http://localhost", nil)
if err != nil {
panic(err)
}
requestObject.URL.Opaque = "/%x"
response, err = netClient.goHttpClient.Do(requestObject)
if err != nil {
panic(err)
}
This code creates an invalid request. The net/http server handles the invalid request by responding with 400 Bad Request. Other servers and proxies may do something different.
Upvotes: 3