NetWorks Group Blog

Security practices that make the life of a hacker harder

Posted by Calvin Hedler on May 15, 2018 9:32:00 AM

Calvin Hedler, Penetration Tester at NetWorks Group explains some of the security practices that make it difficult for a hacker to break into an enterprise environment.

Read More

Topics: Ethical Hacking, Penetration Testing

How do hackers gain and expand a foothold in an enterprise environment?

Posted by Calvin Hedler on May 9, 2018 10:21:44 AM

Calvin Hedler, Penetration Tester at NetWorks Group explains how hackers gain and expand a foothold in an enterprise environment.

Read More

Topics: Ethical Hacking, Penetration Testing

The Dangers of PCI-Only Pen Tests

Posted by Scot Armstrong on Apr 17, 2018 11:09:04 AM

The Dangers of PCI-Only Pen Tests 

In my 11 years of helping customers pen test their network, oftentimes I have seen that  companies choose to test only the bare minimum. I understand that companies have a need to satisfy some compliance like PCI or reassure customers and security budgets can be tight. However, why not get more value out of your pen test?

Read More

Topics: Penetration Testing, Threat Management

Aggressor 101: Unleashing Cobalt Strike for Fun and Profit

Posted by Calvin Hedler on Mar 15, 2018 9:54:37 AM

I use Cobalt Strike a lot. It’s my team’s go-to tool for compromising Windows environments, and that’s what I find myself doing more often than not during red team engagements. One of the reasons I enjoy it so much is that it abstracts a lot of the common things that we need to do on engagements, giving us more flexibility to focus on our objectives, and how best to accomplish them.

Even so, I’m obsessed with making our workflow even more efficient, and giving us the power to accomplish objectives even faster. One of the best ways to do this is with Aggressor Script, Cobalt Strike’s native scripting language. I should also add a caveat to this post: I am not a software developer. I do not have a formal background in developing, nor do I focus on efficiency or speed when I’m writing Aggressor.

Recently, I was able to attend the (excellent) SpecterOps Adversary Tactics: Red Team Operations course, which gave me the opportunity to talk to various red teamers, getting their perspectives on preferred tools, and how they use them. One of the things that surprised me somewhat was how few people make use of the power that Aggressor Script can provide. A sentiment that I heard a lot was that even red teams already paying for Cobalt Strike haven’t implemented much Aggressor Script into their workflows. I’d like to change that.

An Introduction to Aggressor

Aggressor Script is based on Sleep, a language created by Raphael Mudge (also the author of Cobalt Strike). Sleep is basically a Perl-like language which runs on the JVM. Before you start complaining, I believe that the power that Aggressor Script gives you in Cobalt Strike far outweighs any issues some might have with writing Perl, or dealing with Java.

This post will assume that you’re comfortable using Cobalt Strike, and that you know the various concepts behind operating with it. This will not be an introduction to Cobalt Strike.

With that out of the way, what does Aggressor Script actually look like? I find the syntax to be pretty simple, especially if you’re used to writing Perl, though many concepts will be perfectly understandable if you’ve written code before. Here’s a simple “Hello, world!” script, written in Aggressor:

