Ответ 1
Примечание. Прежде чем ответить, я скажу, что это чисто академический ответ, который не предназначен для использования в злонамеренных целях. Я знаю об упражнениях, которые выполняет OP, и они имеют открытый исходный код и не предназначены для того, чтобы побуждать пользователей использовать эти методы в неутвержденных обстоятельствах.
Я подробно расскажу о технике ниже, но для вашей справки я хотел бы взглянуть на трюки Vudo malloc (он упоминается в одной из ваших ссылок выше), потому что мой обзор будет коротким: http://www.phrack.com/issues.html?issue=57&id=8
Подробности о том, как malloc обрабатывает создание блоков памяти, вытягивая память из списков и других вещей. В частности, для этой атаки интерес представляет атака разблокировки (примечание: вы правы, что 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, но бесплатные. Это будет важно позже. Вы должны знать достаточно программирования, чтобы понять, что "блоки" в Doug Lea 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 | addr вы хотите перезаписать -12 (0x0C) | addr, который вы хотите вызвать вместо
Обратите внимание, что отрицательное число устанавливает поле prev_size равным -4, что делает бесплатную маршрутизацию полагающей, что часть prev_size фактически начинается в текущем блоке, который вы контролируете/развращаете.
И да, правильное объяснение не будет полным без упоминания о том, что эта атака не работает с текущими версиями glibc; размер имеет проверку работоспособности, и метод unlink просто не работает. Это в сочетании с смягчениями, такими как рандомизация адреса, делает эту атаку нежизнеспособной ни на чем, кроме устаревших систем. Но метод, описанный здесь, заключается в том, как я сделал эту задачу;)