From 14c56bd37de3c1b65eb6d0b074c013d3caa733b0 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 12 Dec 2023 20:29:25 -0600 Subject: [PATCH 1/3] mirror echidna's shrinking --- fuzzing/fuzzer_worker.go | 56 ++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/fuzzing/fuzzer_worker.go b/fuzzing/fuzzer_worker.go index 27848a23..d7f76bc3 100644 --- a/fuzzing/fuzzer_worker.go +++ b/fuzzing/fuzzer_worker.go @@ -388,6 +388,19 @@ func (fw *FuzzerWorker) testShrunkenCallSequence(possibleShrunkSequence calls.Ca return validShrunkSequence, nil } +func (fw *FuzzerWorker) shrinkParam(callSequence calls.CallSequence) { + i := fw.randomProvider.Intn(len(callSequence)) + abiValuesMsgData := callSequence[i].Call.DataAbiValues + for j := 0; j < len(abiValuesMsgData.InputValues); j++ { + mutatedInput, _ := valuegeneration.MutateAbiValue(fw.sequenceGenerator.config.ValueGenerator, fw.shrinkingValueMutator, &abiValuesMsgData.Method.Inputs[j].Type, abiValuesMsgData.InputValues[j]) + abiValuesMsgData.InputValues[j] = mutatedInput + } +} +func (fw *FuzzerWorker) shorten(callSequence calls.CallSequence) { + i := fw.randomProvider.Intn(len(callSequence)) + callSequence = append(callSequence[:i], callSequence[i+1:]...) +} + // shrinkCallSequence takes a provided call sequence and attempts to shrink it by looking for redundant // calls which can be removed, and values which can be minimized, while continuing to satisfy the provided shrink // verifier. @@ -398,7 +411,7 @@ func (fw *FuzzerWorker) shrinkCallSequence(callSequence calls.CallSequence, shri optimizedSequence := callSequence // First try to remove any calls we can. We go from start to end to avoid index shifting. - for i := 0; i < len(optimizedSequence); { + for i := 0; i < 5000; /* TODO add shrink limit config */ { // If our fuzzer context is done, exit out immediately without results. if utils.CheckContextDone(fw.fuzzer.ctx) { return nil, nil @@ -409,8 +422,13 @@ func (fw *FuzzerWorker) shrinkCallSequence(callSequence calls.CallSequence, shri if err != nil { return nil, err } - possibleShrunkSequence = append(possibleShrunkSequence[:i], possibleShrunkSequence[i+1:]...) + coinToss := fw.randomProvider.Int() % 2 + if coinToss == 0 { + fw.shrinkParam(possibleShrunkSequence) + } else { + fw.shorten(possibleShrunkSequence) + } // Test the shrunken sequence. validShrunkSequence, err := fw.testShrunkenCallSequence(possibleShrunkSequence, shrinkRequest) if err != nil { @@ -426,40 +444,6 @@ func (fw *FuzzerWorker) shrinkCallSequence(callSequence calls.CallSequence, shri } } - // Next try to shrink our values of every transaction a given number of rounds. - for i := 0; i < len(optimizedSequence); i++ { - for optimizationRound := 0; optimizationRound < 200; optimizationRound++ { - // If our fuzzer context is done, exit out immediately without results. - if utils.CheckContextDone(fw.fuzzer.ctx) { - return nil, nil - } - - // Clone the optimized sequence. - possibleShrunkSequence, _ := optimizedSequence.Clone() - - // Loop for each argument in the currently indexed call to mutate it. - abiValuesMsgData := possibleShrunkSequence[i].Call.DataAbiValues - for j := 0; j < len(abiValuesMsgData.InputValues); j++ { - mutatedInput, err := valuegeneration.MutateAbiValue(fw.sequenceGenerator.config.ValueGenerator, fw.shrinkingValueMutator, &abiValuesMsgData.Method.Inputs[j].Type, abiValuesMsgData.InputValues[j]) - if err != nil { - return nil, fmt.Errorf("error when shrinking call sequence input argument: %v", err) - } - abiValuesMsgData.InputValues[j] = mutatedInput - } - - // Test the shrunken sequence. - validShrunkSequence, err := fw.testShrunkenCallSequence(possibleShrunkSequence, shrinkRequest) - if err != nil { - return nil, err - } - - // If this current sequence satisfied our conditions, set it as our optimized sequence. - if validShrunkSequence { - optimizedSequence = possibleShrunkSequence - } - } - } - // If the shrink request wanted the sequence recorded in the corpus, do so now. if shrinkRequest.RecordResultInCorpus { err := fw.fuzzer.corpus.AddTestResultCallSequence(optimizedSequence, fw.getNewCorpusCallSequenceWeight(), true) From b974732b08ae2e8647df471a3cb1aa4932909df8 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Wed, 13 Dec 2023 10:47:14 -0600 Subject: [PATCH 2/3] fix inf. loop, increase shrink prob. --- fuzzing/fuzzer.go | 2 +- fuzzing/fuzzer_worker.go | 36 ++++++++++---------- fuzzing/valuegeneration/mutator_shrinking.go | 11 ++++-- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/fuzzing/fuzzer.go b/fuzzing/fuzzer.go index 4686eba8..244f846d 100644 --- a/fuzzing/fuzzer.go +++ b/fuzzing/fuzzer.go @@ -470,7 +470,7 @@ func defaultCallSequenceGeneratorConfigFunc(fuzzer *Fuzzer, valueSet *valuegener func defaultShrinkingValueMutatorFunc(fuzzer *Fuzzer, valueSet *valuegeneration.ValueSet, randomProvider *rand.Rand) (valuegeneration.ValueMutator, error) { // Create the shrinking value mutator for the worker. shrinkingValueMutatorConfig := &valuegeneration.ShrinkingValueMutatorConfig{ - ShrinkValueProbability: 0.1, + ShrinkValueProbability: 1, } shrinkingValueMutator := valuegeneration.NewShrinkingValueMutator(shrinkingValueMutatorConfig, valueSet, randomProvider) return shrinkingValueMutator, nil diff --git a/fuzzing/fuzzer_worker.go b/fuzzing/fuzzer_worker.go index d7f76bc3..65f04a9d 100644 --- a/fuzzing/fuzzer_worker.go +++ b/fuzzing/fuzzer_worker.go @@ -388,17 +388,20 @@ func (fw *FuzzerWorker) testShrunkenCallSequence(possibleShrunkSequence calls.Ca return validShrunkSequence, nil } -func (fw *FuzzerWorker) shrinkParam(callSequence calls.CallSequence) { - i := fw.randomProvider.Intn(len(callSequence)) - abiValuesMsgData := callSequence[i].Call.DataAbiValues - for j := 0; j < len(abiValuesMsgData.InputValues); j++ { - mutatedInput, _ := valuegeneration.MutateAbiValue(fw.sequenceGenerator.config.ValueGenerator, fw.shrinkingValueMutator, &abiValuesMsgData.Method.Inputs[j].Type, abiValuesMsgData.InputValues[j]) - abiValuesMsgData.InputValues[j] = mutatedInput - } +func (fw *FuzzerWorker) shrinkParam(callSequence *calls.CallSequence) { + i := fw.randomProvider.Intn(len(*callSequence)) + abiValuesMsgData := (*callSequence)[i].Call.DataAbiValues + j := fw.randomProvider.Intn(len(abiValuesMsgData.InputValues)) + // for j := 0; j < len(abiValuesMsgData.InputValues); j++ { + mutatedInput, _ := valuegeneration.MutateAbiValue(fw.sequenceGenerator.config.ValueGenerator, fw.shrinkingValueMutator, &abiValuesMsgData.Method.Inputs[j].Type, abiValuesMsgData.InputValues[j]) + (*abiValuesMsgData).InputValues[j] = mutatedInput + // } + (*callSequence)[i].Call.DataAbiValues = abiValuesMsgData } -func (fw *FuzzerWorker) shorten(callSequence calls.CallSequence) { - i := fw.randomProvider.Intn(len(callSequence)) - callSequence = append(callSequence[:i], callSequence[i+1:]...) + +func (fw *FuzzerWorker) shorten(callSequence *calls.CallSequence) { + i := fw.randomProvider.Intn(len(*callSequence)) + *callSequence = append((*callSequence)[:i], (*callSequence)[i+1:]...) } // shrinkCallSequence takes a provided call sequence and attempts to shrink it by looking for redundant @@ -411,7 +414,7 @@ func (fw *FuzzerWorker) shrinkCallSequence(callSequence calls.CallSequence, shri optimizedSequence := callSequence // First try to remove any calls we can. We go from start to end to avoid index shifting. - for i := 0; i < 5000; /* TODO add shrink limit config */ { + for i := 0; i < 5000; i++ /* TODO add shrink limit config */ { // If our fuzzer context is done, exit out immediately without results. if utils.CheckContextDone(fw.fuzzer.ctx) { return nil, nil @@ -424,24 +427,21 @@ func (fw *FuzzerWorker) shrinkCallSequence(callSequence calls.CallSequence, shri } coinToss := fw.randomProvider.Int() % 2 - if coinToss == 0 { - fw.shrinkParam(possibleShrunkSequence) + if coinToss == 0 || len(possibleShrunkSequence) == 1 { + fw.shrinkParam(&possibleShrunkSequence) } else { - fw.shorten(possibleShrunkSequence) + fw.shorten(&possibleShrunkSequence) } // Test the shrunken sequence. validShrunkSequence, err := fw.testShrunkenCallSequence(possibleShrunkSequence, shrinkRequest) if err != nil { return nil, err } - // If this current sequence satisfied our conditions, set it as our optimized sequence. if validShrunkSequence { optimizedSequence = possibleShrunkSequence - } else { - // We didn't remove an item at this index, so we'll iterate to the next one. - i++ } + } // If the shrink request wanted the sequence recorded in the corpus, do so now. diff --git a/fuzzing/valuegeneration/mutator_shrinking.go b/fuzzing/valuegeneration/mutator_shrinking.go index 20b7ff49..75df8546 100644 --- a/fuzzing/valuegeneration/mutator_shrinking.go +++ b/fuzzing/valuegeneration/mutator_shrinking.go @@ -1,10 +1,11 @@ package valuegeneration import ( - "github.com/crytic/medusa/utils" - "github.com/ethereum/go-ethereum/common" "math/big" "math/rand" + + "github.com/crytic/medusa/utils" + "github.com/ethereum/go-ethereum/common" ) // ShrinkingValueMutator represents a ValueMutator used to shrink function inputs and call arguments. @@ -96,7 +97,9 @@ func (g *ShrinkingValueMutator) MutateBytes(b []byte) []byte { randomGeneratorDecision := g.randomProvider.Float32() if randomGeneratorDecision < g.config.ShrinkValueProbability { // Mutate the data for our desired number of rounds + input := bytesShrinkingMethods[g.randomProvider.Intn(len(bytesShrinkingMethods))](g, b) + return input } return b @@ -182,6 +185,10 @@ var stringShrinkingMethods = []func(*ShrinkingValueMutator, string) string{ i := g.randomProvider.Intn(len(s)) return s[:i] + s[i+1:] }, + // ??? + func(g *ShrinkingValueMutator, s string) string { + return "" + }, } // MutateString takes a string input and returns a mutated value based off the input. From 95b9c6da8240f27b673939c2a86f5a273fb562fb Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Wed, 13 Dec 2023 10:53:53 -0600 Subject: [PATCH 3/3] fix panic --- fuzzing/fuzzer_worker.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fuzzing/fuzzer_worker.go b/fuzzing/fuzzer_worker.go index 65f04a9d..a18b052d 100644 --- a/fuzzing/fuzzer_worker.go +++ b/fuzzing/fuzzer_worker.go @@ -391,12 +391,10 @@ func (fw *FuzzerWorker) testShrunkenCallSequence(possibleShrunkSequence calls.Ca func (fw *FuzzerWorker) shrinkParam(callSequence *calls.CallSequence) { i := fw.randomProvider.Intn(len(*callSequence)) abiValuesMsgData := (*callSequence)[i].Call.DataAbiValues - j := fw.randomProvider.Intn(len(abiValuesMsgData.InputValues)) - // for j := 0; j < len(abiValuesMsgData.InputValues); j++ { - mutatedInput, _ := valuegeneration.MutateAbiValue(fw.sequenceGenerator.config.ValueGenerator, fw.shrinkingValueMutator, &abiValuesMsgData.Method.Inputs[j].Type, abiValuesMsgData.InputValues[j]) - (*abiValuesMsgData).InputValues[j] = mutatedInput - // } - (*callSequence)[i].Call.DataAbiValues = abiValuesMsgData + for j := 0; j < len(abiValuesMsgData.InputValues); j++ { + mutatedInput, _ := valuegeneration.MutateAbiValue(fw.sequenceGenerator.config.ValueGenerator, fw.shrinkingValueMutator, &abiValuesMsgData.Method.Inputs[j].Type, abiValuesMsgData.InputValues[j]) + abiValuesMsgData.InputValues[j] = mutatedInput + } } func (fw *FuzzerWorker) shorten(callSequence *calls.CallSequence) {