如何在运行时检测 KASLR 是否启用或禁用?
答案1
我对之前的答案并不满意,因为他们并没有真正验证 KASLR 的意义,尤其是那些没有实现相同内核命令行界面的嵌入式或自定义内核(例如,ARM64 要求在内核启动时存在一个名为 kaslr-seed 的设备树选择节点。这通常由引导加载程序使用安全随机数生成器来实现)。
在运行时我知道您可以检查两件事:
- 该
/proc/kallsyms
文件查看虚拟内存地址空间中的符号地址。 lsmod
查看虚拟内存地址空间中的内核模块地址。笔记:在某些机器上,lsmod
可能无法显示地址。在这种情况下,请尝试cat /proc/modules
以 root 身份使用。如果不使用 root,地址可能全为零(出于安全原因已清除)。~~感谢用户 @crass 的评论!~~
1 和 2 是类似的检查,但根据您系统上可用的功能,您可能需要使用其中一个。
1. /proc/kallsyms
为此,只需查看前几行/proc/kallsyms
:
root@device:~# head -n 3 /proc/kallsyms
ffffff8008080000 t _head
ffffff8008080000 T _text
ffffff8008080800 T do_undefinstr
请注意,例如的地址_head
是ffff ff80 0808 0000
。
现在重新启动您的机器并再次检查。
root@device:~# head -n 3 /proc/kallsyms
ffffff9fc8c80000 t _head
ffffff9fc8c80000 T _text
ffffff9fc8c80800 T do_undefinstr
注意,例如的地址_head
现在是ffff ff9f c8c8 0000
。
比较高级字节并发现,ffffff80080 != 0xffffff9fc8c
因此地址在重启后会发生变化 => KASLR 已启用。
2. lsmod
与上面的方法类似/proc/kallsyms
:检查 lsmod,重新启动,再次检查 lsmod,并比较地址。
root@device:~# lsmod
iptable_filter 16384 0 - Live 0xffffffa1c49b9000
ip_tables 28672 1 iptable_filter, Live 0xffffffa1c49ad000
请注意,例如的地址iptable_filter
是ffff ffa1 c49b 9000
。
现在重新启动您的机器并再次检查。
root@device:~# lsmod
iptable_filter 16384 0 - Live 0xffffff2100716000
ip_tables 28672 1 iptable_filter, Live 0xffffff210070a000
注意,例如的地址iptable_filter
现在是ffff ff21 0071 6000
。
比较高级字节并发现,ffffff2100716 != 0xffffffa1c49b9
因此地址在重启后会发生变化 => KASLR 已启用。
您可以反复进行这些测试以确定质量随机性。重启后地址有何不同?是否存在明显的模式?KASLR 的安全优势与随机性或熵的质量成正比。
答案2
回答这个问题:
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-4.14.27-041427-generic root=UUID=f3f8e7bc-b337-4194-88b8-3a513f6be55b ro quiet splash loglevel=0 vga=current udev.log-priority=3 fastboot kaslr acpiphp.disable=1 crashkernel=384M-2G:128M,2G-:256M vt.handoff=7
答案3
检查你的内核命令行。(以 Debian 8 为例)
$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-`uname -r` root=/dev/mapper/`hostname`-root ro quiet
kASLR 从 Ubuntu 14.10 开始可用,但默认情况下不启用。在内核命令行上指定“kaslr”选项以使用 kASLR。
笔记:启用 kASLR 将禁用进入休眠模式的能力。
答案4
我喜欢 @bhass1 的回答,但是我不想重启电脑才能进行测试。因此,您可以在虚拟机中执行基本相同的测试(如果可以的话)。我使用的是和qemu
选项,下面是我操作的方法:-kernel
-initrd
首先,我通过查看来检查你正在运行哪个内核cat /proc/cmdline
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-5.2.0-42-generic root=/dev/sda1 ro vt.handoff=7
所以我用核心 vmlinuz-5.2.0-42-generic
。
我们需要使用 initrd 运行内核,这样才能拥有一个最小的环境来检查地址。我使用与我的内核相对应的 initrd,以使模拟更加真实,但这实际上并不重要。我还使用正在运行的内核的内核命令行,以使模拟尽可能接近正在运行的内核,并添加break=top
到内核命令行以尽快进入 shell。
接下来我运行qemu
虚拟机:
sudo qemu-system-x86_64 -m 1024 -kernel /boot/vmlinuz-5.2.0-42-generic \
-append "$(cat /proc/cmdline) break=top" -initrd /boot/initrd.img-5.2.0-42-generic
当我进入 shell 时,我得到了已加载的模块地址:
(initramfs) cat /proc/modules
usbhid 57344 0 - Live 0xffffffffc0269000
hid 131072 1 usbhid, Live 0xffffffffc0248000
现在我将检查正在运行的系统以查看其中一个模块的模块地址是否不同:
sudo grep hid /proc/modules
hid_generic 16384 0 - Live 0xffffffffc20ac000
usbhid 57344 0 - Live 0xffffffffc1a09000
hid 131072 2 hid_generic,usbhid, Live 0xffffffffc1c96000
所以我们在这里可以看到隐藏模块不同(运行:0xffffffffc1c96000
和虚拟:)0xffffffffc0248000
。所以我的内核运行的是 kASLR,虽然它不在内核命令行上(现在在某些发行版上它默认打开)。
您可以在另一个实例中再次检查模块地址qemu
,并验证模块地址在每次 qemu 运行时是否发生变化。此外,您可以添加nokaslr
到内核命令行(选项-append
qemu
)并运行qemu
几次以验证模块地址不要改变。