jwilk / python-afl

American Fuzzy Lop fork server and instrumentation for pure-Python code
https://jwilk.net/software/python-afl
MIT License
350 stars 33 forks source link

Python-afl different behaviour on different python versions #11

Closed ricostrong closed 5 years ago

ricostrong commented 5 years ago

Hey, it seems like python-afl can have different behaviour depending on the python version. My python-afl script works correctly under python2, however it does not work as well in python3

yee@haw:~/fuzz/python$ py-afl-fuzz  -i fuzz/in  -o fuzz/out -- python3 python_afl_fuzz.py
afl-fuzz 2.52b by <lcamtuf@google.com>
[+] You have 12 CPU cores and 1 runnable tasks (utilization: 8%).
[+] Try parallel jobs - see /usr/share/doc/afl-doc/docs/parallel_fuzzing.txt.
[*] Checking CPU core loadout...
[+] Found a free CPU core, binding to #1.
[*] Checking core_pattern...
[*] Checking CPU scaling governor...
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning 'fuzz/in'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,orig:aaa'...
[*] Spinning up the fork server...
[+] All right - fork server is up.

[-] Oops, the program crashed with one of the test cases provided. There are
    several possible explanations:

    - The test case causes known crashes under normal working conditions. If
      so, please remove it. The fuzzer should be seeded with interesting
      inputs - but not ones that cause an outright crash.

    - The current memory limit (50.0 MB) is too low for this program, causing
      it to die due to OOM when parsing valid files. To fix this, try
      bumping it up with the -m setting in the command line. If in doubt,
      try something along the lines of:

      ( ulimit -Sv $[49 << 10]; /path/to/binary [...] <testcase )

      Tip: you can use http://jwilk.net/software/recidivm to quickly
      estimate the required amount of virtual memory for the binary. Also,
      if you are using ASAN, see /usr/share/doc/afl-doc/docs/notes_for_asan.txt.

    - Least likely, there is a horrible bug in the fuzzer. If other options
      fail, poke <lcamtuf@coredump.cx> for troubleshooting tips.

[-] PROGRAM ABORT : Test case 'id:000000,orig:aaa' results in a crash
         Location : perform_dry_run(), afl-fuzz.c:2852

Do you know what might be the issue here?

jwilk commented 5 years ago

It might be that the default memory limit is not sufficient for Python 3.

afl-showmap is the go-to tool for debugging unexpected crashes. What happens when you run:

py-afl-showmap -o /dev/null -- python3 python_afl_fuzz.py < fuzz/in/aaa

?

ricostrong commented 5 years ago
yee@haw:~/fuzz/python$ py-afl-showmap -o /dev/null -- python3 python_afl_fuzz.py < fuzz/in/aaa
afl-showmap 2.52b by <lcamtuf@google.com>
[*] Executing '/usr/bin/python3'...

-- Program output begins --
-- Program output ends --

+++ Program killed by signal 10 +++
[+] Captured 8 tuples in '/dev/null'.

hmmm.. I am not sure if it's the memory limit that's the issue, because running py-afl-fuzz with the '-m none' flag doesn't change anything.

jwilk commented 5 years ago

Could you put PYTHON_AFL_SIGNAL=0 in environment and try py-afl-showmap again?

(For the avoidance of doubt, this for debugging only. You should not be fuzzing with PYTHON_AFL_SIGNAL=0 set.)

ricostrong commented 5 years ago
afl-showmap 2.52b by <lcamtuf@google.com>
[*] Executing '/usr/bin/python3'...

-- Program output begins --
Traceback (most recent call last):
  File "python_afl_fuzz.py", line 21, in <module>
    main()
  File "python_afl_fuzz.py", line 11, in main
    s = sys.stdin.read()
  File "/usr/lib/python3.6/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfd in position 0: invalid start byte
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 63, in apport_excepthook
    from apport.fileutils import likely_packaged, get_recent_crashes
  File "/usr/lib/python3/dist-packages/apport/__init__.py", line 5, in <module>
    from apport.report import Report
  File "/usr/lib/python3/dist-packages/apport/report.py", line 30, in <module>
    import apport.fileutils
  File "/usr/lib/python3/dist-packages/apport/fileutils.py", line 23, in <module>
    from apport.packaging_impl import impl as packaging
  File "/usr/lib/python3/dist-packages/apport/packaging_impl.py", line 24, in <module>
    import apt
  File "/usr/lib/python3/dist-packages/apt/__init__.py", line 23, in <module>
    import apt_pkg
ImportError: /usr/lib/python3/dist-packages/apt_pkg.cpython-36m-x86_64-linux-gnu.so: failed to map segment from shared object

Original exception was:
Traceback (most recent call last):
  File "python_afl_fuzz.py", line 21, in <module>
    main()
  File "python_afl_fuzz.py", line 11, in main
    s = sys.stdin.read()
  File "/usr/lib/python3.6/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfd in position 0: invalid start byte
-- Program output ends --
[+] Captured 8930 tuples in '/dev/null'.

Oh well, after googling a bit more it turns out that reading stdin changed from python2 to python3 s = sys.stdin.read() in python3 is s = sys.stdin.buffer.read(), and sys.stdin.read() isn't an invalid function, so i missed it.

My bad, and thanks for your help.