Wireshark Plugin für S7-Protokoll

Zuviel Werbung?
-> Hier kostenlos registrieren
zu 2)
Meine Vermutung:
Beim Verbindungsaufbau wird ein geheimer Schlüssel ausgehandelt, der später in die Berechnung das Wertes mit einfließt. Das Verfahren entspricht also MAC bzw. HMAC. Beim Verbindungsaufbau verraten auch ein paar Objekt-ID was da ablaufen könnte. Bei einer S7-1200 die keine Integrität beherrscht, fehlen diese Objekt-IDs beim Verbindungsaufbau. Ich habe ein paar zaghafte Versuche unternommen um herauszufinden woraus die sich die Objekt-Daten beim Verbindungsaufbau zusammensetzen, denn da gibt es feste und variable Teile. Wie das im Detail funktioniert weiß ich aber auch nicht.
Damit keine Replay-Angriffe möglich sind, muss es eine Wertänderung im Datenpaket geben, darum die Integritäts-ID. Diese erhöht sich nicht nur, sondern laut meinen Berechnungen wird diese aus der letzten Response usw. berechnet (glaub ich habs im Code-Kommentar vermerkt). D.h. selbst wenn der Datenteil komplett identische Daten aufweist, ist die Signatur aufgrund des sich ändernden ID und dem Hashverfahren völlig unterschiedlich.
Wie die Signatur berechnet wird ist mir nicht bekannt, ich vermute (und es wäre für Siemens auch empfehlenswert) etwas standardisiertes wie SHA-256 (würde von der Byteanzahl passen) zu verwenden.

Wahrscheinlich gab es da mal ein Sicherheitsproblem im Übertragungsprotokoll, denn die Struktur mit FW 1.5 geändert (Position des Integritätsblocks hat sich geändert). Evtl. lässt sich daraus noch etwas ableiten.

zu 1)
Muss ich mir mal ansehen, ich habe das bei der 1500 selber noch nicht nachgerechnet. Bei den ersten 1200er ließen sich noch über die 0x32er Telegramme mit LID/CRC Variablenwerte abfragen. Ob das bei der 1500er überhaupt noch funktioniert weiß ich nicht. Ich hatte bisher kein Zugang zu einer 1500.
 
zu 1) Ja das funktioniert bei der 1500er auch, wie hier im Ausschnitt des Wireshark-Protokolls zu sehen ist.
Anhang anzeigen 33191
Wie gesagt, die Variable heißt "Variable"

zu 2) Ja, SHA256 könnte passen. In einem älteren Post gab es mal eine Passwortübergabe mit SHA1 bzw. HMACSHA1. Da konnte das Passwort auch mit einem Python-Programm ermittelt werden. Evtl. ist es hier ja ähnlich. Allerdings ist hier natürlich die Frage, welcher Hashkey hier verwendet wird. Vielleicht folgende Kandidaten:
- Beim Connect (CreateObject)-Response wird u.a. ein ServerSessionChallenge zurückgeliefert. Dies sind 20 Byte Daten (evtl. SHA1?)
- Beim anschließenden SetMultiVariables-Request wird u.a ein SecurityKeyEncryptedKey gesetzt: 180 Byte Daten (Blob)

Keine Ahnung, ob diese Daten irgendetwas mit der Bildung des Integrity parts zu tun haben.:confused:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
zu 1) Ja das funktioniert bei der 1500er auch, wie hier im Ausschnitt des Wireshark-Protokolls zu sehen ist.

Das in deinem Logfile gezeigte ist aber sozusagen die aktuelle "Standardzugriffsart".
Bei meiner 1200 mit FW2 hier wurde diese Adressierungsart in das alte S7-Protokoll, d.h. mit 0x32 im Kopf, integriert. Bzw. wurde diese nur von einem HMI in TIA V11 verwendet, ab V12 verwendet das HMI die gleiche Zugriffsvariante wie in deinem angehängten Logfile. Anstelle der Anfrageadresse in Form des Any-Pointers gibt es dort eben Zugriff über LID und CRC. Das Wireshark-Baumelement "Item Address" aus S7comm-plus ist identisch in S7comm vorhanden. Das hätte den Vorteil, dass sich damit relativ einfacher Zugriff auf symbolische adressierte Variablen möglich ist, weil eben der ganze bisher unbekannte Schritt mit Authentifizierung und Integrität entfällt, und es sich auch einfach in bestehende Kommunikationsbibliotheken (z.B. libnodave) integrieren lässt. Man muss nur vorab die IDs und das Symbol kennen, das Auslesen der Symbolik inkl. IDs ist nur über S7comm-plus möglich.

Wie gesagt, die Variable heißt "Variable"
Die liegt aber laut deinem Logfile in einem Datenbaustein, dann berechnet sich die CRC aus dem vollständigen Zugriffnamen "DBNAME.VARNAME", d.h. mit Punkt. Wenn die Variable innerhalb einer Struktur liegt, dann wird als Trennzeichen ein 0x09 verwendet.

Wenn du mit das vollständige Symbol sagst, kann ich das mal mit meiner "Formel" nachrechnen.

zu 2) Ja, SHA256 könnte passen. In einem älteren Post gab es mal eine Passwortübergabe mit SHA1 bzw. HMACSHA1. Da konnte das Passwort auch mit einem Python-Programm ermittelt werden. Evtl. ist es hier ja ähnlich. Allerdings ist hier natürlich die Frage, welcher Hashkey hier verwendet wird. Vielleicht folgende Kandidaten:
- Beim Connect (CreateObject)-Response wird u.a. ein ServerSessionChallenge zurückgeliefert. Dies sind 20 Byte Daten (evtl. SHA1?)
- Beim anschließenden SetMultiVariables-Request wird u.a ein SecurityKeyEncryptedKey gesetzt: 180 Byte Daten (Blob)

Keine Ahnung, ob diese Daten irgendetwas mit der Bildung des Integrity parts zu tun haben.:confused:

Die Integrity-ID berechnet sich imho nach:
Response.Integrity-Id = Request.Sequenznummer + Request.Integrity-Id
Ob das "muss" oder rein zufällig so ist habe ich noch nicht überprüft.

Dieser 180 Byte Blob hat nach meinen Analysen die folgenden Eigenschaften:
Insgesamt besteht er aus 7 Teilen
- 16 Bytes immer identisch
- 8 Bytes abhängig vom Schlüssel im HMI
- 24 Bytes immer identisch
- 76 Bytes abhängig vom Schlüssel im HMI
- 16 Bytes abhängig von der Challenge
- 24 Bytes abhängig vom Schlüssel im HMI
- 16 Bytes abhängig von der Challenge

Übrigens:
Von Wonderware gibt es mittlerweile angeblich einen Treiber des das S7comm-plus vollständig unterstützt.
 
Ich habe nochmal einen Test mit einer 1500er, TIA13 und einer HMI gemacht und ein Datenwort gelesen.

wireshark_crc.jpg

Die Variable heißt: Datenbaustein_1.TEST_WORD_6
CRC in WireShark: 0x1d7def11
CRC mit Jochens getcrc: 0x22097493

Anschließend habe ich den DB umbenannt: Datenbaustein_1a.TEST_WORD_6

CRC in wireshark: 0x1d7def11
getcrc: 0x500de358

Wenn ich nur "TEST_WORD_6" mit getcrc berechne, erhalte ich: 0xf13d471e

So wie es aussieht, hat also der Bausteinname keinen Einfluss auf die CRC. Aber nur mit "TEST_WORD_6" liefert Jochens getcrc einen falschen Wert.:confused:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habs mir nochmal angesehen. Es scheint bei der Berechnung einen Unterschied zwischen S7-1200 und S7-1500 zu geben.

Bei der 1200 berechnet sich die CRC rein aus dem Symbolnamen im DB, der DB-Name ist nicht relevant. Die DB-Nummer wird aber mit übermittelt. Das bedeutet, ein DB lässt sich umbenennen und der Zugriff vom HMI funktioniert weiterhin, solange die DB-Nummer nicht geändert wird.

