Screenshooter: The Beacon Screenshot Savior

A C# tool to screenshot user's desktop(s) complete with multiple checks. Will work with Cobalt Strike's Execute-Assembly. Best name we could think of since SharpShooter was taken :(.


We were recently on an internal penetration test where Beacon's Screenshot utility was continuously failing due to an unknown reason. While the Screenshot utility isn't imperative for testing, it does make things a little easier being able to see the user's desktop and what applications they may be running. We used this opportunity to start developing a backup screenshot application just in case we run into this issue again.

The Code

The program flow is simple: do some validation on the passed argument (if an argument is passed) -> check if the argument filename already exists -> screenshot -> catch errors and retry. While writing this tool, I wanted to make sure that it was possible to run it on it's own or specify a path/filename which involved some local checks. The code snippet below checks to see if a single argument is passed, if so it will determine if the argument is a directory or potential filename and go from there. If no argument is passed it will create a filename based on the current date/time.

File checks

Originally I had coded it to save the screenshot in the current working directory if no arguments were passed. This caused some issues while testing and it was decided to use the same output directory as the C# version of EyeWitness - C:\Users\[username]\AppData\Roaming\. This ensures that, even if the user gives the application a specific location to write to and it fails, a fallback location is there to allow the screenshot method to work.

Most of the application deals with checks and ensures ease of use. The most recent addition (snippet below) added the functionality to catch a specific error if the user was running inside of an RDP session but wasn't currently connected. If a Win32Exception is thrown, the application attempts to attach to the current user's RDP session using tscon.exe. This works if the beacon/agent is running in an elevated context (but not SYSTEM!) since using tscon.exe to attach to another session requires admin privileges. If running as SYSTEM, the application will catch that and alert the user to try running in a high integrity context instead.

Checking for RDP error and correcting

The main screenshot code block is fairly small. This creates a new bitmap object consisting of a virtual screen by taking into account any/all external monitors. It then saves it to a file which can then be easily downloaded.

Screenshot code block

Here's a quick snippet of it working with Beacon's Execute-Assembly command using various file arguments.

Beacon's execute-assembly running Screenshooter

Final Thoughts and Link

Currently, I've tested it against a VM with a user connected to an RDP session and it correctly grabs a screenshot when beacon fails but this may change out in the real world. Therefore, if you see any errors please open a GitHub issue and we'll work on fixing it. As always, I'm sure there are better ways to code this so if anyone has recommendations or improvements let us know! You can contact us on Twitter, LinkedIn, Facebook, and of course from our website.

If you want to grab the code check it out here:

C# program to take a full size screenshot of the window. Takes in 0 or 1 flag for a filename. - FortyNorthSecurity/Screenshooter