Am Ende habe ich meinen Shellcode anders geschrieben. Da ich nicht herausfinden konnte, wie ich zurückkehren sollte, ließ ich den Kernel die schwere Arbeit für mich erledigen, um ins Userland zurückzukehren. Die Idee war, mein Privilegien-Eskalationsbit auszuführen und dorthin zurückzuspringen, wo die verwundbare Funktion zurückkehren sollte, wobei die Register und der Stack repariert wurden.
Sobald der Kernel von der verwundbaren Funktion zurückkehrte (wenn er nicht übergelaufen war), bemerkte ich etwas über gdb
. (Die Adressen sind frei erfunden, erklären aber trotzdem das Konzept.)
(gdb) x/i $eip
0xadd1: ret
(gdb) x/xw $esp
0xadd1: 0xadd2
(gdb) x/6i 0xadd2
0xadd2: add esp,0x40
0xadd3: pop ...
0xadd4: pop ...
0xadd5: pop ...
0xadd6: pop ...
0xadd7: ret
Unmittelbar nach der Rückkehr sind also 0x40 Byte Stack ungenutzt und würde einfach mit der add esp
verschwinden Anweisung. Daher habe ich diese Tatsache ausgenutzt und eine ROP-Kette konstruiert (ich hatte sie bereits beim Schreiben dieser Frage konstruiert, ihre Aufgabe war es, SMEP zu deaktivieren und zu meinem Userland-Shellcode zu springen), die 24 Bytes lang war. 4 Bytes würden den EIP zum Zeitpunkt der Rückgabe überschreiben, die restlichen 20 (0x14
) würde direkt in den unbenutzten Stapel folgen. Dies lässt uns mit 0x2c
zurück Bytes unbenutzter Stack noch.
Aber wenn wir zu 0xadd2
zurückkehren würden , würden wir riskieren, ein weiteres 0x14
zu verlieren Bytes wertvoller Registerinformationen aus dem Stack und das Auffüllen der Register mit ungültigen Daten. Wir könnten add 0x2c
bis esp
in unserem Userland Shellcode, und springe direkt zu 0xadd3
, wobei das eigentliche add
übersprungen wird Anleitung.
Beachten Sie auch aus der Debugging-Sitzung alles außer eax
und ebx
wurden fachgerecht restauriert. Da mein Überlauf beide zerstört hatte, musste ich sie mit Werten wiederherstellen, die den Fällen ähnelten, in denen die Funktion eine saubere Rückgabe machte. (Dies zu tun war einfach:Ich habe einen Haltepunkt bei 0xadd2
gesetzt , und extrahierte die Werte aus info reg
)
Mein endgültiger Userland-Shellcode war also dieser:
Execute privesc payload -> add esp,0x2c -> register fixup -> jump to 0xadd3
Dabei kam der Codepfad vollkommen sauber zurück, und der Kernel erledigte die Aufgabe, für mich in den Benutzermodus zurückzukehren.