|

Shellcode своими руками
Xakep, номер #044, стр. 044-038-1
Buggzy (alienhard@mail.ru)
В этом тексте ты найдешь ответы на многие интересующие вопросы о переполнении буфера: что такое переполнение стека, как находить уязвимые программы, как писать эксплоиты, можно ли написать универсальный эксплоит, существует ли универсальная защита от переполнения стека и многое другое. В конце я дам некоторые приемы, интересные опытному юзеру.
Что это и как работает?
Допустим, в какой-то процедуре используется буфер для хранения данных и буфер находится в стеке. Под буфер выделен определенный объем памяти. Кроме того, есть еще несколько переменных, тоже хранящихся в стеке. Посмотрим, как все это выглядит.
....
<переменная 3 - 4 байта>
<переменная 2 - 4 байта>
<буфер - 1024 байта>
<переменная 1 - 4 байта>
<адрес возврата - 4 байта>
....
Мы наблюдаем в стеке три переменные и "адрес возврата" - 4-байтовое число, описывающее, куда передать управление после того, как текущая процедура доработает до конца. Теперь предположим, что программа хочет записать данные в N-ый байт буфера. Как она это сделает? К адресу начала буфера будет прибавлено N, и данные будут записаны по полученному адресу. Все правильно, но что будет, если N=1025?
Обычно компилятор не проверяет, чтобы N принимало допустимое значение, и оставляет это на совести человека. А что, если человек не подумал об этом? Тогда данные, которые должны были попасть в буфер, попадут в другую область памяти, что и называется переполнением буфера, а для случая, когда буфер лежит в стеке, - переполнением стека.
В нашем случае, при N=1025, они изменят значение <переменная 1>. При N=1029 изменится и значение адреса возврата, и после окончания работы процедуры управление будет передано не по тому адресу, по которому задумывал создатель, а по адресу, взятому из данных, переполнивших буфер. Если атакующий сознательно переполнил буфер, то он может подставить такой адрес, что будет выполнен любой код, какой он захочет.
Зачем нужно эксплуатировать переполнения?
Код, выполняемый при переполнении, признается системой кодом той программы, в которой была уязвимость. Т.е. он выполняется на той машине, где находится уязвимая программа, и с правами, которые имеет эта программа. Таким образом, атакующий может повысить свои права доступа или получить управление над удаленной машиной.
Как искать переполнения?
Самое примитивное переполнение буфера - работа со строками в текстовых протоколах (HTTP, SMTP, POP, FTP). Вот классический пример ошибки, найденной незадолго до написания статьи в одном из FTP-серверов "made in China" под управлением Windows. При подключении к серверу передается строка: "pass AAAAAAA...." - больше 1024 символов. Если в сервере нет переполнения, он должен сообщить об ошибке и работать нормально, а если есть - то он оборвет соединение и нередко вообще перестанет работать (ситуация, когда сервер перестает работать после определенным образом сконструированного запроса, называется DoS-атакой, но это не очень интересно).
Другой способ поиска переполнений - анализ исходного кода или дизассемблирование программы - требует наличия исходника, бинарника, умения программировать и дизассемблировать, и поэтому многим не понравится. Однако многие уязвимости можно найти только таким способом.
Содержание Вперед на стр. 044-038-2
|