ACHTUNG: AdressLittle ist NICHT SO SICHER WIE BEWORBEN!
Verfasst: 19.05.2025, 19:00
Originalbeitrag @itsicherheitVorwort vom Team und Purgatory:
Moin,
es geht hier um ein etwas prikäreres Thema das ein wenig Vorlauf und Erklärungsbedarf des Teams (und meinerseits) benötigt um es verständlich zu machen. Es geht um das Programm Adress Little für das wir @Joachim-68VB einen exklusiven Bereich gegeben haben und ihm voller Vertrauen auch erweiterte Forenrechte für diesen Bereich gegeben haben. Vor etwa zwei Wochen wurde in dem Bereich ein Beitrag gepostet den ich, vor allem um Joachim-68VB zu schützen, erst einmal offline genommen habe und in unseren internen Bereich verschoben habe. Der Ersteller war @itsicherheit. Der Grund war, dass einige Aussagen getroffen wurden die ich sehr grenzwertig (wenn auch nicht direkt angreifend) fand und schlussendlich im Team auch so Anklang für meine Entscheidung fand. Ich editierte den Beitrag, und zwar so, dass er fundiert und nicht angreifend war, oder so verstanden werden konnte. Ich war im Dialog mit dem Ersteller des Beitrags als auch dem Programmierer von Adress Little. Gerade letzterem ließ ich meine editierte Version via PM zukommen mit der Bitte um eine Stellungsnahme via PM dazu, gab ihm also genug Zeit das prüfen zu können. Die Antwort war kurz, knapp und kam schnell. Zitat: "Könnt Ihr veröffentlichen." Zitat Ende.
Also tat ich das und brachte den von mir editierten Beitrag online. Es dauerte nicht einmal eine Stunde und Joachim-68VB löschte den Beitrag, ohne jegliche Antwort. Dazu ein Auszug aus unserem Moderationsprotokoll:
Unten ist zu sehen zu welcher Uhrzeit ich den Beitrag verschoben habe und oben wann er gelöscht wurde, auch der Grund wurde angegeben. Nun zum Grund warum ich den Beitrag editiert habe.
Es stand da, dass über diverse Foren, auch in PMs, mit dem Programmierer kommuniziert wurde, dass sein Programm nicht so sicher sei wie von ihm angegeben. Weiterhin wurde geschrieben, dass der Programmierer entweder überhaupt nicht reagiert oder nur mit Beschimpfungen. Da sowas bei uns im Forum überhaupt nichts zu suchen hat habe ich dementsprechende Textzeilen entfernt. Aber der Programmierer spiegelt mit seinem Verhalten ja wieder, dass zumindest irgendwas daran wahr zu sein scheint.
Wir lassen solches Verhalten nicht zu, nicht bei unseren Usern, selbst nicht bei uns. Wenn wir eine Plattform dazu geben ein Programm zu bewerben muss der jeweilige Programmierer auch bereit dazu sein mit Kritik, ob relevant oder nicht, umgehen zu können. Aus diesem Grunde haben wir Joachim-68VB, zumindest erst einmal temporär, die Sonderrechte entzogen und uns entschlossen diesen Beitrag nochmal zu posten. Leider fehlt uns das erste Drittel des Beitrags in dem der Ersteller auf die AES256 Verschlüsselung (mit Codezeilen) eingeht und sie zunächst einmal für korrekt einstuft. Aber dann kommt das Aber...
Er wirbt damit, dass eure Daten alle AES256 verschlüsselt sind.
Ja, stimmt. Sie wurden mit dem Algorithmus umgewandelt; schaut man sich die Datei im Detail an, sieht das auf den ersten Blick auch gut aus:
Code: Alles auswählen
41 44 52 4C 36 34 30 30 53 2D 4A 53 20 12 B5 24 ADRL6400S-JS µ$
Schauen wir mal, was das genau ist:
Code: Alles auswählen
public static readonly string CryptDefault = "ADRL6400S-JS ";
Es wird jetzt brisant und man muss kein Softwareentwickler sein, um das zu verstehen.
Ich erkläre es zuerst für jedermann:
Der Key ist quasi der Schlüssel zu euren Daten und der Init Vector ist eine Startinformation, ab der der Algo weitergehen kann.
Wenn die Verschlüsselung das Ziel ist, ist der Init Vector die Startadresse, ähnlich wie das bei Maps wäre, wenn ihr wohin navigiert.
Nun ist es aber so, nun ist es aber so, (Edit Purgatory:) dass man sich gedacht hat, man (Edit Purgatory Ende) könne die Generierung dieser Daten, die PRO VERSCHLÜSSELUNG EINMALIG ZU SEIN HABEN(!), umgehen kann, indem er diese aus dem Passwort der Benutzer generiert. Geniale Idee, könnte man meinen...
Code: Alles auswählen
public static string Text_AES_Codieren(string TextInput, string TextPassword) {
string str = "";
if (TextPassword.Length > 0 & TextInput.Length > 0) {
using (AesManaged aesManaged = new AesManaged()) {
byte[] salt = new byte[8] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8 };
using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(TextPassword, salt)) {
aesManaged.Key = rfc2898DeriveBytes.GetBytes(aesManaged.Key.Length);
aesManaged.IV = rfc2898DeriveBytes.GetBytes(aesManaged.IV.Length);
}
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, aesManaged.CreateEncryptor(), CryptoStreamMode.Write);
byte[] bytes = Encoding.UTF8.GetBytes(TextInput);
cryptoStream.Write(bytes, 0, bytes.Length);
cryptoStream.Close();
str = Convert.ToBase64String(memoryStream.ToArray());
}
}
return str;
}
Das bedeutet ganz konkret, dass jeder Angreifer mit Mustererkennung und Rainbow-Tables kinderleicht an die gespeicherten Daten kommt.
Noch dazu ist der verwendete Algorithmus mit modernen Grafikkarten relativ schnell in seiner Standardkonfiguration, die hier angewandt wird, knackbar. Minuten sollten hier haushoch ausreichen.
Eine bessere Implementierung wäre z.B.:
Code: Alles auswählen
new Rfc2898DeriveBytes(password, salt, 200_000, HashAlgorithmName.SHA256);
Weiterhin ist der verwendete Generator (AesManaged) obsolet und sollte auf gar keinen Fall mehr verwendet werden! Hier wäre
Code: Alles auswählen
Aes.Create()
Selbiges geht übrigens auch für die Entschlüsselung dieser Daten:
Code: Alles auswählen
public static string Text_AES_Decodieren(string TextInput, string TextPassword) {
string str = "";
if (TextPassword.Length > 0 & TextInput.Length > 0) {
using (AesManaged aesManaged = new AesManaged()) {
byte[] salt = new byte[8]
{
(byte) 1,
(byte) 2,
(byte) 3,
(byte) 4,
(byte) 5,
(byte) 6,
(byte) 7,
(byte) 8
};
using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(TextPassword, salt)) {
aesManaged.Key = rfc2898DeriveBytes.GetBytes(aesManaged.Key.Length);
aesManaged.IV = rfc2898DeriveBytes.GetBytes(aesManaged.IV.Length);
}
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, aesManaged.CreateDecryptor(), CryptoStreamMode.Write);
try {
byte[] buffer = Convert.FromBase64String(TextInput);
cryptoStream.Write(buffer, 0, buffer.Length);
cryptoStream.Close();
str = Encoding.UTF8.GetString(memoryStream.ToArray());
} catch (Exception ex) {
ProjectData.SetProjectError(ex);
str = "";
ProjectData.ClearProjectError();
}
}
}
return str;
}
Als Letztes möchte ich hier noch den Hinweis geben, dass das Programm neben dem unsicheren Code auch noch verwendete Sicherheitsschlüssel und Passwörter enthält:
Code: Alles auswählen
public static readonly string KeyCtr1 = "<1j<Wm§2T]B&|S59XJ3qa62uu?CWdHo-]";
public static readonly string KeyCtr2 = "M<v/E/q9&+wmh-B\\JP!(6prAdF/d)3Qz";
public static readonly string KeyCtr3 = "KQ\\j-)J$RH7€Y7Sy06%2/-7r4q+q&XY[";
public static readonly string KeyCtr4 = "§tDGez~%iFfg~q%-/Qzy|HG€4if4o§[";
public static readonly string KeyCtr5 = "gM1YEu%\\/3$a%j)J[rZoPL*d?VJ4CcPY";
public static readonly string KeyCtr6 = "y5]kszi%-mx[$*g1üugx1~oWd~=b]M4=D1";
public static readonly string KeyCtrDark1 = "dgBbDQAF?/KmoEr5h4-wTZs#%Ce*P)(3";
public static readonly string KeyCtrDark2 = "$Z21Ksnp8g)yHa0(Wf5w!ECbRxtrF?o6";
public static readonly string KeyCtrDark3 = "Dya1G9tgnV0+L4$(BXR%p6q2ONd7/PE=";
public static readonly string KeyCtrDark4 = "XPqsYvd3A\\rZ5%OkoiuDHnM0Gf*/NaS&";
public static readonly string KeyCtrDark5 = ")*CjxEMrGiS-pd=c%$0LshFa7#K+nA23";
public static readonly string DataCryptReg = "Gp6pdwRyNmGiZqPIkT7jJtIxTlSp9I2MqBimeQLWGfkNpEW69wkXPT58dFTIxB";
public static readonly string Adrl6400Pass = "ADRL6400";
public static readonly string DefaultAESPass = "Hg#pUr85/%)$Achim";
Beispiel:
Code: Alles auswählen
Grund.Text_AES_Codieren(Grund.KeyCtr1 + Grund.KeyCtrDark1, Grund.KeyCtrDark1);
Anders sieht es bei der Win32-Interop aus, die er gebaut hat:
Code: Alles auswählen
public static readonly string Key10 = "uzt64vugi~6r654";
public static readonly string Key20 = "jhvgiu6r76u+guzgu";
public static readonly string Key30 = "hg567/&($/&&§%";
public static readonly string Key40 = "hguzv#56787ubhjAAAj";
public static readonly string Key50 = "QwPaS!*s/bk)ygx?";
public static readonly string Key60 = "vEn*Nr7gJLRGX4z-";
public static readonly string Key70 = "5N4\\zXUeOTfZF&WM";
public static readonly string Key80 = "nuMJ1#p(s4P3Y&8z\\Sx-GdZh+Rb6XAfK";
public static string KeyAll0 = ")p(bMX%hM1~T+J5!§xksgo\\&ywtDL>e5~Z87vdz-ELR$+a§8m-0aU=su7K_z_#XT";
Originalbeitrag @itsicherheit Ende
Schlussworte vom Team und Purgatory:
Wir möchten, dass alle Beteiligten die meinen hier eine Meinung abgeben zu wollen oder vielmehr zu können, fundiert und pragmatisch antworten. Anfeindungen, von welcher Seite auch immer, werden von uns konsequent, und ohne Vorwarnung, editiert oder auch gelöscht.