Skip to content

Commit

Permalink
feat: add flag to ignore crashes
Browse files Browse the repository at this point in the history
  • Loading branch information
NSEcho committed Sep 17, 2023
1 parent 9d10541 commit fa5fd07
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 7 deletions.
18 changes: 15 additions & 3 deletions cmd/fuzz.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cmd

import (
"context"
"errors"
"fmt"
"github.com/fatih/color"
"github.com/frida/frida-go/frida"
"github.com/nsecho/furlzz/mutator"
Expand Down Expand Up @@ -77,6 +79,11 @@ var fuzzCmd = &cobra.Command{
return err
}

crash, err := cmd.Flags().GetBool("crash")
if err != nil {
return err
}

l.Infof("Fuzzing base URL \"%s\"", base)
if strings.Contains(base, "FUZZ") {
l.Infof("Read %d inputs from %s directory",
Expand Down Expand Up @@ -123,7 +130,7 @@ var fuzzCmd = &cobra.Command{
l.Infof("Session detached; reason=%s", reason.String())
out := crashSHA256(lastInput)
err := func() error {
f, err := os.Create(out)
f, err := os.Create(fmt.Sprintf("fcrash_%s_%s", app, out))
if err != nil {
return err
}
Expand Down Expand Up @@ -167,13 +174,17 @@ var fuzzCmd = &cobra.Command{
_ = script.ExportsCall("setup", method, uiapp, delegate, scene)
l.Infof("Finished setup")

m := mutator.NewMutator(base, runs, fn, validInputs...)
m := mutator.NewMutator(base, app, runs, fn, crash, validInputs...)
ch := m.Mutate()

for mutated := range ch {
lastInput = mutated.Input
l.Infof("[%s] %s\n", color.New(color.FgCyan).Sprintf("%s", mutated.Mutation), mutated.Input)
_ = script.ExportsCall("fuzz", method, mutated.Input)
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
if err := script.ExportsCallWithContext(ctx, "fuzz", method, mutated.Input); err == frida.ErrContextCancelled {
sess.Detach()
break
}
if timeout > 0 {
time.Sleep(time.Duration(timeout) * time.Second)
}
Expand All @@ -191,6 +202,7 @@ func init() {
fuzzCmd.Flags().StringP("delegate", "d", "", "if the method is scene_activity, you need to specify UISceneDelegate class")
fuzzCmd.Flags().StringP("uiapp", "u", "", "UIApplication name")
fuzzCmd.Flags().StringP("scene", "s", "", "scene class name")
fuzzCmd.Flags().BoolP("crash", "c", false, "ignore previous crashes")
fuzzCmd.Flags().UintP("runs", "r", 0, "number of runs")
fuzzCmd.Flags().UintP("timeout", "t", 1, "sleep X seconds between each case")

Expand Down
30 changes: 30 additions & 0 deletions mutator/helpers.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package mutator

import (
"io"
"os"
"path/filepath"
)

func (m *Mutator) getFuzzedInput() string {
if m.multipleRounds {
if m.lastInput == "" {
Expand All @@ -17,3 +23,27 @@ func (m *Mutator) fetchInput() string {
k := m.r.Intn(len(m.validInputs))
return m.validInputs[k]
}

func readCrashes(app string) ([]string, error) {
files, _ := filepath.Glob("fcrash_*_*")

var crashes []string
for _, fl := range files {
data, err := func() ([]byte, error) {
f, err := os.Open(fl)
if err != nil {
return nil, err
}
defer f.Close()

data, _ := io.ReadAll(f)
return data, nil
}()
if err != nil {
return nil, err
}
crashes = append(crashes, string(data))
}

return crashes, nil
}
39 changes: 35 additions & 4 deletions mutator/mutator.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
package mutator

import (
"bytes"
"fmt"
"math/rand"
"strings"
"time"
)

func NewMutator(inp string, runs uint, fnName string, validInputs ...string) *Mutator {
func NewMutator(inp, app string, runs uint, fnName string, ignoreCrashes bool, validInputs ...string) *Mutator {
var crashes []string
if ignoreCrashes {
c, err := readCrashes(app)
if err != nil {
panic(fmt.Sprintf("error reading crashes: %v", err))
}
crashes = c
}

return &Mutator{
fuzzIdx: strings.Index(inp, "FUZZ"),
baseURL: inp,
input: inp,
fnName: fnName,
ignoreCrashes: ignoreCrashes,
ch: make(chan *Mutated, 100),
r: rand.New(rand.NewSource(time.Now().UnixNano())),
runs: runs,
validInputs: validInputs,
crashes: crashes,
multipleRounds: false,
}
}
Expand All @@ -27,9 +40,11 @@ type Mutator struct {
input string
lastInput string
fnName string
ignoreCrashes bool
ch chan *Mutated
r *rand.Rand
validInputs []string
crashes []string
multipleRounds bool
}

Expand All @@ -42,19 +57,25 @@ func (m *Mutator) Mutate() <-chan *Mutated {
go func() {
if m.runs > 0 {
for i := 0; i < int(m.runs); i++ {
m.mutateAndSend()
inp := m.mutateAndSend()
for !inp {
inp = m.mutateAndSend()
}
}
close(m.ch)
} else {
for {
m.mutateAndSend()
inp := m.mutateAndSend()
for !inp {
inp = m.mutateAndSend()
}
}
}
}()
return m.ch
}

func (m *Mutator) mutateAndSend() {
func (m *Mutator) mutateAndSend() bool {
var mutatedInput string
var method string
mut := m.r.Intn(len(mutations) + 1)
Expand Down Expand Up @@ -92,6 +113,15 @@ func (m *Mutator) mutateAndSend() {
mutatedInput = applyFunctions[m.fnName](mutatedInput)
}

if m.ignoreCrashes && len(m.crashes) > 0 {
for _, crash := range m.crashes {
crashInp := strings.Replace(crash, m.baseURL[:m.fuzzIdx], "", -1)
if bytes.Equal([]byte(crashInp), []byte(mutatedInput)) {
return false
}
}
}

if m.fuzzIdx == -1 || len(m.validInputs) == 0 {
m.ch <- &Mutated{
Input: mutatedInput,
Expand All @@ -104,4 +134,5 @@ func (m *Mutator) mutateAndSend() {
}
}
m.lastInput = mutatedInput
return true
}

0 comments on commit fa5fd07

Please sign in to comment.