Raspberry Pi Zero W – Remote Keystroke Injection
De Raspberry Pi Zero W is een apparaatje welke nog ontbrak aan mijn collectie. Nu hij recentelijk aan mijn kit is toegevoegd was de eerste vraag die in me opkwam uiteraard: wat voor leuks kunnen we hiermee gaan doen? De Zero is natuurlijk een lekker klein apparaatje welke niet erg opvalt en waarmee we best wat leuke dingen kunnen doen. Laten we er eens tool van maken die we nog niet in onze kit hebben. Een remote keystroke injection tool. Om dit te realiseren moeten we de USB poort op de Raspberry configureren als HID device en de WiFi als access-point. Op die manier kunnen we remote inloggen op de Raspberry om op die manier keystrokes door te sturen naar de verbonden computer. Ik weet niet of dit helemaal mogelijk is…maar we beginnen er gewoon aan. Doen jullie mee?
Ok we hebben dus 2 objectives. De USB poort configureren als HID device zodat de computer hem herkent als een “toetsenbord” en de WiFi omzetten als access-point. Aangezien dat het makkelijkste is gaan we daarmee beginnen. Maar uiteraard niet alvorens we de huishoudelijke klussen hebben gedaan.
Raspberry Pi Zero W Configureren
We gaan dit hele systeem baseren op Raspian (Stretch). Laten we dus maar beginnen met het downloaden van Raspian (Stretch) van de download pagina. Na het downloaden branden we deze op het microSD kaartje. Als dat gedaan is zijn we klaar om de Raspberry Pi Zero W te booten.
Allereerst gaan we SSH inschakelen, en stellen we in dat Raspian boot naar de CLI in plaats van naar de desktop. Je kunt eventueel ook je hostnaam en wachtwoord aanpassen. Dit alles doen we gewoon via de instellingen.
Daarna gaan we het systeem updaten.
sudo apt-get update && sudo apt-get upgrade |
In mijn geval was mijn fstab file (file systems table) overschreven en dat resulteerde in “root account is locked” melding en een diskcheck tijdens elke boot met de melding “Checking in progress on 1 disk”. Om dit te maken is het zaak om het fstab bestand te herstellen zoals deze hoort op een Raspberry Pi Raspian installatie en dat is als volgt:
nano /etc/fstab |
Raspberry Pi instellen als Access Point
Deze actie kunnen we op verschillende manieren voltooien, namelijk:
1) Handmatig. Deze stap is afdoende en zorgt voor minimale installatie (neemt weinig opslagruimte in beslag). Echter geeft deze stap je minder inzicht (grafisch gezien) en meer handmatig configuratiewerk.
2) Automatisch met RaspAP. RaspAP is een applicatie waarmee je je Raspberry Pi in kunt stellen als access point. RaspAP is gemakkelijk te installeren en geeft vanuit een overzichtelijke webinterface toegang tot alle installatieopties en access point eigenschappen.
Handmatige Installatie
Ok. Laten we starten met de handmatige installatie.
Om het voor elkaar te krijgen dat de Raspberry Pi als een access point fungeert moeten we de volgende zaken regelen:
- DNSMasq installeren
- HostAPD installeren
- Vast IP adres instellen (DNSMasq)
- DHCP configureren
- DHCP server installeren voor cliënts
- Access point maken met HostAPD
- Routeringen instellen
DNSMasq biedt verschillende extra diensten zoals DNS forewarder, DHCP server, router advertisement en netwerk boot functies. Dnsmasq vereist niet veel systeembronnen en is daarom uitermate geschikt voor Raspberry Pi. DNSMasq komen we ook vaak tegen in diverse home routers en IOT devices.
HostAPD is een daemon voor access point en authentication servers. HostAPD kan worden gebruikt om een draadloze hotspot te maken met Linux en dat is exact wat we willen bereiken. HostAPD implementeert IEEE 802.11 access point beheer, met IEEE 802.1X / WPA / WPA2 en EAP Authenticatie methodes evenals een RADIUS-client, EAP-server en RADIUS-authenticatieserver.
Als je Raspberry Pi up-to-date is kunnen we deze software installeren:
apt-get install dnsmasq hostapd |
Als het niet lukt om “hostapd” te installeren update dan je sources.list file met de juiste repositories. Deze kun je hier vinden. Je sources.list vindt je hier:
nano /etc/apt/sources.list |
Vervang “wheezy” in de source URL’s voor “stretch” omdat wij nu gebruik maken van Raspian Stretch.
Omdat de configuratiebestanden nog niet klaar zijn stoppen we de services:
systemctl stop hostapd systemctl stop dnsmasq |
We stoppen de services niet met het “service” commando (service hostapd stop” maar gebruiken hiervoor “systemctl”. In dit voorbeeld hadden we ook “service” kunnen gebruiken. Service is een “high level” commando welke wordt gebruikt voor het starten en stoppen van services binnen diverse Unix en Linux distributies. Afhankelijk van de servicemanager “op low level” worden opdrachten die aangeroepen worden met het “service commando door verschillende binaries doorgestuurd. Bij CentOS 7 wordt het bijvoorbeeld doorgestuurd naar systemctl, terwijl het op CentOS 6 direct het /etc/init.d script aanroept. Het service commando is voldoende voor standaard servicebeheer, maar de directe aanroep van systemctl meer controle en meer mogelijkheden.
Laten we nu eens een vast IP adres plaatsen. Om dit te doen passen we het dchpcd.conf bestand.
sudo nano /etc/dhcpcd.conf |
We passen de wlan0 (wireless) configuratie als volgt aan. Mocht deze informatie volledig ontbreken dan voeg je deze toe aan het bestand.
static ip_address=192.168.179.1/24 denyinterfaces eth0 denyinterfaces wlan0 |
En dan zijn we klaar om de DHCP server te configureren. Omdat het configuratiebestand van DNSMasq veel overbodige informatie bevat hernoemen we deze:
mv /etc/dnsmasq.conf /etc/dnsmasq.conf.origineel |
En we maken uiteraard een nieuw bestand aan.
nano /etc/dnsmasq.conf |
In dit bestand komen slechts 2 regels tekst. Een tekst om de interface te definieren en een regel om de DHCP scope te definieren:
interface=wlan0 dhcp-range=192.168.179.100,192.168.179.200,255.255.255.0,24h |
We definiëren een scope van 100 IP adressen (192.168.179.100,192.168.179.200) in een 24 bits subnet (255.255.255.0) en de IP lease is 24 uur (24h).
Nu de DHCP server configuratie klaar is gaan we het access point instellen.
Het instellen van ons access point doen we door het “hostapd” configuratiebestand te bewerken. Dit is een leeg bestand en moet voorzien worden van een aantal regels. Plak onderstaande regels erin.
nano /etc/hostapd/hostapd.conf |
interface=wlan0 bridge=br0 hw_mode=g channel=11 wmm_enabled=0 macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP ssid=toetsenbord wpa_passphrase=wachtwoord |
In bovenstaande bestand definiëren we wlan0 als interface en ook wordt het SSID gedefinieerd evenals het kanaal (11), WPA configuratie etc. Nu dat allemaal in orde is moeten we het systeem vertellen waar dit bestand gevonden kan worden. Dat doen we als volgt. Bewerk onderstaande bestand:
nano /etc/default/hostapd |
En nu zoek je de regel die begint met “DEAMON_CONF” en uncomment deze regel (haal het # weg). Hier vul je het pad in naar het configuratiebestand.
DAEMON_CONF="/etc/hostapd/hostapd.conf" |
Tenslotte zijn er nog een aantal netwerkzaken die we moeten regelen. We stellen het geheel in als een bridged setup. Dus al het verkeer wordt doorgestuurd over de ethernet interface. Nu heeft de Raspberry Pi Zero W geen ethernet interface maar in theorie kunnen we deze wel aankoppelen om internettoegang te geven aan de draadloze cliënts. In het licht van deze post dus overbodig maar aangezien de 2e methode (RaspAP) dit ook default doet wil ik de configuratie zo goed mogelijk nabouwen.
Pas het volgende bestand aan:
nano /etc/sysctl.conf |
En haal het hekje weg voor de regel:
net.ipv4.ip_forward=1 |
Deze regel activeert IP forwarding / routing. Nu gaan we masquerade inschakelen om het WiFi te kunnen delen:
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE |
Nu gaan we deze IP table opslaan:
sh -c "iptables-save > /etc/iptables.ipv4.nat" |
En deze gaan we toevoegen aan het /etc/rc.local bestand zodat deze regels weer ingeladen worden na een reboot.
nano /etc/rc.local |
Voeg onderaan dit bestand (net voor de “exit” regel) het volgende toe:
iptables-restore < /etc/iptables.ipv4.nat |
Nu gaan we de bridge functie maken. Deze stap is optioneel. Om dit voor elkaar te krijgen moet er nog 1 pakket gedownload worden.
apt-get install bridge-utils |
Als dat gebeurt is gaan we de bridge (br0) aanmaken:
brctl addbr br0 |
En we voegen de eth0 interface toe aan de bridge:
brctl addif br0 eth0 |
Tenslotte moeten we de interfaces file bewerken:
nano /etc/network/interfaces |
En voegen we onderstaande toe aan het einde van het bestand:
auto br0 iface br0 inet manual bridge_ports eth0 wlan0 |
Als dit allemaal is opgeslagen kunnen we de Raspberry Pi Zero W rebooten. Na de reboot moet het aangemaakte wireless netwerk beschikbaar zijn.
Automatisch Access Point met RaspAP
Als je iets meer inzicht en grafische controle wilt hebben over je access point dan is RaspAP een betere en makkelijkere oplossing van bovenstaande handmatige installatie. RaspAP installeer je als volgt:
wget -q https://git.io/voEUQ -O /tmp/raspap && bash /tmp/raspap |
Ga akkoord met de default settings. De installatie installeert de applicatie en dependencies zodat je meteen aan de slag kunt.
Op de GitHub pagina kun je ook de handmatige installatie van RaspAP terugvinden en uitvoeren.
Als de installatie voltooid is dan is een reboot nodig alvorens het access point up is. Het default access point heeft de volgende configuratie:
- IP adres: 10.3.141.1
- Gebruikersnaam: admin
- Wachtwoord: secret
Het WiFi dat uitgezonden wordt heeft deze config:
- IP: in de DHCP range van 10.3.141.50 tot 10.3.141.255
- SSID: raspi-webgui
- Wachtwoord: ChangeMe
Je kunt nu verbinden met de web console op de Raspberry door naar ip: http://10.3.141.1 te gaan in je browser. Ook kun je de web console benaderen door met een cliënt te verbinden en naar die URL te gaan.
Pas de configuratie naar wens aan. Let er alleen op dat als je de configuratie van het hotspot aanpast het /etc/hostapd/hostapd.conf bestand aangevuld / aangepast wordt met deze configuratie. Als je na opslaan de landcode hebt staan op de default (in de web console is dat Afganistan) dan zal het access point na reboot niet functioneren. Stel dus je instellingen goed in maar laat “country_code” in het hostapd.conf bestand leeg of verwijder de informatie na het opslaan van de configuratie.
Mocht je problemen hebben met het starten van de hostapd service controleer dan ook goed je regional instellingen en zet je datum en tijd goed.
Verbergen SSID
Wat je misschien nog wilt doen is het verbergen van je WiFi SSID. Ongeacht of je de handmatige of de automatische configuratiemethode hebt gebruikt, het verbergen van je SSID is in beide gevallen hetzelfde.
Edit nogmaals je “/etc/hostapd/hostapd.conf” bestand en zet de regel “ignore_broadcast_ssid” op 1 i.p.v. op 0. Als deze regel er nog niet tussen staat dan voeg je hem in zijn geheel toe.
USB input als HID Keyboard
De tweede grote taak is het configureren van de USB input. Deze moeten we gaan configureren als een HID device zodat computers de Raspberry Pi Zero W herkennen als een toetsenbord. Om dit te doen moet er het e.e.a. gebeuren. De meeste stappen zijn direct overgenomen uit deze tutorial. Uiteraard heb ik waar nodig verbeteringen en tweaks aangebracht. Laten we aan de slag gaan.
We beginnen met het activeren van een aantal modules en drivers.
Allereerst voegen we de dwc2 driver toe aan de bootfile en aan de modules. Dit is een upstream driver welke in verschillende modussen kan functioneren. Namelijk als host en als OTG driver. Deze driver hebben we nodig om data vanuit de Raspberry Pi Zero W naar de cliënt te sturen.
echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt echo "dwc2" | sudo tee -a /etc/modules |
Vervolgens gaan we ook de “libcomposite” kernel module toevoegen aan de modules. Deze module maakt het mogelijk om verschillende apparaten te emuleren zoals HID, mass storage en ethernet adapters.
echo "libcomposite" | sudo tee -a /etc/modules |
Nu de juiste drivers geladen worden zijn we klaar om ons “virtual file system” te configureren. Dit systeem kunnen we vinden in /sys/.
We gaan een script aanmaken welke we automatisch tijdens het booten op laten starten. Zoals we al eerder gezien hebben gebruiken we daar de “rc.local” file voor. Laten we het scipt maken:
nano /usr/bin/isticktoit_usb |
En we maken het script uitvoerbaar:
chmod +x /usr/bin/isticktoit_usb |
Vervolgens zorgen we ervoor dat het script automatisch laad tijdens het opstarten:
nano /etc/rc.local |
En we voegen nu aan het einde van het bestand (voor “exit 0”) het volgende toe:
/usr/bin/isticktoit_usb # libcomposite config |
Nu dat klaar is gaan we het script maken.
nano /usr/bin/isticktoit_usb |
Volgens hiervoor genoemde tutorial zijn dit de default values welke in het script moeten komen:
#!/bin/bash cd /sys/kernel/config/usb_gadget/ mkdir -p isticktoit cd isticktoit echo 0x1d6b > idVendor # Linux Foundation echo 0x0104 > idProduct # Multifunction Composite Gadget echo 0x0100 > bcdDevice # v1.0.0 echo 0x0200 > bcdUSB # USB2 mkdir -p strings/0x409 echo "fedcba9876543210" > strings/0x409/serialnumber echo "Tobias Girstmair" > strings/0x409/manufacturer echo "iSticktoit.net USB Device" > strings/0x409/product mkdir -p configs/c.1/strings/0x409 echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration echo 250 > configs/c.1/MaxPower # Add functions here mkdir -p functions/hid.usb0 echo 1 > functions/hid.usb0/protocol echo 1 > functions/hid.usb0/subclass echo 8 > functions/hid.usb0/report_length echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\ \x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\ \x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\ \x00\\xc0 > functions/hid.usb0/report_desc ln -s functions/hid.usb0 configs/c.1/ # End functions ls /sys/class/udc > UDC |
Download hier het volledige script.
In principe zijn de default values prima. Deze staan al ingesteld als “USB gadget” en dus als HID input device. Wat we wel gaan doen is het aanpassen van een aantal ID’s. Namelijk:
echo 0x413c > idVendor # Dell Computer Corp echo 0x2106 > idProduct # Dell QuietKey Keyboard |
En:
echo "9649612237691992" > strings/0x409/serialnumber echo "Dell Computer Corp" > strings/0x409/manufacturer echo "HID_DEVICE_SYS_KEYBOARD" > strings/0x409/product |
Als we nu de Raspberry Pi Zero W rebooten en aansluiten op de PC ziet er dit als volgt uit in de device manager.
Het werkt!!
We hebben nu in feite een USB Rubber Ducky welke we remote kunnen aansturen door te verbinden met het access point. Alleen… hoe sturen we deze exact aan? Hoe gaan we commando’s doorsturen.
Let op:
Het aansturen van je Remote HID Keyboard
Je kunt je toetsenbord aansturen via Python. Het is goed om te weten hoe de codering van toetsen werkt. Een toets bevat altijd 8 bytes, namelijk:
- 1 byte – Modifier keys zoals Control, Shift, Alt etc.)
- 1 byte – Ongebruikt / gereserveerd voor OEM
- 6 bytes – Ingedrukte key codes
Als we kijken naar de 1e byte dan heeft deze modifier key dus 8 bits die gebruikt kunnen worden. Elke bit heeft een waarde.
- bit 7 – Meta (rechts)
- bit 6 – ALT (rechts)
- bit 5 – SHIFT (rechts)
- bit 4 – CONTROL (rechts)
- bit 3 – Meta (links)
- bit 2 – ALT (links)
- bit 1 – SHIFT (links)
- bit 0 – CONTROL (links)
Om dus een hoofdletter te typen moet je de juiste bit in de modifier key instellen op 1 wat overeen komt met de linker SHIFT en dus wordt het een hoofdletter. De HID keytcodes voor bovenstaande modifier bits zijn als volgt:
- bit 7 – 0x80 – Meta (rechts)
- bit 6 – 0x40 – ALT (rechts)
- bit 5 – 0x20 – SHIFT (rechts)
- bit 4 – 0x10 – CONTROL (rechts)
- bit 3 – 0x08 – Meta (links)
- bit 2 – 0x04 – ALT (links)
- bit 1 – 0x02 – SHIFT (links)
- bit 0 – 0x01 – CONTROL (links)
#Bash: \x02 #Python: chr(32) |
Als je een toetsencombinatie gebruikt, bijvoorbeeld CTRL + ALT dan tel je de waardes bij elkaar op (01+04=05 en dus x05).
De letters van het alfabet beginnen bij “nummer 4” want er zijn namelijk 4 codes welke gereserveerd zijn.
- x00 – Geen toets ingedrukt
- x01 – Keyboard Roll Over (teveel toetsen ingedrukt)
- x02 – Keyboard POST fail
- x03 – Keyboard error (ongedefinieerd)
Letter “a” is dus 0x04, letter “b” is 0x05 en letter z is 0x1d (codes zijn in HEX formaat, dus nummer 29). Vanaf nummer 30 (x1e) gaat het verder met nummer 1. Nummer 39 (x27) is het nummer 0. Dan volgen er vele andere toetsenbord letters zoals de ENTER, ESC, CAPSLOCK etc.
Zoals je hierboven al zag hanteert Python dezelfde codes maar dan aangegeven als waarde en niet hexadecimaal. De a is “chr(4)” en de z is “chr(29)”. Nummer 5 is “chr(34)”. Deze komen dus overeen.
Waar je ook op moet letten is dat na elke toets die we indrukken deze ook weer losgelaten moet worden. Dit doen we met het 0-karakter (ofwel “\0\0\0\0\0\0\0\0” of “NULL_CHAR*8” in Python. Doe je dat niet dan zal de toets ingedrukt blijven waardoor het opgegeven karakter zich blijft herhalen.
Als we een woordje willen laten typen door het toetsenbord gebruiken we dus de volgende codes. Het woord dat we gaan maken is “Hallo”:
#Bash: #H \x20\0\xb\0\0\0\0\0 #a \0\0\x4\0\0\0\0\0 #l \0\0\xf\0\0\0\0\0 #l \0\0\xf\0\0\0\0\0 #o \0\0\x12\0\0\0\0\0 #Release toetsen \0\0\0\0\0\0\0\0 #Python: #H (chr(32)+NULL_CHAR+chr(11)+NULL_CHAR*5) #a (NULL_CHAR*2 +chr(4)+NULL_CHAR*5) #l (NULL_CHAR*2 +chr(15)+NULL_CHAR*5) #l (NULL_CHAR*2 +chr(15)+NULL_CHAR*5) #o (NULL_CHAR*2 +chr(18)+NULL_CHAR*5) #Release toetsen (NULL_CHAR*8) |
In het hexadecimale voorbeeld (welke we prima in b.v. Bash kunnen gebruiken) zien we dat de opmaak van de 8 bytes gescheiden is met een slash \. De 2e bit is altijd een 0. Dit is het gereserveerde bit. Het eerste bit is 0 als er geen speciale toets ingedrukt is. Bij de hoofdletter H wordt de SHIFT ingedrukt en is dus hier het eerste bit “x20”. Het 3e bit wordt gevuld met het overeenkomstige karakter.
In het Python voorbeeld zien we dat we een hoofdletter beginnen en vervolgens (byte 2) altijd een 0 karakter geven. Als we 2x een 0 karakter hebben zoals bij een gewon letter geven we dat aan met *2, dus “NULL_CHAR*2”. Vervolgens geven we het overeenkomstige karakter aan gevolgd door 5x een 0 byte, dus “NULL_CHAR*5”.
In een script verwerken we dit met een “write_report” functie welke het door ons gecreëerde HID device aanstuurt. Dat zal meestal “/dev/hidg0” zijn.
In zijn totaliteit ziet bovenstaande script er als volgt uit:
Bash
#!/bin/bash function write_report { echo -ne $1 > /dev/hidg0 } #H write_report "\x20\0\xb\0\0\0\0\0" #a write_report "\0\0\x4\0\0\0\0\0" #l write_report "\0\0\xf\0\0\0\0\0" #l write_report "\0\0\xf\0\0\0\0\0" #o write_report "\0\0\x12\0\0\0\0\0" #Release toetsen write_report "\0\0\0\0\0\0\0\0" |
Python:
#!/usr/bin/env python3 NULL_CHAR = chr(0) def write_report(report): with open('/dev/hidg0', 'rb+') as fd: fd.write(report.encode()) #H write_report (chr(32)+NULL_CHAR+chr(11)+NULL_CHAR*5) #a write_report (NULL_CHAR*2 +chr(4)+NULL_CHAR*5) #l write_report (NULL_CHAR*2 +chr(15)+NULL_CHAR*5) #l write_report (NULL_CHAR*2 +chr(15)+NULL_CHAR*5) #o write_report (NULL_CHAR*2 +chr(18)+NULL_CHAR*5) #Release toetsen write_report (NULL_CHAR*8) |
Om direct, zonder script vanuit Bash iets te sturen naar je HID device moet je ervoor zorgen dat je allereerst voldoende rechten hebt op het apparaat:
chmod 777 /dev/hidg0 |
En vervolgens kun je output sturen:
echo -ne "\x00\x00\x00\x4\x00\x00\x00\x00" > /dev/hidg0 && echo -ne "\x00\x00\x00\x00\x00\x00\x00\x00" > /dev/hidg0 |
Ook hier eindig je weer met een 0-karakter zodat de toets losgelaten wordt.
Download hier mijn Excel bestand met alle hexadecimale en decimale codes.
Conclusie
Zijn jullie er nog? Het is ons gelukt!!
Dit is toch nog een aardig project geworden waarbij we verschillende aspecten bekeken en nader toegelicht hebben. Access points, Linux, HID devices en natuurlijk de Raspberry Pi Zero W.
Weet jij meer leuke toepassingen waarvoor we deze Raspberry Pi Zero W met wat tweaken voor in kunnen zetten? Laat het me weten en als het idee leuk genoeg is ga ik kijken of ik het kan maken. Of we bouwen het samen?
In de volgende post ga ik ervoor zorgen dat het programmeren van remote keystrokes super makkelijk word. Makkelijker nog dan het programmeren van een USB Rubber Ducky!
Ik hoop in ieder geval dat deze post inspiratievol was en dat je hem interessant vond. Ja? Deel hem dan s.v.p. eventjes op je sociale kanalen of op je website. Je zou er mij in ieder geval een groot plezier mee doen 😉 Dankjewel!