Skip to content
This repository has been archived by the owner on Jan 5, 2021. It is now read-only.

afl-fuzz.exe on stock binaries in dumb mode #4

Open
andigena opened this issue Jan 26, 2016 · 3 comments
Open

afl-fuzz.exe on stock binaries in dumb mode #4

andigena opened this issue Jan 26, 2016 · 3 comments
Assignees
Labels

Comments

@andigena
Copy link

I've tried fuzzing a few binaries but some mysterious errors pop up. This gist shows the output of afl-fuzz on the Imagemagick distributed with FOE2. Note the 6 [unknown (0x10128)] afl-fuzz 63812 sig_send: error sending signal 11, pid 63812, pipe handle 0x84, nb 0, packsize 164, Win32 error 6 line.
The reported speed must be way off, there are plenty of WerFault.exe processes spawn and after a while the afl status screen is hammered with more such sig_send lines. The same thing happens when fuzzing /bin/cat. Also, I'm not sure if it's relevant but the compilation of test-instr.c fails during make build (see above gist).

This is on an 32-bit Windows 7 vm with freshly installed cygwin. Here are the ldd outputs of the involved binaries

@arizvisa
Copy link
Owner

This is actually happening because cygwin uses a differing mechanism to send signals than afl-cygwin does. afl-cygwin wraps waitpid and snags the error code using GetExitCodeProcess. This is done because there's a native forking implementation that was implemented for performance and is how you'd check to see if a spawned application has segfaulted on Windows. (This is all implemented in winapi.c). In this fashion, the parent monitors the child for the sig11 or any sigXX.

However, if you are using cygwin's api's (by building a posix application with it as you did), cygwin actually creates a pipe and writes to it which is how it handles signalling internally. This is actually initialized by cygwin's rt in a function sigproc_init() that's reachable by cygwin1.dll!_dll_crt0, or cygwin1.dll!cygwin_dll_init (which eventually calls _dll_crt0). The way cygwin does this I imagine is that they're initializing an SEH record and when an exception happens they'll call sig_send to write the signal down their end of the pipe. In this fashion, the child screams the signal to the parent before it dies.

Since the (native) fork-implementation is being used by afl-cygwin and your target is using (non-native) cygwin to dispatch a signal, the new process hasn't actually initialized signal processing, and so when your cygwin target tries to write to this pipe (to dispatch a signal the cygwin way) afl-cygwin is not able to receive it because it's using a different mechanism instead of cygwin's signal pipe.

The proper fix to it would be done in winapi.c within _fork_child_entry. This is the part that I need to expose through the build-process to either check if a user's forked process is actually cygwin-enabled (by checking for the cygwin1.dll!cygwin_internal interface being available). If it is a cygwin-process then call cygwin1.dll!cygwin_dll_init to properly initialize signalling as well as other cygwin-specific things. If it's not a cygwin-process then all one has to do is to re-initialize ntdll.dll. The other thing to do for robustness would be to hook in the newly fork()d process via Vectored Exception Handling so that one could catch an exception before cygwin's SEH handler catches it (and tries to handle signals oob). I haven't done the work to test hooking the VEH handler yet tho. In any case, the process needs to just die in the way that Windows and native_waitpid expects it to die.

The other (easier but non-performant) way to fix it is to go to winapi.h and comment out some of the defines related to process creation and signalling. Near the bottom of winapi.h you should be able to comment out fork, waitpid, exec*, and kill. This disables the wrappers for those functions that were implemented which causes everything to fallback to cygwin's regular api's. (Keep in mind cygwin essentially has to dupe things like an fd-table and a couple other things so your fork() perf is fuxed.) The only thing that cygwin doesn't implement which afl seems to depend on is posix's shm api. Let me know if for some reason this doesn't work.

These are some of the things that I planned on exposing through the build-system so that someone can enable some of these hacks as well as change the hardcoded offset for reinitializing ntdll.dll (maybe searching a symbol table for it). One could either solve it as I had up above, or just make waitpid check both situations: if the process is still alive and the cygwin-signal-pipe is ready or windows term'd the process with an AV-related exit-code.

Anyways, I had put this project down due to other things that came up at work. :-) Once I finish my current project, I'll get around to making some of the aspects of this afl hack more user-friendly as well as commit the patch for afl-1.96b. Thanks for getting farther than anybody else. ;-p

Let me know if there's anything I missed.

@arizvisa
Copy link
Owner

Lol. I didn't realize how long that was (didn't feel that long typing it).. but here's the tldr:

afl-cygwin is using native-win32-api to emulate the receiving of signals, whereas Imagemagick is using cygwin to dispatch signals. Since winapi.c is usurping this, Imagemagick is communicating over a different mechanism. Read above for why and how.

Here's one way to fix it until I commit the patch for 1.96b which'll add some hacks to un-usurp what cygwin usurps....much usurping. wow...

The other (easier but non-performant) way to fix it is to go to winapi.h and comment out some of the defines related to process creation and signalling. Near the bottom of winapi.h you should be able to comment out fork, waitpid, exec*, and kill. This disables the wrappers for those functions that were implemented which causes everything to fallback to cygwin's regular api's. (Keep in mind cygwin essentially has to dupe things like an fd-table and a couple other things so your fork() perf is fuxed.) The only thing that cygwin doesn't implement which afl seems to depend on is posix's shm api. Let me know if for some reason this doesn't work.

@arizvisa arizvisa self-assigned this Feb 8, 2016
@arizvisa arizvisa added the bug label Feb 8, 2016
arizvisa added a commit that referenced this issue Mar 8, 2016
…ixed a few issues too.

Makefile:
    Added support for a new build variable, NATIVE, which specifies to build using the windows-native forking code.
    Tweaked the Makefile to properly depend on winapi.o without having to hack it into LDFLAGS to link everything with it.
        This fixes issue #2.
    Modified the "all" rule, so that it uses the rules for the .exe PROGS.

afl-as:
    Split CALL into a NATIVECALL and regular CALL in order to support choosing between cygwin-native and windows-native forking.
    Added an ifdef that looks for the executable version of as, "as.exe", on the windows platform.

afl-gcc:
    Added an ifdef that looks for the executable versions of gnu's compilers on the windows platform.
        Prevents a user from having to explicitly specify the tools to compile and link with.

winapi:
    Removed all the function pointers and replaced them with a direct call.
    Renamed init to native_init so that the code injected by afl-as can be consistent.
        Also prevents potential name collision issues in the future.
    Added support to where for automatically appending the correct suffix based on the contents of PATHEXT.
        This allows a user to not have to explicitly specify the suffix of a tool.
    Added cygwin_conv_path support to exec*
        which when combined with the previous modification fixes issue #3.
    Pre-wrote some vectored exception handlers for the native forking.
        This frames part of the fix for issue #4.
    Added the offset/address for LdrpInitialize instead of just LdrpInitializeProcess.
        This API call isn't exposed by ntdll, but can be used to re-initialize ntdll's state. (This will be chooseable in the next commit.)
    Fixed a potential bug in execvp that slipped it's way in.
@arizvisa
Copy link
Owner

arizvisa commented Mar 8, 2016

This has been partially addressed in the cygwin-native build by commit e9b0fe7.

However, I'm leaving this issue open until it's fixed in both the cygwin-native and windows-native version.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants