Jump to content
zbeng

Securitate Linux prin /dev/kmem

Recommended Posts

Posted

1. Conceptul de regiuni de memorie non executabile

2. Metode de oprire a executiei codului injectat

3. Implementare proprie.

3.1 Apeluri de sistem si interceptarea lor.

3.2 Utilizarea interceptarii in scopuri non executabile.

3.3 Intrarea in kernel mode fara suport lkm.

3.4 Etapele aplicarii patch-ului.

1.

Exploiturile se bazeaza in general pe urmatorul concept: directionarea executiei programului la un set de instructiuni (shellcode) furnizate de atacator.

Prin faptul ca shellcode-ul este primit sub forma de date de intrare, este plasat intr-una din urmatoarele portiuni de memorie: stack, heap, .data sau .bss.

Impiedicare executiei unui shellcode se poate face deci prin marcarea logica a portiunilor de memorie mentionate mai sus ca non executabile .

O implementare a conceptului a fost realizata de Solar Designer impotriva executiei codului din stack prin proiectul Openwall (openwall.com/linux).

Un proiect mai nou de acelasi gen este PaX (http://pageexec.virtualave.net). PaX impiedica executia din toate zonele de memorie writable, aplica metode de

generare aleatorie a regiunilor de memorie alocate pentru protectie impotriva tehnicilor return-into-libc, ... .

2.

Discutarea crearii unui soft pentru marcarea regiunilor de memorie ca non executabile are sens pe sistemele fara suport hardware pentru acest lucru.

Principala si singura exceptie pana acum sunt arhitecturile IA-32. PaX implementeaza memoria non executabila prin urmatorul mod: de fiecare data cand accesam o

pagina de memorie in linux, daca este setat bitul supervisor in PTE ( page table entry ), actiunea normala in cazul accesului unui program din ring 3 (user space) este

trimiterea semnalului SIGSEGV programului. PaX seteaza supervisor in toate zonele writable de memorie si modifica functia care se ocupa de protectia paginilor cu

bitul supervisor cu o functie proprie.In cazul cererii de executie a memoriei functia testeaza daca executia din zona respectiva de memorie este permisa. In caz

negativ programul este terminat si are loc scrierea in loguri a incidentului.

3.

3.1

In linux toate functiile puse la dispozitia utilizatorului se executa prin intermediul apelurilor de sistem (system calls). Un apel de sistem este executat

prin apelarea intreruperii 0x80 cu numarul apelului in registrul eax si cu parametrii in ebx,ecx,edx. Intreruperea 0x80 trece in kernel mode si apeleaza functia

system_call, care preia adresa functiei corespunzatoare apelului de sistem cerut dintr-un tabel de adrese de memorie ( sys_call_table ). RootKit-urile clasice

de kernel isi fac treaba prin modificarea adreselor din tabela respectiva.

O alta idee de a intercepta apelurile de sistem a fost inovata de sd si devik prin SucKIT (http://www.phrack.org/phrack/58/p58-0x07). Ideea este

de a modifica adresa sys_call_table in system_call.

Alterarea executiei apelurilor de sistem se poate face si prin schimbarea functiei corespunzatoare int 0x80 in IDT ( interrupt descriptor table ).

(http://www.phrack.org/phrack/59/p59-0x04.txt)

Ideea prezentata de acest articol este de a redirectiona toate apelurile de sistem prin inserarea la inceputul functiei system_call a unui ansamblu push - ret, determinand

astfel fiecare apel de sistem sa treaca intai prin codul nostru.

3.2.

La apelul functiei system_call eip-ul ( instruction pointer) de provenienta se gaseste pe stack. Impiedicarea executiei codului din portiuni de memorie

nepermise ( stack, heap, .data, .bss) se poate face prin verificarea apartenentei eip-ului extras unei reuniuni de intervale de memorie : stack ( in linux

0xbf000000-0xbfffffff), heap ( current->mm->start_brk pana la current->mm->brk ) , .data ( current->mm->start_data pana la current->mm->end_data) si .bss.

0x0807814c->0x080790e4 at 0x0002f14c: .data ALLOC LOAD DATA HAS_CONTENTS

0x08079110->0x08079f78 at 0x00030110: .bss ALLOC

0x08079f78 : current->mm->start_brk

0xxxxxxxx : current->mm->brk

Avem mai sus un exemplu de asezare a zonelor de memorie writable a unui elf. Din asezare se vede ca multimea zonelor protejate

este cuprinsa in stack ( 0xbf000000-0xbfffffff) si current->mm->start_data --- current->mm->brk.

Functia noastra trebuie sa testeze daca eipul salvat pe stack apartine zonei descrise ; daca da apeleaza int 0x80 cu eax 0x1 ( exit ), daca

nu executa primi 6 bytes inlocuiti din system_call si apoi sare la system_call+6.

3.3

Sarcinile de mai sus pot fi indeplinite de un loadable kernel module. Calea pe care am ales-o este de a scrie in /dev/kmem - fisierul prin care se poate

citi sau scrie in memoria kernelului. Tehnica a fost aplicata pentru

prima data de Silvio Cesare ( http://www.big.net.au/~silvio/runtime-kern...em-patching.txt ).

Locul in care va fi plasata functia de filtrare este spatiul alocat in memoria kernel pentru sys_olduname.

Obtinerea variabilei current se obtine prin macroul definit in entry.S din sursa kernelului

#define GET_CURRENT(reg)

movl $-8192, reg;

andl %esp, reg

Mai ramane o problema: determinarea structurii task_struct si mm_struct (este diferita pentru aproximativ fiecare

versiune de kernel) pentru a determina current->mm->start_data si current->mm->brk.

In sys_getuid avem urmatoarea portiune de cod:

mov $0xffffe000,%eax

and %esp,%eax

mov 0x58(%eax),%eax

andb $0xfe,0x74(%eax)

primele doua instructiuni extrag current iar ultimele adreseaza current->mm->dumpable care se afla de obicei

la o distanta de 15*4 bytes dupa start_data. Din codul de mai sus extragem distanta mm in task_struct (0x5b) si

distanta dumpable in mm_struct (0x74) si le introducem in codul propriu.

3.4 Etape:

1. determinarea adresei IDT ( interrupt descriptor table ) prin instructiunea sidt

2. aflarea din IDT a adresei functiei system_call

3. prepararea functiei prin extragerea din sys_setgid a distantei mm in task_struct si dumpable in mm_struct

4. adaugarea primilor 6 bytes din system_call la sfarsitul functiei de filtrare

5. adaugarea unui push $(system_call+6) - ret la sfarsitul functiei noastre

6. introducerea functiei in sys_olduname.

7. inserarea unui push $sys_olduname - ret in system_call.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...