Используйте переполнение кучи для записи произвольных данных
Я пытался изучить основы атаки переполнения кучи. Я в основном заинтересован в использовании повреждения или модификации метаданных чанка для основы атаки, но я также открыт для других предложений. Я знаю, что моя цель эксплойта - переписать printf()
указатель функции с этим из challenge()
указатель на функцию, но я не могу понять, как этого добиться. У меня есть следующий кусок кода, который я хочу использовать, который использует malloc
от glibc 2.11.2
:
void challenge()
{
puts("you win\n");
}
int main(int argc, char **argv)
{
char *inputA, *inputB, *inputC;
inputA = malloc(32);
inputB = malloc(32);
inputC = malloc(32);
strcpy(inputA, argv[1]);
strcpy(inputB, argv[2]);
strcpy(inputC, argv[3]);
free(inputC);
free(inputB);
free(inputA);
printf("execute challenge to win\n");
}
Очевидно, что добиться фактической перезаписи метаданных выделенного фрагмента тривиально. Однако я не смог найти способ использовать этот код, используя какие-либо стандартные методы. Я прочитал и попытался реализовать методы из:
- Бумага: w00w00 о переполнении кучи
- Хотя документ очень ясно,
unlink
Техника устарела в течение некоторого времени.
- Хотя документ очень ясно,
- Malloc Maleficarum.txt
- В этом документе рассматриваются методы эксплойтов, имевшие место в дни w00w00, и рассматриваются новые версии glibc. Тем не менее, я не обнаружил, что, учитывая 5 методов, подробно описанных в статье, приведенный выше код соответствует любому из предварительных условий для этих методов.
- Понимание кучи путем ее разрушения (pdf)
- PDF дает довольно хороший обзор того, как работает куча, но фокусируется на двойных бесплатных методах.
Первоначально я пытался использовать этот код, манипулируя значением размера чанка для inputC, чтобы он указывал на начало чанка inputC. Когда это не сработало, я попытался еще раз указать на блок ввода B. Именно тогда я понял, что новый glibc выполняет проверку работоспособности значения размера.
Как пользователь может создать эксплойт, чтобы воспользоваться преимуществами бесплатного, предполагая, что он имеет возможность редактировать метаданные выделенного фрагмента в произвольные значения и использовать его для перезаписи значения в GOT или записи в любой другой произвольный адрес?
Примечание. Когда я пишу "произвольный адрес", я понимаю, что страницы памяти могут быть только для чтения или защищены, я имею в виду адрес, на который я могу предположить, что могу писать.
3 ответа
Примечание. Прежде чем ответить, я скажу, что это чисто академический ответ, не предназначенный для использования в злонамеренных целях. Мне известно об упражнениях, которые выполняет OP, и они имеют открытый исходный код и не предназначены для того, чтобы поощрять пользователей использовать эти методы в неутвержденных обстоятельствах.
Ниже я подробно опишу технику, но для справки я бы взглянул на хитрости Vudo malloc (на них есть ссылка в одной из ваших ссылок выше), потому что мой обзор будет кратким: http://www.phrack.com/issues.html?issue=57&id=8
В нем подробно рассказывается, как malloc обрабатывает создание блоков памяти, извлечение памяти из списков и другие вещи. В частности, атака unlink представляет интерес для этой атаки (обратите внимание: вы правы, что glibc теперь выполняет проверку исправности размеров по этой конкретной причине, но вы должны использовать более старую версию libc для этого упражнения... legacy bro).
Из статьи выделенный блок и свободный блок используют одну и ту же структуру данных, но данные обрабатываются по-разному. Посмотреть здесь:
chunk -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| prev_size: size of the previous chunk, in bytes (used |
| by dlmalloc only if this previous chunk is free) |
+---------------------------------------------------------+
| size: size of the chunk (the number of bytes between |
| "chunk" and "nextchunk") and 2 bits status information |
mem -> +---------------------------------------------------------+
| fd: not used by dlmalloc because "chunk" is allocated |
| (user data therefore starts here) |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| bk: not used by dlmalloc because "chunk" is allocated |
| (there may be user data here) |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| |
| |
| user data (may be 0 bytes long) |
| |
| |
next -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| prev_size: not used by dlmalloc because "chunk" is |
| allocated (may hold user data, to decrease wastage) |
+---------------------------------------------------------+
Выделенные блоки не используют указатели fd или bk, но свободные будут. Это будет важно позже. Вы должны знать достаточно программирования, чтобы понять, что "блоки" в malloc Дуга Ли организованы в двусвязный список; есть один список для свободных блоков и другой для распределенных (технически есть несколько списков для свободных в зависимости от размеров, но это не имеет значения, поскольку код выделяет блоки одинакового размера). Поэтому, когда вы освобождаете определенный блок, вы должны исправить указатели, чтобы сохранить список в такте.
например, скажем, вы освобождаете блок y из списка ниже:
x <-> y <-> z
Обратите внимание, что на приведенной выше диаграмме места для bk и fd содержат необходимые указатели для итерации по списку. Когда malloc хочет удалить блок p из списка, он вызывает, среди прочего, макрос для исправления списка:
#define unlink( y, BK, FD ) {
BK = P->bk;
FD = P->fd;
FD->bk = BK;
BK->fd = FD;
}
Сам макрос не сложен для понимания, но важно отметить, что в старых версиях libc он не выполняет проверку работоспособности размера или указателей, в которые записывается. В вашем случае это означает, что без какой-либо рандомизации адресов вы можете предсказуемо и надежно определить состояние кучи и перенаправить произвольный указатель на адрес по вашему выбору, переполнив кучу (через strncopy здесь) определенным образом.,
Есть несколько вещей, необходимых для запуска атаки:
- указатель fd для вашего блока указывает на адрес, который вы хотите перезаписать, минус 12 байтов. Смещение связано с тем, что malloc очищает выравнивание при изменении списка.
- Указатель bk вашего блока указывает на ваш шелл-код
- Размер должен быть -4. Это выполняет несколько вещей, а именно устанавливает биты состояния в блоке.
Таким образом, вам придется поэкспериментировать со смещениями в вашем конкретном примере, но общий вредоносный формат, который вы пытаетесь передать с помощью strcpy, имеет формат:
| мусор, чтобы заполнить законный буфер | -4 | -4 | адрес, который вы хотите перезаписать -12 (0x0C) | Адр вы хотите позвонить вместо
Обратите внимание, что отрицательное число устанавливает в поле prev_size значение -4, что заставляет свободную маршрутизацию полагать, что блок prev_size фактически начинается в текущем фрагменте, который вы контролируете / портите.
И да, правильное объяснение не будет полным без упоминания о том, что эта атака не работает на текущих версиях glibc; У размера есть проверка работоспособности, и метод unlink просто не будет работать. Это в сочетании с такими мерами, как рандомизация адресов, делает эту атаку нежизнеспособной, кроме устаревших систем. Но описанный здесь метод - это то, как я справился с этой задачей;)
Обратите внимание, что большинство методов, описанных в Malloc Malleficarum, теперь защищены. Glibc значительно улучшил все эти двойные бесплатные сценарии.
Если вы хотите улучшить свои знания о методах Malloc Malleficarum, прочитайте Malloc Des-Malleficarum и House of Lore: Reloaded, написанные blackngel. Вы можете найти эти тексты в phrack.
Я также работаю над этим, и я могу сказать вам, что, например, Дом Разума больше не эксплуатируется, по крайней мере, как объясняется в текстах. Хотя может быть возможно обойти новые ограничения, добавленные в код. Добавьте, что самый простой способ выполнить ваш код - переписать адрес.dtors, поэтому ваш код всегда будет выполняться после завершения программы.
Если вы загрузите код glibc и изучите критические зоны malloc. И т. Д., Вы найдете проверки кода, которые не описаны в ранее упомянутых документах. Эти проверки были включены, чтобы остановить двойную бесплатную вечеринку.
С другой стороны, презентация Джастина Н. Фергюсона ("Понимание кучи, разбив ее"), которую вы можете найти в YouTube (BlackHat 2007), идеально подходит для понимания всей механики кучи, но я должен признать, что показанные методы далеко не надежный, но, по крайней мере, он открывает новое поле для эксплуатации кучи.
В любом случае, я тоже работаю над этим, поэтому, если вы хотите связаться со мной, мы можем поделиться нашими достижениями. Вы можете связаться со мной в домене overflowedminds.net как newlog (создайте почтовый адрес самостоятельно ^^).
Переполнения кучи сложно осуществить, и они очень сильно зависят от компоновки кучи, хотя похоже, что вы идете после кучи Windows CRT, которая имеет множество мер по снижению риска, специально предназначенных для предотвращения атак такого типа.
Если вы действительно хотите делать подобные вещи, вам нужно с радостью перейти в WinDbg и войти в такие функции, как free, чтобы точно увидеть, что происходит внутри free, и, следовательно, какого рода контроль вы могли бы достичь через кучу переполнение предыдущего значения.
Я не дам вам более конкретной помощи, чем по той простой причине, что демонстрации переполнения кучи обычно достаточно для защитной безопасности - эксперты по оборонной безопасности могут сообщать о переполнении кучи без необходимости фактически полностью ее использовать. Единственные люди, которым необходимо полностью использовать переполнение кучи на всем пути к удаленному выполнению кода, - это люди, оскорбительно эксплуатирующие ошибки, и если вы хотите это сделать, вы сами.