Zum Inhalt springen
AutoST by Zyberum GmbH
Menü
FuzzingUDS

Eine UDS-Fuzzing-Methodik, die echte Bugs findet

Wie du ein ECU über UDS fuzzt, ohne Läufe zu verschwenden: wohin injizieren, wie einen Crash erkennen, wie ein Finding reproduzierbar machen, und am Prüfstand bleiben.

Tom Zaubermann · Veröffentlicht · 9 Min. Lesezeit

Ein ECU über UDS zu fuzzen heißt, fehlerhafte und unerwartete Diagnosenachrichten zu senden und auf den Moment zu achten, in dem sich das ECU nicht mehr erwartbar verhält. Gut gemacht findet es Parser-Bugs, State-Machine-Fehler und Ressourcenerschöpfung, die kein positiver Test erreicht. Schlecht gemacht verbrennt es Stunden mit Traffic, den das ECU im ersten Byte ablehnt. Der Unterschied ist Methode: injiziere dort, wo das ECU wirklich parst, erkenne einen Crash von außen, und mache jedes Finding reproduzierbar. Das ist ausschließlich eine Prüfstands-Aktivität, nie ein Fahrzeug im Verkehr.

Wohin injizieren

Ein UDS-Request über CAN wird von ISO-TP (ISO 15765-2) getragen und als Service-Identifier, optionale Sub-Funktion und Payload geformt. Jede Schicht ist ein Ort, an dem ein Parser scheitern kann, und jede verdient eine andere Mutationsstrategie.

ZielWas du mutierstWas es beansprucht
Service-IDDas SID-Byte, auch nicht-standardisierte WerteDen Service-Dispatcher
Sub-FunktionDas Sub-Funktions-Byte und seine Reserve-BitsDie Verzweigung je Service
PayloadLänge und Inhalt der DatenbytesDen Parser des Service selbst
ISO-TP-FramingFirst-Frame-Länge, Flow Control, Consecutive-Frame-SequenzDie Transportschicht unter UDS

Die ISO-TP-Schicht vergessen die meisten, und dort sehen wir am häufigsten einen Reset. Ein First Frame kann eine Länge von bis zu 4095 Bytes angeben; ein ECU, das diesen Puffer allokiert, bevor es die echten Daten prüft, oder das eine Lücke in der Sequenznummer falsch behandelt, lässt sich ohne ein einziges gültiges UDS-Byte umwerfen.

tx 10 0F FF 01 02 ...   First Frame behauptet 0xFFF = 4095 Bytes
tx 21 ...               Consecutive Frame, falsche Sequenznummer

Eine sinnvolle Strategie, nicht reiner Zufall

Völlig zufällige Bytes erzeugen meist 7F xx 11 oder 7F xx 13 und lehren dich wenig. Ein produktiver Lauf grenzt das Feld zuerst ein:

  1. Zuerst enumerieren. Wisse, welche Services in welcher Session antworten, bevor du fuzzt. Einen nicht unterstützten Service zu fuzzen ist vergeudete Mühe.
  2. Mit gültiger Struktur anfangen. Starte von wohlgeformten Requests, die das ECU akzeptiert, und mutiere nach außen. Eine fast gültige Payload erreicht tieferen Code als eine, die sofort abgelehnt wird.
  3. Länge aggressiv fuzzen. Off-by-One, Null-Länge und überlange Payloads finden Puffer-Bugs schneller als Inhalts-Mutation.
  4. Eine Session offen halten. Sende periodisch TesterPresent oder tritt erneut in die Session ein, denn ein Service, den du fuzzen willst, kann seine Session mitten im Lauf schließen.
  5. Eine Ausschlussliste führen. Schließe 0x11 ECUReset, 0x27 SecurityAccess und 0x34/0x36 Download-Services aus, es sei denn, du willst sie, sonst setzt der Lauf das ECU ständig zurück und du lernst nichts.

Einen Crash von außen erkennen

Du kannst den Speicher des ECU nicht sehen, also ist die Erkennung indirekt. Drei kombinierte Signale fangen fast alles:

  • Liveness. Nach jeder Iteration ein TesterPresent (3E 00) senden und 7E 00 erwarten. Keine Antwort oder eine falsche heißt, das ECU hat aufgehört zu antworten oder sich zurückgesetzt.
  • DTC-Monitor. Optional den DTC-Count lesen (19 01) und jede Änderung markieren. Ein neuer Fehlercode während eines Fuzz-Laufs deutet auf einen internen Fehler, selbst wenn das ECU am Leben bleibt.
  • Timeouts und Transportfehler. Ein Request, der auslaufzeitet oder einen ISO-TP-Fehler erzeugt, wird mit seiner exakten Payload aufgezeichnet.
