Monday, December 10, 2018

I C(Sharp) Your Clipboard Contents

Clipboard Monitoring

Have you ever wondered what occurs when you push Ctrl+C or right click some highlighted text/image and click copy on Windows?

We're going to look into detecting changes to the clipboard, clipboard events, and reading the data copied to the clipboard. Additionally, we'll read the user's current active window for additional context on where the user was copying data from. We will achieve this with a Windows form and .NET's Platform Invoke (P/Invoke) functionality. The ability to P/Invoke provides interoperability and allows us to call unmanaged DLLs within our managed C# code.

Clipboard data can be useful during a penetration test to defeat some password managers or can provide additional context about your target in conjunction with screenshots and keyloggers.

Detecting Clipboard Events

Anytime the clipboard is updated, a WM_CLIPBOARDUPDATE message is sent to all windows registered in the clipboard format list. A window can be added to the clipboard format list using AddClipboardFormatListener(). Additionally, the WndProc() method processes all messages for any given Windows form.

Knowing this, we are able to use AddClipboardFormatListener() to add our Windows form to the clipboard format list. Once it is part of the clipboard format list, our Windows form will receive WM_CLIPBOARDUPDATE messages which we can listen for by overriding the WndProc() method. When a WM_CLIPBOARDUPDATE message is received, we can read the data from the clipboard or perform any other actions when the contents of the clipboard are changed.


Most of the code I will be showing is not original work. I've simply moved things around, added some functionality and added additional comments. I'd like to preface this section with the following links:

The NativeMethods class holds various constants and native Windows functions that we are calling through P/Invoke.

Originally, I assigned the STAThread attribute to the Main() method. However, when using execute-assembly in Cobalt Strike I ran into the following error.

It seemed that the STAThread attribute was not being assigned to the Main() method when using execute-assembly. The Clipboard class serves to override the Clipboard.GetText() method so that we can assign the STAThread attribute to our thread and retrieve the clipboard contents.

The ClipboardNotification class adds  our window to the clipboard format listeners list and overrides the WndProc() method.  When our window receives the WM_CLIPBOARDUPDATE message, the user's current active window is sent to standard output as well as the contents of the clipboard.

Below is an example of the output from testing:

Below is some testing against common password managers such as Keepass and 1Password:

As you can see, we were able to identify when the clipboard is updated in order to read the clipboard contents and the current active windows. Thanks for reading! You can find my code at I hope you learned a little about the Windows clipboard or C# today. If you spot any errors, please let me know by Twitter (@slyd0g) or by e-mail (

Considerations / Future Work

  • If using this with Cobalt Strike, it will keep a post-exploitation process spawned (as set by spawnto) which could lead to detection. You will have to manually kill the job using jobkill.
  • I plan to create a small aggressor script to start/stop the clipboard monitoring. Eventually, I want to create a copy event store similar to the credential store already in Cobalt Strike.



  1. Hallo Justin, you show that indeed you can read via clipboard monitoring the usernames and passwords of prefilled login forms of popular password managers (you mention keepass and 1Password, but the red icon I see in the browser is the one of LastPass - and indeed my interest is mainly for LastPass). However, you show an explicit "copy username" action done by the user. What if the user used the automatic pre-fill functionality of LastPass and simply pressed the Login button, without any other action? Would SharpClipboard be able to retrieve the username and Password as well?