From 8678cc957201ee45560196a5850464bdd8033ffc Mon Sep 17 00:00:00 2001 From: frjcomp <107982661+frjcomp@users.noreply.github.com> Date: Thu, 17 Oct 2024 15:48:09 +0200 Subject: [PATCH] Vuln check (#45) * Add vulnerability command --- readme.md | 2 ++ src/pipeleak/cmd/root.go | 1 + src/pipeleak/cmd/vuln.go | 63 +++++++++++++++++++++++++++++++++++++++ src/pipeleak/go.mod | 3 ++ src/pipeleak/go.sum | 7 +++++ src/pipeleak/nist/nist.go | 29 ++++++++++++++++++ 6 files changed, 105 insertions(+) create mode 100644 src/pipeleak/cmd/vuln.go create mode 100644 src/pipeleak/nist/nist.go diff --git a/readme.md b/readme.md index e16b505..793fe90 100644 --- a/readme.md +++ b/readme.md @@ -57,6 +57,8 @@ You can tweak `--threads`, `--max-artifact-size` and `--job-limit` to obtain a c `register` command: Best effort automation to register a new user on an instance. +`vuln` command: Check the installed version for CVEs in the NIST Vulnerability database + Setting an HTTP proxy is possible by setting the environment variable `HTTP_PROXY` e.g. to route through Burp: ```bash diff --git a/src/pipeleak/cmd/root.go b/src/pipeleak/cmd/root.go index a426bfc..6ba7fc4 100644 --- a/src/pipeleak/cmd/root.go +++ b/src/pipeleak/cmd/root.go @@ -31,6 +31,7 @@ func init() { rootCmd.AddCommand(NewShodanCmd()) rootCmd.AddCommand(cmd.NewRunnersRootCmd()) rootCmd.AddCommand(NewRegisterCmd()) + rootCmd.AddCommand(NewVulnCmd()) rootCmd.PersistentFlags().BoolVarP(&JsonLogoutput, "json", "", false, "Use JSON as log output format") } diff --git a/src/pipeleak/cmd/vuln.go b/src/pipeleak/cmd/vuln.go new file mode 100644 index 0000000..0e93d38 --- /dev/null +++ b/src/pipeleak/cmd/vuln.go @@ -0,0 +1,63 @@ +package cmd + +import ( + "github.com/CompassSecurity/pipeleak/helper" + "github.com/CompassSecurity/pipeleak/nist" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" + "github.com/tidwall/gjson" +) + +var ( + gitlabApiToken string +) + +func NewVulnCmd() *cobra.Command { + vulnCmd := &cobra.Command{ + Use: "vuln [no options!]", + Short: "Check if the installed GitLab version is vulnerable", + Run: CheckVulns, + } + vulnCmd.Flags().StringVarP(&gitlabUrl, "gitlab", "g", "", "GitLab instance URL") + err := vulnCmd.MarkFlagRequired("gitlab") + if err != nil { + log.Fatal().Stack().Err(err).Msg("Unable to require gitlab flag") + } + + vulnCmd.Flags().StringVarP(&gitlabApiToken, "token", "t", "", "GitLab API Token") + err = vulnCmd.MarkFlagRequired("token") + if err != nil { + log.Fatal().Msg("Unable to require token flag") + } + vulnCmd.MarkFlagsRequiredTogether("gitlab", "token") + + vulnCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Verbose logging") + return vulnCmd +} + +func CheckVulns(cmd *cobra.Command, args []string) { + if verbose { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + log.Debug().Msg("Verbose log output enabled") + } + + installedVersion := helper.DetermineVersion(gitlabUrl, gitlabApiToken) + log.Info().Str("version", installedVersion.Version).Msg("GitLab") + + log.Info().Str("version", installedVersion.Version).Msg("Fetching CVEs for this version") + vulnsJsonStr, err := nist.FetchVulns(installedVersion.Version) + if err != nil { + log.Fatal().Msg("Unable fetch vulnerabilities from NIST") + } + + result := gjson.Get(vulnsJsonStr, "vulnerabilities") + result.ForEach(func(key, value gjson.Result) bool { + cve := value.Get("cve.id").String() + description := value.Get("cve.descriptions.0.value").String() + log.Info().Str("cve", cve).Str("description", description).Msg("Vulnerable") + return true + }) + + log.Info().Msg("Finished vuln scan") +} diff --git a/src/pipeleak/go.mod b/src/pipeleak/go.mod index 2d6df56..7005cde 100644 --- a/src/pipeleak/go.mod +++ b/src/pipeleak/go.mod @@ -11,6 +11,7 @@ require ( github.com/maragudk/goqite v0.2.3 github.com/rs/zerolog v1.33.0 github.com/spf13/cobra v1.8.1 + github.com/tidwall/gjson v1.18.0 github.com/trufflesecurity/trufflehog/v3 v3.82.9 github.com/xanzy/go-gitlab v0.112.0 gitlab.com/mitchenielsen/gitlab-ci-go v0.0.4 @@ -200,6 +201,8 @@ require ( github.com/tailscale/depaware v0.0.0-20240804103531-585336c3e1b3 // indirect github.com/tetratelabs/wazero v1.8.0 // indirect github.com/therootcompany/xz v1.0.1 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/ulikunitz/xz v0.5.12 // indirect github.com/vbatts/tar-split v0.11.3 // indirect github.com/wasilibs/go-re2 v1.7.0 // indirect diff --git a/src/pipeleak/go.sum b/src/pipeleak/go.sum index ce2668a..a64ea9e 100644 --- a/src/pipeleak/go.sum +++ b/src/pipeleak/go.sum @@ -726,6 +726,13 @@ github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmc github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= diff --git a/src/pipeleak/nist/nist.go b/src/pipeleak/nist/nist.go new file mode 100644 index 0000000..ed08dd7 --- /dev/null +++ b/src/pipeleak/nist/nist.go @@ -0,0 +1,29 @@ +package nist + +import ( + "github.com/CompassSecurity/pipeleak/helper" + "github.com/rs/zerolog/log" + "io" +) + +func FetchVulns(version string) (string, error) { + client := helper.GetNonVerifyingHTTPClient() + res, err := client.Get("https://services.nvd.nist.gov/rest/json/cves/2.0?cpeName=cpe:2.3:a:gitlab:gitlab:" + version + ":*:*:*:*:*:*:*") + if err != nil { + return "{}", err + } + defer res.Body.Close() + + if res.StatusCode == 200 { + resData, err := io.ReadAll(res.Body) + if err != nil { + log.Error().Int("http", res.StatusCode).Msg("unable to read HTTP response body") + return "{}", err + } + + return string(resData), nil + } else { + log.Error().Int("http", res.StatusCode).Msg("failed fetching vulnerabilities") + return "{}", nil + } +}