Was bei der 1500 in den Symbolnamen mit hineinspielt habe ich noch nicht herausgefunden. Falls dem Symbol noch etwas vorangestellt sein sollte (z.B. "DB.variable") und die Berechnung ist identisch, so ist dieses Präfix zumindest länger als 4 Zeichen, bis dahin habe ich alle Werte durchprobiert. Dass die Prüfsummenberechnung eine völlig andere ist kann ich mir fast nicht vorstellen.
 
Hmmm...

Ich habe auch mal für die CRC-Berechnung alle Startwerte von 0 bis UInt32.Max für "TEST_WORD_6" durchprobiert. Leider ohne Erfolg.
 
Doch, man bekommt eine Lösung mit so einer Bruteforce-Suche. Bei TEST_WORD_6 müsstest du die 4 Bytes 0x61, 0x90, 0xc8, 0x37 voranstellen, dann kommt mit der bisherigen Berechnung 0x1d7def11 heraus.

Vermutlich ist das aber nur eine zufällige Kollision bei der CRC Berechnung, das heißt es ist eine Lösung, aber nicht die einzige.

Mit den 4 Bytes kann ich zumindest die CRC für meine Steuerung _nicht_ berechnen. Ich habe mir zum Test 4 Variablen in einem DB abgelegt, und dann für die Erste ebenfalls einen 4 Byte-Präfix gefunden um auf die CRC zu kommen. Damit lassen sich aber auch nicht die CRC für die anderen Variablen in dem DB bestimmen. Damit kann man schonmal ausschließen, dass der gefundene Präfix korrekt ist, falls dieser z.B. Steuerungsabhängig sein sollte und darum bei dir und bei mir verschieden.
Es könnte z.B. auch DATENBAUSTEIN oder TIAISTDOOF davor (oder dahinter) stehen, alleine mit Bruteforce kommt man bei großer Länge nicht dahinter. Zumal auch noch alles ganz anders sein kann.
 
Ich glaub ich hab's:
An TEST_WORD_6 muss man noch den Variablentyp anhängen (für WORD = 0x04) und die CRC mit TiaCrcHelper.getcrc() berechnen. Die errechnete CRC dann nochmals an TiaCrcHelper.getcrc() übergeben:

List<byte> Var = new List<byte>(Encoding.ASCII.GetBytes("TEST_WORD_6"));
Var.Add(0x04);
UInt32 crc = TiaCrcHelper.getcrc(BitConverter.GetBytes(TiaCrcHelper.getcrc(Var.ToArray())));

und siehe da: crc = 0x1d7def11, wie auch im TIA-Wireshark-Protokoll.


Unklar sind jetzt noch:
- Das 32 Byte lange "Packet Digest" im Integrity part und
- Der 180 Byte Blob im
SetMultiVariables-Request (SecurityKeyEncryptedKey)

Hat einer von euch noch eine Ahnung, wie diese sich zusammensetzen?
 
Das Anfügen des Datentyps ist durchaus sinnvoll. Bisher fußte die Zuverlässigkeit darauf, dass das TIA-Portal bei einer Änderung am Programm eine neue ID generiert, was vielleicht etwas wackelig war.

Was es bringen soll das ganze zweimal durch die Prüfsummenbildung zu schicken ist mir schleierhaft. Ich könnte mir nur vorstellen, dass es damit nicht zu "zufällig" richtigen Prüfsummen kommt, wenn das Verfahren wie bei der 1200 angewendet wird.
Ansonsten gilt bei Prüfsummenverfahren nicht unbedingt "viel hilft viel", ganz im Gegenteil.
 
Haben wir denn jetzt schon genügend Infos um Symbolische Variablen aus einer 1500er zu lesen? Kann msn auch die existierenden Variablen auslesen?
Du kannst alle notwendigen Informationen aus der Steuerung auslesen, das TIA-Portal Projekt dazu nicht benötigt. Das funktioniert bei den ersten 1200er mit alter Firmware, wie auch bei den aktuellen 1500. Wobei es da wieder Unterschiede im Aufbau gibt. Du müsst also die Symbolik auslesen, und darin für das gewünschte Symbol die ID und den Datentyp suchen und übernehmen.

