Решил попрактиковаться в переполнении буфера. Накатал быстренько уязвимую программу. При передаче такого аргумента `perl -e 'print "A"x100'` в отладчике gdb выдаёт: Вывод команды i r: Тогда как, на сколько я понимаю, регистр eip должен быть перезаписан на 0x41414141. А у меня вместо 0x41414141 в eip 0x8048407. И может ли это быть защита со стороны ОС или компилятора? Никакие патчи не ставил. В чём проблема? Уязвимая программа: Код (Text): #include <stdio.h> #include <string.h> int main (int argc, char *argv[]) { char buf[10]; if (argc > 1) strcpy(buf, argv[1]); return 0; } Дистрибутив Mandriva 2009.1 Компилятор gcc 4.3.2
Надо посмотреть во что ваш main компилируется и тогда станет ясно почему это не пашет. Судя по всему, а конкретно по esp=0x4141413d eip=0x8048407<main+99> у вас произошёл обвал потому что указатель стека восстановился из затёртого же стека и юзался до возврата из функции.
Код (Text): (gdb) disas main Dump of assembler code for function main: 0x08048374 <main+0>: lea 0x4(%esp),%ecx 0x08048378 <main+4>: and $0xfffffff0,%esp 0x0804837b <main+7>: pushl -0x4(%ecx) 0x0804837e <main+10>: push %ebp 0x0804837f <main+11>: mov %esp,%ebp 0x08048381 <main+13>: push %ecx 0x08048382 <main+14>: sub $0x24,%esp 0x08048385 <main+17>: mov %ecx,-0x18(%ebp) 0x08048388 <main+20>: mov -0x18(%ebp),%eax 0x0804838b <main+23>: cmpl $0x1,(%eax) 0x0804838e <main+26>: jle 0x80483aa <main+54> 0x08048390 <main+28>: mov -0x18(%ebp),%edx 0x08048393 <main+31>: mov 0x4(%edx),%eax 0x08048396 <main+34>: add $0x4,%eax 0x08048399 <main+37>: mov (%eax),%eax 0x0804839b <main+39>: mov %eax,0x4(%esp) 0x0804839f <main+43>: lea -0xe(%ebp),%eax 0x080483a2 <main+46>: mov %eax,(%esp) 0x080483a5 <main+49>: call 0x80482b0 <strcpy@plt> 0x080483aa <main+54>: mov $0x0,%eax 0x080483af <main+59>: add $0x24,%esp 0x080483b2 <main+62>: pop %ecx 0x080483b3 <main+63>: pop %ebp 0x080483b4 <main+64>: lea -0x4(%ecx),%esp 0x080483b7 <main+67>: ret End of assembler dump.
ну вы хотя бы посмотрите, что у вас в стеке Код (Text): main.return l -0x4(%ecx) %ebp %ecx 0x20 some bytes %eax strcpy.return ...
чтобы перезаписать адрес возврата, надо проанализировать стек атакуемой функции. если вы хотите тренироваться переполнять буфер программы, то для начала прочитайте как это делается (правильно), а потом уже приступайте к реализации на практике, а не тупо лепите что попало.
Делаю в точности как в статье по переполнению буфера. В статье происходит одно - у меня совсем другое. Вот и пытаюсь выяснить в чём проблема...
ну а проанализировать стек, убедиться, что все попадает туда куда надо, посмотреть, что там по тому адресу, куда вы отправляете выполнение. в статье разве этого не написано?
Проблема хотя бы в том что разные компилы компилят разный код и как следствие переполнять разные результаты нужно по разному. Вот и всё. Как именно переполнение устраивать смотрится из кода на асме а не на сишнике.
Ох, обожаем этот синтаксис. Агррхъ. ) Код (Text): lea ecx, [esp+4] ; pArg1 and esp, -$10 push [ecx-4] ; ret addr push ebp mov ebp, esp push ecx ; pArg1 sub esp, $24 ... add esp, $24 pop ecx pop ebp lea esp, [ecx-4] ret InFlame В общем, это можно рассматривать как некий сорт защиты от переполнения, реализуемой компилятором. Не знаем, как называется – вообще говоря, первый раз видим такое. Вероятно, существуют какие-нибудь ключи для gcc, контролирующие создание подобного кода. Вот vc9 под винду для защиты от переполнения может класть в стек кукис (GSCookie == (ebp + delta) xor [__security_cookie], delta обычно нуль), а перед выполнением возврата вызывать микрофункцию, которая проверяет, не изменился ли этот самый кукис – и бьёт тревогу, ежели что. InFlame Так. В явном виде никто не сказал ещё? Вероятно, на этом этапе уже стало ясно, но ежели что: исключение происходит при выполнении инструкции ret – процессор пытается прочитать адрес возврата из невалидной области памяти по адресу 4141413d (== 41414141 - 4). Если стек рандомизируется (различен при каждом запуске программы), то вероятность овладевания чрезвычайно низка.
Делал по этой статье http://www.securitylab.ru/contest/212095.php, да и не только по этой (тут, на wasm'е ещё читал) - результат один. А кто-нибудь пытался проделывать нечто похожее, используя компилятор gcc версий >4.3? Может быть действительно проблема в компиляторе?
В данном случае если положения стека известно заранее (стек всегда в одном и том же месте) и смещение в нём постоянно и нужные значения можно передать через заполняющую буфер функцию, то это можно обойти. Просто в буфер передаётся сначала 10 байт мусора или кода, потом 4 байта для ecx из которых получится esp, потом какой нить мусор или полезное значение для ebp ну и адрес возврата на нужный код по 4 байта соответственно. Собственно в значении для ecx и проблема, но если стек известен всё прокатит.