我最近了解到(至少在Fedora和Red Hat Enterprise Linux上),编译为位置独立可执行文件(PIE)的可执行程序将获得更强大的地址空间随机化(ASLR)保护。
因此:如何在Linux上测试特定的可执行文件是否被编译为位置独立可执行文件?
-pie -fpie
特殊的编译器标志才能将程序编译为PIE。不过,该链接还有其他有趣的信息-谢谢!
我最近了解到(至少在Fedora和Red Hat Enterprise Linux上),编译为位置独立可执行文件(PIE)的可执行程序将获得更强大的地址空间随机化(ASLR)保护。
因此:如何在Linux上测试特定的可执行文件是否被编译为位置独立可执行文件?
-pie -fpie
特殊的编译器标志才能将程序编译为PIE。不过,该链接还有其他有趣的信息-谢谢!
Answers:
您可以使用Fedora和Debian(如)中提供perl
的hardening-check
软件包中包含的脚本。阅读此Debian Wiki页面,了解有关检查哪些编译标志的详细信息。它特定于Debian,但该理论也适用于Red Hat。hardening-includes
例:
$ 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
sudo apt-get install hardening-includes
然后hardening-check
可执行的perl脚本在通常的PATH
(/usr/bin/hardening-check
)上可用;只是个建议:建议./
从答案中删除;-)
devscripts
。
我曾经readelf --relocs
通过以下方式测试x86-64上的静态或动态库是PIC:
$ 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
此方法可能适用于可执行文件,但我没有那样使用。
-fPIE -no-pie
,即使它可能已链接为PIE可执行文件,也始终会在同一地址加载该可执行文件。使用file a.out
并查找ELF executable
(非PIE)与ELF共享对象(PIE): x86-64 Linux中不再允许使用32位绝对地址吗?
只需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信息之后打印的不同类型。
executable
和shared object
。我认为共享对象需要可重定位,因此在我看来已经使用PIE进行了编译。
gcc -fPIE -pie
现在这是许多发行版中的默认选项。
file
5.36现在可以根据的DT_1_PIE
标记实际识别PIE-ness DT_FLAGS_1
,并明确表示pie executable
而不是shared object
。
file
5.36清楚地说
file
如果可执行文件为PIE,则5.36实际上清楚地打印了它。例如,PIE可执行文件显示为:
main.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, not stripped
非PIE则为:
main.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
该功能是在5.33中引入的,但仅做了简单的chmod +x
检查。在此之前,它只是shared object
为PIE 打印。
在5.34中,本来打算开始检查更专业的DF_1_PIE
ELF元数据,但是由于实现中的错误,它实际上使事情中断,并将GCC PIE可执行文件显示为shared objects
。
我已经解释了file
源代码(包括错误),并确切地检查了ELF格式的哪些字节,并在以下网址进行了详尽的检查:https : //stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object而不是/ 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内核/动态加载程序是否更改了可执行文件的位置或不。
setarch -R
man7.org/linux/man-pages/man8/setarch.8.html “ -R, --addr-no-randomize
禁用虚拟地址空间的随机化。打开ADDR_NO_RANDOMIZE
。”来禁用ASLR 。“ man7.org/linux/man-pages/man2/personality.2.html ” ADDR_NO_RANDOMIZE
(从Linux 2.6.12开始)设置此标志后,禁用地址空间布局随机化。
Github上有bash脚本checksec.sh来检查可执行文件的缓解属性(包括RELRO,Stack Canary,NX位,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