Das ist aber alles mehr oder weniger aufwändig, weil du auch wenn nur an ausgewählte Informationen kommen willst, immer das komplette Telegramm von Anfang bis Ende verstehen musst, da es so gut wie keine Längenangaben oder sonstige Ankerpunkte gibt an denen man neu aufsetzen könnte.
 
Haben wir denn jetzt schon genügend Infos um Symbolische Variablen aus einer 1500er zu lesen? Kann msn auch die existierenden Variablen auslesen?

Für das Protokoll benötigt man auch noch Infos über die Zusammensetzung dieser Pakete:
- Das 32 Byte lange "Packet Digest" im Integrity part und
- Der 180 Byte Blob im
SetMultiVariables-Request (SecurityKeyEncryptedKey)

Wenn dies klar wäre, dürfte man die symbolischen Variablen aus der 1500er lesen können.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Für das Protokoll benötigt man auch noch Infos über die Zusammensetzung dieser Pakete:
- Das 32 Byte lange "Packet Digest" im Integrity part und
- Der 180 Byte Blob im SetMultiVariables-Request (SecurityKeyEncryptedKey)

Hast du den Rest denn schon fertig? Meine Test-Steuerungen benötigen nämlich beide Felder nicht (eine 1200 mit alter Firmware, und TIA-Plcsim-1500). Ob die Felder notwendig sind, ist nach meiner Erkenntnis abhängig vom ersten Antworttelegramm (Response CreateObject). Ist dort ein Eintrag mit ID 299 nicht vorhanden oder hat der Wert 0, dann wird kein Key benötigt.

Als Verfahren kommt aber mit ziemlicher Sicherheit SHA256 zum Einsatz, ist nur die Frage was und wie dort mit hinein-verwurstet werden muss.
Den Anfang mit deadfee1 haben wir ja schonmal...
 
Hast du den Rest denn schon fertig? Meine Test-Steuerungen benötigen nämlich beide Felder nicht (eine 1200 mit alter Firmware, und TIA-Plcsim-1500). Ob die Felder notwendig sind, ist nach meiner Erkenntnis abhängig vom ersten Antworttelegramm (Response CreateObject). Ist dort ein Eintrag mit ID 299 nicht vorhanden oder hat der Wert 0, dann wird kein Key benötigt.

Nein fertig ist noch nichts. Ich analysiere nur die unbekannten Teile des Protokolls.
Ich habe hier eine 1511 und die liefert bei ServerSessionRole (=299) den Wert 536870912 (was auch immer das bedeuten mag).

Als Verfahren kommt aber mit ziemlicher Sicherheit SHA256 zum Einsatz, ist nur die Frage was und wie dort mit hinein-verwurstet werden muss.
Den Anfang mit deadfee1 haben wir ja schonmal...

Stimmt addee1fe ist immer gleich. Das anschließende b4000000 könnte die Blob-Länge (=180) sein. Dann zweimal 01000000 (=1) irgendwelche Int32-Variablen.
 
Nein fertig ist noch nichts. Ich analysiere nur die unbekannten Teile des Protokolls.
Ich habe hier eine 1511 und die liefert bei ServerSessionRole (=299) den Wert 536870912 (was auch immer das bedeuten mag).

536870912 = 0x20000000, das sieht schon sinnvoller aus. TIA-S7-Plcsim sagt als Antwort an dieser Stelle eine 0, bei der alten 1200 gibt es das Feld überhaupt nicht. Bei beiden Varianten wird anschließend kein Key übertragen. Ich meine das wären die einzig sichtbaren Unterschiede.

Stimmt addee1fe ist immer gleich. Das anschließende b4000000 könnte die Blob-Länge (=180) sein. Dann zweimal 01000000 (=1) irgendwelche Int32-Variablen.
Ich habe ja oben schon aufgeschrieben welche Teile meiner Meinung nach Konstant sind. Ich habs so getestet, dass ich mir eine eigene Fake-S7 programmiert habe, die verschiedene Challenge Werte zurückschickt, oder auch andere Felder modifizieren kann.

Hast du zufällig ein Logfile von der Kommunikation mit einer aktuellen 1200 (FW V4), oder auch einer der aktuellsten 1500?
 
Zurück
Oben