# helloworld.cna
# Prints "Hello, world!"
# 001SPARTaN
sub hello {
    println("Hello, world!");

Pretty easy. We create a new function named “hello” with sub hello {...} , and print text to the console with println("Hello, world!") . Statements in Aggressor must end with a semicolon, and functions must be defined before they’re called. Because the function doesn’t take any arguments, calling it with hello() will run the code.

Now that we have our first script, how do we actually use it? First, open up Cobalt Strike, and connect to your teamserver. Once your client is connected, go to View->Script Console, and type load /path/to/helloworld.cna (the full path is required). With that, you should see something like the following:

Hello, world!

The cool thing about the script console is that it lets you test stuff out without having to write a full script, too. We can create the same function using the ecommand in the script console to evaluate Aggressor snippets. To do this, we can take the same code, and instead put it on a single line. In the script console, type e sub hello {println("Hello, world!");} , and hit enter. This won’t return anything, but we can then run our hello() function by running e hello() in the script console. 

Just like that, we can test out bits of Aggressor. When I’m writing Aggressor scripts, I constantly use the script console to prototype small bits of code, and make sure they’re working before I pull them into a larger script. It’s a very useful tool to debug scripts, or to quickly run snippets that don’t necessarily constitute a full scripts.

Now that we’ve gone over how to run Aggressor scripts, let’s explore how to construct more useful scripts.

The Building Blocks

In order to build useful Aggressor scripts, we’ll need a bit more to go on than just printing stuff to the console. To do that, we need to learn about the various datatypes in Sleep, and how to work with them. The main datatypes in Sleep are strings, arrays, and hashes. Strings are denoted with $ , arrayswith @ , and hashes with %.

If you’ve written code in another language, these datatypes should be familiar. Strings contain characters or strings of characters; arrays can hold multiple strings, arrays, or hashes (you can mix types in an array); and hashes contain multiple key-value pairs. What do these look like in practice?

This is a string with a few words:

$string = "This is a string.";

This is an array with three elements; a string, a number, and the $stringvariable that we defined before:

@array = @("The first element.", 2, $string);

This is a hash with three elements; key1 has a value of "value1", the value for key2 is the array we defined as @array, and key3 contains our $stringvariable.

%hash = %(key1 => "value1", key2 => @array, key3 => $string);

Using the x command in the script console, we can examine what these variables contain:

Strings, arrays, and hashes; the primary datatypes in Sleep

As you can see, Sleep has no issues combining datatypes, or dealing with nested arrays or hashes. In fact, it’s often very useful to nest arrays and hashes to create structures for storing things.

Before we start writing useful Aggressor scripts, I’ll go through how to access data stored in arrays and hashes. These two datatypes behave like they do in other languages. First, data contained in arrays can be accessed by its index, or its position in the array. Let’s define an array:

@array = @("First", "Second", "Third");

The index of the first element in an array is 0. To view this value, we can use @array[0] :


To access the other elements in the array, we can use their indices in the same way:

Fun with arrays!

We can also use these in println statements to directly print the values. The dot operator will concatenate two values as a string:


Hashes work in a similar way, though instead of using the index of an item, you’ll use the key that the value is stored under. Here’s what that looks like:

Fun with hashes!

The key values can be named whatever you’d like, and the value can be any type of data you want. Now that we’ve learned about the datatypes in Aggressor, how do we use this information to do useful things inside of Cobalt Strike?

Scripting Cobalt Strike

At the core of Cobalt Strike is the Cobalt Strike data model. This is where all of the information accessible to operators is stored, and it gives us a large amount of data to use for automating things in Cobalt Strike. The data collected in the data model includes information about the current beacons, credentials gathered from compromised systems, screenshots, downloaded files, and many other things.

For an example of how to use this data, let’s say we have a single beacon on a system. We can get an array of all the currently connected beacons by using the beacons() function, a built-in function in Aggressor. We can view this information with x beacons() in the script console.

If you try this, you’ll get a lot of information about each beacon. Beacons are arranged in an array, and each beacon is stored as a hash in this array. This is what that looks like with a single beacon in the data model:

Beacon data returned with the beacons() function

So what can we do with the information in the data model? Let’s start with a fairly simple task that you might want to do: run a command on all of the beacons that you have connected to a teamserver.

Your First Aggressor Script

Let’s build this script out a piece at a time. First, we’ll start with creating a script to run a command on a single beacon. To do this, we’re going to use the bshell function, a built-in function of Cobalt Strike. Here’s the definition from the official Aggressor Script documentation:

bshell — Ask Beacon to run a command with cmd.exe
$1  - the id for the beacon. This may be an array or a single ID.
$2  - the command and arguments to run

So how do we write a script to utilize this? We’re going to create an alias, or a command that you can type into any beacon console to execute custom Aggressor code. Here’s what that looks like:

alias shellcmd {
    bshell($1, $2);

If you haven’t written Aggressor before, you might be curious about the $1and $2 variables we’re using in bshell. Whenever a function takes arguments in Aggressor, those arguments are passed to the function as numbered variables, named in the order in which they’re passed. For aliases, the first argument is the beacon ID that the alias is being used on, and any arguments after that are things you type after the alias when you run it from a beacon console. In this case, if you type shellcmd whoami into a beacon console, $2 will be "whoami". If you want to rename these variables to something that is easier to keep track of, you can assign them to other variables that you create. For more information on the functions available for use in Aggressor, and the arguments they take, check out this page.

To test this new alias out, save the script, and load it into Cobalt Strike (through the script console or through the script manager). You should now be able to type shellcmd <COMMAND> into a beacon console, and it will run the command for you! Note that you will also be able to tab-complete this alias.

Using our custom alias to run whoami

Right now, this isn’t a very impressive script. It does the same thing as the built-in shell command, but you have to type more to use it. How can we make our script run a command on all beacons, not just a single beacon? First, let’s write a bit of Aggressor to run a set command on multiple beacons, and then we’ll modify it until we can run whatever command we want on multiple beacons.

To do this, we’ll first need to iterate through all the beacons connected to the teamserver. Cobalt Strike makes this pretty easy. Remember that beacons()function from earlier? We can use that to iterate through all beacons with a simple foreach loop. Here’s what that looks like:

# Print beacon IDs for all beacons connected to the teamserver
foreach %beacon (beacons()) {
    println("Beacon ID: " . %beacon['id']);

Here, we’re using a foreachloop to iterate through every beacon returned by the beacons() function. Remember, beacon information returned by this function is stored as a hash for each beacon. From the hash, we’re selecting the id key with %beacon['id'], and printing this ID.

How can we modify this script to instead run a command on every beacon returned by beacons()? Let’s start by rewriting it to run whoami on every beacon.

foreach %beacon (beacons()) {
    $bid = %beacon['id'];
    bshell($bid, "whoami");

Again, this is a pretty simple script, but we need to make it a little more useful. Instead of just running whoami on every beacon, let’s create a beacon alias that will run whatever command we want on every beacon. There are a couple ways to do this, but here’s a good start:

sub runcmd {
    $bid = $1;
    $cmd = $2;
    bshell($bid, $cmd);
alias runall {
    # Iterate through all beacons in data model
    foreach %beacon (beacons()) {
        # Call runcmd on each beacon
        runcmd(%beacon['id'], $2);

To run this script, type runall into a beacon console, followed by a command. Due to the way alias works in Aggressor, if you want to run a command with spaces in it, you’ll need to wrap it in double quotes. There are ways to get around this, but I wanted to keep this post as a basic introduction to Aggressor.

Hopefully this post has given you a better idea of how to write basic Aggressor scripts! This is just scratching the surface of what’s possible with Cobalt Strike. You can use events to automatically trigger actions. You can alter the Cobalt Strike GUI with additional menu items or even custom visualizations. Aggressor doesn’t have functionality you want? You can even use inline Java object expressions to incorporate functionality from any Java library!

It might not be the prettiest language, but Aggressor gives you a tremendous amount of power, and allows you to expand Cobalt Strike however you want to. If you’re a Cobalt Strike user and you’re not writing Aggressor, you’re missing out on one of the most powerful tools available to you. In future posts, I’ll go through more of what makes Aggressor so useful. Until then, I hope this has been a useful introduction.

Questions? Comments? Hit me up on Twitter, or come hang out in the BloodHound Slack, especially the #aggressor channel.

Read More

Topics: Ethical Hacking, Penetration Testing

Do You Trust Your CEO’s Email?

Posted by Scot Armstrong on Mar 8, 2018 10:08:58 AM

If you received an email from your company CEO asking you to perform a task or pay a vendor, would you proceed without question or would you verify?  “It’s an email from the CEO, I have to do this” you might think.  You might be better off verifying that request if it involves money or confidential information.

Read More

Topics: Ethical Hacking, Penetration Testing

Why your next PCI Assessment can be smoother than you think

Posted by Mike Stailey on Nov 15, 2017 9:34:57 AM

PCI Compliance is here to stay:

Typically, IT managers dread the annual PCI assessment. With publicized credit card breaches on the rise, meeting PCI compliancy will be even more so of a requirement with potential increases in punitive actions for companies not meeting that compliancy. To add to the existing complexity of PCI DSS, with emerging threats of capabilities to breach corporate networks on a consistent basis, PCI requirements will remain in a perpetual state of change. 

Read More

Topics: Ethical Hacking, Vulnerability Management, Compliance, Penetration Testing, Threat Management

Active Directory Password Filters: The Missing Windows Feature

Posted by Aaron Pohl on Oct 23, 2017 11:28:38 AM

As penetration testers, we get a lot of joy out of compromising Windows networks. They are basically our favorite targets because of how insecure they are by default. Microsoft has always favored backward compatibility over security, and while it is possible to really lock down an AD (Active Directory) environment, it takes a lot of effort. While setting up an organization’s network in the first place, many admins take the stance of, “Let’s just get it working, and then we’ll add security on afterwards.” Nine times out of ten, they never go back and enable the security features until after there is an incident.

Read More

Topics: Ethical Hacking, Information Security, Penetration Testing, Threat Management

Why Full-Scope Penetration Testing Matters // Your Castle has No Walls.

Posted by Aaron Pohl on Apr 19, 2017 10:20:00 AM

We often hear from prospective clients that they have a third party perform external penetration testing every year, and it never finds anything serious, so if the attackers can’t get in from the outside, why bother testing anything else? At first, the logic seems sound – Using a castle as an analogy for the network: You’ve built a castle with really strong walls. – If nothing can breach the walls, then the squishy villagers, the rulers, and the royal jewels inside are safe and secure. This thinking follows the traditional 90’s style of network architecture, where the only route into the corporate network was through the border firewall, through the modem – the one hardline into the office.

Read More

Topics: Ethical Hacking, Information Security, Vulnerability Management, Penetration Testing, Threat Management

Don’t Abuse Scope to Hide the Skeletons in your Network.

Posted by Aaron Pohl on Apr 10, 2017 3:25:00 PM

 It happens all the time. A new penetration test work order comes into my inbox, and the customer is asking us to test only a handful of external IP addresses. A quick WHOIS request shows me that the customer owns an entire class C of public IP space, and that they didn’t even include their public webserver in the scope. In an ideal world, I’d get in touch with our Project Manager. We’d get in touch with the customer, and we talk about the scope, the customer would say it was a simple mistake, and give us a full list of IP addresses they control.

Read More

Topics: Ethical Hacking, Information Security, Penetration Testing, Threat Management

Your Passwords Are Bad (and there’s probably no fool-proof solution.)

Posted by Aaron Pohl on Aug 3, 2016 11:21:00 AM

Adobe, MySpace, LinkedIn, and many other large organizations have had major password breaches in the last few years. Breaches where attackers have exfiltrated usernames, email addresses, passwords, and in some cases, plaintext password hints and other data from the company’s database. The initial response is always, "Log into that service, and change your password before the hackers get in and take over that account!" The sad truth is that it’s rarely that account that matters – it’s the other accounts where you (or your users) used the same password and email address that you’re (or they’re) already using on the compromised account with another service.

Read More

Topics: Ethical Hacking, Information Security, Vulnerability Management, Penetration Testing, Threat Management

Subscribe to our blog!