Примечание. Прежде чем ответить, скажу, что это чисто академический ответ, не предназначенный для использования в злонамеренных целях. Мне известно об упражнениях, которые выполняет 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 просто не будет работать. Это в сочетании с такими мерами, как рандомизация адресов, делает эту атаку нежизнеспособной, кроме устаревших систем. Но описанный здесь метод - это то, как я справился с этой задачей;)