diff --git a/config/config-local.yml b/config/config-local.yml index 33b0e61168..6a253c46f3 100644 --- a/config/config-local.yml +++ b/config/config-local.yml @@ -3,6 +3,9 @@ name: "GitHub Field CodeQL Local Threat Model Configuration" disable-default-queries: true queries: + # Go local queries + - uses: advanced-security/codeql-queries/go/suites/codeql-go-local.qls@main + # Java local queries - uses: advanced-security/codeql-queries/java/suites/codeql-java-local.qls@main diff --git a/go/CWE-078/CodeInjectionLocal.ql b/go/CWE-078/CodeInjectionLocal.ql new file mode 100644 index 0000000000..91e087f343 --- /dev/null +++ b/go/CWE-078/CodeInjectionLocal.ql @@ -0,0 +1,45 @@ +/** + * @name Command built from user-controlled sources + * @description Building a system command from user-controlled sources is vulnerable to insertion of + * malicious code by the user. + * @kind path-problem + * @problem.severity warning + * @security-severity 4.0 + * @precision low + * @id go/command-injection + * @tags security + * external/cwe/cwe-078 + * local + */ + +import go +import semmle.go.security.CommandInjection +import DataFlow::PathGraph +import semmle.go.security.CommandInjectionCustomizations::CommandInjection +import github.LocalSources + +class CommandInjectionLocalConfiguration extends TaintTracking::Configuration { + CommandInjectionLocalConfiguration() { this = "CommandInjection" } + + // Local sources of input + override predicate isSource(DataFlow::Node source) { source instanceof LocalSources::Sources } + + override predicate isSink(DataFlow::Node sink) { + exists(Sink s | sink = s | not s.doubleDashIsSanitizing()) + } + + override predicate isSanitizer(DataFlow::Node node) { + super.isSanitizer(node) or + node instanceof Sanitizer + } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + guard instanceof SanitizerGuard + } +} + +// TODO: DoubleDashSanitizingConfiguration? +from CommandInjectionLocalConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "This command depends on $@.", source.getNode(), + "a user-provided value" diff --git a/go/CWE-078/examples/CommandInjection.go b/go/CWE-078/examples/CommandInjection.go new file mode 100644 index 0000000000..fb48a83123 --- /dev/null +++ b/go/CWE-078/examples/CommandInjection.go @@ -0,0 +1,32 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "os/exec" +) + +func runPing(ip *string) { + cmdString := fmt.Sprintf("ping %v", *ip) + fmt.Printf("Command :: %s\n", cmdString) + cmd := exec.Command(cmdString) + err := cmd.Run() + if err != nil { + log.Fatal(err) + } +} + +func main() { + ip := flag.String("ip", "8.8.8.8", "IP Address to contact") + flag.Parse() + + log.Printf(" Flag >> %s\n", *ip) + runPing(ip) + + ip2 := os.Args[0] + log.Printf(" Argv >> %s", ip2) + runPing(&ip2) + +} diff --git a/go/github/LocalSources.qll b/go/github/LocalSources.qll new file mode 100644 index 0000000000..d68ea5acae --- /dev/null +++ b/go/github/LocalSources.qll @@ -0,0 +1,27 @@ +import go + +// ========== Sources ========== +module LocalSources { + abstract class Sources extends DataFlow::Node { } + + // https://pkg.go.dev/os#Args + // class OsArgs extends Sources { + // OsArgs() { + // exists(ValueEntity value | value.hasQualifiedName(package("os", ""), "Args") and this = value) + // } + // } + class OsGetenv extends Sources, DataFlow::CallNode { + OsGetenv() { + // https://pkg.go.dev/os#Getenv + this.getTarget().hasQualifiedName(package("os", ""), "Getenv") + or + // https://pkg.go.dev/os#Environ + this.getTarget().hasQualifiedName(package("os", ""), "Environ") + } + } + + // https://pkg.go.dev/flag + class Flag extends Sources, DataFlow::CallNode { + Flag() { this.getTarget().hasQualifiedName(package("flag", ""), "String") } + } +} diff --git a/go/suites/codeql-go-local.qls b/go/suites/codeql-go-local.qls new file mode 100644 index 0000000000..3b2e185afc --- /dev/null +++ b/go/suites/codeql-go-local.qls @@ -0,0 +1,11 @@ +# See https://help.semmle.com/codeql/codeql-cli/procedures/query-suites.html#filtering-the-queries-in-a-query-suite +# for additional ways to exclude queries + +- description: "GitHub's Field Team CodeQL GoLang extended Suite" + +- qlpack: github-queries-go +- include: + tags contain: local + +- import: codeql-suites/go-security-extended.qls + from: codeql-go