0vercl0k / wtf

wtf is a distributed, code-coverage guided, customizable, cross-platform snapshot-based fuzzer designed for attacking user and / or kernel-mode targets running on Microsoft Windows and Linux user-mode (experimental!).

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Server not creating outputs

Flerov opened this issue · comments

I had a hard time getting bochscpu ready. The provided build-bochscpu.bat was not working for me.
So I did it myself and copied the directories bochscpu /-build / -ffi into the bxbuild-win folder.

I can start the server and the fuzzer like shown in the example. But the server is not saving into outputs/
The server shows me a lot of crashes but I dont see any in the crashes/ folder.

What did I do wrong?
Help much appreciated I'm stuck on here for a couple of days thanks alot!
Screenshot (27)

Thanks for the fast replies.
I realised that everything was setup properly except of the point I took my Snapshot.
Would you mind giving me some insight at what point it is best to take a Snapshot.
I was following your readme to HEVD and took the Snapshot (like in your pictures) right before the call (right before stepping over) hevd_client!_imp_DeviceIoControl then i switched contect back to kernel and took the dump.
I'm also pretty sure that I was not inside of the break-handler since I was breaking at hevd_client!main and stepped through till right before the DeviceIo call. Made me confused on how it went wrong.

Okay so I just looked at this. Here's what I've done:

  • I downloaded the 7z archive with the HEVD example (I noticed a typo in the server.bat script actually, so fixed that, and also modified the fuzz-bxcpu to enable the new --edges option). It seems to run fine on my end:
Saving output in .\outputs\0dc68b253aaf6886f031fcfad031cbed
Saving crash in .\crashes\crash-0x50-0xffffffffffdde340-0x0-0xffffbf84fb10e780-0x2-0x0
Saving crash in .\crashes\crash-0x50-0xfffffffeffdde337-0x0-0xffffbf84fb10e780-0x2-0x0
Saving crash in .\crashes\crash-0x50-0xffffffffffdde637-0x0-0xffffbf84fb10e780-0x2-0x0
Saving crash in .\crashes\crash-0x50-0xffffff0dffdde337-0x0-0xffffbf84fb10e780-0x2-0x0
Saving output in .\outputs\b192415a46b4b52cd902081d27eb07f0
Saving output in .\outputs\4275bb5cdef5d27f56c1b4502066b3cc
Saving output in .\outputs\dd9a8d7f4cd071c5bf74f195b62f3966
Saving crash in .\crashes\crash-0x50-0xffffffe3ddff37ff-0x0-0xffffbf84fb10e780-0x2-0x0
Saving crash in .\crashes\crash-0x50-0xffffffffffdda337-0x0-0xffffbf84fb10e780-0x2-0x0
Saving crash in .\crashes\crash-0x50-0xffffffffabdde337-0x0-0xffffbf84fb10e780-0x2-0x0
Saving crash in .\crashes\crash-0x50-0xffffffffddff37e3-0x0-0xffffbf84fb10e780-0x2-0x0
Saving crash in .\crashes\crash-0x50-0xffffff94ffdde337-0x0-0xffffbf84fb10e780-0x2-0x0
Saving crash in .\crashes\crash-0x50-0xffffffffffdde341-0x0-0xffffbf84fb10e780-0x2-0x0
  • Now, it seems like you might be providing your own dump. So I also reviewed the code that handles crashes. The client part is in client.cc here, and on the server-side in server.h here:
    //
    // If the client reported a crash, let's check if it has a name, if so
    // we'll save it in the crashes folder.
    //

    if (const auto &Crash = std::get_if<Crash_t>(&Result)) {
      if (Crash->CrashName.size() > 0) {
        const auto &OutputPath = Opts_.CrashesPath / Crash->CrashName;
        const auto &Success =
            SaveFile(OutputPath, (uint8_t *)ReceivedTestcase.data(),
                     ReceivedTestcase.size());
        if (!Success) {
          fmt::print("Could not create the destination file.\n");
          return false;
        }

        const bool WroteFile = *Success;
        if (WroteFile) {
          fmt::print("Saving crash in {}\n", OutputPath.string());
        }
      }
    }
  • Now in terms of snapshotting, you can really snapshot wherever you want. The idea is that you want to pick a place where it makes your life easier: it allocates memory for you (as you can't extend existing allocation once you snapshot'ed, etc), and exercise all the code you want to target; from user to kernel, kernel to user, only user or only kernel.

  • Now, in this case you are reusing an existing fuzzer module which has assumptions baked on how the snapshotting happened. For this module, I used this hevd_client.cc with the BREAK environment variable to control the break. If you load the state.dmp in windbg you can exactly see where I generated the snapshot (I actually took it in usermode):

hevd_client!main+0xae:
00007ff6`f5bb111e ff15dc1e0100    call    qword ptr [hevd_client!_imp_DeviceIoControl (00007ff6`f5bc3000)] ds:002b:00007ff6`f5bc3000={KERNEL32!DeviceIoControlImplementation (00007ff8`3e2e6360)}

kd> lsa .
    17:         __debugbreak();
    18:     }
    19: 
    20:     DWORD Returned = 0;
>   21:     DeviceIoControl(
    22:         H,
    23:         0xdeadbeef,
    24:         Buffer.data(),
    25:         Buffer.size(),
    26:         Buffer.data(),

Does this help?

Cheers

Thanks a lot for your thorough reply.
It helped me a lot.

I finally tried it again by setting the env var "BREAK" but I'm no longer able to see the exact same call to _imp_DeviceIoControl. Instead I only see a mov instruction at that point so I was just disassembling the rest from that point and breaked on the call what a shame that I forgot the basics for a day.

Oh yes, the break will make you break at the artificial int3; you can rewrite it dynamically with eb . 90 and step over it until your desired spot; I took the dump on the call [&DeviceIoControl] 🙂

Can I help you with anything else?

Cheers

Amazing I didnt know about that :D will keep it.
No thank you I will close the issue