wtdcode / fuzzercorn

Bring libfuzzer to Unicorn
26 stars 1 forks source link

Problem while fuzzing with qiling #2

Open SamNzo opened 1 year ago

SamNzo commented 1 year ago

I am trying to use fuzzercorn with qiling with this example: https://github.com/qilingframework/qiling/blob/master/examples/fuzzing/linux_x8664/libfuzzer_x8664_linux.py

I first installed fuzzercorn with pip but when executing libfuzzer_x8664_linux.py I got the following

WARNING: Failed to find function "__sanitizer_acquire_crash_state".
WARNING: Failed to find function "__sanitizer_print_stack_trace".
WARNING: Failed to find function "__sanitizer_set_death_callback".

It expected an input as if I executed the binary without fuzzing and then returned a seg fault

To fix it I tried to clone the fuzzercorn repo, build libfuzzercorn.so and create a sym link between it and the one I installed with pip

This time when executing libfuzzer_x8664_linux.py I still had this waiting for an input

WARNING: Failed to find function "__sanitizer_acquire_crash_state".
WARNING: Failed to find function "__sanitizer_print_stack_trace".
WARNING: Failed to find function "__sanitizer_set_death_callback".

But when I entered one it looked like libfuzzer was working

A
A�Y���
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 1757911264
INFO: 4096 Extra Counters
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2  INITED ft: 2 corp: 1/1b exec/s: 0 rss: 84Mb
#2048   pulse  ft: 2 corp: 1/1b lim: 21 exec/s: 682 rss: 86Mb
#4096   pulse  ft: 2 corp: 1/1b lim: 43 exec/s: 682 rss: 87Mb
#8192   pulse  ft: 2 corp: 1/1b lim: 80 exec/s: 630 rss: 89Mb
#16384  pulse  ft: 2 corp: 1/1b lim: 163 exec/s: 630 rss: 93Mb

However it keeps doing this until it eventually runs out of memory without finding any crash

I'm confused, do you know what am I doing wrong ?

thx

wtdcode commented 1 year ago

Hey, thanks for your interest! The symbol seems from sanitizers and shouldn't be used with fuzzercorn actually. i.e. you could safely ignore them.

SamNzo commented 1 year ago

Thank you, this answers my first question !

But I still have two more:

wtdcode commented 1 year ago

This doesn't seem correct indeed. Could you share the full reproduction case, including the script and binary?

SamNzo commented 1 year ago

The script is the following:

#!/usr/bin/python3

from fuzzercorn import *
from unicorn import *
from qiling import Qiling
from qiling.extensions import pipe

import sys, os, ctypes

class SimpleFuzzer:

    def run(self):
        ql = Qiling(["./x8664_fuzz"], "../../rootfs/x8664_linux", console=False)
        ba = ql.loader.images[0].base
        try:
            # Only instrument the function `fun`, so we don't need to instrument libc and ld
            FuzzerCornFuzz(ql.uc, sys.argv, [ql.os.exit_point], self.place_input, self.init, UserData=ql, Ranges=[(ba+0x11c9, ba+0x1274)], CountersCount=4096)
        except Exception as ex:
            os.abort() # Quick exit

    def place_input(self, uc: Uc, data: ctypes.Array, ql: Qiling):
        # Restore from snapshot
        ql.restore(self.snapshot)
        ql.os.stdin = pipe.SimpleInStream(1)
        ql.os.stdin.write(bytes(data))
        return 1

    def init(self, uc: Uc, argv: list, ql: Qiling):
        ba = ql.loader.images[0].base
        # Call os.abort when ___stack_chk_fail is called (stack overflow)
        ql.hook_address(callback=lambda x: os.abort(), address=ba+0x126e) # ___stack_chk_fail
        # Execute binary until given address
        ql.run(end=ba+0x1293) # Run to main.

        # Save a snapshot.
        self.snapshot = ql.save()
        return 0

if __name__ == "__main__":
    # chmod +x ./libfuzzer_x8664_linux.py
    # ./libfuzzer_x8664_linux.py -jobs=6 -workers=6
    SimpleFuzzer().run()

The binary is: https://github.com/qilingframework/qiling/blob/master/examples/fuzzing/linux_x8664/x8664_fuzz