From 51237456c68f47479b2b32f05d5c31c54932a64a Mon Sep 17 00:00:00 2001 From: nathanmartinszup <63246935+nathanmartinszup@users.noreply.github.com> Date: Wed, 18 Nov 2020 09:37:55 -0300 Subject: [PATCH] Feature/horusec-csharp (#131) * Adding base horusec csharp cli * Adding csharp rules structure * Fixing security hashes * Adding horusec csharp cli injetion rules * Adding others rules * Adding sql injection linq rule * Update leaks with set pwd * Update make file and adding pipeline of horusec-csharp * Adding password validation * Adding sql injection rules in csharp cli * Adding rules of cookies, view state * Fixing errors * Adding some cryptography rules to csharp cli * Fixing total rules csharp * Adding weak cipher rules * Adding more rules of csharp * Fixing test * Adding more csharp rules * add NewCsharpRegularDebugBuildEnabled * add NewCsharpRegularDebugBuildEnabled * Adding custom errors disabled rule * Adding rules csharp * Adding rule vulnerable package reference * Adding rule jwt signature validation disabled * Add cors allow origin wildcard rules * Adding NewCsharpAndFormsAuthenticationCookielessMode * Adding regular anti forgery token rule * Adding form validations * Adding missing authorize attribute rule * Adding rules of xml in csharp * Fix test * Adding more csharp rules * Adding password lockout disabled rule * Adding more rules in csharp of cookies and assinatures * Adding cross site rules * Weak password rule * Adding ldap injection filter rule * Adding more rules in csharp * Adding more rules in csharp * Adding more rules in csharp * Adding ldap injection rules * Adding more rules in csharp * Adding csharp in deployments to up version * Adding csharp in deployments to up version * Rename test zip to csharp * Adding horusec csharp cli * Change language to csharp * Adding test to check netcore is deprecated * Updating regular rules * Adding rule no log sensitive information in console * Fix conflict * Fixing error removing old regular expressions * Update weak rsa key length * Removing deplicated rule * Fixing rules of java min 128 bits in key generator * Adding unit tests in csharp engine * Fixing fmt lint * Fixing test * Fixing test * Adding readme.md in horusec-csharp * Update README.md * Fixing tests * Merge and update doc Co-authored-by: Wilian Gabriel Co-authored-by: Wilian Gabriel <63816070+wiliansilvazup@users.noreply.github.com> --- .github/workflows/csharp-pipeline.yml | 46 ++ .github/workflows/deploy-cli-tools.yml | 2 +- Makefile | 39 +- deployments/scripts/update-image-tool.sh | 12 +- .../pkg/engines/csharp/analysis/analysis.go | 65 ++ .../engines/csharp/analysis/analysis_test.go | 57 ++ .../pkg/engines/csharp/rules/rules.go | 43 ++ .../pkg/engines/csharp/rules/rules_test.go | 39 ++ .../examples/csharp-generic-vuln/Errors.cs | 15 + .../NetCoreVulnerabilities.csproj | 14 + .../NetCoreVulnerabilities.sln | 34 + .../examples/csharp-generic-vuln/Program.cs | 12 + .../csharp-generic-vuln/Vulnerabilities.cs | 47 ++ .../engines/java/analysis/analysis_test.go | 2 +- .../enums/engine/advisories/csharp/and/and.go | 499 ++++++++++++++ .../enums/engine/advisories/csharp/csharp.go | 112 ++++ .../engine/advisories/csharp/csharp_test.go | 45 ++ .../enums/engine/advisories/csharp/or/or.go | 204 ++++++ .../advisories/csharp/regular/regular.go | 624 ++++++++++++++++++ .../enums/engine/advisories/java/and/and.go | 4 +- .../advisories/leaks/regular/regular.go | 2 +- .../pkg/enums/languages/languages.go | 6 +- .../pkg/enums/languages/languages_test.go | 4 +- development-kit/pkg/enums/tools/tools.go | 1 + .../pkg/usecases/analysis/analysis.go | 3 +- .../pkg/utils/test/analysis_mock.go | 2 +- .../netcore3-1.zip => csharp/csharp.zip} | Bin e2e/cli/scan_languages/scan_languages_test.go | 8 +- horusec-cli/README.md | 8 +- horusec-cli/config/config.go | 17 + horusec-cli/config/config_test.go | 2 +- .../internal/controllers/analyser/analyser.go | 6 +- .../controllers/analyser/analyser_test.go | 4 +- .../language_detect/language_detect_test.go | 4 +- .../internal/entities/workdir/workdir.go | 6 +- horusec-cli/internal/helpers/messages/warn.go | 2 + .../dotnet/horusec_csharp/config.go | 25 + .../dotnet/horusec_csharp/formatter.go | 141 ++++ .../dotnet/horusec_csharp/formatter_test.go | 146 ++++ .../formatters/dotnet/scs/formatter.go | 4 +- .../services/formatters/service_test.go | 2 +- horusec-cli/internal/usecases/cli/cli_test.go | 4 +- horusec-config.json | 2 +- horusec-csharp/.semver.yaml | 4 + horusec-csharp/README.md | 129 ++++ horusec-csharp/cmd/app/main.go | 57 ++ horusec-csharp/deployments/Dockerfile | 30 + 47 files changed, 2476 insertions(+), 58 deletions(-) create mode 100644 .github/workflows/csharp-pipeline.yml create mode 100644 development-kit/pkg/engines/csharp/analysis/analysis.go create mode 100644 development-kit/pkg/engines/csharp/analysis/analysis_test.go create mode 100644 development-kit/pkg/engines/csharp/rules/rules.go create mode 100644 development-kit/pkg/engines/csharp/rules/rules_test.go create mode 100644 development-kit/pkg/engines/examples/csharp-generic-vuln/Errors.cs create mode 100644 development-kit/pkg/engines/examples/csharp-generic-vuln/NetCoreVulnerabilities.csproj create mode 100644 development-kit/pkg/engines/examples/csharp-generic-vuln/NetCoreVulnerabilities.sln create mode 100644 development-kit/pkg/engines/examples/csharp-generic-vuln/Program.cs create mode 100644 development-kit/pkg/engines/examples/csharp-generic-vuln/Vulnerabilities.cs create mode 100644 development-kit/pkg/enums/engine/advisories/csharp/and/and.go create mode 100644 development-kit/pkg/enums/engine/advisories/csharp/csharp.go create mode 100644 development-kit/pkg/enums/engine/advisories/csharp/csharp_test.go create mode 100644 development-kit/pkg/enums/engine/advisories/csharp/or/or.go create mode 100644 development-kit/pkg/enums/engine/advisories/csharp/regular/regular.go rename development-kit/pkg/utils/test/zips/{netcore3-1/netcore3-1.zip => csharp/csharp.zip} (100%) create mode 100644 horusec-cli/internal/services/formatters/dotnet/horusec_csharp/config.go create mode 100644 horusec-cli/internal/services/formatters/dotnet/horusec_csharp/formatter.go create mode 100644 horusec-cli/internal/services/formatters/dotnet/horusec_csharp/formatter_test.go create mode 100644 horusec-csharp/.semver.yaml create mode 100644 horusec-csharp/README.md create mode 100644 horusec-csharp/cmd/app/main.go create mode 100644 horusec-csharp/deployments/Dockerfile diff --git a/.github/workflows/csharp-pipeline.yml b/.github/workflows/csharp-pipeline.yml new file mode 100644 index 000000000..909048487 --- /dev/null +++ b/.github/workflows/csharp-pipeline.yml @@ -0,0 +1,46 @@ +name: HorusecCSharpPipeline + +on: + push: + branches: [ "master", "develop" ] + pull_request: + branches: [ "**" ] + +jobs: + install-build-test-fmt-lint: + name: install-build-test-fmt-lint + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[skip ci]')" + steps: + - name: Set up Go 1.14 + uses: actions/setup-go@v1 + with: + go-version: 1.14 + id: go + - name: Check out code + uses: actions/checkout@v2 + - name: fmt + run: | + echo "==> Checking that code complies with gofmt requirements..." + gofmt_files=$(gofmt -l `find ./horusec-csharp -name '*.go' | grep -v vendor`) + echo $gofmt_files + if [ ! -z $gofmt_files ]; then + echo 'gofmt needs running on the following files:' + echo "$gofmt_files" + echo "You can use the command: \`gofmt -w \$(gofmt -l \'find ./horusec-csharp -name \'*.go\' | grep -v vendor)\` to reformat code." + exit 1 + fi + echo "=) The project horusec-csharp it's OK!" + - name: lint + run: | + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.25.0 + ./bin/golangci-lint run -v --timeout=2m -c .golangci.yml ./horusec-csharp/... + - name: test + run: | + go clean -testcache + go test -v ./horusec-csharp/... -timeout=2m -parallel=1 -failfast -short +# - name: coverage +# run: make coverage-horusec-csharp + - name: build + run: go build -o "./tmp/bin/horusec-csharp" ./horusec-csharp/cmd/app/main.go + diff --git a/.github/workflows/deploy-cli-tools.yml b/.github/workflows/deploy-cli-tools.yml index 0d4528fe2..3e3777a1c 100644 --- a/.github/workflows/deploy-cli-tools.yml +++ b/.github/workflows/deploy-cli-tools.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: tool_name: - description: 'Tool to deploy on dockerhub: bandit, brakeman, gitleaks, gosec, npmaudit, safety, securitycodescan, hcl, spotbugs, horusec-kotlin, horusec-java, horusec-leaks' + description: 'Tool to deploy on dockerhub: bandit, brakeman, gitleaks, gosec, npmaudit, safety, securitycodescan, hcl, spotbugs, horusec-kotlin, horusec-java, horusec-leaks, horusec-csharp' required: true update_type: description: 'Update Type: alpha, rc, release, minor, major' diff --git a/Makefile b/Makefile index ad31ec4a2..d085939ea 100644 --- a/Makefile +++ b/Makefile @@ -153,38 +153,37 @@ install-semver: chmod +x ./deployments/scripts/install-semver.sh ./deployments/scripts/install-semver.sh +PATH_BINARY_BUILD_CLI ?= $(GOPATH)/bin build-install-cli: - $(GO) build -o horusec ./horusec-cli/cmd/horusec/main.go - chmod +x horusec - rm -rf $(GOPATH)/bin/horusec - mv horusec $(GOPATH)/bin - cd .. + rm -rf "$(PATH_BINARY_BUILD_CLI)/horusec" &> /dev/null + $(GO) build -o "$(PATH_BINARY_BUILD_CLI)/horusec" ./horusec-cli/cmd/horusec/main.go + chmod +x "$(PATH_BINARY_BUILD_CLI)/horusec" horusec version build-install-leaks-cli: - $(GO) build -o horusec ./horusec-leaks/cmd/app/main.go - chmod +x horusec - rm -rf $(GOPATH)/bin/horusec-leaks - mv horusec $(GOPATH)/bin/horusec-leaks - cd .. + rm -rf "$(PATH_BINARY_BUILD_CLI)/horusec-leaks" &> /dev/null + $(GO) build -o "$(PATH_BINARY_BUILD_CLI)/horusec-leaks" ./horusec-leaks/cmd/app/main.go + chmod +x "$(PATH_BINARY_BUILD_CLI)/horusec-leaks" horusec-leaks version build-install-kotlin-cli: - $(GO) build -o horusec ./horusec-kotlin/cmd/app/main.go - chmod +x horusec - rm -rf $(GOPATH)/bin/horusec-kotlin - mv horusec $(GOPATH)/bin/horusec-kotlin - cd .. + rm -rf "$(PATH_BINARY_BUILD_CLI)/horusec-kotlin" &> /dev/null + $(GO) build -o "$(PATH_BINARY_BUILD_CLI)/horusec-kotlin" ./horusec-kotlin/cmd/app/main.go + chmod +x "$(PATH_BINARY_BUILD_CLI)/horusec-kotlin" horusec-kotlin version build-install-java-cli: - $(GO) build -o horusec ./horusec-java/cmd/app/main.go - chmod +x horusec - rm -rf $(GOPATH)/bin/horusec-java - mv horusec $(GOPATH)/bin/horusec-java - cd .. + rm -rf "$(PATH_BINARY_BUILD_CLI)/horusec-java" &> /dev/null + $(GO) build -o "$(PATH_BINARY_BUILD_CLI)/horusec-java" ./horusec-java/cmd/app/main.go + chmod +x "$(PATH_BINARY_BUILD_CLI)/horusec-java" horusec-java version +build-install-csharp-cli: + rm -rf "$(PATH_BINARY_BUILD_CLI)/horusec-csharp" &> /dev/null + $(GO) build -o "$(PATH_BINARY_BUILD_CLI)/horusec-csharp" ./horusec-csharp/cmd/app/main.go + chmod +x "$(PATH_BINARY_BUILD_CLI)/horusec-csharp" + horusec-csharp version + # ========================================================================================= # update-cli: diff --git a/deployments/scripts/update-image-tool.sh b/deployments/scripts/update-image-tool.sh index fed2ed857..901ee1f0e 100755 --- a/deployments/scripts/update-image-tool.sh +++ b/deployments/scripts/update-image-tool.sh @@ -89,13 +89,17 @@ getDirectoryAndImageNameByToolName () { IMAGE_NAME="horuszup/horusec-java" DIRECTORY_CONFIG="$CURRENT_FOLDER/horusec-cli/internal/services/formatters/java/horusecjava/config.go" DIRECTORY_SEMVER="$CURRENT_FOLDER/horusec-java";; + "horusec-csharp") + IMAGE_NAME="horuszup/horusec-csharp" + DIRECTORY_CONFIG="$CURRENT_FOLDER/horusec-cli/internal/services/formatters/csharp/horuseccsharp/config.go" + DIRECTORY_SEMVER="$CURRENT_FOLDER/horusec-csharp";; "horusec-leaks") IMAGE_NAME="horuszup/horusec-leaks" DIRECTORY_CONFIG="$CURRENT_FOLDER/horusec-cli/internal/services/formatters/leaks/horusecleaks/config.go" DIRECTORY_SEMVER="$CURRENT_FOLDER/horusec-leaks";; *) echo "Param Tool Name is invalid, please use the examples bellow allowed and try again!" - echo "Params Tool Name allowed: bandit, brakeman, gitleaks, gosec, npmaudit, safety, securitycodescan, hcl, spotbugs, horusec-kotlin, horusec-java, horusec-leaks" + echo "Params Tool Name allowed: bandit, brakeman, gitleaks, gosec, npmaudit, safety, securitycodescan, hcl, spotbugs, horusec-kotlin, horusec-java, horusec-leaks, horusec-csharp" exit 1;; esac } @@ -172,7 +176,7 @@ updateImage () { updateVersionInConfigFile updateVersionInCliVersionFile - if [[ "$TOOL_NAME" == "horusec-leaks" || "$TOOL_NAME" == "horusec-kotlin" || "$TOOL_NAME" == "horusec-java" ]] + if [[ "$TOOL_NAME" == "horusec-leaks" || "$TOOL_NAME" == "horusec-kotlin" || "$TOOL_NAME" == "horusec-java" || "$TOOL_NAME" == "horusec-csharp" ]] then DIRECTORY_SEMVER="$DIRECTORY_SEMVER/deployments" fi @@ -195,7 +199,7 @@ updateVersionInConfigFile () { } updateVersionInCliVersionFile () { - if [[ "$TOOL_NAME" == "horusec-leaks" || "$TOOL_NAME" == "horusec-kotlin" || "$TOOL_NAME" == "horusec-java" ]] + if [[ "$TOOL_NAME" == "horusec-leaks" || "$TOOL_NAME" == "horusec-kotlin" || "$TOOL_NAME" == "horusec-java" || "$TOOL_NAME" == "horusec-csharp" ]] then sed -i -e "s/{{VERSION_NOT_FOUND}}/$NEW_RELEASE/g" "./development-kit/pkg/cli_standard/cmd/version/version.go" fi @@ -207,7 +211,7 @@ rollbackVersionInConfigFile () { } rollbackVersionInCliVersionFile () { - if [[ "$TOOL_NAME" == "horusec-leaks" || "$TOOL_NAME" == "horusec-kotlin" || "$TOOL_NAME" == "horusec-java" ]] + if [[ "$TOOL_NAME" == "horusec-leaks" || "$TOOL_NAME" == "horusec-kotlin" || "$TOOL_NAME" == "horusec-java" || "$TOOL_NAME" == "horusec-csharp" ]] then sed -i -e "s/$NEW_RELEASE/{{VERSION_NOT_FOUND}}/g" "./development-kit/pkg/cli_standard/cmd/version/version.go" fi diff --git a/development-kit/pkg/engines/csharp/analysis/analysis.go b/development-kit/pkg/engines/csharp/analysis/analysis.go new file mode 100644 index 000000000..3155f765f --- /dev/null +++ b/development-kit/pkg/engines/csharp/analysis/analysis.go @@ -0,0 +1,65 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package analysis + +import ( + "encoding/json" + + engine "github.com/ZupIT/horusec-engine" + "github.com/ZupIT/horusec-engine/text" + "github.com/ZupIT/horusec/development-kit/pkg/cli_standard/config" + "github.com/ZupIT/horusec/development-kit/pkg/engines/csharp/rules" + "github.com/ZupIT/horusec/development-kit/pkg/utils/logger" +) + +type Interface interface { + StartAnalysis() error +} + +type Analysis struct { + configs *config.Config + serviceRules rules.Interface +} + +func NewAnalysis(configs *config.Config) Interface { + return &Analysis{ + configs: configs, + serviceRules: rules.NewRules(), + } +} + +func (a *Analysis) StartAnalysis() error { + textUnit, err := text.LoadDirIntoSingleUnit(a.configs.GetProjectPath(), []string{ + ".cs", ".vb", ".cshtml", ".csproj", ".xml"}) + if err != nil { + return err + } + a.logJSON("Text Unit selected is: ", textUnit) + + allRules := a.serviceRules.GetAllRules() + a.logJSON("All rules selected are: ", allRules) + + outputFilePath := a.configs.GetOutputFilePath() + logger.LogDebugWithLevel("Sending units and rules to engine "+ + " and expected response in path: ", logger.DebugLevel, outputFilePath) + return engine.RunOutputInJSON([]engine.Unit{textUnit}, allRules, outputFilePath) +} + +func (a *Analysis) logJSON(message string, content interface{}) { + b, err := json.Marshal(content) + if err == nil { + logger.LogTraceWithLevel(message, logger.DebugLevel, string(b)) + } +} diff --git a/development-kit/pkg/engines/csharp/analysis/analysis_test.go b/development-kit/pkg/engines/csharp/analysis/analysis_test.go new file mode 100644 index 000000000..6fda2ed50 --- /dev/null +++ b/development-kit/pkg/engines/csharp/analysis/analysis_test.go @@ -0,0 +1,57 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package analysis + +import ( + "encoding/json" + engine "github.com/ZupIT/horusec-engine" + "github.com/ZupIT/horusec/development-kit/pkg/cli_standard/config" + "github.com/stretchr/testify/assert" + "io/ioutil" + "os" + "testing" +) + +func TestNewAnalysis(t *testing.T) { + assert.IsType(t, NewAnalysis(config.NewConfig()), &Analysis{}) +} + +func TestAnalysis_StartAnalysis(t *testing.T) { + t.Run("Should return success when read analysis and return seven vulnerabilities", func(t *testing.T) { + configs := config.NewConfig() + configs.SetOutputFilePath("./csharp-tmp.output.json") + configs.SetProjectPath("../../examples/csharp-generic-vuln") + err := NewAnalysis(configs).StartAnalysis() + assert.NoError(t, err) + fileBytes, err := ioutil.ReadFile("./csharp-tmp.output.json") + data := []engine.Finding{} + _ = json.Unmarshal(fileBytes, &data) + assert.NoError(t, os.RemoveAll(configs.GetOutputFilePath())) + assert.Equal(t, 6, len(data)) + }) + t.Run("Should return error when create file", func(t *testing.T) { + configs := config.NewConfig() + configs.SetOutputFilePath("./////") + err := NewAnalysis(configs).StartAnalysis() + assert.Error(t, err) + }) + t.Run("Should return error when get units in project path", func(t *testing.T) { + configs := config.NewConfig() + configs.SetOutputFilePath("./////") + configs.SetProjectPath("./not exists path") + err := NewAnalysis(configs).StartAnalysis() + assert.Error(t, err) + }) +} diff --git a/development-kit/pkg/engines/csharp/rules/rules.go b/development-kit/pkg/engines/csharp/rules/rules.go new file mode 100644 index 000000000..d98e31a8d --- /dev/null +++ b/development-kit/pkg/engines/csharp/rules/rules.go @@ -0,0 +1,43 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + engine "github.com/ZupIT/horusec-engine" + "github.com/ZupIT/horusec/development-kit/pkg/enums/engine/advisories/csharp" +) + +type Interface interface { + GetAllRules() (rules []engine.Rule) +} + +type Rules struct{} + +func NewRules() Interface { + return &Rules{} +} + +func (r *Rules) GetAllRules() (rules []engine.Rule) { + for index := range csharp.AllRulesCsharpAnd() { + rules = append(rules, csharp.AllRulesCsharpAnd()[index]) + } + for index := range csharp.AllRulesCsharpOr() { + rules = append(rules, csharp.AllRulesCsharpOr()[index]) + } + for index := range csharp.AllRulesCsharpRegular() { + rules = append(rules, csharp.AllRulesCsharpRegular()[index]) + } + return rules +} diff --git a/development-kit/pkg/engines/csharp/rules/rules_test.go b/development-kit/pkg/engines/csharp/rules/rules_test.go new file mode 100644 index 000000000..77c6d234e --- /dev/null +++ b/development-kit/pkg/engines/csharp/rules/rules_test.go @@ -0,0 +1,39 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "testing" + + "github.com/ZupIT/horusec-engine/text" + "github.com/stretchr/testify/assert" +) + +func TestNewRules(t *testing.T) { + assert.IsType(t, NewRules(), &Rules{}) +} + +func TestRules_GetAllRules(t *testing.T) { + t.Run("Should return all rules enable", func(t *testing.T) { + rules := NewRules().GetAllRules() + totalRegexes := 0 + for i := range rules { + textRule := rules[i].(text.TextRule) + totalRegexes += len(textRule.Expressions) + } + assert.Greater(t, len(rules), 0) + assert.Greater(t, totalRegexes, 0) + }) +} diff --git a/development-kit/pkg/engines/examples/csharp-generic-vuln/Errors.cs b/development-kit/pkg/engines/examples/csharp-generic-vuln/Errors.cs new file mode 100644 index 000000000..b3b2101f4 --- /dev/null +++ b/development-kit/pkg/engines/examples/csharp-generic-vuln/Errors.cs @@ -0,0 +1,15 @@ +namespace NetCoreVulnerabilities +{ + public class Errors + { + public void NotUsedVar() + { + var neverUsedVar1 = ""; + } + + public void NotUsedVar2() + { + var neverUsedVar2 = ""; + } + } +} diff --git a/development-kit/pkg/engines/examples/csharp-generic-vuln/NetCoreVulnerabilities.csproj b/development-kit/pkg/engines/examples/csharp-generic-vuln/NetCoreVulnerabilities.csproj new file mode 100644 index 000000000..4641ecf25 --- /dev/null +++ b/development-kit/pkg/engines/examples/csharp-generic-vuln/NetCoreVulnerabilities.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + diff --git a/development-kit/pkg/engines/examples/csharp-generic-vuln/NetCoreVulnerabilities.sln b/development-kit/pkg/engines/examples/csharp-generic-vuln/NetCoreVulnerabilities.sln new file mode 100644 index 000000000..759ffa3c8 --- /dev/null +++ b/development-kit/pkg/engines/examples/csharp-generic-vuln/NetCoreVulnerabilities.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCoreVulnerabilities", "NetCoreVulnerabilities.csproj", "{982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Debug|x64.ActiveCfg = Debug|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Debug|x64.Build.0 = Debug|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Debug|x86.ActiveCfg = Debug|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Debug|x86.Build.0 = Debug|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Release|Any CPU.Build.0 = Release|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Release|x64.ActiveCfg = Release|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Release|x64.Build.0 = Release|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Release|x86.ActiveCfg = Release|Any CPU + {982D3426-4204-4FF2-9DB5-EDCC25EFB9A8}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/development-kit/pkg/engines/examples/csharp-generic-vuln/Program.cs b/development-kit/pkg/engines/examples/csharp-generic-vuln/Program.cs new file mode 100644 index 000000000..53603ba00 --- /dev/null +++ b/development-kit/pkg/engines/examples/csharp-generic-vuln/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace NetCoreVulnerabilities +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/development-kit/pkg/engines/examples/csharp-generic-vuln/Vulnerabilities.cs b/development-kit/pkg/engines/examples/csharp-generic-vuln/Vulnerabilities.cs new file mode 100644 index 000000000..ae3c1a7d1 --- /dev/null +++ b/development-kit/pkg/engines/examples/csharp-generic-vuln/Vulnerabilities.cs @@ -0,0 +1,47 @@ +using System; +using System.Net; +using System.Net.Mail; +using System.Security.Cryptography; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace NetCoreVulnerabilities +{ + public class NetCoreVulnerabilities : ControllerBase + { + public void WeakHashingFunction() + { + var str = new byte[] { }; + var hashProvider = new SHA1CryptoServiceProvider(); + var hash = hashProvider.ComputeHash(str); + } + + public void HardcodedPassword() + { + var client = new SmtpClient(); + client.Credentials = new NetworkCredential("test@test.com", "testpassword"); + var mm = new MailMessage("test", "test", "test", "test"); + client.Send(mm); + } + + public void WeakRandomNumberGenerator() + { + var rnd = new Random(); + var buffer = new byte[16]; + rnd.NextBytes(buffer); + BitConverter.ToString(buffer); + } + + public void CookieWithoutHttpOnlyFlag() + { + var cookie = new CookieOptions(); + cookie.Secure = false; + } + + [HttpGet()] + public string CrossSiteScripting(string myParam) + { + return "value " + myParam; + } + } +} \ No newline at end of file diff --git a/development-kit/pkg/engines/java/analysis/analysis_test.go b/development-kit/pkg/engines/java/analysis/analysis_test.go index 7e88fc630..7f8e3ffbb 100644 --- a/development-kit/pkg/engines/java/analysis/analysis_test.go +++ b/development-kit/pkg/engines/java/analysis/analysis_test.go @@ -40,7 +40,7 @@ func TestAnalysis_StartAnalysis(t *testing.T) { data := []engine.Finding{} _ = json.Unmarshal(fileBytes, &data) assert.NoError(t, os.RemoveAll(configs.GetOutputFilePath())) - assert.Equal(t, len(data), 7) + assert.Equal(t, len(data), 6) }) t.Run("Should return error when create file", func(t *testing.T) { configs := config.NewConfig() diff --git a/development-kit/pkg/enums/engine/advisories/csharp/and/and.go b/development-kit/pkg/enums/engine/advisories/csharp/and/and.go new file mode 100644 index 000000000..63f627ba6 --- /dev/null +++ b/development-kit/pkg/enums/engine/advisories/csharp/and/and.go @@ -0,0 +1,499 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//nolint:lll multiple regex is not possible broken lines +package and + +import ( + engine "github.com/ZupIT/horusec-engine" + "github.com/ZupIT/horusec-engine/text" + "github.com/ZupIT/horusec/development-kit/pkg/enums/confidence" + "github.com/ZupIT/horusec/development-kit/pkg/enums/severity" + "regexp" +) + +func NewCsharpAndCommandInjection() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "782ad071-1cf3-4230-936f-b7a1e794828d", + Name: "Command Injection", + Description: "If a malicious user controls either the FileName or Arguments, he might be able to execute unwanted commands or add unwanted argument. This behavior would not be possible if input parameter are validate against a white-list of characters. For more information access: (https://security-code-scan.github.io/#SCS0001).", + Severity: severity.Medium.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new Process\(\)`), + regexp.MustCompile(`StartInfo.FileName`), + regexp.MustCompile(`StartInfo.Arguments`), + }, + } +} + +func NewCsharpAndXPathInjection() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "010a99b2-9f35-4cb3-9209-248bacba07f8", + Name: "XPath Injection", + Description: "If the user input is not properly filtered, a malicious user could extend the XPath query. For more information access: (https://security-code-scan.github.io/#SCS0003).", + Severity: severity.Medium.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new XmlDocument {XmlResolver = null}`), + regexp.MustCompile(`Load\(.*\)`), + regexp.MustCompile(`SelectNodes\(.*\)`), + }, + } +} + +func NewCsharpAndExternalEntityInjection() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "f3390c7e-8151-4f8a-8bc4-433841569153", + Name: "XML eXternal Entity Injection (XXE)", + Description: "The XML parser is configured incorrectly. The operation could be vulnerable to XML eXternal Entity (XXE) processing. For more information access: (https://security-code-scan.github.io/#SCS0007).", + Severity: severity.Medium.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new XmlReaderSettings\(\)`), + regexp.MustCompile(`XmlReader.Create\(.*\)`), + regexp.MustCompile(`new XmlDocument\(.*\)`), + regexp.MustCompile(`Load\(.*\)`), + regexp.MustCompile(`ProhibitDtd = false`), + regexp.MustCompile(`(new XmlReaderSettings\(\))(([^P]|P[^r]|Pr[^o]|Pro[^h]|Proh[^i]|Prohi[^b]|Prohib[^i]|Prohibi[^t]|Prohibit[^D]|ProhibitD[^t]|ProhibitDt[^d])*)(\.Load\(.*\))`), + }, + } +} + +func NewCsharpAndPathTraversal() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "3b905eb5-5af7-41db-a234-38c934f675b2", + Name: "Path Traversal", + Description: "A path traversal attack (also known as directory traversal) aims to access files and directories that are stored outside the expected directory.By manipulating variables that reference files with “dot-dot-slash (../)” sequences and its variations or by using absolute file paths, it may be possible to access arbitrary files and directories stored on file system including application source code or configuration and critical system files. For more information access: (https://security-code-scan.github.io/#SCS0018).", + Severity: severity.Medium.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`ActionResult`), + regexp.MustCompile(`System.IO.File.ReadAllBytes\(Server.MapPath\(.*\) \+ .*\)`), + regexp.MustCompile(`File\(.*, System.Net.Mime.MediaTypeNames.Application.Octet, .*\)`), + }, + } +} + +func NewCsharpAndSQLInjectionWebControls() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "b6f82b7c-f321-4651-8ad3-87fbf5e0412b", + Name: "SQL Injection WebControls", + Description: "Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database. For more information access: (https://security-code-scan.github.io/#SCS0014).", + Severity: severity.High.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`"Select .* From .* where .*" & .*`), + regexp.MustCompile(`System\.Web\.UI\.WebControls\.SqlDataSource | System\.Web\.UI\.WebControls\.SqlDataSourceView | Microsoft\.Whos\.Framework\.Data\.SqlUtility`), + }, + } +} + +func NewCsharpAndWeakCipherOrCBCOrECBMode() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "f9436bdd-8a80-4168-98fa-17af9f8c51b8", + Name: "Weak Cipher Mode", + Description: "The cipher provides no way to detect that the data has been tampered with. If the cipher text can be controlled by an attacker, it could be altered without detection. The use of AES in CBC mode with a HMAC is recommended guaranteeing integrity and confidentiality. For more information access: (https://security-code-scan.github.io/#SCS0013).", + Severity: severity.Medium.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(using)(([^O]|O[^r]|Or[^g]|Org[^.]|Org\.[^B]|Org\.B[^o]|Org\.Bo[^u]|Org\.Bou[^n]|Org\.Boun[^c]|Org\.Bounc[^y]|Org\.Bouncy[^C]|Org\.BouncyC[^a]|Org\.BouncyCa[^s]|Org\.BouncyCas[^t]|Org\.BouncyCast[^l]|Org\.BouncyCastl[^e])*)(\);)`), + regexp.MustCompile(`CreateEncryptor\(.*\)`), + regexp.MustCompile(`new CryptoStream\(.*\)`), + regexp.MustCompile(`Write\(.*\)`), + regexp.MustCompile(`new BinaryWriter\(.*\)`), + }, + } +} + +func NewCsharpAndFormsAuthenticationCookielessMode() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "81f4b46e-164c-478f-ad3a-df263d73c00c", + Name: "Forms Authentication Cookieless Mode", + Description: "Authentication cookies should not be sent in the URL. Doing so allows attackers to gain unauthorized access to authentication tokens (web server logs, referrer headers, and browser history) and more easily perform session fixation / hijacking attacks. For more information checkout the CWE-598 (https://cwe.mitre.org/data/definitions/598.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`\)`), + }, + } +} + +func NewCsharpAndFormsAuthenticationCrossAppRedirects() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "05cd1279-54a7-4770-9527-3ecd6c83b167", + Name: "Forms Authentication Cross App Redirects", + Description: "Enabling cross-application redirects can allow unvalidated redirect attacks via the returnUrl parameter during the login process. Disable cross-application redirects to by setting the enableCrossAppRedirects attribute to false. For more information checkout the CWE-601 (https://cwe.mitre.org/data/definitions/601.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`\ true;`), + }, + } +} + +func NewCsharpAndActionRequestValidationDisabled() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "d70bc47b-19f3-4ae3-b262-b5131993a341", + Name: "Action Request Validation Disabled", + Description: "Request validation performs blacklist input validation for XSS payloads found in form and URL request parameters. Request validation has known bypass issues and does not prevent all XSS attacks, but it does provide a strong countermeasure for most payloads targeting a HTML context. For more information checkout the CWE-20 (https://cwe.mitre.org/data/definitions/20.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(\[HttpGet\(.*\)\]|\[HttpPost\(.*\)\]|\[HttpPut\(.*\)\]|\[HttpDelete\(.*\)\]|\[HttpGet\]|\[HttpPost\]|\[HttpPut\]|\[HttpDelete\])`), + regexp.MustCompile(`\[ValidateInput\(false\)\]`), + }, + } +} + +func NewCsharpAndXmlDocumentExternalEntityExpansion() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "ee650d6d-683a-4b8d-bdb3-c85a74385bf6", + Name: "Xml Document External Entity Expansion", + Description: "XML External Entity (XXE) vulnerabilities occur when applications process untrusted XML data without disabling external entities and DTD processing. Processing untrusted XML data with a vulnerable parser can allow attackers to extract data from the server, perform denial of service attacks, and in some cases gain remote code execution. The XmlDocument class is vulnerable to XXE attacks when setting the XmlResolver property to resolve external entities. To prevent XmlDocument XXE attacks, set the XmlResolver property to null. For more information checkout the CWE-611 (https://cwe.mitre.org/data/definitions/611.html) advisory.", + Severity: severity.High.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new\sXmlDocument`), + regexp.MustCompile(`(XmlResolver)(([^n]|n[^u]|nu[^l]|nul[^l])*)(;)`), + }, + } +} + +func NewCsharpAndLdapInjectionFilterAssignment() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "44fdf2ad-d554-4660-a235-f1b134751d08", + Name: "Ldap Injection Filter Assignment", + Description: "LDAP Injection vulnerabilities occur when untrusted data is concatenated into a LDAP Path or Filter expression without properly escaping control characters. This can allow attackers to change the meaning of an LDAP query and gain access to resources for which they are not authorized. For more information checkout the CWE-90 (https://cwe.mitre.org/data/definitions/90.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new DirectoryEntry\(.*\)`), + regexp.MustCompile(`new DirectorySearcher\(.*\)`), + regexp.MustCompile(`(\.Filter)(([^E]|E[^n]|En[^c]|Enc[^o]|Enco[^d]|Encod[^e]|Encode[^r]|Encoder[^.]|Encoder\.[^L]|Encoder\.L[^d]|Encoder\.Ld[^a]|Encoder\.Lda[^p]|Encoder\.Ldap[^F]|Encoder\.LdapF[^i]|Encoder\.LdapFi[^l]|Encoder\.LdapFil[^t]|Encoder\.LdapFilt[^e]|Encoder\.LdapFilte[^r]|Encoder\.LdapFilter[^E]|Encoder\.LdapFilterE[^n]|Encoder\.LdapFilterEn[^c]|Encoder\.LdapFilterEnc[^o]|Encoder\.LdapFilterEnco[^d]|Encoder\.LdapFilterEncod[^e])*)(\);)`), + }, + } +} + +func NewCsharpAndSqlInjectionDynamicNHibernateQuery() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "de3f01a7-d4cc-4797-861a-224f822418e7", + Name: "Sql Injection: Dynamic NHibernate Query", + Description: "Concatenating untrusted data into a dynamic SQL string and calling vulnerable NHibernate Framework methods can allow SQL Injection. To ensure calls to vulnerable NHibernate Framework methods are parameterized, pass positional or named parameters in the statement. The following NHibernate methods allow for raw SQL queries to be executed: CreateQuery CreateSqlQuery To ensure calls to vulnerable NHibernate methods are parameterized, use named parameters in the raw SQL query. Then, set the named parameter values when executing the query. For more information checkout the CWE-89 (https://cwe.mitre.org/data/definitions/89.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(?i)["|'](SELECT|INSERT|UPDATE|DELETE).*\+`), + regexp.MustCompile(`(CreateQuery\(.*\);)(([^S]|S[^e]|Se[^t]|Set[^S]|SetS[^t]|SetSt[^r]|SetStr[^i]|SetStri[^n]|SetStrin[^g])*)(;)`), + }, + } +} + +func NewCsharpAndLdapInjectionDirectorySearcher() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "25a8b14a-3870-40a6-8960-f71f6c2dcf62", + Name: "Ldap Injection Directory Searcher", + Description: "LDAP Injection vulnerabilities occur when untrusted data is concatenated into a LDAP Path or Filter expression without properly escaping control characters. This can allow attackers to change the meaning of an LDAP query and gain access to resources for which they are not authorized. For more information checkout the CWE-90 (https://cwe.mitre.org/data/definitions/90.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new DirectoryEntry\(.*\)`), + regexp.MustCompile(`(new DirectorySearcher)(([^E]|E[^n]|En[^c]|Enc[^o]|Enco[^d]|Encod[^e]|Encode[^r]|Encoder[^.]|Encoder\.[^L]|Encoder\.L[^d]|Encoder\.Ld[^a]|Encoder\.Lda[^p]|Encoder\.Ldap[^F]|Encoder\.LdapF[^i]|Encoder\.LdapFi[^l]|Encoder\.LdapFil[^t]|Encoder\.LdapFilt[^e]|Encoder\.LdapFilte[^r]|Encoder\.LdapFilter[^E]|Encoder\.LdapFilterE[^n]|Encoder\.LdapFilterEn[^c]|Encoder\.LdapFilterEnc[^o]|Encoder\.LdapFilterEnco[^d]|Encoder\.LdapFilterEncod[^e])*)(\);)`), + }, + } +} + +func NewCsharpAndLdapInjectionPathAssignment() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "75913edd-76d0-4132-8aeb-4b554961732b", + Name: "Ldap Injection Path Assignment", + Description: "LDAP Injection vulnerabilities occur when untrusted data is concatenated into a LDAP Path or Filter expression without properly escaping control characters. This can allow attackers to change the meaning of an LDAP query and gain access to resources for which they are not authorized. For more information checkout the CWE-90 (https://cwe.mitre.org/data/definitions/90.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.AndMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new DirectoryEntry\(\)`), + regexp.MustCompile(`(\.Path)(([^E]|E[^n]|En[^c]|Enc[^o]|Enco[^d]|Encod[^e]|Encode[^r]|Encoder[^.]|Encoder\.[^L]|Encoder\.L[^d]|Encoder\.Ld[^a]|Encoder\.Lda[^p]|Encoder\.Ldap[^D]|Encoder\.LdapD[^i]|Encoder\.LdapDi[^s]|Encoder\.LdapDis[^t]|Encoder\.LdapDist[^i]|Encoder\.LdapDisti[^n]|Encoder\.LdapDistin[^g]|Encoder\.LdapDisting[^u]|Encoder\.LdapDistingu[^i]|Encoder\.LdapDistingui[^s]|Encoder\.LdapDistinguis[^h]|Encoder\.LdapDistinguish[^e]|Encoder\.LdapDistinguishe[^d]|Encoder\.LdapDistinguished[^N]|Encoder\.LdapDistinguishedN[^a]|Encoder\.LdapDistinguishedNa[^m]|Encoder\.LdapDistinguishedNam[^e]|Encoder\.LdapDistinguishedName[^E]|Encoder\.LdapDistinguishedNameE[^n]|Encoder\.LdapDistinguishedNameEn[^c]|Encoder\.LdapDistinguishedNameEnc[^o]|Encoder\.LdapDistinguishedNameEnco[^d]|Encoder\.LdapDistinguishedNameEncod[^e])*)(\);)`), + }, + } +} diff --git a/development-kit/pkg/enums/engine/advisories/csharp/csharp.go b/development-kit/pkg/enums/engine/advisories/csharp/csharp.go new file mode 100644 index 000000000..21214ca28 --- /dev/null +++ b/development-kit/pkg/enums/engine/advisories/csharp/csharp.go @@ -0,0 +1,112 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//nolint:lll multiple regex is not possible broken lines +package csharp + +import ( + "github.com/ZupIT/horusec-engine/text" + "github.com/ZupIT/horusec/development-kit/pkg/enums/engine/advisories/csharp/and" + "github.com/ZupIT/horusec/development-kit/pkg/enums/engine/advisories/csharp/or" + "github.com/ZupIT/horusec/development-kit/pkg/enums/engine/advisories/csharp/regular" +) + +func AllRulesCsharpRegular() []text.TextRule { + return []text.TextRule{ + regular.NewCsharpRegularNoLogSensitiveInformationInConsole(), + regular.NewCsharpRegularOutputCacheConflict(), + regular.NewCsharpRegularOpenRedirect(), + regular.NewCsharpRegularRequestValidationDisabledAttribute(), + regular.NewCsharpRegularRequestValidationDisabledConfigurationFile(), + regular.NewCsharpRegularRequestValidationIsEnabledOnlyForPages(), + regular.NewCsharpRegularViewStateNotEncrypted(), + regular.NewCsharpRegularViewStateMacDisabled(), + regular.NewCsharpRegularSQLInjectionOLEDB(), + regular.NewCsharpRegularSQLInjectionMsSQLDataProvider(), + regular.NewCsharpRegularSQLInjectionEntityFramework(), + regular.NewCsharpRegularSQLInjectionNhibernate(), + regular.NewCsharpRegularSQLInjectionNpgsql(), + regular.NewCsharpRegularCertificateValidationDisabled(), + regular.NewCsharpRegularWeakCipherAlgorithm(), + regular.NewCsharpRegularNoUseHtmlRaw(), + regular.NewCsharpRegularNoLogSensitiveInformation(), + regular.NewCsharpRegularNoReturnStringConcatInController(), + regular.NewCsharpRegularSQLInjectionOdbcCommand(), + regular.NewCsharpRegularWeakHashingFunctionMd5OrSha1(), + regular.NewCsharpRegularWeakHashingFunctionDESCrypto(), + regular.NewCsharpRegularNoUseCipherMode(), + regular.NewCsharpRegularDebugBuildEnabled(), + regular.NewCsharpRegularVulnerablePackageReference(), + regular.NewCsharpRegularCorsAllowOriginWildCard(), + regular.NewCsharpRegularMissingAntiForgeryTokenAttribute(), + regular.NewCsharpRegularUnvalidatedWebFormsRedirect(), + regular.NewCsharpRegularIdentityPasswordLockoutDisabled(), + regular.NewCsharpRegularRawInlineExpression(), + regular.NewCsharpRegularRawBindingExpression(), + regular.NewCsharpRegularRawWriteLiteralMethod(), + regular.NewCsharpRegularUnencodedWebFormsProperty(), + regular.NewCsharpRegularUnencodedLabelText(), + regular.NewCsharpRegularWeakRandomNumberGenerator(), + regular.NewCsharpRegularWeakRsaKeyLength(), + regular.NewCsharpRegularXmlReaderExternalEntityExpansion(), + regular.NewCsharpRegularLdapInjectionDirectoryEntry(), + } +} + +func AllRulesCsharpAnd() []text.TextRule { + return []text.TextRule{ + and.NewCsharpAndCommandInjection(), + and.NewCsharpAndXPathInjection(), + and.NewCsharpAndExternalEntityInjection(), + and.NewCsharpAndPathTraversal(), + and.NewCsharpAndSQLInjectionWebControls(), + and.NewCsharpAndFormsAuthenticationCookielessMode(), + and.NewCsharpAndFormsAuthenticationWeakCookieProtection(), + and.NewCsharpAndFormsAuthenticationCrossAppRedirects(), + and.NewCsharpAndWeakCipherOrCBCOrECBMode(), + and.NewCsharpAndFormsAuthenticationWeakTimeout(), + and.NewCsharpAndHeaderCheckingDisabled(), + and.NewCsharpAndVersionHeaderEnabled(), + and.NewCsharpAndEventValidationDisabled(), + and.NewCsharpAndWeakSessionTimeout(), + and.NewCsharpAndStateServerMode(), + and.NewCsharpAndJwtSignatureValidationDisabled(), + and.NewCsharpAndInsecureHttpCookieTransport(), + and.NewCsharpAndHttpCookieAccessibleViaScript(), + and.NewCsharpAndDirectoryListingEnabled(), + and.NewCsharpAndLdapAuthenticationDisabled(), + and.NewCsharpAndCertificateValidationDisabled(), + and.NewCsharpAndActionRequestValidationDisabled(), + and.NewCsharpAndXmlDocumentExternalEntityExpansion(), + and.NewCsharpAndLdapInjectionFilterAssignment(), + and.NewCsharpAndSqlInjectionDynamicNHibernateQuery(), + and.NewCsharpAndLdapInjectionDirectorySearcher(), + and.NewCsharpAndLdapInjectionPathAssignment(), + } +} + +func AllRulesCsharpOr() []text.TextRule { + return []text.TextRule{ + or.NewCsharpOrLDAPInjection(), + or.NewCsharpOrSQLInjectionLinq(), + or.NewCsharpOrInsecureDeserialization(), + or.NewCsharpOrCookieWithoutSSLFlag(), + or.NewCsharpOrCookieWithoutHttpOnlyFlag(), + or.NewCsharpOrSQLInjectionEnterpriseLibraryData(), + or.NewCsharpOrCQLInjectionCassandra(), + or.NewCsharpOrPasswordComplexity(), + or.NewCsharpOrNoInputVariable(), + or.NewCsharpOrIdentityWeakPasswordComplexity(), + } +} diff --git a/development-kit/pkg/enums/engine/advisories/csharp/csharp_test.go b/development-kit/pkg/enums/engine/advisories/csharp/csharp_test.go new file mode 100644 index 000000000..849b3aaa5 --- /dev/null +++ b/development-kit/pkg/enums/engine/advisories/csharp/csharp_test.go @@ -0,0 +1,45 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package csharp + +import ( + "fmt" + "github.com/ZupIT/horusec-engine/text" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestRulesEnum(t *testing.T) { + var totalRules []text.TextRule + totalRules = append(totalRules, AllRulesCsharpOr()...) + totalRules = append(totalRules, AllRulesCsharpAnd()...) + totalRules = append(totalRules, AllRulesCsharpRegular()...) + lenExpectedTotalRules := 74 + t.Run("Should not exists duplicated ID in rules and return lenExpectedTotalRules in csharp", func(t *testing.T) { + encountered := map[string]bool{} + + for v := range totalRules { + if encountered[totalRules[v].ID] == true { + msg := fmt.Sprintf("This rules in Csharp is duplicated ID(%s) => Name: %s, Description: %s, Type: %v", totalRules[v].ID, totalRules[v].Name, totalRules[v].Description, totalRules[v].Type) + assert.False(t, encountered[totalRules[v].ID], msg) + } else { + // Record this element as an encountered element. + encountered[totalRules[v].ID] = true + } + } + assert.Equal(t, len(totalRules), lenExpectedTotalRules, "totalRules in csharp is not equal the expected") + assert.Equal(t, len(encountered), lenExpectedTotalRules, "encountered in csharp is not equal the expected") + }) +} diff --git a/development-kit/pkg/enums/engine/advisories/csharp/or/or.go b/development-kit/pkg/enums/engine/advisories/csharp/or/or.go new file mode 100644 index 000000000..493bbba68 --- /dev/null +++ b/development-kit/pkg/enums/engine/advisories/csharp/or/or.go @@ -0,0 +1,204 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//nolint:lll multiple regex is not possible broken lines +package or + +import ( + engine "github.com/ZupIT/horusec-engine" + "github.com/ZupIT/horusec-engine/text" + "github.com/ZupIT/horusec/development-kit/pkg/enums/confidence" + "github.com/ZupIT/horusec/development-kit/pkg/enums/severity" + "regexp" +) + +func NewCsharpOrLDAPInjection() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "236724c0-482a-47f4-ba10-7ae14f47fd7b", + Name: "LDAP Injection", + Description: "The dynamic value passed to the LDAP query should be validated. For more information access: (https://security-code-scan.github.io/#SCS0031).", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(new DirectorySearcher\(\))(([^E]|E[^n]|En[^c]|Enc[^o]|Enco[^d]|Encod[^e]|Encode[^r]|Encoder[^.]|Encoder\.[^L]|Encoder\.L[^d]|Encoder\.Ld[^a]|Encoder\.Lda[^p]|Encoder\.Ldap[^F]|Encoder\.LdapF[^i]|Encoder\.LdapFi[^l]|Encoder\.LdapFil[^t]|Encoder\.LdapFilt[^e]|Encoder\.LdapFilte[^r]|Encoder\.LdapFilter[^E]|Encoder\.LdapFilterE[^n]|Encoder\.LdapFilterEn[^c]|Encoder\.LdapFilterEnc[^o]|Encoder\.LdapFilterEnco[^d]|Encoder\.LdapFilterEncod[^e])*)(\)";)`), + regexp.MustCompile(`(new DirectoryEntry\(\))(([^E]|E[^n]|En[^c]|Enc[^o]|Enco[^d]|Encod[^e]|Encode[^r]|Encoder[^.]|Encoder\.[^L]|Encoder\.L[^d]|Encoder\.Ld[^a]|Encoder\.Lda[^p]|Encoder\.Ldap[^D]|Encoder\.LdapD[^i]|Encoder\.LdapDi[^s]|Encoder\.LdapDis[^t]|Encoder\.LdapDist[^i]|Encoder\.LdapDisti[^n]|Encoder\.LdapDistin[^g]|Encoder\.LdapDisting[^u]|Encoder\.LdapDistingu[^i]|Encoder\.LdapDistingui[^s]|Encoder\.LdapDistinguis[^h]|Encoder\.LdapDistinguish[^e]|Encoder\.LdapDistinguishe[^d]|Encoder\.LdapDistinguished[^N]|Encoder\.LdapDistinguishedN[^a]|Encoder\.LdapDistinguishedNa[^m]|Encoder\.LdapDistinguishedNam[^e]|Encoder\.LdapDistinguishedName[^E]|Encoder\.LdapDistinguishedNameE[^n]|Encoder\.LdapDistinguishedNameEn[^c]|Encoder\.LdapDistinguishedNameEnc[^o]|Encoder\.LdapDistinguishedNameEnco[^d]|Encoder\.LdapDistinguishedNameEncod[^e])*)(,.*";)`), + }, + } +} + +func NewCsharpOrSQLInjectionLinq() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "32fbdff3-2092-4d42-90a2-784842bebfd0", + Name: "SQL Injection LINQ", + Description: "Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database.. For more information access: (https://security-code-scan.github.io/#SCS0002).", + Severity: severity.High.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`ExecuteQuery\(.*SELECT .* FROM .* WHERE .* \+ .* \+ .*\)`), + regexp.MustCompile(`var .* = "SELECT .* FROM .* WHERE .* \+ .* \+ .*"`), + }, + } +} + +func NewCsharpOrInsecureDeserialization() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "a5a1dcad-76e7-4d9d-afe4-0dba1bcca105", + Name: "Insecure Deserialization", + Description: "Arbitrary code execution, full application compromise or denial of service. An attacker may pass specially crafted serialized .NET object of specific class that will execute malicious code during the construction of the object. For more information access: (https://security-code-scan.github.io/#SCS0028).", + Severity: severity.Low.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new\sBinaryFormatter\(\)\.Deserialize\(.*\)`), + regexp.MustCompile(`new\sJavaScriptSerializer\(..*\)`), + }, + } +} + +func NewCsharpOrSQLInjectionEnterpriseLibraryData() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "0ea39e22-de31-4888-9348-58f4170755fd", + Name: "SQL Injection Enterprise Library Data", + Description: "Arbitrary code execution, full application compromise or denial of service. An attacker may pass specially crafted serialized .NET object of specific class that will execute malicious code during the construction of the object. For more information access: (https://security-code-scan.github.io/#SCS0036).", + Severity: severity.High.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(GetSqlStringCommand\(.*\))(([^A]|A[^d]|Ad[^d]|Add[^I]|AddI[^n]|AddIn[^P]|AddInP[^a]|AddInPa[^r]|AddInPar[^a]|AddInPara[^m]|AddInParam[^e]|AddInParame[^t]|AddInParamet[^e]|AddInParamete[^r])*)(ExecuteDataSet\(.*\))`), + regexp.MustCompile(`ExecuteDataSet\(CommandType.*, "(SELECT|select).*(FROM|from).*(WHERE|where).*"\)`), + }, + } +} + +func NewCsharpOrCQLInjectionCassandra() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "56dbcac5-f61b-4ad0-bcf3-214bca83b172", + Name: "CQL Injection Cassandra", + Description: "Arbitrary code execution, full application compromise or denial of service. An attacker may pass specially crafted serialized .NET object of specific class that will execute malicious code during the construction of the object. For more information access: (https://security-code-scan.github.io/#SCS0038).", + Severity: severity.High.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(Prepare\("(SELECT|select).*(FROM|from).*(WHERE|where).*\))(([^B]|B[^i]|Bi[^n]|Bin[^d])*)(Execute\(.*\))`), + regexp.MustCompile(`Execute\("(SELECT|select).*(FROM|from).*(WHERE|where).*"\)`), + }, + } +} + +func NewCsharpOrPasswordComplexity() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "9027bece-7a6f-4e6e-b7e5-5dbbe0870562", + Name: "Password Complexity", + Description: "PasswordValidator should have at least two requirements for better security, the RequiredLength property must be set with a minimum value of 8. For more information access: (https://security-code-scan.github.io/#SCS0027).", + Severity: severity.Low.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new\sPasswordValidator\(\)`), + regexp.MustCompile(`new\sPasswordValidator(\n?\s*{)(\n*.*=.*,?)(\s|\n)*[^a-z]}`), + regexp.MustCompile(`new\sPasswordValidator(\n?\s*{)((\n|.*)*RequiredLength=[0-7][^\d])`), + regexp.MustCompile(`(new\sPasswordValidator)(([^R]|R[^e]|Re[^q]|Req[^u]|Requ[^i]|Requi[^r]|Requir[^e]|Require[^d]|Required[^L]|RequiredL[^e]|RequiredLe[^n]|RequiredLen[^g]|RequiredLeng[^t]|RequiredLengt[^h])*)(})`), + }, + } +} + +func NewCsharpOrCookieWithoutSSLFlag() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "c3c93cc6-f010-42fa-9e13-34dbaf33b852", + Name: "Cookie Without SSL Flag", + Description: "It is recommended to specify the Secure flag to new cookie. The Secure flag is a directive to the browser to make sure that the cookie is not sent by unencrypted channel. For more information access: (https://security-code-scan.github.io/#SCS0008) and (https://cwe.mitre.org/data/definitions/614.html).", + Severity: severity.Low.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`requireSSL\s*=\s*['|"]false['|"]`), + regexp.MustCompile(`(\)`), + regexp.MustCompile(`(new\sHttpCookie\(.*\))(.*|\n)*(\.Secure\s*=\s*false)`), + regexp.MustCompile(`(new\sHttpCookie)(([^S]|S[^e]|Se[^c]|Sec[^u]|Secu[^r]|Secur[^e])*)(})`), + }, + } +} + +func NewCsharpOrCookieWithoutHttpOnlyFlag() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "837c504d-38b4-4ea6-987b-d91e92ac86a2", + Name: "Cookie Without HttpOnly Flag", + Description: "It is recommended to specify the HttpOnly flag to new cookie. For more information access: (https://security-code-scan.github.io/#SCS0009) or (https://cwe.mitre.org/data/definitions/1004.html).", + Severity: severity.Low.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`httpOnlyCookies\s*=\s*['|"]false['|"]`), + regexp.MustCompile(`(new\sHttpCookie\(.*\))(.*|\n)*(\.HttpOnly\s*=\s*false)`), + regexp.MustCompile(`(new\sHttpCookie)(([^H]|H[^t]|Ht[^t]|Htt[^p]|Http[^O]|HttpO[^n]|HttpOn[^l]|HttpOnl[^y])*)(})`), + }, + } +} + +func NewCsharpOrNoInputVariable() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "d5f46985-1527-47b0-a5c1-71c9ab121cf7", + Name: "No input variable", + Description: "The application appears to allow XSS through an unencrypted / unauthorized input variable. https://owasp.org/www-community/attacks/xss/. For more information checkout the CWE-79 (https://cwe.mitre.org/data/definitions/79.html) advisory.", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`\s*var\s+\w+\s*=\s*"\s*\<\%\s*=\s*\w+\%\>";`), + regexp.MustCompile(`\.innerHTML\s*=\s*.+`), + }, + } +} + +func NewCsharpOrIdentityWeakPasswordComplexity() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "928962a4-0e8c-494d-9e96-771ca9b4863f", + Name: "Identity Weak Password Complexity", + Description: "Weak passwords can allow attackers to easily guess user passwords using wordlist or brute force attacks. Enforcing a strict password complexity policy mitigates these attacks by significantly increasing the time to guess a user’s valid password. For more information checkout the CWE-521 (https://cwe.mitre.org/data/definitions/521.html) advisory.", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new PasswordValidator\(\)`), + regexp.MustCompile(`RequiredLength = \b([0-7])\b`), + regexp.MustCompile(`(new PasswordValidator)(([^R]|R[^e]|Re[^q]|Req[^u]|Requ[^i]|Requi[^r]|Requir[^e]|Require[^d]|Required[^L]|RequiredL[^e]|RequiredLe[^n]|RequiredLen[^g]|RequiredLeng[^t]|RequiredLengt[^h])*)(};)`), + regexp.MustCompile(`(new PasswordValidator)(([^R]|R[^e]|Re[^q]|Req[^u]|Requ[^i]|Requi[^r]|Requir[^e]|Require[^D]|RequireD[^i]|RequireDi[^g]|RequireDig[^i]|RequireDigi[^t]|RequireDigit[^ ]|RequireDigit [^=]|RequireDigit =[^ ]|RequireDigit = [^t]|RequireDigit = t[^r]|RequireDigit = tr[^u]|RequireDigit = tru[^e])*)(};)`), + regexp.MustCompile(`(new PasswordValidator)(([^R]|R[^e]|Re[^q]|Req[^u]|Requ[^i]|Requi[^r]|Requir[^e]|Require[^L]|RequireL[^o]|RequireLo[^w]|RequireLow[^e]|RequireLowe[^r]|RequireLower[^c]|RequireLowerc[^a]|RequireLowerca[^s]|RequireLowercas[^e]|RequireLowercase[^ ]|RequireLowercase [^=]|RequireLowercase =[^ ]|RequireLowercase = [^t]|RequireLowercase = t[^r]|RequireLowercase = tr[^u]|RequireLowercase = tru[^e])*)(};)`), + regexp.MustCompile(`(new PasswordValidator)(([^R]|R[^e]|Re[^q]|Req[^u]|Requ[^i]|Requi[^r]|Requir[^e]|Require[^N]|RequireN[^o]|RequireNo[^n]|RequireNon[^L]|RequireNonL[^e]|RequireNonLe[^t]|RequireNonLet[^t]|RequireNonLett[^e]|RequireNonLette[^r]|RequireNonLetter[^O]|RequireNonLetterO[^r]|RequireNonLetterOr[^D]|RequireNonLetterOrD[^i]|RequireNonLetterOrDi[^g]|RequireNonLetterOrDig[^i]|RequireNonLetterOrDigi[^t]|RequireNonLetterOrDigit[^ ]|RequireNonLetterOrDigit [^=]|RequireNonLetterOrDigit =[^ ]|RequireNonLetterOrDigit = [^t]|RequireNonLetterOrDigit = t[^r]|RequireNonLetterOrDigit = tr[^u]|RequireNonLetterOrDigit = tru[^e])*)(};)`), + regexp.MustCompile(`(new PasswordValidator)(([^R]|R[^e]|Re[^q]|Req[^u]|Requ[^i]|Requi[^r]|Requir[^e]|Require[^U]|RequireU[^p]|RequireUp[^p]|RequireUpp[^e]|RequireUppe[^r]|RequireUpper[^c]|RequireUpper[^c]|RequireUpperc[^a]|RequireUpperca[^s]|RequireUppercas[^e]|RequireUppercase[^ ]|RequireUppercase [^=]|RequireUppercase =[^ ]|RequireUppercase = [^t]|RequireUppercase = t[^r]|RequireUppercase = tr[^u]|RequireUppercase = tru[^e])*)(};)`), + }, + } +} diff --git a/development-kit/pkg/enums/engine/advisories/csharp/regular/regular.go b/development-kit/pkg/enums/engine/advisories/csharp/regular/regular.go new file mode 100644 index 000000000..9c849eed7 --- /dev/null +++ b/development-kit/pkg/enums/engine/advisories/csharp/regular/regular.go @@ -0,0 +1,624 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//nolint:lll multiple regex is not possible broken lines +package regular + +import ( + "regexp" + + engine "github.com/ZupIT/horusec-engine" + "github.com/ZupIT/horusec-engine/text" + "github.com/ZupIT/horusec/development-kit/pkg/enums/confidence" + "github.com/ZupIT/horusec/development-kit/pkg/enums/severity" +) + +func NewCsharpRegularNoLogSensitiveInformationInConsole() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "71755d83-d536-4839-8997-6b611b319678", + Name: "No Log Sensitive Information in console", + Description: "The App logs information. Sensitive information should never be logged. For more information checkout the CWE-532 (https://cwe.mitre.org/data/definitions/532.html) advisory.", + Severity: severity.Info.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`((Log|log).*\.(V|D|I|W|E|F|S))|(Console.Write)`), + }, + } +} + +func NewCsharpRegularOutputCacheConflict() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "5fc0eefc-31b3-4d07-8d97-37834aff963e", + Name: "OutputCache Conflict", + Description: "Having the annotation [OutputCache] will disable the annotation [Authorize] for the requests following the first one. For more information access: (https://security-code-scan.github.io/#SCS0019).", + Severity: severity.Medium.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(\[Authorize\])(.*|\n)*(\[OutputCache\])`), + }, + } +} + +func NewCsharpRegularOpenRedirect() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "eb1e2fb1-38f0-419f-b6f8-d9dd78d9cb6d", + Name: "Open Redirect", + Description: "Your site may be used in phishing attacks. An attacker may craft a trustworthy looking link to your site redirecting a victim to a similar looking malicious site: 'http://yourdomain.com?redirect=https://urdomain.com/login'. For more information access: (https://security-code-scan.github.io/#SCS0027).", + Severity: severity.Low.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`String.IsNullOrEmpty.*\n?.*{?\n?.*return\sRedirect\(.*\);`), + }, + } +} + +func NewCsharpRegularRequestValidationDisabledAttribute() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "bd2e5131-5afa-4063-a303-7d5cb2696265", + Name: "Request Validation Disabled (Attribute)", + Description: "Request validation is disabled. Request validation allows the filtering of some XSS patterns submitted to the application. For more information access: (https://security-code-scan.github.io/#SCS0017).", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`\[ValidateInput\(false\)\]`), + }, + } +} + +func NewCsharpRegularSQLInjectionOLEDB() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "2586df5f-1302-48b7-b5ab-780bccf16963", + Name: "SQL Injection OLE DB", + Description: "Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database. For more information access: (https://security-code-scan.github.io/#SCS0020).", + Severity: severity.High.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(new OleDbConnection\(.*\))(([^P]|P[^a]|Pa[^r]|Par[^a]|Para[^m]|Param[^e]|Parame[^t]|Paramet[^e]|Paramete[^r]|Parameter[^s]|Parameters[^.]|Parameters\.[^A]|Parameters\.A[^d]|Parameters\.Ad[^d])*)(\.ExecuteReader\(.*\))`), + }, + } +} + +func NewCsharpRegularRequestValidationDisabledConfigurationFile() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "055817b7-8a0c-4024-b170-e96ad4fe32a0", + Name: "Request Validation Disabled (Configuration File)", + Description: "The validateRequest which provides additional protection against XSS is disabled in configuration file. For more information access: (https://security-code-scan.github.io/#SCS0017) or (https://cwe.mitre.org/data/definitions/20.html).", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`validateRequest\s*=\s*['|"]false['|"]`), + }, + } +} + +func NewCsharpRegularSQLInjectionMsSQLDataProvider() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "c418d2d0-1a99-4f44-8e22-8af3c56a3f60", + Name: "SQL Injection MsSQL Data Provider", + Description: "Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database. For more information access: (https://security-code-scan.github.io/#SCS0026).", + Severity: severity.High.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(new SqlCommand\(.*\))(([^P]|P[^a]|Pa[^r]|Par[^a]|Para[^m]|Param[^e]|Parame[^t]|Paramet[^e]|Paramete[^r]|Parameter[^s]|Parameters[^.]|Parameters\.[^A]|Parameters\.A[^d]|Parameters\.Ad[^d]|Parameters\.Add[^W]|Parameters\.AddW[^i]|Parameters\.AddWi[^t]|Parameters\.AddWit[^h]|Parameters\.AddWith[^V]|Parameters\.AddWithV[^a]|Parameters\.AddWithVa[^l]|Parameters\.AddWithVal[^u]|Parameters\.AddWithValu[^e])*)(Open\(\)|ExecuteReader\(\))`), + }, + } +} + +func NewCsharpRegularRequestValidationIsEnabledOnlyForPages() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "54a8ac1a-83df-4d7d-97de-e0901080b451", + Name: "Request validation is enabled only for pages", + Description: "The requestValidationMode which provides additional protection against XSS is enabled only for pages, not for all HTTP requests in configuration file. For more information access: (https://security-code-scan.github.io/#SCS0030).", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`requestValidationMode\s*=\s*['|"][0-3][^\d].*['|"]`), + }, + } +} + +func NewCsharpRegularSQLInjectionEntityFramework() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "ae6164f0-e336-4fd1-9337-1214afe24972", + Name: "SQL Injection Entity Framework", + Description: "Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database, please use SqlParameter to create query with parameters. For more information access: (https://security-code-scan.github.io/#SCS0035) or (https://cwe.mitre.org/data/definitions/89.html) .", + Severity: severity.High.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(Database\.ExecuteSqlCommand)(([^S]|S[^q]|Sq[^l]|Sql[^P]|SqlP[^a]|SqlPa[^r]|SqlPar[^a]|SqlPara[^m]|SqlParam[^e]|SqlParame[^t]|SqlParamet[^e]|SqlParamete[^r])*)(\);)`), + }, + } +} + +func NewCsharpRegularViewStateNotEncrypted() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "25926a6c-b546-482d-81ee-8d82cd6919d5", + Name: "View State Not Encrypted", + Description: "The viewStateEncryptionMode is not set to Always in configuration file. Web Forms controls use hidden base64 encoded fields to store state information. If sensitive information is stored there it may be leaked to the client side. For more information access: (https://security-code-scan.github.io/#SCS0023) or (https://cwe.mitre.org/data/definitions/200.html).", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`viewStateEncryptionMode\s*=\s*['|"](Auto|Never)['|"]`), + }, + } +} + +func NewCsharpRegularSQLInjectionNhibernate() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "5c53c81e-5125-45a1-8b2c-bfa2b50a9cc5", + Name: "SQL Injection Nhibernate", + Description: "Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database. For more information access: (https://security-code-scan.github.io/#SCS0037).", + Severity: severity.High.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(CreateSQLQuery)(([^S]|S[^e]|Se[^t]|Set[^P]|SetP[^a]|SetPa[^r]|SetPar[^a]|SetPara[^m]|SetParam[^e]|SetParame[^t]|SetParamet[^e]|SetParamete[^r])*)(\);)`), + }, + } +} + +func NewCsharpRegularViewStateMacDisabled() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "cbd6b77e-b4d5-4507-8835-3262faf669e4", + Name: "View State MAC Disabled", + Description: "The enableViewStateMac is disabled in configuration file. (This feature cannot be disabled starting .NET 4.5.1). The view state could be altered by an attacker. For more information access: (https://security-code-scan.github.io/#SCS0024) or (https://cwe.mitre.org/data/definitions/807.html).", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`enableViewStateMac\s*=\s*['|"]false['|"]`), + }, + } +} + +func NewCsharpRegularSQLInjectionNpgsql() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "4a5d6ab4-ee09-4b39-b6b5-1f485c15e041", + Name: "SQL Injection Npgsql", + Description: "Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database. For more information access: (https://security-code-scan.github.io/#SCS0039).", + Severity: severity.High.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(NpgsqlCommand\(.*\))(([^P]|P[^a]|Pa[^r]|Par[^a]|Para[^m]|Param[^e]|Parame[^t]|Paramet[^e]|Paramete[^r]|Parameter[^s]|Parameters[^.]|Parameters\.[^A]|Parameters\.A[^d]|Parameters\.Ad[^d]|Parameters\.Add[^W]|Parameters\.AddW[^i]|Parameters\.AddWi[^t]|Parameters\.AddWit[^h]|Parameters\.AddWith[^V]|Parameters\.AddWithV[^a]|Parameters\.AddWithVa[^l]|Parameters\.AddWithVal[^u]|Parameters\.AddWithValu[^e])*)(ExecuteNonQuery\(.*\)|ExecuteReader\(.*\))`), + }, + } +} + +func NewCsharpRegularCertificateValidationDisabled() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "c83a6f75-898e-4621-be87-b9ef0ce85ce7", + Name: "Certificate Validation Disabled", + Description: "Disabling certificate validation is often used to connect easily to a host that is not signed by a root certificate authority. As a consequence, this is vulnerable to Man-in-the-middle attacks since the client will trust any certificate. For more information access: (https://security-code-scan.github.io/#SCS0004).", + Severity: severity.Medium.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`ServicePointManager\.ServerCertificateValidationCallback \+= (.*) => true;`), + }, + } +} + +func NewCsharpRegularWeakCipherAlgorithm() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "654e89b5-714c-4006-bd08-345c60e5ce00", + Name: "Weak cipher algorithm", + Description: "Broken or deprecated ciphers have typically known weakness. A attacker might be able to brute force the secret key use for the encryption. The confidentiality and integrity of the information encrypted is at risk. For more information access: (https://security-code-scan.github.io/#SCS0010).", + Severity: severity.Medium.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(DES.Create\(\))(([^A]|A[^e]|Ae[^s]|Aes[^M]|AesM[^a]|AesMa[^n]|AesMan[^a]|AesMana[^g]|AesManag[^e]|AesManage[^d])*)(Write\(.*\))`), + }, + } +} + +func NewCsharpRegularNoUseHtmlRaw() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "e9527806-0f8e-4e9b-903c-549e1840b24a", + Name: "No use Html.Raw", + Description: "The application uses the potentially dangerous Html.Raw construct in conjunction with a user-supplied variable. The recommendation is to avoid using HTML assembly, but if it is extremely necessary to allow Html, we suggest the following: support only a fixed subset of Html, after the user submits content, analyze the Html and filter it in a whitelist of allowed tags and attributes. For more information checkout the CWE-79 (https://cwe.mitre.org/data/definitions/79.html) advisory.", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`Html\.Raw\(`), + }, + } +} + +func NewCsharpRegularNoLogSensitiveInformation() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "2da09ea2-b2bb-4ee6-8ec7-f3b390fdec7f", + Name: "No log sensitive information debug mode", + Description: "The application is configured to display standard .NET errors. This can provide the attacker with useful information and should not be used in a production application. https://docs.microsoft.com/en-us/aspnet/web-forms/overview/older-versions-getting-started/deploying-web-site-projects/displaying-a-custom-error-page-cs. For more information checkout the CWE-12 (https://cwe.mitre.org/data/definitions/12.html) advisory.", + Severity: severity.Low.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`<\s*customErrors\s+mode\s*=\s*\"Off\"\s*/?>`), + }, + } +} + +func NewCsharpRegularNoReturnStringConcatInController() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "b9b63a1c-33b3-43e5-82ce-aed6a58fb2fd", + Name: "No return string concat in controller", + Description: "A potential Cross-Site Scripting (XSS) was found. The endpoint returns a variable from the client entry that has not been coded. Always encode untrusted input before output, regardless of validation or cleaning performed. https://docs.microsoft.com/en-us/aspnet/core/security/cross-site-scripting?view=aspnetcore-3.1. For more information checkout the CWE-79 (https://cwe.mitre.org/data/definitions/79.html) advisory.", + Severity: severity.Low.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(?:public\sclass\s.*Controller|.*\s+:\s+Controller)(?:\n*.*)*return\s+.*\".*\+`), + }, + } +} + +func NewCsharpRegularSQLInjectionOdbcCommand() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "192e60ba-5454-4399-bbe3-8c4e75845a16", + Name: "SQL Injection OdbcCommand", + Description: "Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database. For more information checkout the CWE-79 (https://cwe.mitre.org/data/definitions/79.html) advisory.", + Severity: severity.High.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`.*\s*new\sOdbcCommand\(.*\".*\+(?:.*\n*)*.ExecuteReader\(`), + }, + } +} + +func NewCsharpRegularWeakHashingFunctionMd5OrSha1() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "263e1cb3-31ee-443e-80e0-31f81bbfb340", + Name: "Weak hashing function md5 or sha1", + Description: "MD5 or SHA1 have known collision weaknesses and are no longer considered strong hashing algorithms. For more information checkout the CWE-326 (https://cwe.mitre.org/data/definitions/326.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new\sSHA1CryptoServiceProvider\(`), + regexp.MustCompile(`new\sMD5CryptoServiceProvider\(`), + }, + } +} + +func NewCsharpRegularWeakHashingFunctionDESCrypto() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "6ba6bebf-3626-4645-b2c7-f8e169e8db3d", + Name: "Weak hashing function DES Crypto", + Description: "DES Crypto have known collision weaknesses and are no longer considered strong hashing algorithms. For more information checkout the CWE-326 (https://cwe.mitre.org/data/definitions/326.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new\sTripleDESCryptoServiceProvider\(`), + regexp.MustCompile(`new\sDESCryptoServiceProvider\(`), + regexp.MustCompile(`TripleDES\.Create\(`), + regexp.MustCompile(`DES\.Create\(`), + }, + } +} + +func NewCsharpRegularNoUseCipherMode() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "1faf6a8f-94fe-4eed-a60c-4a4317b4bd25", + Name: "No Use Cipher mode", + Description: "This mode is not recommended because it opens the door to various security exploits. If the plain text to be encrypted contains substantial repetitions, it is possible that the cipher text will be broken one block at a time. You can also use block analysis to determine the encryption key. In addition, an active opponent can replace and exchange individual blocks without detection, which allows the blocks to be saved and inserted into the stream at other points without detection. ECB and OFB mode will produce the same result for identical blocks. The use of AES in CBC mode with an HMAC is recommended, ensuring integrity and confidentiality. https://docs.microsoft.com/en-us/visualstudio/code-quality/ca5358?view=vs-2019. For more information checkout the CWE-326 (https://cwe.mitre.org/data/definitions/326.html) and CWE-327 (https://cwe.mitre.org/data/definitions/327.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`CipherMode\.ECB`), + regexp.MustCompile(`CipherMode\.OFB`), + regexp.MustCompile(`CipherMode\.CTS`), + regexp.MustCompile(`CipherMode\.CFB`), + }, + } +} + +func NewCsharpRegularDebugBuildEnabled() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "e4c52f0d-abdb-4958-9e85-e7d34caf7e99", + Name: "Debug Build Enabled", + Description: "Binaries compiled in debug mode can leak detailed stack traces and debugging messages to attackers. Disable debug builds by setting the debug attribute to false. For more information checkout the CWE-11 (https://cwe.mitre.org/data/definitions/11.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`\`), + }, + } +} + +func NewCsharpRegularCorsAllowOriginWildCard() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "6fa83684-e29d-44a8-ac20-bdd955d45363", + Name: "Cors Allow Origin Wild Card", + Description: "Cross-Origin Resource Sharing (CORS) allows a service to disable the browser’s Same-origin policy, which prevents scripts on an attacker-controlled domain from accessing resources and data hosted on a different domain. The CORS Access-Control-Allow-Origin HTTP header specifies the domain with permission to invoke a cross-origin service and view the response data. Configuring the Access-Control-Allow-Origin header with a wildcard (*) can allow code running on an attacker-controlled domain to view responses containing sensitive data. For more information checkout the CWE-942 (https://cwe.mitre.org/data/definitions/942.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`app\.UseCors\(builder => builder\.AllowAnyOrigin\(\)\);`), + }, + } +} + +func NewCsharpRegularMissingAntiForgeryTokenAttribute() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "21debfa9-f639-4af2-bc33-b1399fc24a89", + Name: "Missing Anti Forgery Token Attribute", + Description: "Cross Site Request Forgery attacks occur when a victim authenticates to a target web site and then visits a malicious web page. The malicious web page then sends a fake HTTP request (GET, POST, etc.) back to the target website. The victim’s valid authentication cookie from the target web site is automatically included in the malicious request, sent to the target web site, and processed as a valid transaction under the victim’s identity. For more information checkout the CWE-352 (https://cwe.mitre.org/data/definitions/352.html) advisory.", + Severity: severity.Info.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(\[HttpGet\]|\[HttpPost\]|\[HttpPut\]|\[HttpDelete\])(([^V]|V[^a]|Va[^l]|Val[^i]|Vali[^d]|Valid[^a]|Valida[^t]|Validat[^e]|Validate[^A]|ValidateA[^n]|ValidateAn[^t]|ValidateAnt[^i]|ValidateAnti[^F]|ValidateAntiF[^o]|ValidateAntiFo[^r]|ValidateAntiFor[^g]|ValidateAntiForg[^e]|ValidateAntiForge[^r]|ValidateAntiForger[^y]|ValidateAntiForgery[^T]|ValidateAntiForgeryT[^o]|ValidateAntiForgeryTo[^k]|ValidateAntiForgeryTok[^e]|ValidateAntiForgeryToke[^n])*)(ActionResult)`), + }, + } +} + +func NewCsharpRegularUnvalidatedWebFormsRedirect() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "fa1a798e-b43f-43d1-8e13-2d53039e79ce", + Name: "Unvalidated Web Forms Redirect", + Description: "Passing unvalidated redirect locations to the Response.Redirect method can allow attackers to send users to malicious web sites. This can allow attackers to perform phishing attacks and distribute malware to victims. For more information checkout the CWE-601 (https://cwe.mitre.org/data/definitions/601.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Low.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`Response\.Redirect\(Request\.QueryString\[".*"\]\)`), + }, + } +} + +func NewCsharpRegularIdentityPasswordLockoutDisabled() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "ab6aa12f-362c-4be2-8a5b-0e37b4b0d7a1", + Name: "Identity Password Lockout Disabled", + Description: "Password lockout mechanisms help prevent continuous brute force attacks again user accounts by disabling an account for a period of time after a number of invalid attempts. The ASP.NET Identity SignInManager protects against brute force attacks if the lockout parameter is set to true. For more information checkout the CWE-307 (https://cwe.mitre.org/data/definitions/307.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`CheckPasswordSignInAsync\(.*, .*, false\)`), + }, + } +} + +func NewCsharpRegularRawInlineExpression() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "e6169641-f92d-492b-a6a8-cbe22e951abf", + Name: "Raw Inline Expression", + Description: "Data is written to the browser using a raw write: <%= var %>. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.). Instead of using a raw write, use the inline HTML encoded shortcut (<%: var %>) to automatically HTML encode data before writing it to the browser. For more information checkout the CWE-79 (https://cwe.mitre.org/data/definitions/79.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`\<\%=.*\%\>`), + }, + } +} + +func NewCsharpRegularRawBindingExpression() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "f148484d-23d3-41cf-9a51-f7bee058575d", + Name: "Raw Binding Expression", + Description: "Data is written to the browser using a raw binding expression: <%# Item.Variable %>. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.). Instead of using a raw binding expression, use the HTML encoded binding shortcut (<%#: Item.Variable %>) to automatically HTML encode data before writing it to the browser. For more information checkout the CWE-79 (https://cwe.mitre.org/data/definitions/79.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`\<\%#[^:].*\%\>`), + }, + } +} + +func NewCsharpRegularRawWriteLiteralMethod() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "94179e8d-daf8-4632-9d8c-dcc687e440b6", + Name: "Raw Write Literal Method", + Description: "Data is written to the browser using the raw WriteLiteral method. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.). Instead of using the raw WriteLiteral method, use a Razor helper that performs automatic HTML encoding before writing it to the browser. For more information checkout the CWE-79 (https://cwe.mitre.org/data/definitions/79.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`WriteLiteral\(`), + }, + } +} + +func NewCsharpRegularUnencodedWebFormsProperty() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "b511f0cb-64da-40b8-ba18-dc7b78fed9d4", + Name: "Unencoded Web Forms Property", + Description: "Data is written to the browser using a WebForms property that does not perform output encoding. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.). WebForms controls are often found in HTML contexts, but can also appear in other contexts such as JavaScript, HTML Attribute, or URL. Fixing the vulnerability requires the appropriate Web Protection Library (aka AntiXSS) context-specific method to encode the data before setting the WebForms property. For more information checkout the CWE-79 (https://cwe.mitre.org/data/definitions/79.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(litDetails\.Text)(([^H]|H[^t]|Ht[^m]|Htm[^l]|Html[^E]|HtmlE[^n]|HtmlEn[^c]|HtmlEnc[^o]|HtmlEnco[^d]|HtmlEncod[^e])*)(;)`), + }, + } +} + +func NewCsharpRegularUnencodedLabelText() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "4aa38f87-2ae0-4565-8b1b-c66128a5c206", + Name: "Unencoded Label Text", + Description: "Data is written to the browser using the raw Label.Text method. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.). Label controls are often found in HTML contexts, but can also appear in other contexts such as JavaScript, HTML Attribute, or URL. Fixing the vulnerability requires the appropriate Web Protection Library (aka AntiXSS) context-specific method to encode the data before setting the Label.Text property. For more information checkout the CWE-79 (https://cwe.mitre.org/data/definitions/79.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(lblDetails\.Text)(([^H]|H[^t]|Ht[^m]|Htm[^l]|Html[^E]|HtmlE[^n]|HtmlEn[^c]|HtmlEnc[^o]|HtmlEnco[^d]|HtmlEncod[^e])*)(;)`), + }, + } +} + +func NewCsharpRegularWeakRandomNumberGenerator() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "4b546b8d-0d0c-4b37-ad5f-f8f788019a3e", + Name: "Weak Random Number Generator", + Description: "The use of a predictable random value can lead to vulnerabilities when used in certain security critical contexts. For more information access: (https://security-code-scan.github.io/#SCS0005) or (https://cwe.mitre.org/data/definitions/338.html).", + Severity: severity.Low.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new Random\(\)`), + }, + } +} + +func NewCsharpRegularWeakRsaKeyLength() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "126b300d-d512-4ca4-a32a-3aad096edb35", + Name: "Weak Rsa Key Length", + Description: "Due to advances in cryptanalysis attacks and cloud computing capabilities, the National Institute of Standards and Technology (NIST) deprecated 1024-bit RSA keys on January 1, 2011. The Certificate Authority Browser Forum, along with the latest version of all browsers, currently mandates a minimum key size of 2048-bits for all RSA keys. For more information checkout the CWE-326 (https://cwe.mitre.org/data/definitions/326.html) advisory.", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(new RSACryptoServiceProvider\()(\)|[0-9][^\d]|[0-9]{2}[^\d]|[0-9]{3}[^\d]|[0-1][0-9]{3}[^\d]|20[0-3][0-9]|204[0-7])`), + }, + } +} + +func NewCsharpRegularXmlReaderExternalEntityExpansion() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "3a3f1a75-e2ab-4fc6-a366-517c5771ecae", + Name: "Xml Reader External Entity Expansion", + Description: "XML External Entity (XXE) vulnerabilities occur when applications process untrusted XML data without disabling external entities and DTD processing. Processing untrusted XML data with a vulnerable parser can allow attackers to extract data from the server, perform denial of service attacks, and in some cases gain remote code execution. The XmlReaderSettings and XmlTextReader classes are vulnerable to XXE attacks when setting the DtdProcessing property to DtdProcessing.Parse or the ProhibitDtd property to false.\n\n \n\nTo prevent XmlReader XXE attacks, avoid using the deprecated ProhibitDtd property. Set the DtdProcessing property to DtdProcessing.Prohibit. For more information checkout the CWE-611 (https://cwe.mitre.org/data/definitions/611.html) advisory.", + Severity: severity.High.ToString(), + Confidence: confidence.High.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(new\sXmlReaderSettings)(([^P]|P[^r]|Pr[^o]|Pro[^h]|Proh[^i]|Prohi[^b]|Prohib[^i]|Prohibi[^t])*)(})`), + }, + } +} + +func NewCsharpRegularLdapInjectionDirectoryEntry() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "f5f1ace5-84f0-43ed-b9c1-60ced0286b73", + Name: "Ldap Injection Directory Entry", + Description: "LDAP Injection vulnerabilities occur when untrusted data is concatenated into a LDAP Path or Filter expression without properly escaping control characters. This can allow attackers to change the meaning of an LDAP query and gain access to resources for which they are not authorized. Fixing the LDAP Injection Directory Entry vulnerability requires untrusted data to be encoded using the appropriate Web Protection Library (aka AntiXSS) LDAP encoding method: Encoder.LdapDistinguishedNameEncode(). For more information checkout the CWE-90 (https://cwe.mitre.org/data/definitions/90.html) advisory.", + Severity: severity.High.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`(new\sDirectoryEntry\(.*LDAP.*\{)(([^E]|E[^n]|En[^c]|Enc[^o]|Enco[^d]|Encod[^e]|Encode[^r])*)(;)`), + }, + } +} diff --git a/development-kit/pkg/enums/engine/advisories/java/and/and.go b/development-kit/pkg/enums/engine/advisories/java/and/and.go index 7ba62d236..a3093318c 100644 --- a/development-kit/pkg/enums/engine/advisories/java/and/and.go +++ b/development-kit/pkg/enums/engine/advisories/java/and/and.go @@ -1416,7 +1416,7 @@ func NewJavaAndRSAUsageWithShortKey() text.TextRule { Type: text.AndMatch, Expressions: []*regexp.Regexp{ regexp.MustCompile(`KeyPairGenerator.getInstance\(.*\)`), - regexp.MustCompile(`initialize\(\b(0|[1-9][0-9]?)\b|\b(0|[1-9][0-9][0-9]?)\b|\b(0|[1][0-9][0-9][0-9]|[2][0][0-4][0-7]?)\b\)`), + regexp.MustCompile(`(initialize\()(\)|[0-9][^\d]|[0-9]{2}[^\d]|[0-9]{3}[^\d]|[0-1][0-9]{3}[^\d]|20[0-3][0-9]|204[0-7])`), }, } } @@ -1433,7 +1433,7 @@ func NewJavaAndBlowfishUsageWithShortKey() text.TextRule { Type: text.AndMatch, Expressions: []*regexp.Regexp{ regexp.MustCompile(`KeyGenerator.getInstance\(['|"]Blowfish['|"]\)`), - regexp.MustCompile(`init\(\b(0|[1-9][0-9]?)\b|\b(0|[1][0-2][0-7]?)\b\)`), + regexp.MustCompile(`(init\()(\)|[0-9][^\d]|[0-9]{2}[^\d]|[0-1][0-2][0-7])`), }, } } diff --git a/development-kit/pkg/enums/engine/advisories/leaks/regular/regular.go b/development-kit/pkg/enums/engine/advisories/leaks/regular/regular.go index ab823b691..9ff69476f 100644 --- a/development-kit/pkg/enums/engine/advisories/leaks/regular/regular.go +++ b/development-kit/pkg/enums/engine/advisories/leaks/regular/regular.go @@ -441,7 +441,7 @@ func NewLeaksRegularHardCodedPassword() text.TextRule { }, Type: text.Regular, Expressions: []*regexp.Regexp{ - regexp.MustCompile(`(password.*=\s*['|\"]\w+[[:print:]]*['|\"])|(pass.*=\s*['|\"]\w+[[:print:]]*['|\"]\s)|(pwd.*=\s*['|\"]\w+[[:print:]]*['|\"]\s)|(passwd.*=\s*['|\"]\w+[[:print:]]*['|\"]\s)|(senha.*=\s*['|\"]\w+[[:print:]]*['|\"])`), + regexp.MustCompile(`(?i)((set)?password.*(=|\()\s*['|\"]\w+[[:print:]]*['|\"])|((set)?pass.*(=|\()\s*['|\"]\w+[[:print:]]*['|\"]\s)|((set)?pwd.*(=|\()\s*['|\"]\w+[[:print:]]*['|\"]\s)|((set)?passwd.*(=|\()\s*['|\"]\w+[[:print:]]*['|\"]\s)|((set)?senha.*(=|\()\s*['|\"]\w+[[:print:]]*['|\"])`), }, } } diff --git a/development-kit/pkg/enums/languages/languages.go b/development-kit/pkg/enums/languages/languages.go index f3fa98514..a9afe8e19 100644 --- a/development-kit/pkg/enums/languages/languages.go +++ b/development-kit/pkg/enums/languages/languages.go @@ -20,7 +20,7 @@ type Language string const ( Go Language = "Go" - DotNet Language = "C#" + CSharp Language = "C#" Ruby Language = "Ruby" Python Language = "Python" Java Language = "Java" @@ -48,7 +48,7 @@ func ParseStringToLanguage(value string) (l Language) { func SupportedLanguages() []Language { return []Language{ Go, - DotNet, + CSharp, Ruby, Python, Java, @@ -65,7 +65,7 @@ func (l Language) MapEnableLanguages() map[string]Language { return map[string]Language{ Go.ToString(): Go, Leaks.ToString(): Leaks, - DotNet.ToString(): DotNet, + CSharp.ToString(): CSharp, Ruby.ToString(): Ruby, Python.ToString(): Python, Java.ToString(): Java, diff --git a/development-kit/pkg/enums/languages/languages_test.go b/development-kit/pkg/enums/languages/languages_test.go index e1ac9599d..258cf7297 100644 --- a/development-kit/pkg/enums/languages/languages_test.go +++ b/development-kit/pkg/enums/languages/languages_test.go @@ -21,13 +21,13 @@ import ( func TestToString(t *testing.T) { t.Run("should success parse to string", func(t *testing.T) { - assert.NotEmpty(t, DotNet.ToString()) + assert.NotEmpty(t, CSharp.ToString()) }) } func TestMapEnableLanguages(t *testing.T) { t.Run("should map enable languages", func(t *testing.T) { - assert.Len(t, DotNet.MapEnableLanguages(), 10) + assert.Len(t, CSharp.MapEnableLanguages(), 10) }) } diff --git a/development-kit/pkg/enums/tools/tools.go b/development-kit/pkg/enums/tools/tools.go index d56c49a2c..e1533e26d 100644 --- a/development-kit/pkg/enums/tools/tools.go +++ b/development-kit/pkg/enums/tools/tools.go @@ -31,6 +31,7 @@ const ( GitLeaks Tool = "GitLeaks" TfSec Tool = "TfSec" Semgrep Tool = "Semgrep" + HorusecCsharp Tool = "HorusecCsharp" ) func (t Tool) ToString() string { diff --git a/development-kit/pkg/usecases/analysis/analysis.go b/development-kit/pkg/usecases/analysis/analysis.go index 8e6dfd541..c50721ca0 100644 --- a/development-kit/pkg/usecases/analysis/analysis.go +++ b/development-kit/pkg/usecases/analysis/analysis.go @@ -176,6 +176,7 @@ func (au *UseCases) sliceTools() []interface{} { tools.HorusecKotlin, tools.HorusecLeaks, tools.Semgrep, + tools.HorusecCsharp, } } @@ -183,7 +184,7 @@ func (au *UseCases) sliceTools() []interface{} { func (au *UseCases) sliceLanguages() []interface{} { return []interface{}{ languages.Go, - languages.DotNet, + languages.CSharp, languages.Ruby, languages.Python, languages.Java, diff --git a/development-kit/pkg/utils/test/analysis_mock.go b/development-kit/pkg/utils/test/analysis_mock.go index 01ed86cd7..9d1459e82 100644 --- a/development-kit/pkg/utils/test/analysis_mock.go +++ b/development-kit/pkg/utils/test/analysis_mock.go @@ -98,7 +98,7 @@ func ReturnEachTypeOfVulnerability() []horusec.Vulnerability { Code: "-----BEGIN CERTIFICATE-----", Details: "Found SSH and/or x.509 Cerficates SecurityCodeScan", SecurityTool: tools.SecurityCodeScan, - Language: languages.DotNet, + Language: languages.CSharp, Severity: severity.Low, VulnHash: uuid.New().String(), Type: enumHorusec.Vulnerability, diff --git a/development-kit/pkg/utils/test/zips/netcore3-1/netcore3-1.zip b/development-kit/pkg/utils/test/zips/csharp/csharp.zip similarity index 100% rename from development-kit/pkg/utils/test/zips/netcore3-1/netcore3-1.zip rename to development-kit/pkg/utils/test/zips/csharp/csharp.zip diff --git a/e2e/cli/scan_languages/scan_languages_test.go b/e2e/cli/scan_languages/scan_languages_test.go index 7350021f2..5ebeb6842 100644 --- a/e2e/cli/scan_languages/scan_languages_test.go +++ b/e2e/cli/scan_languages/scan_languages_test.go @@ -48,7 +48,7 @@ func TestHorusecCLILanguages(t *testing.T) { } var wg sync.WaitGroup go RunGolangTest(t, &wg) - go RunNetCoreTest(t, &wg) + go RunCsharpTest(t, &wg) go RunRubyTest(t, &wg) go RunPythonBanditTest(t, &wg) go RunPythonSafetyTest(t, &wg) @@ -105,11 +105,11 @@ func RunKotlinTest(t *testing.T, s *sync.WaitGroup) { assert.GreaterOrEqual(t, len(analysis.AnalysisVulnerabilities), 1, "Vulnerabilities in kotlin is not expected") } -func RunNetCoreTest(t *testing.T, s *sync.WaitGroup) { +func RunCsharpTest(t *testing.T, s *sync.WaitGroup) { defer s.Done() - fileOutput := runHorusecCLIUsingZip(t, "netcore3-1") + fileOutput := runHorusecCLIUsingZip(t, "csharp") analysis := extractVulnerabilitiesFromOutput(fileOutput) - assert.GreaterOrEqual(t, len(analysis.AnalysisVulnerabilities), 1, "Vulnerabilities in netcore is not expected") + assert.GreaterOrEqual(t, len(analysis.AnalysisVulnerabilities), 1, "Vulnerabilities in csharp is not expected") } func RunRubyTest(t *testing.T, s *sync.WaitGroup) { diff --git a/horusec-cli/README.md b/horusec-cli/README.md index 6f3e34161..dabfd2e24 100644 --- a/horusec-cli/README.md +++ b/horusec-cli/README.md @@ -168,7 +168,7 @@ The configuration file receive an object with the content follow: "horusecCliRiskAcceptHashes": "", "horusecCliWorkDir": { "go": [], - "netCore": [], + "csharp": [], "ruby": [], "python": [], "java" : [], @@ -262,7 +262,7 @@ Using the web platform **[HORUSEC-MANAGER](http://localhost:8043)** follow there #### WorkDir The WorkDir is an representation to run multiple projects inside one directory, that can be configured through the horusec-config.json file. -Let's assume that your project is a netcore app using angular and has the following structure: +Let's assume that your project is a C# with .netcore 3.1 app using angular and has the following structure: ```text |- NetCoreProject/ |--- horusec-config.json @@ -278,7 +278,7 @@ For this example the configuration would be: ```bash { "horusecCliWorkDir": { - "netCore": [ + "csharp": [ "NetCoreProject" ], "javaScript": [ @@ -293,7 +293,7 @@ The interface of languages accepts is: ``` { go []string - netCore []string + csharp []string ruby []string python []string java []string diff --git a/horusec-cli/config/config.go b/horusec-cli/config/config.go index fa8ddaccd..489ece728 100644 --- a/horusec-cli/config/config.go +++ b/horusec-cli/config/config.go @@ -16,6 +16,8 @@ package config import ( "encoding/json" + "github.com/ZupIT/horusec/development-kit/pkg/utils/logger" + "github.com/ZupIT/horusec/horusec-cli/internal/helpers/messages" "os" "strings" @@ -338,10 +340,25 @@ func (c *Config) GetWorkDir() *workdir.WorkDir { } func (c *Config) SetWorkDir(toParse interface{}) { + if c.netCoreKeyIsDeprecated(toParse) { + logger.LogWarnWithLevel(messages.MsgWarnNetCoreDeprecated, logger.WarnLevel) + } c.WorkDir = &workdir.WorkDir{} c.WorkDir.ParseInterfaceToStruct(toParse) } +// nolint:gocyclo is necessary to check all validations +func (c *Config) netCoreKeyIsDeprecated(toParse interface{}) bool { + workdirParsed, ok := toParse.(map[string]interface{}) + if ok && workdirParsed["netcore"] != nil { + netCore, ok := workdirParsed["netcore"].([]interface{}) + if ok && netCore != nil && len(netCore) > 0 { + return true + } + } + return false +} + func (c *Config) GetEnableGitHistoryAnalysis() bool { return c.EnableGitHistoryAnalysis } diff --git a/horusec-cli/config/config_test.go b/horusec-cli/config/config_test.go index 4903c9bb5..4a5ef1d53 100644 --- a/horusec-cli/config/config_test.go +++ b/horusec-cli/config/config_test.go @@ -70,7 +70,7 @@ func TestNewHorusecConfig(t *testing.T) { configs.SetFilterPath(uuid.New().String()) configs.SetEnableGitHistoryAnalysis(true) configs.SetProjectPath("./") - configs.SetWorkDir(wd.String()) + configs.SetWorkDir(map[string]interface{}{"netcore": []interface{}{"test"}}) configs.SetCertPath("./") configs.SetCertInsecureSkipVerify(true) configs.SetRepositoryName("horus") diff --git a/horusec-cli/internal/controllers/analyser/analyser.go b/horusec-cli/internal/controllers/analyser/analyser.go index a16d2ae71..eb86f66de 100644 --- a/horusec-cli/internal/controllers/analyser/analyser.go +++ b/horusec-cli/internal/controllers/analyser/analyser.go @@ -16,6 +16,7 @@ package analyser import ( "fmt" + horuseccsharp "github.com/ZupIT/horusec/horusec-cli/internal/services/formatters/dotnet/horusec_csharp" "log" "os" "os/signal" @@ -173,7 +174,7 @@ func (a *Analyser) runMonitorTimeout(monitor int64) { func (a *Analyser) mapDetectVulnerabilityByLanguage() map[languages.Language]func(string) { return map[languages.Language]func(string){ - languages.DotNet: a.detectVulnerabilityDotNet, + languages.CSharp: a.detectVulnerabilityDotNet, languages.Leaks: a.detectVulnerabilityLeaks, languages.Go: a.detectVulnerabilityGo, languages.Java: a.detectVulnerabilityJava, @@ -187,8 +188,9 @@ func (a *Analyser) mapDetectVulnerabilityByLanguage() map[languages.Language]fun } func (a *Analyser) detectVulnerabilityDotNet(projectSubPath string) { - a.monitor.AddProcess(1) + a.monitor.AddProcess(2) go scs.NewFormatter(a.formatterService).StartAnalysis(projectSubPath) + go horuseccsharp.NewFormatter(a.formatterService).StartAnalysis(projectSubPath) } func (a *Analyser) detectVulnerabilityLeaks(projectSubPath string) { diff --git a/horusec-cli/internal/controllers/analyser/analyser_test.go b/horusec-cli/internal/controllers/analyser/analyser_test.go index 7286516b3..51f2973b2 100644 --- a/horusec-cli/internal/controllers/analyser/analyser_test.go +++ b/horusec-cli/internal/controllers/analyser/analyser_test.go @@ -57,7 +57,7 @@ func TestAnalyser_AnalysisDirectory(t *testing.T) { languageDetectMock.On("LanguageDetect").Return([]languages.Language{ languages.Go, languages.Leaks, - languages.DotNet, + languages.CSharp, languages.Ruby, languages.Python, languages.Java, @@ -110,7 +110,7 @@ func TestAnalyser_AnalysisDirectory(t *testing.T) { languageDetectMock.On("LanguageDetect").Return([]languages.Language{ languages.Go, languages.Leaks, - languages.DotNet, + languages.CSharp, languages.Ruby, languages.Python, languages.Java, diff --git a/horusec-cli/internal/controllers/language_detect/language_detect_test.go b/horusec-cli/internal/controllers/language_detect/language_detect_test.go index d138484e0..948bc1387 100644 --- a/horusec-cli/internal/controllers/language_detect/language_detect_test.go +++ b/horusec-cli/internal/controllers/language_detect/language_detect_test.go @@ -224,7 +224,7 @@ func TestNewLanguageDetect(t *testing.T) { t.Run("Should run language detect and return DOTNET and GITLEAKS", func(t *testing.T) { configs := &config.Config{} analysis := analysisUseCases.NewAnalysisUseCases().NewAnalysisRunning() - analysisName := "netcore3-1" + analysisName := "csharp" assert.NoError(t, unZipToTmp(analysisName, analysis.ID)) @@ -233,7 +233,7 @@ func TestNewLanguageDetect(t *testing.T) { langs, _ := controller.LanguageDetect(getSourcePath(analysis.ID)) assert.Contains(t, langs, languages.Leaks) - assert.Contains(t, langs, languages.DotNet) + assert.Contains(t, langs, languages.CSharp) assert.Contains(t, langs, languages.Generic) assert.Len(t, langs, 3) }) diff --git a/horusec-cli/internal/entities/workdir/workdir.go b/horusec-cli/internal/entities/workdir/workdir.go index 0944de596..ead9ef23a 100644 --- a/horusec-cli/internal/entities/workdir/workdir.go +++ b/horusec-cli/internal/entities/workdir/workdir.go @@ -25,6 +25,7 @@ import ( type WorkDir struct { Go []string `json:"go"` NetCore []string `json:"netCore"` + CSharp []string `json:"csharp"` Ruby []string `json:"ruby"` Python []string `json:"python"` Java []string `json:"java"` @@ -58,9 +59,12 @@ func (w *WorkDir) Type() string { } func (w *WorkDir) Map() map[languages.Language][]string { + cSharp := []string{} + cSharp = append(cSharp, w.NetCore...) + cSharp = append(cSharp, w.CSharp...) return map[languages.Language][]string{ languages.Go: w.Go, - languages.DotNet: w.NetCore, + languages.CSharp: cSharp, languages.Ruby: w.Ruby, languages.Python: w.Python, languages.Java: w.Java, diff --git a/horusec-cli/internal/helpers/messages/warn.go b/horusec-cli/internal/helpers/messages/warn.go index 2390afe33..3104cbd49 100644 --- a/horusec-cli/internal/helpers/messages/warn.go +++ b/horusec-cli/internal/helpers/messages/warn.go @@ -29,4 +29,6 @@ const ( "that are not considered to be analyzed. To see more details use flag --log-level=debug" MsgWarnGitHistoryEnable = "{HORUSEC_CLI} Starting the analysis with git history enabled. " + "ATTENTION the waiting time can be longer when this option is enabled!" + MsgWarnNetCoreDeprecated = "{HORUSEC_CLI} 'netCore' key in workdir will change to 'csharp', " + + "please change in your horusec-config.json" ) diff --git a/horusec-cli/internal/services/formatters/dotnet/horusec_csharp/config.go b/horusec-cli/internal/services/formatters/dotnet/horusec_csharp/config.go new file mode 100644 index 000000000..76c1d90a4 --- /dev/null +++ b/horusec-cli/internal/services/formatters/dotnet/horusec_csharp/config.go @@ -0,0 +1,25 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package horuseccsharp + +const ( + ImageName = "horuszup/horusec-csharp" + ImageTag = "v0.0.1" + ImageCmd = ` + {{WORK_DIR}} + horusec-csharp run -o="./output-ANALYSISID.json" + cat ./output-ANALYSISID.json + ` +) diff --git a/horusec-cli/internal/services/formatters/dotnet/horusec_csharp/formatter.go b/horusec-cli/internal/services/formatters/dotnet/horusec_csharp/formatter.go new file mode 100644 index 000000000..fd8dca478 --- /dev/null +++ b/horusec-cli/internal/services/formatters/dotnet/horusec_csharp/formatter.go @@ -0,0 +1,141 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package horuseccsharp + +import ( + vulnhash "github.com/ZupIT/horusec/development-kit/pkg/utils/vuln_hash" + "strconv" + + engine "github.com/ZupIT/horusec-engine" + "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec" + "github.com/ZupIT/horusec/development-kit/pkg/enums/languages" + "github.com/ZupIT/horusec/development-kit/pkg/enums/severity" + "github.com/ZupIT/horusec/development-kit/pkg/enums/tools" + jsonUtils "github.com/ZupIT/horusec/development-kit/pkg/utils/json" + "github.com/ZupIT/horusec/development-kit/pkg/utils/logger" + dockerEntities "github.com/ZupIT/horusec/horusec-cli/internal/entities/docker" + "github.com/ZupIT/horusec/horusec-cli/internal/helpers/messages" + "github.com/ZupIT/horusec/horusec-cli/internal/services/formatters" +) + +type Formatter struct { + formatters.IService +} + +func NewFormatter(service formatters.IService) formatters.IFormatter { + return &Formatter{ + service, + } +} + +func (f *Formatter) StartAnalysis(projectSubPath string) { + if f.ToolIsToIgnore(tools.HorusecCsharp) { + logger.LogDebugWithLevel(messages.MsgDebugToolIgnored+tools.HorusecCsharp.ToString(), logger.DebugLevel) + return + } + + err := f.startHorusecCsharpAnalysis(projectSubPath) + f.SetLanguageIsFinished() + f.LogAnalysisError(err, tools.HorusecCsharp, projectSubPath) +} + +func (f *Formatter) startHorusecCsharpAnalysis(projectSubPath string) error { + f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.HorusecCsharp) + + output, err := f.ExecuteContainer(f.getImageTagCmd(projectSubPath)) + if err != nil { + f.SetAnalysisError(err) + return err + } + + f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.HorusecCsharp) + return f.formatOutput(output) +} + +func (f *Formatter) getImageTagCmd(projectSubPath string) *dockerEntities.AnalysisData { + return &dockerEntities.AnalysisData{ + Image: ImageName, + Tag: ImageTag, + CMD: f.AddWorkDirInCmd(ImageCmd, projectSubPath, tools.HorusecCsharp), + Language: languages.CSharp, + } +} + +func (f *Formatter) formatOutput(output string) error { + var reportOutput []engine.Finding + + if output == "" || output == "null" { + logger.LogDebugWithLevel(messages.MsgDebugOutputEmpty, logger.DebugLevel, + map[string]interface{}{"tool": tools.HorusecCsharp.ToString()}) + + return f.setOutputInHorusecAnalysis(reportOutput) + } + + outputParsed, err := f.convertOutputAndValidate(output, &reportOutput) + if err != nil { + return err + } + + return f.setOutputInHorusecAnalysis(outputParsed) +} + +func (f *Formatter) convertOutputAndValidate(output string, reportOutput *[]engine.Finding) ([]engine.Finding, error) { + if err := jsonUtils.ConvertStringToOutput(output, reportOutput); err != nil { + logger.LogErrorWithLevel(f.GetAnalysisIDErrorMessage(tools.HorusecCsharp, output), err, logger.ErrorLevel) + return *reportOutput, err + } + + return *reportOutput, nil +} + +func (f *Formatter) setOutputInHorusecAnalysis(reportOutput []engine.Finding) error { + for index := range reportOutput { + vulnerability := f.setupVulnerabilitiesSeverities(reportOutput, index) + vulnerability = f.setupCommitAuthorInVulnerability(vulnerability) + vulnerability = vulnhash.Bind(vulnerability) + + f.GetAnalysis().AnalysisVulnerabilities = append(f.GetAnalysis().AnalysisVulnerabilities, + horusec.AnalysisVulnerabilities{ + Vulnerability: *vulnerability, + }) + } + return nil +} + +func (f *Formatter) setupVulnerabilitiesSeverities( + reportOutput []engine.Finding, index int) ( + vulnerabilitySeverity *horusec.Vulnerability) { + line := strconv.Itoa(reportOutput[index].SourceLocation.Line) + return &horusec.Vulnerability{ + Line: line, + Column: strconv.Itoa(reportOutput[index].SourceLocation.Column), + Confidence: reportOutput[index].Confidence, + File: f.RemoveSrcFolderFromPath(reportOutput[index].SourceLocation.Filename), + Code: f.GetCodeWithMaxCharacters(reportOutput[index].CodeSample, reportOutput[index].SourceLocation.Column), + Details: reportOutput[index].Name + "\n" + reportOutput[index].Description, + SecurityTool: tools.HorusecCsharp, + Language: languages.CSharp, + Severity: severity.ParseStringToSeverity(reportOutput[index].Severity), + } +} +func (f *Formatter) setupCommitAuthorInVulnerability(vulnerability *horusec.Vulnerability) *horusec.Vulnerability { + commitAuthor := f.GetCommitAuthor(vulnerability.Line, vulnerability.File) + vulnerability.CommitAuthor = commitAuthor.Author + vulnerability.CommitEmail = commitAuthor.Email + vulnerability.CommitHash = commitAuthor.CommitHash + vulnerability.CommitMessage = commitAuthor.Message + vulnerability.CommitDate = commitAuthor.Date + return vulnerability +} diff --git a/horusec-cli/internal/services/formatters/dotnet/horusec_csharp/formatter_test.go b/horusec-cli/internal/services/formatters/dotnet/horusec_csharp/formatter_test.go new file mode 100644 index 000000000..1d7867df0 --- /dev/null +++ b/horusec-cli/internal/services/formatters/dotnet/horusec_csharp/formatter_test.go @@ -0,0 +1,146 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package horuseccsharp + +import ( + "errors" + "testing" + + "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec" + cliConfig "github.com/ZupIT/horusec/horusec-cli/config" + "github.com/ZupIT/horusec/horusec-cli/internal/entities/workdir" + "github.com/ZupIT/horusec/horusec-cli/internal/services/docker" + "github.com/ZupIT/horusec/horusec-cli/internal/services/formatters" + "github.com/stretchr/testify/assert" +) + +func TestParseOutputHorusecCsharp(t *testing.T) { + t.Run("HorusecCsharp Should not return panic and but append errors found in analysis", func(t *testing.T) { + analysis := &horusec.Analysis{} + dockerAPIControllerMock := &docker.Mock{} + dockerAPIControllerMock.On("DeleteContainersFromAPI") + dockerAPIControllerMock.On("CreateLanguageAnalysisContainer").Return("", errors.New("test")) + + config := &cliConfig.Config{ + WorkDir: &workdir.WorkDir{}, + } + + service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{}) + + assert.NotPanics(t, func() { + NewFormatter(service).StartAnalysis("") + assert.Equal(t, len(analysis.AnalysisVulnerabilities), 0) + assert.NotEqual(t, len(analysis.Errors), 0) + }) + }) + t.Run("HorusecCsharp Should not return panic and exists vulnerabilities when call start horusec csharp", func(t *testing.T) { + analysis := &horusec.Analysis{} + responseContainer := ` +[ + { + "ID": "1079260f-aea3-4d10-9b14-1a96d7043dad", + "Name": "test vuln", + "Severity": "HIGH", + "CodeSample": "test code;", + "Confidence": "LOW", + "Description": "example description.", + "SourceLocation": { + "Filename": "test.cs", + "Line": 2, + "Column": 7 + } + } +] +` + dockerAPIControllerMock := &docker.Mock{} + dockerAPIControllerMock.On("DeleteContainersFromAPI") + dockerAPIControllerMock.On("CreateLanguageAnalysisContainer").Return(responseContainer, nil) + + config := &cliConfig.Config{ + WorkDir: &workdir.WorkDir{}, + } + + service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{}) + + assert.NotPanics(t, func() { + NewFormatter(service).StartAnalysis("") + assert.NotEqual(t, len(analysis.AnalysisVulnerabilities), 0) + }) + }) + t.Run("HorusecCsharp Should return empty analysis when format is empty", func(t *testing.T) { + analysis := &horusec.Analysis{} + dockerAPIControllerMock := &docker.Mock{} + + config := &cliConfig.Config{ + WorkDir: &workdir.WorkDir{}, + } + + service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{}) + + formatter := Formatter{ + service, + } + + err := formatter.formatOutput("") + assert.NoError(t, err) + assert.Len(t, analysis.AnalysisVulnerabilities, 0) + }) + t.Run("HorusecCsharp Should return empty analysis when format is null", func(t *testing.T) { + analysis := &horusec.Analysis{} + dockerAPIControllerMock := &docker.Mock{} + + config := &cliConfig.Config{ + WorkDir: &workdir.WorkDir{}, + } + + service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{}) + + formatter := Formatter{ + service, + } + + err := formatter.formatOutput("null") + assert.NoError(t, err) + assert.Len(t, analysis.AnalysisVulnerabilities, 0) + }) + t.Run("HorusecCsharp Should return error when invalid output", func(t *testing.T) { + analysis := &horusec.Analysis{} + dockerAPIControllerMock := &docker.Mock{} + + config := &cliConfig.Config{ + WorkDir: &workdir.WorkDir{}, + } + + service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{}) + + formatter := Formatter{ + service, + } + + err := formatter.formatOutput("invalid output") + assert.Error(t, err) + }) + t.Run("Should not execute tool because it's ignored", func(t *testing.T) { + analysis := &horusec.Analysis{} + dockerAPIControllerMock := &docker.Mock{} + config := &cliConfig.Config{ + ToolsToIgnore: "gosec,securitycodescan,brakeman,safety,bandit,npmaudit,yarnaudit,spotbugs,horuseckotlin,horusecjava,horusecleaks,gitleaks,tfsec,semgrep,horuseccsharp", + } + service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{}) + formatter := NewFormatter(service) + + formatter.StartAnalysis("") + }) +} diff --git a/horusec-cli/internal/services/formatters/dotnet/scs/formatter.go b/horusec-cli/internal/services/formatters/dotnet/scs/formatter.go index c2fea86c0..9c26a79d6 100644 --- a/horusec-cli/internal/services/formatters/dotnet/scs/formatter.go +++ b/horusec-cli/internal/services/formatters/dotnet/scs/formatter.go @@ -129,7 +129,7 @@ func (f *Formatter) setCommitAuthor(vulnerability *horusec.Vulnerability) *horus func (f *Formatter) getDefaultVulnerabilitySeverity() *horusec.Vulnerability { vulnerabilitySeverity := &horusec.Vulnerability{} vulnerabilitySeverity.SecurityTool = tools.SecurityCodeScan - vulnerabilitySeverity.Language = languages.DotNet + vulnerabilitySeverity.Language = languages.CSharp return vulnerabilitySeverity } @@ -152,7 +152,7 @@ func (f *Formatter) getConfigData(projectSubPath string) *dockerEntities.Analysi Tag: ImageTag, CMD: f.AddWorkDirInCmd(ImageCmd, fileUtil.GetSubPathByExtension(f.GetConfigProjectPath(), projectSubPath, "*.csproj"), tools.SecurityCodeScan), - Language: languages.DotNet, + Language: languages.CSharp, } } diff --git a/horusec-cli/internal/services/formatters/service_test.go b/horusec-cli/internal/services/formatters/service_test.go index 1be1106c9..11699b610 100644 --- a/horusec-cli/internal/services/formatters/service_test.go +++ b/horusec-cli/internal/services/formatters/service_test.go @@ -119,7 +119,7 @@ func TestAddWorkDirInCmd(t *testing.T) { t.Run("should success add workdir with no errors", func(t *testing.T) { cliConfig := &config.Config{} cliConfig.WorkDir = &workdir.WorkDir{} - cliConfig.WorkDir.NetCore = []string{"test"} + cliConfig.WorkDir.CSharp = []string{"test"} monitorController := NewFormatterService(&horusec.Analysis{}, &docker.Mock{}, cliConfig, &horusec.Monitor{}) diff --git a/horusec-cli/internal/usecases/cli/cli_test.go b/horusec-cli/internal/usecases/cli/cli_test.go index 68f40b7cf..ff48e4ef4 100644 --- a/horusec-cli/internal/usecases/cli/cli_test.go +++ b/horusec-cli/internal/usecases/cli/cli_test.go @@ -117,7 +117,7 @@ func TestValidateConfigs(t *testing.T) { config := &cliConfig.Config{ WorkDir: &workdir.WorkDir{ Go: []string{"./"}, - NetCore: []string{""}, + CSharp: []string{""}, Ruby: []string{}, Python: []string{}, Java: []string{}, @@ -136,7 +136,7 @@ func TestValidateConfigs(t *testing.T) { config := &cliConfig.Config{ WorkDir: &workdir.WorkDir{ Go: []string{"NOT EXISTS PATH"}, - NetCore: []string{}, + CSharp: []string{}, Ruby: []string{}, Python: []string{}, Java: []string{}, diff --git a/horusec-config.json b/horusec-config.json index 829f50558..fecb952f3 100644 --- a/horusec-config.json +++ b/horusec-config.json @@ -14,7 +14,7 @@ "horusecCliRiskAcceptHashes": "45aa5c46df5ba51d7e59da826544412352c189a6acf5707f941922181c94f989, ba56b6e4ac8f790026b82a488c5624d7e2d6f6dd60584a9375c3c8948b608dbf, 2ce87bddc40e085562618f441750eeefe3cffc79d0b05b2e07a98f644c55b2c5, e2eaa19612eed0124b1fec396f8d41381c618c677c2025fc07c1cd0ccbe92b3c, 2b156198552b17c44bab579d68b8cb4204789859ef69a37a7a11e65667cbc66f, 0ffc51a6b0187bec02837cb1e8dddfa05519e83d861af3fbd553bc4d0fbe852d, 4294bf00b848d82c4e012f45e0747996eb75109e089a626af930580a7a179ea4, fa41e0534388707279458969d1dcdb58ff932357660e8855d2bb4170fdbcb391, 5114704fb26983f549c5f179a0a90d8e95c8db28f9e68d32d864b2a6743cb499", "horusecCliWorkDir": { "go": [], - "netCore": [], + "csharp": [], "ruby": [], "python": [], "java" : [], diff --git a/horusec-csharp/.semver.yaml b/horusec-csharp/.semver.yaml new file mode 100644 index 000000000..380baee26 --- /dev/null +++ b/horusec-csharp/.semver.yaml @@ -0,0 +1,4 @@ +alpha: 0 +beta: 0 +rc: 0 +release: v0.0.1 diff --git a/horusec-csharp/README.md b/horusec-csharp/README.md new file mode 100644 index 000000000..3c699c87e --- /dev/null +++ b/horusec-csharp/README.md @@ -0,0 +1,129 @@ +# HORUSEC-CSHARP-CLI +This is a Command Line Interface to make it search vulnerabilities in C# project. +To learn more about the structure of this service you can see more in this /assets/horusec-csharp.jpg. + +## Using with docker +To use with docker you can running this example: +```bash + LOCAL_PROJECT_PATH="$(pwd)/horusec-csharp/examples"; \ + docker run --rm \ + -v $LOCAL_PROJECT_PATH:/src \ + horuszup/horusec-csharp:latest \ + /bin/sh -c "horusec-csharp run -p /src -o /tmp/output.json && cat /tmp/output.json" +``` + +## Using locally +To use locally is necessary clone horusec in your local machine and run: +```bash +make build-install-csharp-cli +``` + +#### Check the installation +```bash +horusec-csharp version +``` + +## Commands +The available commands to usage are: + +| Command | Description | +|---------|-------------| +| run | This command start analysis with default values and in your current directory | +| version | You see actual version running in your local machine | + +### Using Flags +You can pass some flags and change their values, for example: +```bash +horusec-csharp --help +``` + +All available flags are: + +| Flag Flag | Flag shortcut | Default Value | Description | +|------------------|---------------|----------------------|-------------| +| log-level | l | info | This setting will define what level of logging I want to see. The available levels are: "panic","fatal","error","warn","info","debug","trace" | +| json-output-file | o | output.json | Name of the json file to save result of the analysis | +| project-path | p | ${CURRENT_DIRECTORY} | This setting is to know if I want to change the analysis directory and do not want to run in the current directory. If this value is not passed, Horusec will ask if you want to run the analysis in the current directory. If you pass it it will start the analysis in the directory informed by you without asking anything. | + +## Output +When you run analysis you receive this example of output +```json +[ + { + "ID": "263e1cb3-31ee-443e-80e0-31f81bbfb340", + "Name": "Weak hashing function md5 or sha1", + "Severity": "MEDIUM", + "MEDIUM": "MEDIUM", + "CodeSample": "var hashProvider = new SHA1CryptoServiceProvider();", + "Description": "MD5 or SHA1 have known collision weaknesses and are no longer considered strong hashing algorithms. For more information checkout the CWE-326 (https://cwe.mitre.org/data/definitions/326.html) advisory.", + "SourceLocation": { + "Filename": "/src/csharp-generic-vuln/Vulnerabilities.cs", + "Line": 15, + "Column": 31 + } + } +] +``` + +## How add more rules? +To add new rules it is necessary to understand the structure of this CLI. When we start the CLI we use a base called [cli_standard](/development-kit/pkg/cli_standard) its goal is to have the initial commands and call the controller to the CLI in this example is the package [analysis](/development-kit/pkg/engines/csharp/analysis), this package will call its [rules](/development-kit/pkg/engines/csharp/analysis) which in turn triggers all the rules that it considers necessary for this CLI. +### Rules +The rules added in horusec-csharp are grouped in two places in this project which are:: +* Rules specific to [C# language](/development-kit/pkg/enums/engine/advisories/csharp) + +All rules follow a flow subdivided between the types: +* `And` + * The purpose of these rules would be `if all the rules exist in the analyzed file, it will be charged`. +* `Or` + * The purpose of these rules would be `if any rule exists in the analyzed file, it will be charged` +* `Regular` + * The purpose of these rules would be `if any rules exist in the analyzed file and have exactly what is expected, it will be charged` + +### Example adding more rules in C# Language +To exemplify the process of how to add a new rule is quite simple. First you must create a new constructor with a very descriptive name in the file you want and started with the text `NewCsharp + TypeRule + Name` example `NewCsharpRegularWeakHashingFunctionMd5OrSha1`, this new constructor will return a [text.TextRule](https://github.com/ZupIT/horusec-engine/text), then you will return it and add the new constructor to the list of rules that will be executed in the file [csharp.go](/development-kit/pkg/enums/engine/advisories/csharp/csharp.go). + +In this builder's content add: +```text + Metadata.ID: "text type field preferred a UUID v4" + Metadata.Name: "descriptive name of the vulnerability" + Metadata.Description: "brief description of the vulnerability and if possible add a reference to the CWE that it fits" + Metadata.Severity: "using the severity enum rate how critical this vulnerability is" + Metadata.Confidence: "using the confidence enum classify how assertive this vulnerability is" + Type: "classify the type of this vulnerability according to the package" + Expressions: "List of regular expressions you want to add if the vulnerability exists in the analyzed file" +``` + +`regular.go` +```go +... +func NewCsharpRegularWeakHashingFunctionMd5OrSha1() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "263e1cb3-31ee-443e-80e0-31f81bbfb340", + Name: "Weak hashing function md5 or sha1", + Description: "MD5 or SHA1 have known collision weaknesses and are no longer considered strong hashing algorithms. For more information checkout the CWE-326 (https://cwe.mitre.org/data/definitions/326.html) advisory.", + Severity: severity.Medium.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.Regular, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`new\sSHA1CryptoServiceProvider\(`), + regexp.MustCompile(`new\sMD5CryptoServiceProvider\(`), + }, + } +} +``` + +`csharp.go` +```go +... +func AllRulesCsharpRegular() []text.TextRule { + return []text.TextRule{ + ... + regular.NewCsharpRegularWeakHashingFunctionMd5OrSha1(), + } +} +... +``` + +Finally check if all tests have passed and if possible add a unit test within [csharp_test.go](/development-kit/pkg/enums/engine/advisories/csharp/csharp_test.go) exemplifying the scenario that this new rule would apply. diff --git a/horusec-csharp/cmd/app/main.go b/horusec-csharp/cmd/app/main.go new file mode 100644 index 000000000..eb04b9b07 --- /dev/null +++ b/horusec-csharp/cmd/app/main.go @@ -0,0 +1,57 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "os" + + "github.com/ZupIT/horusec/development-kit/pkg/cli_standard/cmd" + "github.com/ZupIT/horusec/development-kit/pkg/cli_standard/cmd/run" + "github.com/ZupIT/horusec/development-kit/pkg/cli_standard/cmd/version" + "github.com/ZupIT/horusec/development-kit/pkg/cli_standard/config" + "github.com/ZupIT/horusec/development-kit/pkg/engines/csharp/analysis" + "github.com/ZupIT/horusec/development-kit/pkg/utils/logger" + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "horusec-csharp", + Short: "Horusec-csharp CLI", + RunE: func(cmd *cobra.Command, args []string) error { + logger.LogPrint("Horusec Csharp Command Line Interface") + return cmd.Help() + }, + Example: `horusec-csharp run`, +} + +var configs *config.Config + +// nolint +func init() { + configs = config.NewConfig() + cmd.InitFlags(configs, rootCmd) +} + +func main() { + controller := analysis.NewAnalysis(configs) + rootCmd.AddCommand(run.NewRunCommand(configs, controller).CreateCobraCmd()) + rootCmd.AddCommand(version.NewVersionCommand().CreateCobraCmd()) + + if err := rootCmd.Execute(); err != nil { + os.Exit(1) + } else { + os.Exit(0) + } +} diff --git a/horusec-csharp/deployments/Dockerfile b/horusec-csharp/deployments/Dockerfile new file mode 100644 index 000000000..60f945ab1 --- /dev/null +++ b/horusec-csharp/deployments/Dockerfile @@ -0,0 +1,30 @@ +# Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM golang:alpine AS builder + +RUN apk update && apk add --no-cache git + +ADD . /go/src/github.com/ZupIT/horusec +WORKDIR /go/src/github.com/ZupIT/horusec +COPY . . + +RUN go get -t -v -d ./... + +RUN env GOOS=linux GOARCH=amd64 go build -o /bin/horusec-csharp ./horusec-csharp/cmd/app/main.go + +FROM golang:alpine + +COPY --from=builder /bin/horusec-csharp /bin/horusec-csharp +RUN chmod +x /bin/horusec-csharp