Как проверить, был ли двоичный файл Linux скомпилирован как позиционно-независимый код?


38

Недавно я узнал, что (по крайней мере, в Fedora и Red Hat Enterprise Linux) исполняемые программы, которые скомпилированы как независимые от позиции исполняемые файлы (PIE), получают более надежную защиту от рандомизации адресного пространства (ASLR).

Итак: Как проверить, был ли определенный исполняемый файл скомпилирован как независимый от позиции исполняемый файл в Linux?


1
Не уверен насчет 32-битного, но в x86_64 код по умолчанию не зависит от позиции . И, конечно же, все системные пакеты скомпилированы таким образом для любой арки.
Майкл Хэмптон

1
@ Майкл Хэмптон, я не думаю, что это правильно. (Будьте осторожны с разницей между исполняемым двоичным файлом и разделяемой библиотекой; ваше утверждение может быть правильным для разделяемых библиотек, но я не думаю, что оно подходит для исполняемых файлов.) Даже в x86_64 двоичные файлы не выглядят как PIE по умолчанию. Я только что написал небольшую тестовую программу, и на x86_64 она не была скомпилирована как PIE. Я думаю, что вы должны передать -pie -fpieспециальные флаги компилятора, чтобы скомпилировать программу в виде пирога. Эта ссылка содержала другую интересную информацию - спасибо!
DW

1
У этого парня есть сценарий bash для обнаружения: blog.fpmurphy.com/2008/06/position-independent-executables.html
CMCDragonkai

Ответы:


32

Вы можете использовать perlскрипт, содержащийся в hardening-checkпакете, доступный в Fedora и Debian (as hardening-includes). Прочтите эту вики-страницу Debian, чтобы узнать, какие флаги компиляции проверены. Это специфично для Debian, но теория применима и к Red Hat.

Пример:

$ hardening-check $(which sshd)
/usr/sbin/sshd:
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes (some protected functions found)
 Read-only relocations: yes
 Immediate binding: yes

Хороший ответ, также применимый к Ubuntu 16.04 LTS и, возможно, к другим версиям Ubuntu. sudo apt-get install hardening-includesи тогда hardening-checkисполняемый Perl-скрипт доступен по обычному PATH( /usr/bin/hardening-check); просто гнида: Предложите удалить ./из ответа ;-)
Дилетант

