Erkennen von Schwachstellen in verschlüsselten Daten

Dank einem entsprechenden Posting von SANS habe ich mir mal wieder ein paar Gedanken gemacht über die Thematik und den Einsatz von Entropy, also der Zeichendichte von einem String, einem Text oder einer gesamten Applikation.

Obwohl die Einsatzgebiete eigentlich recht umfassend sind, habe ich die Entropy eigentlich bisher nur zur Analyse von modifizierten Files unter Windows eingesetzt, wie in meinem Artikel über densityScout beschrieben. Doch eigentlich sind der Fantasie keine Grenzen gesetzt, da ich dank der Entropy eine einfache Anomaly-Detection auf jedem nur erdenklichen String durchführen kann, sei das nun ein Teil aus einem Text, ein Dateiname oder gar ein abgefragter DNS-Request.

Und so habe ich mir kurzerhand ein kleines Java-Tool genannt „entropyCalc“ geschrieben, womit ich genau die Problematik in dem SANS-Artikel angehen möchte: Ein verschlüsselter Text soll analysiert werden, ob er komplett verschlüsselt wurde, oder ob noch einzelne Textstellen unverschlüsselt erhalten sind:

A tool for dividing the input in X parts and calculating the entorpy of each. This can help analysing a file encrypted by a ransomware regarding its quality.

Call the prepared JAR passing the path of the file (path/to/file) and the number of parts (numb_of_parts) the file should be divided into. Optionally you can pass a max value for the entropy to display:

java -jar entorpyCalc.jar /path/to/file numb_of_parts [max_entorpy_val]

Zu finden gibts das ganze unter meinem GitHub-Account.

Wie die Beschreibung schon sagt, ist das Tool recht einfach gehalten: Ich kann ein File eingeben und die Anzahl an Parts bestimmen. Zusätzlich kann ich auch noch einen optionalen Filter setzen, damit mir nur Werte tiefer meiner gesetzten Marke angezeigt werden.

Wenn man damit nun das Test-File /res/test.bin mit initial 200 Parts analysiert, so interessiert mich vor allem mal die letzten 3 Zeilen mit der Zusammenfassung:

...
[039985 - 040188] 6.902040462088795
[040189 - 040392] 6.870033966927124
[040393 - 040596] 6.877924361409659
[040597 - 040800] 6.883538317427925
[040801 - 040943] 6.663231126927669

[Minimum] 4.425002256404638
[Maximum] 7.1385534526549055
[Average] 7.924522721343111

Da ich hier bereits grosse Abweichungen zwischen Minimum und Maximum sehe, weiss ich, dass da etwas noch in Echtform da sein muss. Also erhöhen wir einfach mal auf 1000 Parts und setzen 4.0 als die Obergrenze an Dichten für die angezeigten Parts:

[004161 - 004200] 2.885290338447572
[004201 - 004240] 0.9975846798245739
[004241 - 004280] 2.957351274437585
[004481 - 004520] 3.4607912955405005

[Minimum] 0.9975846798245739
[Maximum] 5.3219280948873635
[Average] 7.924522721343111

Und sofort ersichtlich wird, dass da garantiert noch etwas unverschlüsseltes drinstecken muss, denn eine Dichte von 0.99 ist sehr stark an einer normalen Sprache angelehnt. Weiter kann ich sehen, dass mein String irgendwo zwischen Zeichen 4161 und 4200 beginnen und zwischen Zeichen 4481 und 4520 enden muss, da hier auch noch eine tiefere Dichte erzielt wurde.

Was ich aktuell noch nicht bieten kann, ist eine Methodik zum Eingrenzen des genauen Strings, aber daran arbeite ich noch und vielleicht kommt mir ja die zündende Idee noch.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.