Beginning the operational tracking

5 minute read


In my previous post, I started describing what I want to see in offensive frameworks in terms of tracking. I spent the past week updating Apfell to start including this kind of logic to support a broad range of features that will come soon.


The first step in this revolves around payloads. In normal frameworks, you make a payload and forget about it - you use it as you need it and think nothing else of it. I want to keep track of more though. Currently, Apfell has the following as the definition of a Payload:

class Payload(p.Model):
    # this is actually a sha256 from other information about the payload
    uuid = p.CharField(unique=True, null=True)
    # tag a payload with information like spearphish, custom bypass, lat mov, etc (indicates "how")
    tag = p.CharField(null=True)
    # creator of the payload, cannot be null! must be attributed to somebody (indicates "who")
    operator = p.ForeignKeyField(Operator, null=False)
    creation_time = p.DateTimeField(, null=False)  # (indicates "when")
    payload_type = p.CharField(null=False)
    # this will signify if a current callback made / spawned a new callback that's checking in
    #   this helps track how we're getting callbacks (which payloads/tags/parents/operators)
    pcallback = p.ForeignKeyField(p.DeferredRelation('Callback'), null=True)
    callback_host = p.CharField(null=False)
    callback_port = p.IntegerField(null=False)
    obfuscation = p.BooleanField(null=False)
    callback_interval = p.IntegerField(null=False)
    use_ssl = p.BooleanField(null=False)
    location = p.CharField(null=True)  # location on disk of the payload

There’s a lot of information here, but there are a few things I want to point out.


When creating payloads, I encourge people to specify a default ‘tag’ value. This is used to automatically populate the description field of callbacks when they check in. If you’re smart about how you use this, you can easily tell what a new callback means (did your spearphish work? Did bob’s crontab persistence on boxA go off again? did alice spawn a new callback from callback 5? etc). This field can be null, but I think it’s pretty useful.


Users aren’t the only ones that create new payloads. That might sound odd, but think about what happens when you use a built-in lateral movement technique or want to spawn a new callback? You’re not creating that new payload, the current callback is. Now, when that new payload is used, I want to keep track of where it came from. If this “pcallback” field is Null, I know that an operator specifically created this payload. But, if it was created by a callback, I track it here.


This is where the payload exists on disk. As part of spawning new callbacks, the implant needs to know which payload to use, and the Apfell server needs to know where that file is located to serve it up. Right now, all auto-generated payloads are saved to “payloads/operations/default” with the file name being the UUID of the implant. Once I start implementing operations though, the payloads will be saved in an operation specific folder.


This value is a SHA256 of some information about the payload. Just looking at the UUID itself, it’s meaningless. But, when a new callback checks in and provides this value, I can do a lookup into the Payloads table to find a wealth of information about the new callback.


The natural next piece for this involves the callbacks that use these payloads. I’ve added two new fields to the callback model:

pcallback = p.ForeignKeyField(p.DeferredRelation('Callback'), null=True)
registered_payload = p.ForeignKeyField(Payload, null=False)  # what payload is associated with this callback


When a new callback checks in and looks up information about the payload used to spawn it, it finds the payload’s pcallback field. This field is copied over to the callback to indicate which callback spawned it. If this is Null, then no callback created it - instead it was the result of some initial access into the environment (like spearphishing, willing participant, etc).

Operations page

So, what does a normal view look like now: alt text

You can see that we have some information in the description field, but it’s still not crazy easy to follow just off of the descriptions. But, all of these descriptions were auto populated, so that’s cool.

I haven’t worked this into a new page yet or added other analytics (they’re coming though), but for a first example with this information, we can look at the hierarchy of callbacks: alt text

Web Hosting

I promised this in the first release that I would provide a front-end to host files instead of just using the API. Well, here it is! It auto-populates when you create new ones via the “Create” button. Additionally, you can use the “start” and “stop” buttons to start and stop the different folders you’re hosting. It’s important to note though that this information is not saved in the database! That means when you restart your server, you will lose all of these hosts. I’ll change this in the future, but right now having this be persistent isn’t all that necessary since it’s not on target hosts. alt text

Database Management

I also added in a new page for you to do a bit of database cleanup between operations. It’s super annoying to have to do this stuff manually, so I created some easy buttons for you to clean up the tables in the database and even remove the “auto-generated” payloads Apfell creates. alt text


One of the next things I’m going to work on is reporting features. Thus, you’ll notice a new reporting tab in the navigation bar with a bunch of things disabled. They’re just placeholders for now, but I wanted to note down ideas for different kinds of reports.


If you have ideas for specific analytics, report types, features, etc that you wanted implemented, just let me know! I’m always eager to hear ideas, despite not having a bunch of time to implement all of them.