tx <gefuzzter Request>
tx 3E 00           Liveness-Prüfung
(keine Antwort)    -> Crash-Kandidat an dieser Iteration

Eine einzelne verpasste Liveness-Prüfung ist ein Kandidat, kein bestätigtes Finding. Bestätige es durch Wiederholung der letzten Payloads, denn auch Prüfstände haben Aussetzer.

Ein Finding reproduzierbar machen

Ein Crash, den du nicht reproduzieren kannst, ist eine Anekdote, kein Bug-Report. Treibe den Lauf mit einem gespeicherten Pseudo-Zufalls-Seed, sodass die gesamte Sequenz deterministisch ist: gleicher Seed, gleiche Payloads, gleiche Reihenfolge. Zeichne je Finding die Iterationsnummer, den Zeitstempel, den auslösenden Monitor, die Payload und eine kurze Historie der vorangehenden Payloads auf. Dieses Paket ist, was ein Entwickler zum Beheben braucht, und was ein ISO/SAE-21434-Verifikationsbericht als Nachweis braucht.

Auf einem über UDS gefuzzten On-Board-Charger setzte sich das ECU bei einer bestimmten überlangen 0x2E-WriteDataByIdentifier-Payload zurück. Weil der Lauf geseedet war, spielten wir die exakte Iteration erneut ab und die Entwickler reproduzierten sie noch am selben Tag auf ihrem eigenen Prüfstand.

Sicher bleiben

Fuzzing kann ein ECU in einen Fehlerzustand versetzen, in einer hängenden Session lassen oder bricken. Drei Regeln verhindern, dass daraus ein Vorfall wird:

  • Auf einem isolierten Prüfstand laufen lassen, nie an einem Fahrzeug, das sich bewegen könnte, oder einem System, dessen Ausfall jemanden verletzen könnte.
  • Einen Wiederherstellungspfad bereithalten: einen bekannt guten Flash, eine Power-Cycle-Prozedur, einen Weg aus der Programming-Session.
  • Die Programming-Session und Reset-Services mit Vorsicht behandeln und ausschließen, sofern nicht der Flash-Pfad selbst das Testziel ist.

Die Fuzzing-Engine von AutoST setzt genau diese Methodik um: geseedete, reproduzierbare UDS- und CAN-Läufe, eine TesterPresent-Liveness-Prüfung nach jeder Iteration, einen optionalen DTC-Monitor, Payload-Erfassung je Finding und eine ausdrückliche Prüfstands-Haltung. Die Methode zählt mehr als das Tool, aber das Tool macht sie über jedes ECU und jeden Build hinweg wiederholbar.

FAQ

Häufig gestellte Fragen

Was ist der Unterschied zwischen UDS-Fuzzing und CAN-Fuzzing?

UDS-Fuzzing mutiert strukturierte Diagnosenachrichten über ISO-TP: Service-Identifier, Sub-Funktionen und Payloads. CAN-Fuzzing sendet rohe Frames auf Arbitration-IDs. UDS-Fuzzing erreicht die Diagnoselogik, CAN-Fuzzing erreicht alles, was einen Frame parst, auch Code unter dem Diagnose-Stack.

Woher weiß ein Fuzzer, dass das ECU abgestürzt ist?

Er kann nicht hineinsehen, also beobachtet er von außen: eine TesterPresent-Liveness-Prüfung nach jeder Iteration, einen optionalen DTC-Count-Monitor und Timeouts oder Transportfehler auf dem gefuzzten Request. Eine ausbleibende Antwort, ein Reset oder ein neuer Fehlercode ist das Signal.

Warum braucht ein Fuzzing-Lauf einen Seed?

Ein gespeicherter Pseudo-Zufalls-Seed macht den ganzen Lauf reproduzierbar. Ohne ihn ist ein einmal gesehener Crash einer, den du einem Entwickler nie wieder zeigen kannst. Mit ihm spielst du die exakte Sequenz erneut ab und übergibst die auslösende Payload.

Ruf uns anDemo buchen

Wähle einen Termin, der dir passt

In neuem Tab öffnen