Deutschlands Bester Hacker - Schwarzer Freitag (OT) - Das Writeup

Disclaimer: Im August 2026 fand die Qualifikation für das Finale von Deutschlands Bester Hacker statt, welches ich auf Platz 1 abschließen konnte. Nur zwei Teilnehmer waren in der Lage, alle Challenges zu lösen. Dieses Writeup wurde mit KI auf Basis meiner Notizen erstellt und kann Fehler enthalten, bei Fragen bitte direkt an mich wenden im DBH-Discord.

Wettbewerb Deutschlands Bester Hacker 2026 — Qualifikation
Kategorie OTOperational TechnologyHardware und Software zur Überwachung oder Steuerung physischer Anlagen, Maschinen und industrieller Prozesse.
Punkte 338
Angriffsklasse Unautorisierte DNP3DNP3Fernwirkprotokoll für Leitsysteme, verbreitet in Energieversorgung und Wasserwirtschaft.-Control-Kommandos (Secure Auth deaktiviert)
Flag DBH{5CH4LT3R_0FF_DNP3_UNS3CUR3D}

Die Challenge

Gegeben waren drei Artefakte:

  • umspannwerk_traffic.pcap
  • rtu_config.xml
  • umspannwerk_hmi_server.py

Das Szenario beschreibt einen Ausfall im Umspannwerk Nord: Die Leistungsschalter CB-1, CB-2 und CB-3 öffnen ohne Schaltauftrag. Aufgabe ist es, Netzwerktraffic, RTURemote Terminal UnitFeldgerät, das Messwerte einer entfernten Anlage erfasst und Schaltbefehle der Leitstelle ausführt.-Konfigurationsbackup und HMIHuman Machine InterfaceBedien- und Beobachtungsoberfläche, über die Personal einen industriellen Prozess überwacht und steuert.-Diagnoseserver zu analysieren und daraus die Flag zu rekonstruieren.

Aufklärung

In rtu_config.xml ist die RTU als simuliertes SEL-3530 RTAC-System beschrieben. Relevant sind die DNP3-Parameter:

<DNP3OutstationAddress>10</DNP3OutstationAddress>
<DNP3MasterAddress>1</DNP3MasterAddress>
<ListenPort>20000</ListenPort>
<Protocol>DNP3-TCP</Protocol>

Die RTU lauscht also auf DNP3-TCP Port 20000 mit Outstation-Adresse 10. Die Netzwerkkonfiguration zeigt zwei bekannte Stationen:

<Master ip="10.0.0.100" description="SCADA-SRV Leitstelle" auth="true"/>
<Master ip="10.0.0.55"  description="EWS Wartung"          auth="false"/>

10.0.0.100 ist der autorisierte SCADASCADALeitsystem zur Überwachung und Steuerung räumlich verteilter industrieller Prozesse.-Master, 10.0.0.55 nur eine Engineering Workstation für Wartung — die keine Direct-Operate-Kommandos ausführen sollte.

Die betroffenen Schalter sind ebenfalls in der Konfiguration zu finden:

<BinaryOutput index="0" description="CB-1 TRIP/CLOSE cmd" writeEnabled="true"/>
<BinaryOutput index="1" description="CB-2 TRIP/CLOSE cmd" writeEnabled="true"/>
<BinaryOutput index="2" description="CB-3 TRIP/CLOSE cmd" writeEnabled="true"/>

CB-4 und CB-5 sind nicht schreibbar. Das Schadensbild passt also exakt zur Konfiguration: nur die drei schreibbaren Breaker-Control-Points wurden missbraucht.

Die Schwachstelle

Entscheidend ist der Security-Block:

<DNP3AuthV5Enabled>false</DNP3AuthV5Enabled>

DNP3 Secure AuthenticationAuthenticationÜberprüfung der behaupteten Identität eines Benutzers oder Systems. ist deaktiviert. Das ist die zentrale Schwachstelle: Die RTU verlässt sich auf eine logische Master-Zuordnung, prüft die DNP3-Kommandos aber nicht kryptografisch. Die Rollenverteilung steht damit nur auf dem Papier.

Der Angriff

Im PCAP fällt zunächst normaler Traffic zwischen SCADA-Master 10.0.0.100 und der RTU 10.0.0.200 auf. Kurz vor dem Alarm erscheinen jedoch Pakete von einer anderen Quelle:

