Skip to content
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

G107 - SSRF #236

Merged
merged 6 commits into from
Sep 4, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Initial SSRF Rule
  • Loading branch information
cschoenduve-splunk committed Aug 30, 2018
commit 8bad224bfe905ce1ca0b54afe110b5746b938022
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ or to specify a set of rules to explicitly exclude using the '-exclude=' flag.
- G104: Audit errors not checked
- G105: Audit the use of math/big.Int.Exp
- G106: Audit the use of ssh.InsecureIgnoreHostKey
- G107: Url provided to HTTP request as taint input
- G201: SQL query construction using format string
- G202: SQL query construction using string concatenation
- G203: Use of unescaped data in HTML templates
- G204: Audit use of command execution
- G301: Poor file permissions used when creating a directory
- G302: Poor file permisions used with chmod
- G302: Poor file permissions used with chmod
- G303: Creating tempfile using a predictable path
- G304: File path provided as taint input
- G305: File traversal when extracting zip archive
Expand Down Expand Up @@ -79,7 +80,7 @@ that are not considered build artifacts by the compiler (so test files).
As with all automated detection tools there will be cases of false positives. In cases where gosec reports a failure that has been manually verified as being safe it is possible to annotate the code with a '#nosec' comment.

The annotation causes gosec to stop processing any further nodes within the
AST so can apply to a whole block or more granularly to a single expression.
AST so can apply to a whole block or more granularly to a single expression.

```go

Expand Down Expand Up @@ -178,7 +179,7 @@ You can build the docker image as follows:
make image
```

You can run the `gosec` tool in a container against your local Go project. You just have to mount the project in the
You can run the `gosec` tool in a container against your local Go project. You just have to mount the project in the
`GOPATH` of the container:

```
Expand Down
1 change: 1 addition & 0 deletions rules/rulelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func Generate(filters ...RuleFilter) RuleList {
{"G104", "Audit errors not checked", NewNoErrorCheck},
{"G105", "Audit the use of big.Exp function", NewUsingBigExp},
{"G106", "Audit the use of ssh.InsecureIgnoreHostKey function", NewSSHHostKey},
{"G107", "Url provided to HTTP request as taint input", NewSSRFCheck},

// injection
{"G201", "SQL query construction using format string", NewSQLStrFormat},
Expand Down
4 changes: 4 additions & 0 deletions rules/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ var _ = Describe("gosec rules", func() {
runner("G106", testutils.SampleCodeG106)
})

It("should detect ssrf via http requests with variable url", func() {
runner("G107", testutils.SampleCodeG107)
})

It("should detect sql injection via format strings", func() {
runner("G201", testutils.SampleCodeG201)
})
Expand Down
47 changes: 47 additions & 0 deletions rules/ssrf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package rules

import (
"github.com/GoASTScanner/gas"
"go/ast"
"go/types"
)

type ssrf struct {
gas.MetaData
gas.CallList
}

// ID returns the identifier for this rule
func (r *ssrf) ID() string {
return r.MetaData.ID
}

// Match inspects AST nodes to determine if certain net/http methods are called with variable input
func (r *ssrf) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if node := r.ContainsCallExpr(n, c); node != nil {
for _, arg := range node.Args {
if ident, ok := arg.(*ast.Ident); ok {
obj := c.Info.ObjectOf(ident)
if _, ok := obj.(*types.Var); ok && !gas.TryResolve(ident, c) {
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
}
}
}
}
return nil, nil
}

// NewSSRFCheck detects cases where HTTP requests are sent
func NewSSRFCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) {
rule := &ssrf{
CallList: gas.NewCallList(),
MetaData: gas.MetaData{
ID: id,
What: "Potential HTTP request made with variable url",
Severity: gas.Medium,
Confidence: gas.Medium,
},
}
rule.Add("net/http", "Do", "Get", "Head", "Post", "PostForm", "RoundTrip")
return rule, []ast.Node{(*ast.CallExpr)(nil)}
}
22 changes: 22 additions & 0 deletions testutils/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,28 @@ import (
)
func main() {
_ = ssh.InsecureIgnoreHostKey()
}`, 1}}

// SampleCodeG107 - SSRF via http requests with variable url
SampleCodeG107 = []CodeSample{{`
package main
import (
"net/http"
"io/ioutil"
"fmt"
)
func main() {
url := os.Getenv("tainted_url")
resp, err := http.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Printf("%s", body)
}`, 1}}
// SampleCodeG201 - SQL injection via format string
SampleCodeG201 = []CodeSample{
Expand Down