From 54217ffa2aa09f05ea098b8fd0505d7bf59205b6 Mon Sep 17 00:00:00 2001 From: alexandreps1123 Date: Sat, 17 Feb 2024 02:23:08 -0300 Subject: [PATCH 01/10] feat: add new case build orderer strategy --- fuzz/common.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fuzz/common.go b/fuzz/common.go index 6b054b9..afeb942 100644 --- a/fuzz/common.go +++ b/fuzz/common.go @@ -33,6 +33,8 @@ func buildOrderer(strategy common.PowerScheduleStrategy, contract *dto.ContractD return newCoverageBasedOrderer() case common.DISTANCE_BASED_STRATEGY: return newDistanceBasedOrderer(contract) + case common.DISTANCE_COVERAGE_BASED_STRATEGY: + return newDistanceCoverageBasedOrderer(contract) default: panic(fmt.Sprintf("invalid power schedule strategy: %s", strategy)) } From b19c05dcbc5d9ef42945e23494c16e5321f99c73 Mon Sep 17 00:00:00 2001 From: alexandreps1123 Date: Sat, 17 Feb 2024 04:34:56 -0300 Subject: [PATCH 02/10] feat: add new const strategy --- pkg/common/types.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/common/types.go b/pkg/common/types.go index 08d6145..c1b7ad8 100644 --- a/pkg/common/types.go +++ b/pkg/common/types.go @@ -77,8 +77,9 @@ type DistanceMap map[string]map[string]uint32 // blockPC => instruction => dista type PowerScheduleStrategy string const ( - DISTANCE_BASED_STRATEGY PowerScheduleStrategy = "distance_based" - COVERAGE_BASED_STRATEGY PowerScheduleStrategy = "coverage_based" + DISTANCE_BASED_STRATEGY PowerScheduleStrategy = "distance_based" + COVERAGE_BASED_STRATEGY PowerScheduleStrategy = "coverage_based" + DISTANCE_COVERAGE_BASED_STRATEGY PowerScheduleStrategy = "distance_coverage_based" ) type TaskReport struct { From ea6a0191210c32f1f69c581b565f2e4a4e741fa1 Mon Sep 17 00:00:00 2001 From: alexandreps1123 Date: Wed, 21 Feb 2024 11:23:44 -0300 Subject: [PATCH 03/10] feat: multi strategy orderer --- fuzz/distance_coverage_orderer.go | 80 +++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 fuzz/distance_coverage_orderer.go diff --git a/fuzz/distance_coverage_orderer.go b/fuzz/distance_coverage_orderer.go new file mode 100644 index 0000000..00f67b2 --- /dev/null +++ b/fuzz/distance_coverage_orderer.go @@ -0,0 +1,80 @@ +package fuzz + +import ( + "math" + "sort" + + "github.com/dogefuzz/dogefuzz/pkg/dto" +) + +type distanceCoverageBasedOrderer struct { + contract *dto.ContractDTO +} + +func newDistanceCoverageBasedOrderer(contract *dto.ContractDTO) *distanceCoverageBasedOrderer { + return &distanceCoverageBasedOrderer{contract} +} + +func (o *distanceCoverageBasedOrderer) OrderTransactions(transactions []*dto.TransactionDTO) { + sort.SliceStable(transactions, func(i, j int) bool { + return o.computeScore(transactions[i]) > o.computeScore(transactions[j]) + }) +} + +func (o *distanceCoverageBasedOrderer) computeScore(transaction *dto.TransactionDTO) float64 { + return math.Max(o.computeCriticalInstructionsHits(transaction), math.Max(o.computeCoverage(transaction), o.computeDistance(transaction))) +} + +func (o *distanceCoverageBasedOrderer) computeCoverage(transaction *dto.TransactionDTO) float64 { + var totalInstructions = len(o.contract.DistanceMap) + var coveragePercentage float64 = 0 + + if totalInstructions != 0 { + coveragePercentage = float64(transaction.Coverage) / float64(totalInstructions) + } + + return coveragePercentage +} + +func (o *distanceCoverageBasedOrderer) computeDistance(transaction *dto.TransactionDTO) float64 { + var maxDistance map[string]uint32 + var distanceSum int64 = 0 + var distancePercentage float64 = 0 + + for _, distance := range o.contract.DistanceMap { + if maxDistance != nil { + maxDistance = make(map[string]uint32) + for pc := range distance { + maxDistance[pc] = 0 + } + } + + for instr := range maxDistance { + if val, ok := distance[instr]; ok { + if val != math.MaxUint32 && val > maxDistance[instr] { + maxDistance[instr] = val + } + } + } + } + + for _, distance := range maxDistance { + distanceSum += int64(distance) + } + + if distanceSum != 0 { + distancePercentage = (float64(distanceSum) - float64(transaction.DeltaMinDistance)) / float64(distanceSum) + } + + return distancePercentage +} + +func (o *distanceCoverageBasedOrderer) computeCriticalInstructionsHits(transaction *dto.TransactionDTO) float64 { + var hitsPercentage float64 = 0 + + if o.contract.TargetInstructionsFreq != 0 { + hitsPercentage = float64(transaction.CriticalInstructionsHits) / float64(o.contract.TargetInstructionsFreq) + } + + return hitsPercentage +} From 755b57565acdeccf7f364ebbe827bec81a5187be Mon Sep 17 00:00:00 2001 From: alexandreps1123 Date: Mon, 26 Feb 2024 10:46:12 -0300 Subject: [PATCH 04/10] feat: config to add a new fuzzer type --- cmd/dogefuzz/env.go | 19 ++++++++++++++----- fuzz/common.go | 1 + fuzz/leader.go | 16 ++++++++++------ listener/env.go | 1 + pkg/common/types.go | 7 ++++--- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/cmd/dogefuzz/env.go b/cmd/dogefuzz/env.go index 8efee01..ee8a0aa 100644 --- a/cmd/dogefuzz/env.go +++ b/cmd/dogefuzz/env.go @@ -76,6 +76,7 @@ type Env interface { BlackboxFuzzer() interfaces.Fuzzer GreyboxFuzzer() interfaces.Fuzzer DirectedGreyboxFuzzer() interfaces.Fuzzer + OtherDirectedGreyboxFuzzer() interfaces.Fuzzer PowerSchedule() interfaces.PowerSchedule } @@ -128,11 +129,12 @@ type env struct { transactionsCheckerJob interfaces.CronJob transactionsTimeoutCheckerJob interfaces.CronJob - fuzzerLeader interfaces.FuzzerLeader - blackboxFuzzer interfaces.Fuzzer - greyboxFuzzer interfaces.Fuzzer - directedGreyboxFuzzer interfaces.Fuzzer - powerSchedule interfaces.PowerSchedule + fuzzerLeader interfaces.FuzzerLeader + blackboxFuzzer interfaces.Fuzzer + greyboxFuzzer interfaces.Fuzzer + directedGreyboxFuzzer interfaces.Fuzzer + otherDirectedGreyboxFuzzer interfaces.Fuzzer + powerSchedule interfaces.PowerSchedule } func NewEnv(cfg *config.Config) *env { @@ -477,6 +479,13 @@ func (e *env) DirectedGreyboxFuzzer() interfaces.Fuzzer { return e.directedGreyboxFuzzer } +func (e *env) OtherDirectedGreyboxFuzzer() interfaces.Fuzzer { + if e.otherDirectedGreyboxFuzzer == nil { + e.otherDirectedGreyboxFuzzer = fuzz.NewOtherDirectedGreyboxFuzzer(e) + } + return e.otherDirectedGreyboxFuzzer +} + func (e *env) PowerSchedule() interfaces.PowerSchedule { if e.powerSchedule == nil { e.powerSchedule = fuzz.NewPowerSchedule(e) diff --git a/fuzz/common.go b/fuzz/common.go index afeb942..59d0576 100644 --- a/fuzz/common.go +++ b/fuzz/common.go @@ -15,6 +15,7 @@ type env interface { BlackboxFuzzer() interfaces.Fuzzer GreyboxFuzzer() interfaces.Fuzzer DirectedGreyboxFuzzer() interfaces.Fuzzer + OtherDirectedGreyboxFuzzer() interfaces.Fuzzer PowerSchedule() interfaces.PowerSchedule TransactionService() interfaces.TransactionService diff --git a/fuzz/leader.go b/fuzz/leader.go index 0124ce1..376d3e1 100644 --- a/fuzz/leader.go +++ b/fuzz/leader.go @@ -6,16 +6,18 @@ import ( ) type fuzzerLeader struct { - blackboxFuzzer interfaces.Fuzzer - greyboxFuzzer interfaces.Fuzzer - directedGreyboxFuzzer interfaces.Fuzzer + blackboxFuzzer interfaces.Fuzzer + greyboxFuzzer interfaces.Fuzzer + directedGreyboxFuzzer interfaces.Fuzzer + otherDirectedGreyboxFuzzer interfaces.Fuzzer } func NewFuzzerLeader(e env) *fuzzerLeader { return &fuzzerLeader{ - blackboxFuzzer: e.BlackboxFuzzer(), - greyboxFuzzer: e.GreyboxFuzzer(), - directedGreyboxFuzzer: e.DirectedGreyboxFuzzer(), + blackboxFuzzer: e.BlackboxFuzzer(), + greyboxFuzzer: e.GreyboxFuzzer(), + directedGreyboxFuzzer: e.DirectedGreyboxFuzzer(), + otherDirectedGreyboxFuzzer: e.OtherDirectedGreyboxFuzzer(), } } @@ -27,6 +29,8 @@ func (l *fuzzerLeader) GetFuzzerStrategy(typ common.FuzzingType) (interfaces.Fuz return l.greyboxFuzzer, nil case common.DIRECTED_GREYBOX_FUZZING: return l.directedGreyboxFuzzer, nil + case common.OTHER_DIRECTED_GREYBOX_FUZZING: + return l.otherDirectedGreyboxFuzzer, nil default: return nil, ErrFuzzerTypeNotFound } diff --git a/listener/env.go b/listener/env.go index 051102c..4149f0f 100644 --- a/listener/env.go +++ b/listener/env.go @@ -40,5 +40,6 @@ type Env interface { BlackboxFuzzer() interfaces.Fuzzer GreyboxFuzzer() interfaces.Fuzzer DirectedGreyboxFuzzer() interfaces.Fuzzer + OtherDirectedGreyboxFuzzer() interfaces.Fuzzer PowerSchedule() interfaces.PowerSchedule } diff --git a/pkg/common/types.go b/pkg/common/types.go index c1b7ad8..6ed4d5d 100644 --- a/pkg/common/types.go +++ b/pkg/common/types.go @@ -30,9 +30,10 @@ var ( type FuzzingType string const ( - BLACKBOX_FUZZING FuzzingType = "blackbox" - GREYBOX_FUZZING FuzzingType = "greybox" - DIRECTED_GREYBOX_FUZZING FuzzingType = "directed_greybox" + BLACKBOX_FUZZING FuzzingType = "blackbox" + GREYBOX_FUZZING FuzzingType = "greybox" + DIRECTED_GREYBOX_FUZZING FuzzingType = "directed_greybox" + OTHER_DIRECTED_GREYBOX_FUZZING FuzzingType = "other_directed_greybox" ) type ContractStatus string From a80ea9f69edc6249b2ae5e24fc9a8073e524676b Mon Sep 17 00:00:00 2001 From: alexandreps1123 Date: Mon, 26 Feb 2024 11:01:27 -0300 Subject: [PATCH 05/10] feat: new fuzzer type to use new strategy to order seeds --- fuzz/other_directed_greybox.go | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 fuzz/other_directed_greybox.go diff --git a/fuzz/other_directed_greybox.go b/fuzz/other_directed_greybox.go new file mode 100644 index 0000000..cf1bf02 --- /dev/null +++ b/fuzz/other_directed_greybox.go @@ -0,0 +1,66 @@ +package fuzz + +import ( + "strings" + + "github.com/dogefuzz/dogefuzz/pkg/common" + "github.com/dogefuzz/dogefuzz/pkg/interfaces" + "github.com/ethereum/go-ethereum/accounts/abi" +) + +// This is temporally, it is like 'directed_greybox' but with another strategy to order seeds +type otherDirectedGreyboxFuzzer struct { + powerSchedule interfaces.PowerSchedule + + solidityService interfaces.SolidityService + functionService interfaces.FunctionService + contractService interfaces.ContractService +} + +func NewOtherDirectedGreyboxFuzzer(e env) *otherDirectedGreyboxFuzzer { + return &otherDirectedGreyboxFuzzer{ + powerSchedule: e.PowerSchedule(), + solidityService: e.SolidityService(), + functionService: e.FunctionService(), + contractService: e.ContractService(), + } +} + +func (f *otherDirectedGreyboxFuzzer) GenerateInput(functionId string) ([]interface{}, error) { + function, err := f.functionService.Get(functionId) + if err != nil { + return nil, err + } + + contract, err := f.contractService.Get(function.ContractId) + if err != nil { + return nil, err + } + + abiDefinition, err := abi.JSON(strings.NewReader(contract.AbiDefinition)) + if err != nil { + return nil, err + } + method := abiDefinition.Methods[function.Name] + + seedsList, err := f.powerSchedule.RequestSeeds(functionId, common.DISTANCE_COVERAGE_BASED_STRATEGY) + if err != nil { + return nil, err + } + + chosenSeeds := common.RandomChoice(seedsList) + + inputs := make([]interface{}, len(method.Inputs)) + for inputsIdx, inputDefinition := range method.Inputs { + handler, err := f.solidityService.GetTypeHandlerWithContext(inputDefinition.Type) + if err != nil { + return nil, err + } + handler.SetValue(chosenSeeds[inputsIdx]) + mutationFunction := common.RandomChoice(handler.GetMutators()) + mutationFunction() + inputs[inputsIdx] = handler.GetValue() + } + + return inputs, nil +} From 7c894088f4bb68d813aea5d467479d14b0b3a49a Mon Sep 17 00:00:00 2001 From: alexandreps1123 Date: Wed, 28 Feb 2024 16:56:14 -0300 Subject: [PATCH 06/10] fix: changed condition in computeDistance method --- fuzz/distance_coverage_orderer.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fuzz/distance_coverage_orderer.go b/fuzz/distance_coverage_orderer.go index 00f67b2..61347fa 100644 --- a/fuzz/distance_coverage_orderer.go +++ b/fuzz/distance_coverage_orderer.go @@ -40,9 +40,10 @@ func (o *distanceCoverageBasedOrderer) computeDistance(transaction *dto.Transact var maxDistance map[string]uint32 var distanceSum int64 = 0 var distancePercentage float64 = 0 + var minDistance uint64 = transaction.DeltaMinDistance for _, distance := range o.contract.DistanceMap { - if maxDistance != nil { + if maxDistance == nil { maxDistance = make(map[string]uint32) for pc := range distance { maxDistance[pc] = 0 @@ -62,8 +63,12 @@ func (o *distanceCoverageBasedOrderer) computeDistance(transaction *dto.Transact distanceSum += int64(distance) } + if minDistance >= uint64(math.MaxUint32) { + minDistance -= math.MaxUint32 + } + if distanceSum != 0 { - distancePercentage = (float64(distanceSum) - float64(transaction.DeltaMinDistance)) / float64(distanceSum) + distancePercentage = float64(minDistance) / float64(distanceSum) } return distancePercentage From 4a737ec5d771392b8f5a49f1e4e545f45f135f65 Mon Sep 17 00:00:00 2001 From: alexandreps1123 Date: Tue, 5 Mar 2024 22:54:56 -0300 Subject: [PATCH 07/10] feat: change method to compute coverage --- fuzz/distance_coverage_orderer.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fuzz/distance_coverage_orderer.go b/fuzz/distance_coverage_orderer.go index 61347fa..3edfd7e 100644 --- a/fuzz/distance_coverage_orderer.go +++ b/fuzz/distance_coverage_orderer.go @@ -26,14 +26,14 @@ func (o *distanceCoverageBasedOrderer) computeScore(transaction *dto.Transaction } func (o *distanceCoverageBasedOrderer) computeCoverage(transaction *dto.TransactionDTO) float64 { - var totalInstructions = len(o.contract.DistanceMap) - var coveragePercentage float64 = 0 + var totalInstructions = len(o.contract.CFG.Instructions) + var executedInstructions = len(transaction.ExecutedInstructions) if totalInstructions != 0 { - coveragePercentage = float64(transaction.Coverage) / float64(totalInstructions) + return float64(executedInstructions) / float64(totalInstructions) } - return coveragePercentage + return 0 } func (o *distanceCoverageBasedOrderer) computeDistance(transaction *dto.TransactionDTO) float64 { @@ -75,11 +75,9 @@ func (o *distanceCoverageBasedOrderer) computeDistance(transaction *dto.Transact } func (o *distanceCoverageBasedOrderer) computeCriticalInstructionsHits(transaction *dto.TransactionDTO) float64 { - var hitsPercentage float64 = 0 - if o.contract.TargetInstructionsFreq != 0 { - hitsPercentage = float64(transaction.CriticalInstructionsHits) / float64(o.contract.TargetInstructionsFreq) + return float64(transaction.CriticalInstructionsHits) / float64(o.contract.TargetInstructionsFreq) } - return hitsPercentage + return 0 } From 443fb5e1d6c7213691cf9de1ec6ada23ccd43d0c Mon Sep 17 00:00:00 2001 From: Fausto Carvalho Date: Tue, 26 Mar 2024 17:11:33 -0300 Subject: [PATCH 08/10] Remove optimize as it was reducing coverage report --- pkg/solc/compiler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/solc/compiler.go b/pkg/solc/compiler.go index aa9a3d0..9aabe44 100644 --- a/pkg/solc/compiler.go +++ b/pkg/solc/compiler.go @@ -133,7 +133,7 @@ func (c *solidityCompiler) downloadSolcBinaryBasedOnVersion(version *semver.Vers func buildArgs(version *semver.Version) []string { p := []string{ "--combined-json", "ast,bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc", - "--optimize", // code optimizer switched on + //"--optimize", // code optimizer switched on "--allow-paths", "., ./, ../", // default to support relative path: ./ ../ . } version0_4_6, _ := semver.NewVersion("0.4.6") From dc1dee986d4ac0400cb030c279b6794bfa92cd46 Mon Sep 17 00:00:00 2001 From: Fausto Carvalho Date: Sat, 30 Mar 2024 07:46:40 -0300 Subject: [PATCH 09/10] Download from external source early, and retyr when failed --- pkg/solc/compiler.go | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/pkg/solc/compiler.go b/pkg/solc/compiler.go index 9aabe44..939ab58 100644 --- a/pkg/solc/compiler.go +++ b/pkg/solc/compiler.go @@ -13,6 +13,7 @@ import ( "regexp" "strconv" "strings" + "time" "github.com/Masterminds/semver/v3" "github.com/dogefuzz/dogefuzz/pkg/common" @@ -25,10 +26,15 @@ var ErrContractNotFound = errors.New("the contract was not found in compiled cod type solidityCompiler struct { storageFolder string + versions []string } func NewSolidityCompiler(storageFolder string) *solidityCompiler { - return &solidityCompiler{storageFolder: storageFolder} + versions, err := getDescendingOrderedVersionsFromSolidyBinariesEndpoint() + if err != nil { + versions = []string{} + } + return &solidityCompiler{storageFolder: storageFolder, versions: versions} } func (c *solidityCompiler) CompileSource(contractName string, contractSource string) (*common.Contract, error) { @@ -36,12 +42,24 @@ func (c *solidityCompiler) CompileSource(contractName string, contractSource str return nil, ErrEmptySourceFile } - solcVersion, err := getIdealSolcVersionBasedOnSource(contractSource) - if err != nil { - return nil, err + var solcVersion *semver.Version + maxRetries := 5 + var err error + for retries := 1; retries <= maxRetries; retries++ { + if retries == maxRetries { + return nil, err + } + + solcVersion, err = c.getIdealSolcVersionBasedOnSource(contractSource) + if err != nil { + time.Sleep(100 * time.Millisecond) + continue + } + break } var solcBinaryLocation string + if location, ok := c.getSolcBinaryLocationIfExists(solcVersion); ok { solcBinaryLocation = location } else { @@ -154,10 +172,14 @@ func run(cmd *exec.Cmd, source string, maxVersion *semver.Version) (map[string]* return compiler.ParseCombinedJSON(stdout.Bytes(), source, maxVersion.String(), maxVersion.String(), strings.Join(buildArgs(maxVersion), " ")) } -func getIdealSolcVersionBasedOnSource(source string) (*semver.Version, error) { - versions, err := getDescendingOrderedVersionsFromSolidyBinariesEndpoint() - if err != nil { - return nil, err +func (c *solidityCompiler) getIdealSolcVersionBasedOnSource(source string) (*semver.Version, error) { + var versions = c.versions + if len(versions) == 0 { + var err error + versions, err = getDescendingOrderedVersionsFromSolidyBinariesEndpoint() + if err != nil { + return nil, err + } } versionConstraint, err := extractVersionConstraintFromSource(source) From ab74b3031473ea3e46035dfaf91bc4f3c766ede3 Mon Sep 17 00:00:00 2001 From: Fausto Carvalho Date: Thu, 4 Apr 2024 19:27:37 -0300 Subject: [PATCH 10/10] Back with optimize in solc as vandal dont like it --- pkg/solc/compiler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/solc/compiler.go b/pkg/solc/compiler.go index 939ab58..842e61e 100644 --- a/pkg/solc/compiler.go +++ b/pkg/solc/compiler.go @@ -151,7 +151,7 @@ func (c *solidityCompiler) downloadSolcBinaryBasedOnVersion(version *semver.Vers func buildArgs(version *semver.Version) []string { p := []string{ "--combined-json", "ast,bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc", - //"--optimize", // code optimizer switched on + "--optimize", // code optimizer switched on "--allow-paths", "., ./, ../", // default to support relative path: ./ ../ . } version0_4_6, _ := semver.NewVersion("0.4.6")