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

38

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

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

DW
источник
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

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

user2387
источник
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.

p5yx
источник
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 изменяет местоположение исполняемого файла или не.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
источник
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
Sourc7
источник