diff --git a/cmd/fuzz.go b/cmd/fuzz.go index 53a26ce..5dd38bf 100644 --- a/cmd/fuzz.go +++ b/cmd/fuzz.go @@ -15,7 +15,7 @@ var fuzzCmd = &cobra.Command{ Use: "fuzz", Short: "Fuzz URL scheme", RunE: func(cmd *cobra.Command, args []string) error { - var validInputs [][]byte + var validInputs []string var err error base, err := cmd.Flags().GetString("base") @@ -112,7 +112,7 @@ var fuzzCmd = &cobra.Command{ l.Infof("Attached to %s", app) - var lastInput []byte + var lastInput string sess.On("detached", func(reason frida.SessionDetachReason, crash *frida.Crash) { l.Infof("Session detached; reason=%s", reason.String()) @@ -122,7 +122,7 @@ var fuzzCmd = &cobra.Command{ if err != nil { return err } - f.Write(lastInput) + f.WriteString(lastInput) return nil }() if err != nil { @@ -162,13 +162,13 @@ var fuzzCmd = &cobra.Command{ _ = script.ExportsCall("setup", method, uiapp, delegate) l.Infof("Finished setup") - m := mutator.NewMutator([]byte(base), runs, fn, validInputs...) + m := mutator.NewMutator(base, runs, fn, 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, string(mutated.Input)) + _ = script.ExportsCall("fuzz", method, mutated.Input) if timeout > 0 { time.Sleep(time.Duration(timeout) * time.Second) } diff --git a/cmd/root.go b/cmd/root.go index 90e8e3b..27debc6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -29,13 +29,13 @@ func Execute(sc string) error { return rootCmd.Execute() } -func readInputs(dirPath string) ([][]byte, error) { +func readInputs(dirPath string) ([]string, error) { files, err := os.ReadDir(dirPath) if err != nil { return nil, err } - var validInputs [][]byte + var validInputs []string for _, fl := range files { if fl.IsDir() { @@ -54,13 +54,13 @@ func readInputs(dirPath string) ([][]byte, error) { if err != nil { return nil, err } - validInputs = append(validInputs, data) + validInputs = append(validInputs, string(data)) } return validInputs, nil } -func crashSHA256(inp []byte) string { +func crashSHA256(inp string) string { h := sha256.New() - h.Write(inp) + h.Write([]byte(inp)) return fmt.Sprintf("%x", h.Sum(nil)) } diff --git a/mutator/helpers.go b/mutator/helpers.go index c0155e7..b793089 100644 --- a/mutator/helpers.go +++ b/mutator/helpers.go @@ -1,8 +1,8 @@ package mutator -func (m *Mutator) getFuzzedInput() []byte { +func (m *Mutator) getFuzzedInput() string { if m.multipleRounds { - if len(m.lastInput) == 0 { + if m.lastInput == "" { m.lastInput = m.fetchInput() } return m.lastInput @@ -10,7 +10,7 @@ func (m *Mutator) getFuzzedInput() []byte { return m.fetchInput() } -func (m *Mutator) fetchInput() []byte { +func (m *Mutator) fetchInput() string { if m.fuzzIdx == -1 || len(m.validInputs) == 0 { return m.input } diff --git a/mutator/mutations.go b/mutator/mutations.go index 1360e24..0f2f1f2 100644 --- a/mutator/mutations.go +++ b/mutator/mutations.go @@ -1,10 +1,11 @@ package mutator import ( - "bytes" + "strings" + "unicode" ) -type mutateFn func(m *Mutator) []byte +type mutateFn func(m *Mutator) string var mutations = map[string]mutateFn{ "insert": insert, @@ -18,60 +19,46 @@ var mutations = map[string]mutateFn{ } // insert inserts random byte at random location inside the input -func insert(m *Mutator) []byte { +func insert(m *Mutator) string { inp := m.getFuzzedInput() pos := m.r.Intn(len(inp)) - char := byte(m.r.Intn(255)) - - res := make([]byte, len(inp)+1) - - k := 0 - - for i := 0; i < len(inp); i++ { - if i == pos { - res[k] = char - res[k+1] = inp[i] - k += 2 - } else { - res[k] = inp[i] - k++ + var char byte + for { + c := m.r.Intn(unicode.MaxASCII) + if unicode.IsPrint(rune(c)) { + char = byte(c) + break } } - return res + return inp[:pos] + string(char) + inp[pos:] } // del deletes random byte -func del(m *Mutator) []byte { +func del(m *Mutator) string { inp := m.getFuzzedInput() pos := m.r.Intn(len(inp)) - res := make([]byte, len(inp)-1) - - k := 0 - for i := 0; i < len(inp); i++ { - if i == pos { - continue - } - res[k] = inp[i] - k++ - } - - return res + return inp[:pos] + inp[pos+1:] } // substitute substitutes byte at random position with random byte -func substitute(m *Mutator) []byte { +func substitute(m *Mutator) string { inp := m.getFuzzedInput() pos := m.r.Intn(len(inp)) - char := byte(m.r.Intn(255)) - - res := make([]byte, len(inp)) - + var char byte + for { + c := m.r.Intn(unicode.MaxASCII) + if unicode.IsPrint(rune(c)) { + char = byte(c) + break + } + } + var res string for i, c := range inp { if i == pos { - res[i] = char + res += string(char) } else { - res[i] = c + res += string(c) } } return res @@ -79,7 +66,7 @@ func substitute(m *Mutator) []byte { // byteOp takes random byte and random position inside the string // and do arithmetic operation on them (+, -, *, /) -func byteOp(m *Mutator) []byte { +func byteOp(m *Mutator) string { b := make([]byte, 1) m.r.Read(b) inp := m.getFuzzedInput() @@ -87,21 +74,21 @@ func byteOp(m *Mutator) []byte { op := m.r.Intn(4) - res := make([]byte, len(inp)) + res := make([]rune, len(inp)) for i, r := range inp { if i == pos { switch op { case 0: - res[i] = r + b[0] + res[i] = r + rune(b[0]) case 1: - res[i] = r - b[0] + res[i] = r - rune(b[0]) case 2: - res[i] = r * b[0] + res[i] = r * rune(b[0]) default: if b[0] != 0 { - res[i] = r / b[0] + res[i] = r / rune(b[0]) } else { - res[i] = r + b[0] + res[i] = r + rune(b[0]) } } } else { @@ -109,12 +96,12 @@ func byteOp(m *Mutator) []byte { } } - return res + return string(res) } // duplicateRange duplicates random range inside the original string random // number of times -func duplicateRange(m *Mutator) []byte { +func duplicateRange(m *Mutator) string { inp := m.getFuzzedInput() start := m.r.Intn(len(inp)) @@ -128,43 +115,29 @@ func duplicateRange(m *Mutator) []byte { } rng := inp[start:end] - duplicatedBytes := bytes.Repeat(rng, countOfDuplications) - - res := make([]byte, len(inp)+len(duplicatedBytes)) - - k := 0 - for i := 0; i < end; i++ { - res[k] = inp[i] - k++ - } - - for i := 0; i < len(duplicatedBytes); i++ { - res[k] = duplicatedBytes[i] - k++ - } - for i := end; i < len(inp); i++ { - res[k] = inp[i] - k++ - } + res := "" + res += inp[:start] + res += strings.Repeat(rng, countOfDuplications) + res += inp[end:] return res } // bitFlip flips the bit at random position inside random location inside input -func bitFlip(m *Mutator) []byte { +func bitFlip(m *Mutator) string { inp := m.getFuzzedInput() pos := m.r.Intn(len(inp)) bitPosition := m.r.Intn(8) - res := make([]byte, len(inp)) + res := "" for i, r := range inp { if i == pos { - res[i] = r ^ (1 << bitPosition) + res += string(r ^ (1 << bitPosition)) } else { - res[i] = r + res += string(r) } } @@ -172,19 +145,19 @@ func bitFlip(m *Mutator) []byte { } // bitmask applies random bitmask on random location inside the string -func bitmask(m *Mutator) []byte { +func bitmask(m *Mutator) string { inp := m.getFuzzedInput() pos := m.r.Intn(len(inp)) bm := m.r.Intn(255) - res := make([]byte, len(inp)) + res := "" for i, r := range inp { if pos == i { - res[i] = inp[i] ^ uint8(bm) + res += string(inp[i] ^ uint8(bm)) } else { - res[i] = r + res += string(r) } } @@ -192,12 +165,12 @@ func bitmask(m *Mutator) []byte { } // duplicate duplicates original string random number of times (2 < 10) -func duplicate(m *Mutator) []byte { +func duplicate(m *Mutator) string { inp := m.getFuzzedInput() var count int for count = m.r.Intn(10); count < 1; count = m.r.Intn(10) { } - return bytes.Repeat(inp, count) + return strings.Repeat(inp, count) } diff --git a/mutator/mutator.go b/mutator/mutator.go index 10cabb0..44c02cd 100644 --- a/mutator/mutator.go +++ b/mutator/mutator.go @@ -1,14 +1,14 @@ package mutator import ( - "bytes" "math/rand" + "strings" "time" ) -func NewMutator(inp []byte, runs uint, fnName string, validInputs ...[]byte) *Mutator { +func NewMutator(inp string, runs uint, fnName string, validInputs ...string) *Mutator { return &Mutator{ - fuzzIdx: bytes.Index(inp, []byte("FUZZ")), + fuzzIdx: strings.Index(inp, "FUZZ"), baseURL: inp, input: inp, fnName: fnName, @@ -23,18 +23,18 @@ func NewMutator(inp []byte, runs uint, fnName string, validInputs ...[]byte) *Mu type Mutator struct { fuzzIdx int runs uint - baseURL []byte - input []byte - lastInput []byte + baseURL string + input string + lastInput string fnName string ch chan *Mutated r *rand.Rand - validInputs [][]byte + validInputs []string multipleRounds bool } type Mutated struct { - Input []byte + Input string Mutation string } @@ -55,7 +55,7 @@ func (m *Mutator) Mutate() <-chan *Mutated { } func (m *Mutator) mutateAndSend() { - var mutatedInput []byte + var mutatedInput string var method string mut := m.r.Intn(len(mutations) + 1) // run random mutations random number of times @@ -99,7 +99,7 @@ func (m *Mutator) mutateAndSend() { } } else { m.ch <- &Mutated{ - Input: bytes.Replace(m.baseURL, []byte("FUZZ"), mutatedInput, -1), + Input: strings.Replace(m.baseURL, "FUZZ", mutatedInput, -1), Mutation: method, } } diff --git a/mutator/post_process.go b/mutator/post_process.go index 172e35a..140e0cb 100644 --- a/mutator/post_process.go +++ b/mutator/post_process.go @@ -5,19 +5,17 @@ import ( "net/url" ) -type applyFn func(input []byte) []byte +type applyFn func(input string) string var applyFunctions = map[string]applyFn{ "url": urlEncode, "base64": base64Encode, } -func urlEncode(input []byte) []byte { - return []byte(url.QueryEscape(string(input))) +func urlEncode(input string) string { + return url.QueryEscape(input) } -func base64Encode(input []byte) []byte { - dst := make([]byte, base64.StdEncoding.EncodedLen(len(input))) - base64.StdEncoding.Encode(dst, input) - return dst +func base64Encode(input string) string { + return base64.StdEncoding.EncodeToString([]byte(input)) }