Github Project: https://github.com/pmsosa/duckhunt
Imagine you are at your desk working in your computer, you stand up to pick a cup of coffee from the nearby coffee machine. In that time, a sneaky someone gets up plugs a strange pendrive into your computer, waits ten seconds, and walks away. They just compromised your computer in a blink of an eye a la Mr. Robot style.
It might sound crazy, but these kinds of attacks are real, and you can buy the necessary equipment to do them here. This specific attack is called a RubberDucky (or BadUSB) attack. In here, a simple USB pretends to be a keyboard and as soon as it is connected it starts typing an already pre-programmed attack (stealing your passwords or some data, downloading and installing malware, opening ports of backdoors, etc.) These kinds of attacks rely on the fact that computers accept whatever is typed into them by nature. What's more is that since the Rubberducky can type at ridiculous speeds, it is able to perform very sophisticated attacks in a matter of seconds.
(If you are a regular user that doesn't really want to keep reading and instead wants to be more secure against these attacks, feel free to jump directly here and get the version of the program that works best for you. No shame in that 🙂 )
Automated Key Injection Attacks
RubberDucky attacks form part of a bigger type of attacks that I like to call Automated Key Injection Attacks (AKIA). These attacks, as the name suggest, group all attacks were pre-programmed keystrokes are injected into the system. This injection can be done in different ways, for example:
- USB pretending to be a keyboard - (Hardware Attack) - eg. Rubberducky & BadUSB
- Injecting fake keystrokes to wireless keyboard dongles (Wireless Attack) - eg. Mousejack
- Malicious software injecting keystrokes into the system (Software Attack)
The intrinsic problem with these attacks is that they exploit the very basic trust between the computer and the user input peripherals (mouse, keyboard). In other words, a computer wont be able to distinguish between a good user or a bad user. Now the general thought in the hacking community is that if a malicious user has access to your computer for prolonged periods of time, then they will most likely get in. So AKIA attacks focus only on the pre-programmed attacks where malicious users only have a very tight attack window.
My general rule of thumb when hacking is that I should learn both the attack and defense vectors of any vulnerability, so while I was playing around with RubberDucky and performing Mousejacks I tried to come up with a simple solution to mitigate these attacks. What came out of this was the DuckHunt project, with the main idea being distinguishing good users from bad users. For now, DuckHunt consists of a simple script that checks the average typing speed of the user. In the presence of a duckhunt/mousejack attack it would notice the heavy speed increase and block the keystrokes. I added 4 different protection policies:
- Normal: While an attack is detected, all keyboard input is blocked. Once the attack is deemed finished, keyboard will be unblocked. Also, attacks get logged.
- Paranoid: Once an attack is detected, all keyboard input is blocked until a specified user specified password is typed. Also, attacks get logged.
- Sneaky: While an attack is detected one out of every 5-7 keystrokes is blocked, thus breaking the attack but without alerting the attacker that there is any type of security. Also, attacks get logged.
- Logging Only: When an attack is detected it becomes logged, however the attack itself is not stopped.
Aside from the protection policies, I also decided to add a few extra features, such as program blacklisting which essentially blocks anyone from typing into blacklisted programs (eg. Commandline or Powershell)
You might argue that this isn't the perfect solution, and the fact is that there are still many ideas that roam my mind that I would love to add to DuckHunt. The main purpose of this project is to initiate a discussion/brainstorming on how these issues could be mitigated.
As of right now, I added the code to github and also added two builds that will protect users that don't really know anything about computers. So if you or someone you know don't really want to worry about these attacks, but also don't want to hack around configuring and messing with code then simply download the build that best works for you and add it to your startup folder (so that it automatically runs every time the computer runs).
Small code explanation
The code is actually deceivingly simple and it was inspired by one of my previous project: Pylogger (the python keylogger for Windows). In fact I would recommend looking at that post if you wish to better understand the inner workings of DuckHunt. Here we will discuss a general overview of the code.
The essence of DuckHunt is that you build a small hook with Pyhook that will receive all the keystroke events from your computer. In this case we bind the KeyDown event to our function KeyStroke. In other words, every time a key is pressed, we run Keystroke().
# create and register a hook manager kl = pyHook.HookManager() kl.KeyDown = KeyStroke # register the hook and execute forever kl.HookKeyboard() pythoncom.PumpMessages()
Now, we will timestamp each keystroke and count how much time has passed between keystrokes. We will save an array with our latest speeds. The array will help us differenciate between cases when the speed between an actual attack and just two close button presses. In other words, a human might happen to press two buttons really quickly one after the other while typing some particular word, but it will be strange if the human manages to hit 25-50 letters in a row at a really really high speed.
If the average speed is faster than our given threshold we assume an attack is in motion and we catch the event. What we do with it will depend purely on our security policy. However the main thing you need to know is that to stop a keystroke from being sent you simply return False to the hook.
The last thing you can see in this snippet of code is how we check for blacklisted windows (e.g Command Prompt).
#This is triggered every time a key is pressed def KeyStroke(event): #Initial Condition if (prevTime == -1): prevTime = event.Time; return True if (i <= len(history)): i = 0; #TypeSpeed = NewKeyTime - OldKeyTime history[i] = event.Time - prevTime print event.Time,"-",prevTime,"=",history[i] prevTime = event.Time speed = sum(history) / float(len(history)) i=i+1 print "\rAverage Speed:",speed #Blacklisting for window in blacklist.split(","): if window in event.WindowName: return caught(event) #Intrusion detected if (speed > threshold): return caught(event) else: intrusion = False # pass execution to next hook registered return True
Last but not least, here is our caught function, notice we use the wind32ui.MessageBox to alert in Paranoid mode. One could take that little extra out if you want to really confuse an attacker.
def caught(event): global intrusion, policy, randdrop print "Quack! Quack! -- Time to go Duckhunting!" intrusion = True; #Paranoid Policy if (policy == "paranoid"): win32ui.MessageBox("Someone might be trying to inject keystrokes into your computer.\nPlease check your ports or any strange programs running.\nEnter your Password to unlock keyboard.", "KeyInjection Detected",4096) # MB_SYSTEMMODAL = 4096 -- Always on top. return False; #Sneaky Policy elif (policy == "sneaky"): randdrop += 1 #Drop every 5th letter if (randdrop==7): randdrop = 0; return False; else: return True; #Logging Only Policy elif (policy == "log"): log(event) return True; #Normal Policy log(event) return False
I'll keep developing and adding more features and fixes to this program. Probably starting with a much needed support for OSX and Linux. My aim is to spark a discussion regarding this issue and find possible prevention techniques, specially for "non-techy" users that are unaware of these attacks. If you found this interesting, feel free to check out the code in github or drop me a line.