Литмир - Электронная Библиотека

· int noguest=1;

· char pass[16];

· int a=1;

· for (;a«argc;a++)

· {

· if (argv[a][0]-'/')

· {

· if (!strcmp( amp;argv[a][0],"/GUEST:ON")) noguest=0;

·}

· else

· {

· if (strlen(argv[a])»16)

· printf("Too long arg: %s\n",argv[a]);

· else

· strcpy( amp;pass[0],argv[a]);

·}

·}

· if ((!strcmp("KPNC++\n", amp;pass[0])) || (!noguest))

· printf("Password ok\n");

· else

· printf("Wrong password\n");

·

·

·}

Дизассемблирование позволяет установить, что переменная “noguest” расположена в «хвосте» буфера buff и может быть искажена при его переполнении. Поскольку, при проверке длины строки допущена ошибка «if (strlen(argv[a])»16)…», завершающий ноль шестнадцатисимвольной строки обнулит значение переменной “noguest” и откроет злоумышленнику путь в систему. Это демонстрирует следующий эксперимент:

· buff.var.exe 1234567890123456

· Password ok

Но если увеличить длину строки хотя бы на один байт, программа отбросит ее как неправильную:

· buff.var.exe 12345678901234567

· Too long arg: 12345678901234567

· Wrong password

Конечно, вероятность возникновения подобной ситуации на практике очень мала. Для атаки необходимо неблагоприятное стечение многих маловероятных обстоятельств. Размер буфера должен быть кратен величие выравнивания, иначе переполняющий байт запишется в «черную дыру» [321] и ничего не произойдет. Следующая за буфером переменная должна быть критична к обнулению, т.е. если программист открывал бы доступ на машину при ненулевом значении флага guest, опять бы ничего не произошло. Поэтому, в большинстве случаев несанкционированного доступа к машине получить не удастся, а вот «завесить» ее гораздо вероятнее.

Например, следующий код (на, диске, прилагаемом к книге, он находится в файле “/SRC/buff.var.2.c”), в отличие от предыдущего, трудно назвать искусственным и «притянутым за уши»:

· #include «stdio.h»

· #include «string.h»

·

· main (int argc,char **argv)

· {

·

· char pass[16];

· int a=1;

· for (;a«argc;a++)

· {

· if (argv[a][0]-'/')

· {

· if (!strcmp( amp;argv[a][0],"/GUEST:ON"))

· {

· printf("Guest user ok\n");

· break;

·}

·}

· else

· {

· if (strlen(argv[a])»16)

· printf("Too long arg: %s\n",argv[a]);

· else

· strcpy( amp;pass[0],argv[a]);

·}

·}

· if ((!strcmp("KPNC++\n", amp;pass[0])))

· printf("Password ok\n");

· else

· printf("Wrong password\n");

·

·}

Переполнение буфера вызовет запись нуля в счетчик цикла ‘a’, в результате чего цикл никогда не достигнет своего конца, а программа «зависнет». А если буфер окажется расположенным в вершине стека, то «вылетевший» за его пределы ноль исказит значение регистра EBP. Большинство компиляторов генерируют код, использующий для адресации локальных переменных регистр EBP, поэтому искажение его значения приведет к нарушению работы вызывающей процедуры.

Такую ситуацию демонстрирует следующий пример (на диске, прилагаемом к книге, он расположен в файле “/SRC/buff.ebp.c”):

· #include «stdio.h»

· #include «string.h»

·

· int Auth()

· {

· char pass[16];

· printf("Passwd:");fgets( amp;pass[0],17,stdin);

· return!strcmp("KPNC++\n", amp;pass[0]);

·}

·

· main (int argc,char **argv)

· {

·

· int guest=0;

· if (argc»2) if (!strcmp( amp;argv[1][0],"/GUEST:ON")) guest=1;

·

· if (Auth() || guest) printf("Password ok\n");

· else

· printf("Wrong password\n");

·

·}

Ввод строки наподобие “1234567890123456123” затрет сохраненное значение регистра EBP, в результате чего при попытке прочитать значение переменной guest произойдет обращение к совсем другой области памяти, которая, скорее всего, содержит ненулевое значение. В результате злоумышленник сможет несанкционированно войти в систему.

Модификация сохраненного значения регистра EBP имеет побочный эффект - вместе с регистром EBP изменяется и регистр-указатель верхушки стека. Большинство компиляторов генерируют приблизительно следующие прологи и эпилоги функций (в листинге они выделены жирным шрифтом):

·.text:00401040 Main proc near; CODE XREF: start+AFp

·.text:00401040

·.text:00401040 var_4 = dword ptr -4

·.text:00401040

·.text:00401040 push ebp

·.text:00401041 mov ebp, esp

·.text:00401043 push ecx

·.text:00401044 push offset aChahgeEbp; "Chahge EBP\n"

·.text:00401049 call sub_0_401214

·.text:0040104E add esp, 4

·.text:00401051 call Auth

·.text:00401056 mov [ebp+var_4], eax

·.text:00401059 cmp [ebp+var_4], 0

·.text:0040105D jz short loc_0_40106E

·.text:0040105F push offset aPasswordOk; "Password ok\n"

·.text:00401064 call sub_0_401214

119
{"b":"837821","o":1}