.dtors виглядає записаним, але намагається написати segfault


9

Це Ubuntu 9.04, 2.6.28-11-сервер, 32bit x86


$ cat test.c
main() { int *dt = (int *)0x08049f18; *dt = 1; }
$ readelf -S ./test
...
  [18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
...
$ ./test
Segmentation fault
$

Для непосвячених: gcc створює сегмент деструктора .dtors, у виконуваному ельфі, який викликається після main()виходів. Ця таблиця давно доступна для запису, і схоже, що це має бути в моєму випадку (див. readelfВихід). Але спроба записатись у таблицю спричиняє сегментацію.

Я усвідомлюю, що останнім часом відбувся рух до readonly .dtors, plt, але я не розумію, що це невідповідність між segfault та segfault readelf.


Справжнє питання - чому ви хочете, щоб це було написано?
alex

1
Я викладаю клас безпеки, який передбачає розрив низки вразливих програм, але одна вправа передбачає написання .dtors для виконання shellcode. Це більше не працює, і я намагаюся відстежити проблему.
Fixee

Невідповідність полягає в тому, що, ймовірно, є певні переміщення даних (які потрібно виправити перед відміткою лише для читання, і ніяк не можна лінуватися, тому вони будуть постійними після встановлення).
ніндзя

Відповіді:


5

Ці розділи позначені GNU_RELRO (тільки переселення зчитування), що означає, що як тільки динамічний завантажувач налагодив (під час завантаження, там немає ледачих переїздів) усі переміщення, він позначає ці розділи лише для читання. Зауважте, що більша частина .got.pltзнаходиться на іншій сторінці, тому не отримуйте лікування.

Ви можете побачити сценарій посилання з ld --verbose, якщо ви шукаєте RELRO, ви знайдете щось подібне до:

.got            : { *(.got) }
. = DATA_SEGMENT_RELRO_END (12, .);
.got.plt        : { *(.got.plt) }

що означає, що розділи RELRO закінчуються на 12 байт .got.plt(покажчики на функції динамічного лінкера вже вирішені, тому їх можна позначати лише для читання).

Загартований проект Gentoo має деяку документацію про RELRO за адресою http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO .


5

Я можу сказати, чому це не вдається, хоча я насправді не знаю, яка частина системи відповідає. Незважаючи .dtorsна те, що в двійковому коді позначено для запису, він виглядає так, що він (разом із .ctorsGOT та кількома іншими речами) відображається в окрему незаписану сторінку в пам'яті. У моїй системі .dtorsставлять на 0x8049f14:

$ readelf -S test
  [17] .ctors            PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4
  [18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [19] .jcr              PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4
  [20] .dynamic          DYNAMIC         08049f20 000f20 0000d0 08  WA  6   0  4
  [21] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [22] .got.plt          PROGBITS        08049ff4 000ff4 00001c 04  WA  0   0  4
  [23] .data             PROGBITS        0804a010 001010 000008 00  WA  0   0  4
  [24] .bss              NOBITS          0804a018 001018 000008 00  WA  0   0  4

Якщо я запускаю виконуваний файл і перевіряю /proc/PID/maps, я бачу:

08048000-08049000 r-xp 00000000 08:02 163678     /tmp/test
08049000-0804a000 r--p 00000000 08:02 163678     /tmp/test
0804a000-0804b000 rw-p 00001000 08:02 163678     /tmp/test

.data/ .bssдосі пишуть на своїй власній сторінці, але інші в 0x8049000-0x804a000ні. Я припускаю, що це захисна функція в ядрі (як ви вже сказали, "останнім часом відбувся рух до readonly. W ^ X ; Linux має PaX , але не вбудований у більшість ядер)

Ви можете обійти його за допомогою mprotect, що дозволяє змінювати атрибути пам'яті сторінки:

mprotect((void*)0x8049000, 4096, PROT_WRITE);

З цим моя тестова програма не виходить з ладу, але якщо я спробую замінити кінцевий дозор .dtors( 0x8049f18) адресою іншої функції, ця функція все ще не виконується; цю частину я не можу зрозуміти.

Сподіваємось, хтось інший знає, що відповідає за те, щоб перетворити сторінку наново, і чому зміна .dtors, здається, не робить нічого в моїй системі


3
Якщо OP Linux з PaX mprotectне можуть зробити виконувану сторінку для запису або зробити виконуваний файл, який був доступним для запису раніше, якщо ця функція не вимкнена paxctl -m.
stribika

@stribika Ах, добре знати
Майкл Мрозек
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.