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

9

Это Ubuntu 9.04, 2.6.28-11-server, 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в исполняемом файле elf, который вызывается после main()выхода. Эта таблица уже давно доступна для записи, и похоже, что так и должно быть в моем случае (см. readelfВывод). Но попытка записи в таблицу приводит к ошибке.

Я понимаю, что в последнее время произошло движение к readonly .dtors, plt, но чего я не понимаю, так это несоответствия между readelfsegfault.

Fixee
источник
Реальный вопрос в том, почему вы хотите, чтобы это было доступно для записи?
Алекс
1
Я преподаю класс безопасности, который включает в себя взлом ряда уязвимых программ, но одно упражнение включает в себя запись в .dtors для выполнения шелл-кода. Это больше не работает, и я пытаюсь отследить проблему.
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 .

ninjalj
источник
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 .dtors, plt, got»), но я не знаю, как именно это называется (в OpenBSD есть нечто очень похожее, называемое W ^ X ; Linux имеет PaX , но не встроен в большинство ядер)

Вы можете обойти это с помощью mprotect, который позволяет вам изменять атрибуты в памяти страницы:

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

При этом моя тестовая программа не завершается сбоем, но если я попытаюсь перезаписать конечный страж функции .dtors( 0x8049f18) адресом другой функции, эта функция все равно не будет выполнена; эту часть я не могу понять.

Надеюсь, кто-то еще знает, что отвечает за то, чтобы сделать страницу доступной только для чтения, и почему изменение .dtors, похоже, ничего не делает в моей системе

Михаил Мрозек
источник
3
Если OP Linux с PaX mprotectне может сделать исполняемую страницу доступной для записи или сделать исполняемый файл страницы, который был доступен для записи раньше, если эта функция не отключена с помощью paxctl -m.
стрибика
@stribika Ах, приятно знать
Майкл Мрозек