dgryski/semgrep-go

Proposal: warn about fmt.Sprintf on HTTP request body building

jimen0 opened this issue · 2 comments

Hi,

First of all, thanks for creating and maintaining this repository. The set of rules is very useful. I'd like to propose a new rule for detecting HTTP requests where the body is built using fmt.Sprintf() instead of url.Values{}.Encode(). I was bitten by this some time ago and I think a rule could be created for warning about it.

Scenario

An HTTP request is built using one or more user-controlled parameters for the body value.

TL;DR: I crafted this playground to show the different results.

Detected behavior

Body is manually crafted via fmt.Sprintf or string concatenation (+).

// name is a parameter, user supplied
data := fmt.Sprintf("name=%s&order=1", name)
req, err := http.NewRequest(http.MethodPost, "https://example.com/", strings.NewReader(data))

An attacker could supply a value like test&forge=pwn resulting in the following HTTP request being sent.

POST / HTTP/1.1
Host: example.com
User-Agent: Go-http-client/1.1
Content-Length: 27
Content-Type: application/x-www-form-urlencoded
Cccept-Encoding: gzip, deflate
Connection: close
  
name=test&forge=pwn&order=1

Desired behavior

Body is created via url.Values{}.Encode():

// name is a parameter, user supplied
data := url.Values{
    "name":  {name},
    "order": {"1"},
}
req, err := http.NewRequest(http.MethodPost, "https://example.com/", strings.NewReader(data.Encode()))

Then, the request is securely encoded:

POST / HTTP/1.1
Host: example.com
User-Agent: Go-http-client/1.1
Content-Length: 31
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Connection: close

name=test%26forge%3Dpwn&order=1

Please, let me know if a rule like that would fit into this repository. If so, I could try to write it and contribute it. If you think it doesn't fit into this repository, please feel free to close this issue and sorry about the noise I caused.

I'm not 100% sure this being possible using semgrep, though.

Best,
Miguel

Writing patterns to detect this kind of dataflow might be tricky, but maybe experiment with semgrep's taint tracking support: https://github.com/returntocorp/semgrep/blob/develop/docs/experimental.md#taint-tracking

Hi @dgryski,

Thank you for taking the time to review my proposal and sharing some docs with me. I highly appreciate that. I'll keep an eye on semgrep's repository in case they ever add something that makes it easier to implement this. I'm closing this issue now to avoid making unneeded noise. Regards! 😄