-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Malicious code scanner #296
base: dev
Are you sure you want to change the base?
Changes from 4 commits
2c2320b
9290985
e0a4eac
70956f9
289e2cd
8620964
48bf043
d13464d
3b13941
5572259
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package maliciouscode | ||
|
||
import ( | ||
clientutils "github.com/jfrog/jfrog-client-go/utils" | ||
"path/filepath" | ||
|
||
jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" | ||
"github.com/jfrog/jfrog-cli-security/jas" | ||
"github.com/jfrog/jfrog-cli-security/utils" | ||
"github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" | ||
"github.com/jfrog/jfrog-cli-security/utils/jasutils" | ||
"github.com/jfrog/jfrog-client-go/utils/log" | ||
"github.com/owenrumney/go-sarif/v2/sarif" | ||
) | ||
|
||
const ( | ||
maliciousScanCommand = "mal" | ||
maliciousDocsUrlSuffix = "malicious" | ||
|
||
MaliciousScannerType MaliciousScanType = "malicious-scan" // #nosec | ||
MaliciousScannerDockerScanType MaliciousScanType = "malicious-docker-scan" // #nosec | ||
) | ||
|
||
type MaliciousScanType string | ||
|
||
type MaliciousScanManager struct { | ||
scanner *jas.JasScanner | ||
scanType MaliciousScanType | ||
configFileName string | ||
resultsFileName string | ||
} | ||
|
||
// The getMaliciousScanResults function runs the malicious code scan flow, which includes the following steps: | ||
// Creating an MaliciousSecretManager object. | ||
// Running the analyzer manager executable. | ||
// Parsing the analyzer manager results. | ||
func RunMaliciousScan(scanner *jas.JasScanner, scanType MaliciousScanType, module jfrogappsconfig.Module, threadId int) (vulnerabilitiesResults []*sarif.Run, violationsResults []*sarif.Run, err error) { | ||
var scannerTempDir string | ||
if scannerTempDir, err = jas.CreateScannerTempDirectory(scanner, jasutils.MaliciousCode.String()); err != nil { | ||
return | ||
} | ||
maliciousScanManager := newMaliciousScanManager(scanner, scanType, scannerTempDir) | ||
log.Info(clientutils.GetLogMsgPrefix(threadId, false) + "Running Malicious code scan...") | ||
if vulnerabilitiesResults, violationsResults, err = maliciousScanManager.scanner.Run(maliciousScanManager, module); err != nil { | ||
return | ||
} | ||
log.Info(utils.GetScanFindingsLog(utils.MaliciousCodeScan, sarifutils.GetResultsLocationCount(vulnerabilitiesResults...), sarifutils.GetResultsLocationCount(violationsResults...), threadId)) | ||
return | ||
} | ||
|
||
func newMaliciousScanManager(scanner *jas.JasScanner, scanType MaliciousScanType, scannerTempDir string) (manager *MaliciousScanManager) { | ||
return &MaliciousScanManager{ | ||
scanner: scanner, | ||
scanType: scanType, | ||
configFileName: filepath.Join(scannerTempDir, "config.yaml"), | ||
resultsFileName: filepath.Join(scannerTempDir, "results.sarif"), | ||
} | ||
} | ||
|
||
func (msm *MaliciousScanManager) Run(module jfrogappsconfig.Module) (vulnerabilitiesSarifRuns []*sarif.Run, violationsSarifRuns []*sarif.Run, err error) { | ||
if err = msm.createConfigFile(module, msm.scanner.Exclusions...); err != nil { | ||
return | ||
} | ||
if err = msm.runAnalyzerManager(); err != nil { | ||
return | ||
} | ||
return jas.ReadJasScanRunsFromFile(msm.resultsFileName, module.SourceRoot, maliciousDocsUrlSuffix, msm.scanner.MinSeverity) | ||
} | ||
|
||
type maliciousScanConfig struct { | ||
Scans []maliciousScanConfiguration `yaml:"scans"` | ||
} | ||
|
||
type maliciousScanConfiguration struct { | ||
Roots []string `yaml:"roots"` | ||
Output string `yaml:"output"` | ||
Type string `yaml:"type"` | ||
SkippedDirs []string `yaml:"skipped-folders"` | ||
} | ||
|
||
func (m *MaliciousScanManager) createConfigFile(module jfrogappsconfig.Module, exclusions ...string) error { | ||
roots, err := jas.GetSourceRoots(module, module.Scanners.MaliciousCode) | ||
if err != nil { | ||
return err | ||
} | ||
configFileContent := maliciousScanConfig{ | ||
Scans: []maliciousScanConfiguration{ | ||
{ | ||
Roots: roots, | ||
Output: m.resultsFileName, | ||
Type: string(m.scanType), | ||
SkippedDirs: jas.GetExcludePatterns(module, module.Scanners.MaliciousCode, exclusions...), | ||
}, | ||
}, | ||
} | ||
return jas.CreateScannersConfigFile(m.configFileName, configFileContent, jasutils.MaliciousCode) | ||
} | ||
|
||
func (m *MaliciousScanManager) runAnalyzerManager() error { | ||
return m.scanner.AnalyzerManager.Exec(m.configFileName, maliciousScanCommand, filepath.Dir(m.scanner.AnalyzerManager.AnalyzerManagerFullPath), m.scanner.ServerDetails, m.scanner.EnvVars) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package maliciouscode |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package runner | |
import ( | ||
"errors" | ||
"fmt" | ||
"github.com/jfrog/jfrog-cli-security/jas/maliciouscode" | ||
|
||
"github.com/jfrog/gofrog/parallel" | ||
jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" | ||
|
@@ -33,6 +34,8 @@ type JasRunnerParams struct { | |
|
||
ScansToPerform []utils.SubScanType | ||
|
||
// Malicious code scan flags | ||
MaliciousScanType maliciouscode.MaliciousScanType | ||
// Secret scan flags | ||
SecretsScanType secrets.SecretsScanType | ||
// Contextual Analysis scan flags | ||
|
@@ -51,27 +54,31 @@ func AddJasScannersTasks(params JasRunnerParams) (generalError error) { | |
if params.Scanner.AnalyzerManager.AnalyzerManagerFullPath, generalError = jas.GetAnalyzerManagerExecutable(); generalError != nil { | ||
return fmt.Errorf("failed to set analyzer manager executable path: %s", generalError.Error()) | ||
} | ||
// For docker scan we support only secrets and contextual scans. | ||
// For docker scan we support only secrets, malicious code, and contextual scans. | ||
runAllScanners := false | ||
if params.ApplicableScanType == applicability.ApplicabilityScannerType || params.SecretsScanType == secrets.SecretsScannerType { | ||
runAllScanners = true | ||
} | ||
if generalError = addJasScanTaskForModuleIfNeeded(params, utils.ContextualAnalysisScan, runContextualScan(params.Runner, params.Scanner, params.ScanResults, params.Module, params.DirectDependencies, params.ThirdPartyApplicabilityScan, params.ApplicableScanType, params.TargetOutputDir)); generalError != nil { | ||
return | ||
} | ||
//if generalError = addJasScanTaskForModuleIfNeeded(params, utils.ContextualAnalysisScan, runContextualScan(params.Runner, params.Scanner, params.ScanResults, params.Module, params.DirectDependencies, params.ThirdPartyApplicabilityScan, params.ApplicableScanType, params.TargetOutputDir)); generalError != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't forget to uncomment when done There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
// return | ||
//} | ||
if params.ThirdPartyApplicabilityScan { | ||
// Don't execute other scanners when scanning third party dependencies. | ||
return | ||
} | ||
if generalError = addJasScanTaskForModuleIfNeeded(params, utils.SecretsScan, runSecretsScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.SecretsScanType, params.TargetOutputDir)); generalError != nil { | ||
//if generalError = addJasScanTaskForModuleIfNeeded(params, utils.SecretsScan, runSecretsScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.SecretsScanType, params.TargetOutputDir)); generalError != nil { | ||
// return | ||
//} | ||
if generalError = addJasScanTaskForModuleIfNeeded(params, utils.MaliciousCodeScan, runMaliciousScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.MaliciousScanType, params.TargetOutputDir)); generalError != nil { | ||
return | ||
} | ||
if !runAllScanners { | ||
return | ||
} | ||
if generalError = addJasScanTaskForModuleIfNeeded(params, utils.IacScan, runIacScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.TargetOutputDir)); generalError != nil { | ||
return | ||
} | ||
//if generalError = addJasScanTaskForModuleIfNeeded(params, utils.IacScan, runIacScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.TargetOutputDir)); generalError != nil { | ||
// return | ||
//} | ||
return | ||
return addJasScanTaskForModuleIfNeeded(params, utils.SastScan, runSastScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.TargetOutputDir, params.SignedDescriptions)) | ||
} | ||
|
||
|
@@ -102,6 +109,8 @@ func addJasScanTaskForModuleIfNeeded(params JasRunnerParams, subScan utils.SubSc | |
enabled = params.ConfigProfile.Modules[0].ScanConfig.IacScannerConfig.EnableIacScan | ||
case jasutils.Applicability: | ||
enabled = params.ConfigProfile.Modules[0].ScanConfig.EnableContextualAnalysisScan | ||
case jasutils.MaliciousCode: | ||
enabled = params.ConfigProfile.Modules[0].ScanConfig.MaliciousScannerConfig.EnableMaliciousScan | ||
} | ||
if enabled { | ||
generalError = addModuleJasScanTask(jasType, params.Runner, task, params.ScanResults, params.AllowPartialResults) | ||
|
@@ -145,6 +154,24 @@ func runSecretsScan(securityParallelRunner *utils.SecurityParallelRunner, scanne | |
} | ||
} | ||
|
||
func runMaliciousScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.JasScansResults, | ||
module jfrogappsconfig.Module, maliciousScanType maliciouscode.MaliciousScanType, scansOutputDir string) parallel.TaskFunc { | ||
return func(threadId int) (err error) { | ||
defer func() { | ||
securityParallelRunner.JasScannersWg.Done() | ||
}() | ||
vulnerabilitiesResults, violationsResults, err := maliciouscode.RunMaliciousScan(scanner, maliciousScanType, module, threadId) | ||
securityParallelRunner.ResultsMu.Lock() | ||
defer securityParallelRunner.ResultsMu.Unlock() | ||
// We first add the scan results and only then check for errors, so we can store the exit code in order to report it in the end | ||
extendedScanResults.AddJasScanResults(jasutils.MaliciousCode, vulnerabilitiesResults, violationsResults, jas.GetAnalyzerManagerExitCode(err)) | ||
if err = jas.ParseAnalyzerManagerError(jasutils.MaliciousCode, err); err != nil { | ||
return fmt.Errorf("%s%s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) | ||
} | ||
return dumpSarifRunToFileIfNeeded(scansOutputDir, jasutils.MaliciousCode, vulnerabilitiesResults, violationsResults) | ||
} | ||
} | ||
|
||
func runIacScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.JasScansResults, | ||
module jfrogappsconfig.Module, scansOutputDir string) parallel.TaskFunc { | ||
return func(threadId int) (err error) { | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -22,6 +22,8 @@ type SimpleJsonResults struct { | |||||||||
SecretsViolations []SourceCodeRow `json:"secretsViolations"` | ||||||||||
IacsViolations []SourceCodeRow `json:"iacViolations"` | ||||||||||
SastViolations []SourceCodeRow `json:"sastViolations"` | ||||||||||
MaliciousVulnerabilities []SourceCodeRow `json:"malicious_code"` | ||||||||||
MaliciousViolations []SourceCodeRow `json:"maliciousViolations"` | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
make sure the formats are the same... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||||||||||
Errors []SimpleJsonError `json:"errors"` | ||||||||||
Statuses ScanStatus `json:"scansStatus"` | ||||||||||
MultiScanId string `json:"multiScanId,omitempty"` | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for remote push, while developing, make sure you are pointing to a valid branch.
This is expceting the code to be in the machine locally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok