Проблема переполнения кучи - может перезаписать заголовок чанка, поврежден Free(), но программа не дает сбоя
Я изучал компьютерные уязвимости и работал над этой проблемой в течение бесчисленных часов. Я не могу заставить кучу переполниться правильно. Несмотря на то, что glibc обнаружил повреждение памяти, после отключения MALLOC_CHECK_ моя программа выполняется и корректно завершается, как если бы перезапись заголовка блока не имела значения. Я бегу Kubuntu 12.04.
Это упражнение взято из "Руководства по Shellcoder's, 2-е издание" и также включено в онлайн-уроки по переполнению кучи. Я следовал инструкциям T несколько раз и получил тот же результат.
Вот код моей программы:
/*basicheap*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char ** argv){
char *buf;
char *buf2;
buf=(char*)malloc(1024);
buf2=(char*)malloc(1024);
printf("buf=%p buf2=%p\n", buf, buf2);
strcpy(buf,argv[1]);
free(buf2);
free(buf);
}
когда я пишу мимо буфера с glibc на:
xxx@xxx-xxx:~/CProgs$ ./basicheap $(perl -e 'print "A"x1028')
buf=0x9356718 buf2=0x9356b20
*** glibc detected *** ./basicheap: double free or corruption (!prev): 0x09356b20 ***
======= Backtrace: =========
[0x804abff]
[0x8048f4a]
[0x80490d6]
[0x8048e29]
======= Memory map: ========
08048000-080ec000 r-xp 00000000 08:07 6816172 /home/xxx/CProgs/basicheap
080ec000-080ee000 rw-p 000a3000 08:07 6816172 /home/xxx/CProgs/basicheap
080ee000-080f0000 rw-p 00000000 00:00 0
09355000-09377000 rw-p 00000000 00:00 0 [heap]
b772a000-b772c000 rw-p 00000000 00:00 0
b772c000-b772d000 r-xp 00000000 00:00 0 [vdso]
bfc14000-bfc36000 rw-p 00000000 00:00 0 [stack]
Aborted (core dumped)
xxx@xxx-xxx:~/CProgs$
Когда я пишу мимо буфера с выключенным glibc:
xxx@xxx-xxx:~/CProgs$ MALLOC_CHECK_=0 ./basicheap $(perl -e 'print "A"x1028')
buf=0xa077718 buf2=0xa077b20
xxx@xxx-xxx:~/CProgs$
GDB заголовка Chunk без перезаписи:
(gdb) run $(perl -e 'print "A"x1024')
Starting program: /home/xxx/CProgs/basicheap $(perl -e 'print "A"x1024')
buf=0x80f1718 buf2=0x80f1b20
Breakpoint 1, main (argc=2, argv=0xbfffedf4) at basicheap.c:16
16 free(buf2);
(gdb) x/x buf2-4
0x80f1b1c: 0x00000409
(gdb) x/x buf2-8
0x80f1b18: 0x00000000
(gdb) x/x buf2-12
0x80f1b14: 0x41414141
(gdb)
GDB заголовка чанка с перезаписью:
(gdb) run $(perl -e 'print "A"x1032')
Starting program: /home/xxx/CProgs/basicheap $(perl -e 'print "A"x1032')
buf=0x80f1718 buf2=0x80f1b20
Breakpoint 1, main (argc=2, argv=0xbfffede4) at basicheap.c:16
16 free(buf2);
(gdb) x/x buf2-4
0x80f1b1c: 0x41414141
(gdb) x/x buf2-8
0x80f1b18: 0x41414141
(gdb) x/x buf2-12
0x80f1b14: 0x41414141
(gdb)
Оба раза программа выходит нормально. Что мне не хватает? Изменились ли они, как работает куча на последних версиях Ubuntu? Любая помощь будет принята с благодарностью!
ОБНОВЛЕНИЕ: я прошел через сборку в GDB и обнаружил, что моя программа входит в функцию free_check() и функцию mem2chunk_check().
В функции mem2chunk_check () мое перезаписанное значение регистрируется в регистре ESI, а регистр EDI указывает на адрес этого значения. Единственное, что я вижу, это делает с моим значением в ESI, вычитая 1, а затем сбрасывая значение.
Я не смог найти какую-либо документацию по функции mem2chunk_check () после многих поисков в Google.
Являются ли эти переполнения кучи устаревшими в современных системах?
2 ответа
Во-первых, в настоящее время эксплуатировать кучу в Linux очень сложно. Ну, легко перезаписать разные буферы, если они переполнены, но сложно выполнить произвольный код.
Если вы хотите знать, как работает куча, вам следует прочитать статьи, которые я упоминал в этом посте: Используйте переполнение кучи для записи произвольных данных.
Как только вы поймете эти понятия, я предупреждаю вас, говоря, что большинство методов, использованных / объясненных в malloc malleficarum, были (незаметно) исправлены. Я не знаю, работает ли кто-нибудь из них сегодня.
С другой стороны, если вы действительно хотите улучшить свои знания, я советую вам скачать реализацию ptmalloc (с http://www.malloc.de/en/), на которой основан распределитель в Linux, скомпилируйте его ("сделайте общим", также полезно добавить флаг "-g") и загрузите его с LD_PRELOAD. Таким образом, вы сможете пошагово отлаживать код malloc с помощью gdb.
Удачи!
В последние несколько лет производители по умолчанию использовали "укрепленные" версии любой функции, управляющей памятью. Например, вместо memset вы получаете 'builtin_memset_chk', вместо strcpy вы получаете 'strcpy_chk'
Чтобы ваша простая программа переполнения работала, вы должны собрать свою программу с:
-fno-stack-protector -D_FORTIFY_SOURCE=0