@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae больше не в 17.10 :-(
Чиро Сантилли 新疆 改造 中心 法轮功 六四 事件

В CentOS / RedHat этот пакет доступен в Epel хранилище
vikas027

@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae Похоже, он больше не доступен в Ubuntu 18.04
Вадим Котов

2
Пакет debian, который содержит это, теперь называется devscripts.
Тамас Селеи

15

Я использовал readelf --relocsдля проверки статической или динамической библиотеки PIC на x86-64 следующим образом:

$ readelf --relocs /usr/lib/gcc/x86_64-linux-gnu/4.6/libstdc++.a |\
      awk '$3~/^R_/ && $5!~/^\.debug/{print $3}' |sort -u
R_X86_64_32
R_X86_64_32S
R_X86_64_64
R_X86_64_DTPOFF32
R_X86_64_GOTPCREL
R_X86_64_PC32
R_X86_64_PLT32
R_X86_64_TLSLD
R_X86_64_TPOFF32

Мы видим здесь R_X86_64_32и R_X86_64_32S. Это означает, что код не зависит от позиции. Когда я перестраиваю библиотеку с -fPIC, я получаю:

$ readelf --relocs libstdc++.a |\
      awk '$3~/^R_/ && $5!~/^\.debug/{print $3}' |sort -u
R_X86_64_64
R_X86_64_DTPOFF32
R_X86_64_GOTPCREL
R_X86_64_PC32
R_X86_64_PLT32
R_X86_64_TLSGD
R_X86_64_TLSLD

Этот метод, вероятно, может работать для исполняемых файлов, но я не использовал его таким образом.


8
Не могли бы вы объяснить, как интерпретировать вывод этой строки? Какие критерии использовать для классификации разделяемой библиотеки как PIC против не PIC?
DW

Если вы создали исполняемый файл с -fPIE -no-pie, он всегда будет загружаться по одному и тому же адресу, даже если он мог быть связан как исполняемый файл PIE. Используйте file a.outи ищите ELF executable(не PIE) против общего объекта ELF (PIE): 32-разрядные абсолютные адреса больше не разрешены в x86-64 Linux?
Питер Кордес

12

Просто используйте fileна двоичном:

$ file ./pie-off
./pie-off: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=0dc3858e9f0334060bfebcbe3e854909191d8bdc, not stripped
$ file ./pie-on
./pie-on: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=962235df5bd188e1ec48c151ff61b6435d395f89, not stripped

Обратите внимание на другой тип, напечатанный после информации LSB.


1
Как это показывает, если скомпилировано с PIE / ASLR?
Барух,

3
Единственная разница между выходами из pie-off и pie.on заключается в executableи shared object. Я предполагаю, что общие объекты должны быть перемещаемыми, поэтому, на мой взгляд, они были скомпилированы с помощью PIE.
Ричард Браганса

Да, исполняемые файлы PIE являются общими объектами ELF; Самым простым способом реализации ASLR для исполняемых файлов было использование существующей поддержки в динамическом компоновщике и точки входа ELF в общем объекте. Смотрите также 32-разрядные абсолютные адреса, более не разрешенные в x86-64 Linux? для получения дополнительной информации о параметрах gcc, которые управляют PIE, и gcc -fPIE -pieтеперь это значение по умолчанию во многих дистрибутивах.
Питер Кордес

В новых версиях файла явно упоминается круговая диаграмма: например, исполняемый ELF 64-битный круговой файл LSB, x86-64, версия 1 (SYSV), динамически связанный, интерпретатор /lib64/ld-linux-x86-64.so.2, для GNU / Linux 3.2.0, BuildID [sha1] = 9b502fd78165cb04aec34c3f046c1ba808365a96, раздетый
Брайан Минтон

1
@PeterCordes отмечает, что file5.36 теперь может фактически распознавать PIE-nessness на основе DT_1_PIEфлага DT_FLAGS_1, и четко говорит pie executableвместо shared object.
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件

9

file 5.36 ясно говорит

file5.36 фактически печатает это ясно, если исполняемый файл - ПИРОГ или нет. Например, исполняемый файл PIE выглядит так:

main.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, not stripped

и не пирог, как:

main.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

Эта функция была представлена ​​в 5.33, но она просто chmod +xпроверила. До этого он просто печатался shared objectдля пирога.

В 5.34 предполагалось начать проверку более специализированных DF_1_PIEметаданных ELF, но из-за ошибки в реализации это фактически сломало вещи и показало исполняемые файлы GCC PIE как shared objects.

Я интерпретировал fileисходный код, включая ошибку, и какие именно байты формата ELF он проверяет в мельчайших подробностях по адресу: https://stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object -instead-оф-ан-исполняемым-двоично-по-с / 55704865 # 55704865

Краткое описание поведения файла 5.36:

  • если Elf32_Ehdr.e_type == ET_EXEC
    • Распечатать executable
  • иначе если Elf32_Ehdr.e_type == ET_DYN
    • если присутствует DT_FLAGS_1динамическая запись раздела
      • если DF_1_PIEустановлено в DT_FLAGS_1:
        • Распечатать pie executable
      • еще
        • Распечатать shared object
    • еще
      • если файл исполняемый пользователем, группой или другими
        • Распечатать pie executable
      • еще
        • Распечатать shared object

GDB дважды запускает исполняемый файл и видит ASLR

Одна очень прямая вещь, которую вы можете сделать, это запустить исполняемый файл дважды через GDB и посмотреть, не меняется ли адрес при запуске из-за ASLR.

Я объяснил, как это сделать, подробно по адресу: https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031 # 51308031

Хотя это не обязательно самое практичное решение, и оно невозможно, если вы не доверяете исполняемому файлу, но это забавно, и он в конечном итоге проверяет, что нас действительно волнует, - это если ядро ​​/ динамический загрузчик Linux изменяет местоположение исполняемого файла или не.


1
«Адрес основных изменений между прогонами» - это не эффект чистого PIE, это PIE и включенный ASLR. Да, он почти везде включен, но для машин с отключенным адресом ASLR будет одинаковым оба раза. ASLR может быть включен глобально, но отключен с помощью setarch -R man7.org/linux/man-pages/man8/setarch.8.html « -R, --addr-no-randomize Отключает рандомизацию виртуального адресного пространства. Включает ADDR_NO_RANDOMIZE». man7.org/linux/man-pages/man2/personality.2.html " ADDR_NO_RANDOMIZE(начиная с Linux 2.6.12). При установленном флаге отключите рандомизацию размещения адресного пространства."
osgx

2

На Github есть скрипт bash checksec.sh для проверки свойств смягчения исполняемых файлов (включая RELRO, Stack Canary, NX bit, PIE, RPATH, RUNPATH, Fortify Source).

Запустить checksecс -f(входной файл) аргументами:

$ checksec -f /usr/bin/bash

RELRO           STACK CANARY      NX            PIE             RPATH     RUNPATH      FORTIFY Fortified Fortifiable
Full RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH    YES      13        33
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.