picatz / taint

🚰 Static taint analysis for Go programs.
https://picatz.github.io/#blog/taint
Mozilla Public License 2.0
57 stars 1 forks source link

Add `taint` command #12

Closed picatz closed 11 months ago

picatz commented 11 months ago

This PR aims to introduce the taint command to provide an interactive shell (REPL) to explore a program with, like its call graph or dependencies, and identify potential taint analysis issues.

$ go run ./cmd/taint/main.go
... clears screen ...
Commands (tab complete)

- clear to clear screen.
- exit to quit.

> ...

Note There are commands like callpath, check, pkgs, amongst a few others that are currently not shown in that top level help. That can be figured out later, maybe using cobra.

// ./xss/testdata/src/b
package main

import (
    "net/http"
)

func mirror(w http.ResponseWriter, r *http.Request) {
    input := r.URL.Query().Get("input")

    b := []byte(input)

    w.Write(b) // want "potential XSS"
}

func main() {
    http.HandleFunc("/", mirror)

    http.ListenAndServe(":8080", nil)
}
> load ./xss/testdata/src/b
loaded 1 packages
> pkgs
github.com/picatz/taint/xss/testdata/src/b 1 imports
> nodes
n0:github.com/picatz/taint/xss/testdata/src/b.main
n1:github.com/picatz/taint/xss/testdata/src/b.mirror
n2:(*net/url.URL).Query
n3:(net/url.Values).Get
n4:(net/http.ResponseWriter).Write
n5:net/http.HandleFunc
n6:net/http.ListenAndServe
> callpath (net/http.ResponseWriter).Write
n0:github.com/picatz/taint/xss/testdata/src/b.main → n5:net/http.HandleFunc → n1:github.com/picatz/taint/xss/testdata/src/b.mirror → n4:(net/http.ResponseWriter).Write
> check *net/http.Request (net/http.ResponseWriter).Write 
n5:net/http.HandleFunc → n1:github.com/picatz/taint/xss/testdata/src/b.mirror → n4:(net/http.ResponseWriter).Write
> cg
n4:(net/http.ResponseWriter).Write

n5:net/http.HandleFunc
        → n1:github.com/picatz/taint/xss/testdata/src/b.mirror

n6:net/http.ListenAndServe

n0:github.com/picatz/taint/xss/testdata/src/b.main
        → n5:net/http.HandleFunc
        → n6:net/http.ListenAndServe

n1:github.com/picatz/taint/xss/testdata/src/b.mirror
        → n2:(*net/url.URL).Query
        → n3:(net/url.Values).Get
        → n4:(net/http.ResponseWriter).Write

n2:(*net/url.URL).Query

n3:(net/url.Values).Get

demo


It also acts as a nice standalone example for how to use the package's provided in this module directly, without needing to go through go/analysis.

In hopes my future self (and perhaps others?) will benefit from this breakdown:

  1. First, we need to determine the package "patterns" we want to use:

    https://github.com/picatz/taint/blob/b728a26a4f59e787ecce1207612d80932a9ceac1/cmd/taint/main.go#L159-L161

  2. Next, we need to load our packages, applying our load pattern with a given configuration:

    Here, we set the directory we're working with, amongst other information, like environment variables. We also provide a custom file parsing function. In the future, we can optimize our package loading using these fields. We also are excluding tests, which might need to be configurable in the future.

    https://github.com/picatz/taint/blob/b728a26a4f59e787ecce1207612d80932a9ceac1/cmd/taint/main.go#L163-L172

    Note

    We use a loadMode and parseMode with the works, but we can also make this configurable to make stuff faster in the future: https://github.com/picatz/taint/blob/b728a26a4f59e787ecce1207612d80932a9ceac1/cmd/taint/main.go#L150-L153 For example, by skipping comment parsing, you can save a lot of time/memory: https://github.com/picatz/taint/blob/b728a26a4f59e787ecce1207612d80932a9ceac1/cmd/taint/main.go#L155

    1. Once we have loaded packages, we can build the complete SSA program information:

      https://github.com/picatz/taint/blob/b728a26a4f59e787ecce1207612d80932a9ceac1/cmd/taint/main.go#L180-L186

      Note

      We use ssaMode which instantiates generics and sanity checks functions, but there are other modes to consider like ssa.BareInits|ssa.GlobalDebug: https://github.com/picatz/taint/blob/b728a26a4f59e787ecce1207612d80932a9ceac1/cmd/taint/main.go#L157

  3. Now we have the SSA value graph, we can create a call graph from that information. We're assuming there's only one logical program loaded (which isn't always true, to be clear), and create a call graph rooted in that program's main function:

    https://github.com/picatz/taint/blob/b728a26a4f59e787ecce1207612d80932a9ceac1/cmd/taint/main.go#L188-L211 https://github.com/picatz/taint/blob/b728a26a4f59e787ecce1207612d80932a9ceac1/cmd/taint/main.go#L219