09:47:03  10.0.0.55 -> 10.0.0.200  DNP3 Direct Operate / CROB  index 0
09:47:09  10.0.0.55 -> 10.0.0.200  DNP3 Direct Operate / CROB  index 1
09:47:15  10.0.0.55 -> 10.0.0.200  DNP3 Direct Operate / CROB  index 2

Die Indizes 0, 1 und 2 entsprechen den Binary Outputs für CB-1 bis CB-3 — genau die drei Schalter, die später öffnen.

Die DNP3-Header der Angreiferpakete enthalten außerdem:

Destination address: 10
Source address:      99

Die Source-Adresse 99 wird gleich noch wichtig.

Nach den Schaltbefehlen folgen vier weitere auffällige DNP3-Pakete von 10.0.0.55. Aus ihnen lassen sich jeweils acht Bytes extrahieren, zusammen 32 Bytes:

27 21 2b 18 56 20 2b 57 2f 37 50 31 3c 53 25 25 3c 27 2d 33 50 3c 36 2d 30 50 20 36 31 50 27 1e

Da die DNP3-Source-Adresse des Angreifers 99 = 0x63 ist, liegt XOR mit 0x63 nahe:

0x27 XOR 0x63 = 0x44 = D
0x21 XOR 0x63 = 0x42 = B
0x2b XOR 0x63 = 0x48 = H
0x18 XOR 0x63 = 0x7b = {

Damit beginnt der dekodierte Text mit DBH{ — der richtige Weg ist bestätigt. Reproduzierbar:

payload_hex = """
27 21 2b 18 56 20 2b 57
2f 37 50 31 3c 53 25 25
3c 27 2d 33 50 3c 36 2d
30 50 20 36 31 50 27 1e
"""

data = bytes.fromhex(payload_hex)
key = 0x63

flag = bytes(b ^ key for b in data).decode()
print(flag)

Der zweite Weg über den HMI-Server. umspannwerk_hmi_server.py simuliert einen HMI-Diagnoseserver auf Port 5200 und stellt nach erfolgreicher Unlock-Sequenz die Flag in ModbusModbusEinfaches Industrieprotokoll zum Lesen und Schreiben von Registern und Ein-/Ausgängen.-Holding-Registern bereit. Die Flag liegt ab Register 200 als ASCII, sobald Register 199 auf 1 gesetzt wurde. Die Unlock-Sequenz prüft die Register 100, 101 und 102:

_UNLOCK = [ord(FLAG[0]), ord(FLAG[1]), 95]

Für eine Flag im Format DBH{...} sind die ersten beiden Zeichen D und B:

HR 100 = 68   ('D')
HR 101 = 66   ('B')
HR 102 = 95   ('_')

Der Server schreibt die Flag danach in die Register und gibt sie zusätzlich auf der Konsole aus.

Die Flag

DBH{5CH4LT3R_0FF_DNP3_UNS3CUR3D}

Der Angriff lässt sich damit vollständig rekonstruieren:

  1. Der Angreifer nutzt die Engineering Workstation 10.0.0.55.
  2. Diese ist laut RTU-Konfiguration nicht für Schaltbefehle autorisiert.
  3. Da DNP3 Secure Authentication deaktiviert ist, akzeptiert die RTU die Pakete trotzdem.
  4. Der Angreifer sendet drei DNP3-CROB-Kommandos an die Binary Outputs 0, 1, 2.
  5. Diese entsprechen CB-1, CB-2 und CB-3 — die Schalter öffnen, die Versorgung fällt aus.
  6. Anschließend folgen vier DNP3-Pakete mit XOR-verstecktem PayloadPayloadTeil eines Angriffs oder Exploits, der die beabsichtigte schädliche Wirkung ausführt..
  7. Der XOR-Key ist die DNP3-Source-Adresse des Angreifers: 99 = 0x63.

Was ich mitnehme

Die Challenge zeigt sehr gut, warum reine Netzsegmentierung und statische Master-Listen in OT-Umgebungen nicht ausreichen. Die RTU-Konfiguration enthält zwar eine klare Rollenverteilung zwischen SCADA-Master und Engineering Workstation, aber die entscheidende kryptografische Absicherung ist abgeschaltet. Dadurch konnte ein eigentlich read-only vorgesehenes System kritische Schalthandlungen auslösen.

Der entscheidende Hinweis für den versteckten Payload war die ungewöhnliche DNP3-Source-Adresse 99. Wer Protokollfelder nur als Rauschen liest, übersieht, dass sie hier gleichzeitig der Schlüssel sind.