Aperio is a black-box fuzzer for your web application or API. Seed it with example requests, point it at a testing deployment, and let it find behaviors you didn’t know existed.

Aperio tries to solve one of the major limitations of existing web fuzzers – the inability to test features that require a sequence of interrelated requests. To highlight the difference, let’s look at an example:

Create Album

Request

POST /api/create-album
{
    name: "Summer 2020 Photos"
}

Response

HTTP/1.1 200 OK
{
    album_id: 342987
}

Existing fuzzers see one interesting feature here: the input parameter name. Aperio sees two: the input name and the output album_id. Often, there will be other requests we can make that require some key (like album_id) By extracting the value of album_id and using it in later requests, we can find behaviors that would otherwise not be reachable. Some examples might be:

Delete Album

Request

POST /api/delete-album
{
    album_identifier: 342987
}
Edit Album

Request

POST /api/edit-album
{
    album_identifier: 342987
    description: "Hiking in Seattle"
}

Without a valid album ID we can still do some interesting testing involving invalid album IDs, but we’re still missing out many (if not most) code paths. By first executing a request to create-album and extracting the value of album_id, we can create valid requests and cover a larger and more interesting set of behaviors.

Reproducibility

Once we’ve extracted data from responses, we need to handle that data “ageing”. The simplest example of that is when an album is deleted. Later requests to edit-album that reference the same album may have different behavior – eg, returning an error instead of successfully editing the description.

We work around this issue by building reproducible sequences of requests, with substitutions between responses and later requests. Rather than attacking each endpoint in isolation, Aperio learns data flows to generate interesting (and reproducible) sequences.

In practice, a request sequence might look like this:

  1. POST to /api/album, with a random name.
  2. Copy album_id out of response 1, and into the field album_identifier in the next request.
  3. POST to /api/delete-album with the copied data.
  4. Copy album_id out of response 1, and into the field album_identifier in the next request.
  5. POST to /api/edit-album with the copied data and a random description.

This sequence creates and album, deletes it, then tries to edit the description. This might be handled gracefully by your software – or it might fail! This kind of behavior could never be discovered by a fuzzer that attacks endpoints individually.

Because the sequence is self contained it is consistently reproducible, and does not depend on state (such as a valid album_id) that may no longer exist.

Why fuzz this API?

Developers usually write tests for their APIs, but these tests can only cover a finite number of cases. These test cases can involve putting invalid values into a request or just trying out unusual sequences of requests.

A dedicated tester might come up with a couple of tests like this in an hour. Aperio can generate thousands of sequences every minute, twenty-four hours a day.

Aperio is distributed via docker, and is fully cross platform. Give it a try now.