Найди дыру в Си-скрипте

Xakep, номер #032, стр. 032-070-2


Серьезная часть данных, например, адрес возврата, жизненно необходима для дальнейшей работы программы, поэтому замены на что-то другое могут негативно сказаться на ее работе.

Ghost in the shell... Shellcode

Вернемся еще раз к модным словам и словосочетаниям. К одним из следующих "папских" слов после "buffer overflow" следует отнести "shellcode". Для чего же он нужен, этот шеллкод... Чаще всего нам требуется не просто убить программу, содержащую ошибку с переполнением буфера, а необходимо каким-то образом сделать так, чтобы ломаемая программа исполнила нужную команду, например, сделала "exec ('/bin/sh')". Сего можно достичь при помощи того самого шеллкода. Если вернуться в вышеприведенному примеру дырявой программы, то для того чтобы она сделала нужный нам системный вызов, необходимо вместо "111...." передать ей нечто, именуемое шеллкодом. В данном случае шеллкод - это последовательность команд процессора, которые должны выполниться после завершения работы функции bugged(). Здесь есть еще один тонкий момент. Его суть - адрес возврата. Он пишется в стек при запуске какой-либо функции (в нашем случае эта функция - bugged ()) и указывает на следующую инструкцию, которая идет после call func. После того как функция завершает свою работу, она берет из стека адрес возврата и передает управление коду, который находится по адресу возврата. Переполнив буфер, мы можем также переписать данные в стеке с адресом возврата.

Траблы

При практическом написании шеллкода (на мой взгляд, это одна из самых сложных частей во время исследования программы и написания exploit'а под нее) можно столкнуться с рядом проблем. Во-первых, при перезаписи адреса возврата нам надо впихнуть туда адрес шеллкода, который (адрес) мы изначально не знаем. Во-вторых, перепишется адрес возврата или нет - очень часто зависит от того, с какими параметрами и каким компилятором создана наша уязвимая программа. Вдруг, благодаря новой оптимизирующей функции, адрес возврата будет располагаться на 4 байта раньше или позже чем нужно? Тогда прекрасно ранее сработавший шеллкод здесь круто обломается, и прога в лучшем случае просто уйдет в core.

Помимо переписи адреса возврата, можно найти еще кучу применений для технологии переполнения буфера. Например, можно переписать код подгружаемых в память библиотек и т.д. и т.п. Или же если переделать указатели таким образом, чтобы они направляли на нужные нам данные или код. Но это все конкретика, и поэтому можно о ней пока забыть. О классическом переполнении в принципе все... Хотелось бы еще добавить, что дело не ограничивается стандартной библиотечной функцией strcpy(), которая фигурировала в примере. Существует еще куча других библиотечных функций, таких как strcat(), gets() и т.д., не производящих проверку допустимых значений и при помощи которых программа так же просто может быть приколочена.

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