Linux内核中KASLR功能是什么?有什么作用?怎么破除?以及如何实操?(地址空间、layout random、kallsyms)

1. 背景

KASLR是一个什么技术点其实不重要,但重要的是有了KASLR这个功能后,造成内核中某个符号(函数 or 变量)在System.map中的地址和实际不一样了(实际: cat /proc/kallsyms),进一步带来了分析类似crash问题中的打印地址不准确问题。所以必须得知道这是什么?本文主要从实战层面来谈几个问题:

  1. KASLR是什么?
  2. KASLR如何开启?如何查看开启了?
  3. 破除KASLR的几个方法(有些奇技淫巧)
  4. 破除KASLR后再实战中有何作用?

2. 要点

  • KASLR:kernel address space layout randomization 内核地址空间布局随机化。是一个安全功能,本质是将链接的地址 mapping到 运行的地址多做了一个随机偏移。断句是:KAS LR,KAS的LR

  • 作者:Kees Cook,linux内核的安全工程师(Linux kernel security engineer),曾是Ubuntu Security Team的技术老大。更多参考链接: Cook的LinkedinCook的github仓库Cook更多介绍
    在这里插入图片描述

  • ASLR:address space layout randomization地址空间布局随机化,是一种众所周知的技术,它通过将各种对象随机放置在而不是固定的地址上来增加攻击的难度。参考Wiki

  • ASLR首次提出:Linux PaX 项目首先创造了“ASLR”这个术语,并于 2001 年 7 月作为 Linux 内核的补丁发布了 ASLR 的第一个设计和实现。参考Wiki

  • 第一个默认支持 ASLR 的主流操作系统是 2003 年的 OpenBSD 3.4 版, 其次是 2005 年的 Linux。参考Wiki

  • ASLR是一种“统计防御”,因为一般可以使用暴力方法来克服它

  • 在一个完全不受限制的系统中,尤其是在本地不受信任的用户的系统中,KASLR 不会很有用。但是,在使用容器或具有大量包含进程的系统上,KASLR 可以提供帮助。参考链接

  • Linux 长期以来一直为用户空间程序提供 ASLR。参考链接

  • 在虚拟机内使用较多,提高虚拟机安全性

  • 让内核vmlinux在运行态的地址相比于编译的地址有一个偏移,具体偏移值通过DTS配置

  • 另外如果可以参数化,在bootloader中配置,可以动态设置每次每个设备都是不同的映射地址

  • Red Hat Enterprise Linux 7.5 and later开始引入,参考redhat 官网

  • 如何避免内核消息卸载:通过将 dmesg_restrict sysctl 设置为 1,防止非特权用户访问内核消息。此设置将 dmesg 访问限制为具有 CAP_SYSLOG 权限的用户。proc通过kptr_restrict sysctl 设置为 1。

3. 实操

3.1 查看是否打开:CONFIG_RANDOMIZE_BASE

内核编译是否配置 CONFIG_RANDOMIZE_BASE=y

cat /boot/config-$(uname -r) |grep CONFIG_RANDOMIZE_BASE

实操:
在这里插入图片描述

  • 在bootloader配置中关闭的方式,添加nokaslr的启动项
GRUB_CMDLINE_LINUX="rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet nokaslr"

nokaslr介绍

  • 实操关闭nokaslr效果:
    修改启动grub参数:
    在这里插入图片描述
    启动后查看cmdline以及查看实际的地址是否和链接的相同:

在这里插入图片描述
工程提效:在定位某些复杂并且容易重现的问题依赖地址的使用直接临时修改启动参数的方法比较方便。长久修改需要grub并且配置:

vim /etc/default/grub #修改启动参数 添加nokaslr
grub2-mkconfig -o /boot/grub2/grub.cfg  #生效到实际grub文件
cat /boot/grub2/grub.cfg |grep nokaslr #查看是否生效
# 然后重启,重启后使用上面类似的方法进行确认

实操:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2 计算内核符号表和堆栈空间地址的偏移方法

可以随机找一个内核符号表假设是 kmalloc_info。
通过 /proc/kallsyms获取符号实际的加载地址 A d d r k a l l s y m s Addr_{kallsyms} Addrkallsyms
通过 /boot/System.map-$(uname -r) 获取链接后的地址 A d d r s y s t e m m a p Addr_{systemmap} Addrsystemmap
那么偏移的地址就是他们的delta
A d d r δ = A d d r k a l l s y m s − A d d r s y s t e m m a p Addr_\delta = Addr_{kallsyms} - Addr_{systemmap} Addrδ=AddrkallsymsAddrsystemmap

命令:

cat /boot/System.map-$(uname -r) |grep kmalloc_info
cat /proc/kallsyms |grep kmalloc_info
python3 -c 'print(hex(int("0xffffffff87fa04c0", 16) - int("0xffffffff831a04c0", 16)))'

实操:
获取链接地址和运行加载地址:在这里插入图片描述
计算delta:在这里插入图片描述
所以算出来是:0x4e00000
那么计算出这个delta之后有什么作用呢?对实战有什么帮助呢?

4. 实战作用

在实战中,主要是需要用gdb调试linux内核的时候,比如有qemu场景调试guest主机内核,或者host主机内核都可以。下面主要以gdb调试vmlinux为例子介绍:
gdb使用add-symbol-file 默认基地址就是二进制vmlinux中的各个段地址。如果开启了KASLR,那么这个地址寻找到某个变量的实际地址就不对了。需要加上刚才的偏移。才能正确的使用。

4.1 获取默认链接地址

比如gdb中加载符号地址默认是根据vmlinux二进制文件中的各个段地址进行加载基础地址的。比如选取某个vmlinux查看他的text段的地址:
在这里插入图片描述

4.2 获取偏移后的加载地址:

  • data段的基础地址就是:
    ffffffff82600000 + 0x4e00000 = 0xffffffff87400000
    在这里插入图片描述
  • text段的基础地址就是:
    ffffffff81000000 + 0x4e00000 = 0xffffffff85e00000在这里插入图片描述
    计算这两个段的地址以后在gdb加载的时候指定对应的地址就能正确的映射上去
    在这里插入图片描述
    验证正确性:使用gdb和crash分别查看一个内核全局变量vm_numa_stat中的值
    使用最新的加载地址的gdb获取地址:
    在这里插入图片描述
    使用crash作为正确性对比来源对比:
    在这里插入图片描述
    结论是:都是28872。说明通过随机地址偏移后计算新的地址正确。
    注意这里为什么vm_numa_stat不能直接使用kallsyms中直接使用他的地址?
    实际上是可以的,但是会带来两个问题:
  1. 每次都需要将gdb中符号地址转化
  2. 转化后需要使用地址实际使用
    使用加载时候指定每个段的基础地址这样gdb在使用具体符号(函数或者全局变量)的时候,就能从动态连接的符号表中获取到正确的地址偏移,最终获取到对应的正确数据。
    另外值得注意的是gdb在添加symbol的时候需要先清空表(symbol-file 命令),以及有些数据需要每次都add-symbol-file才会更新。
# 清空表
symbol-file 
#
add-symbol-file  /usr/lib/debug/lib/modules/4.18.0-372.9.1.an8.x86_64/vmlinux -s .data 0xffffffff87400000 -s .text 0xffffffff85e00000

综述

本文从KASLA的功能出发,介绍了基础概念,以及实战场景。
实战场景中以在systemmap中的链接地址和kallsyms中的实际地址进行计算,并且以vmlinux中的各个段基础地址加上偏移计算通用
本方法依赖掌握代码编译链接和动态加载的基础原理,以及gdb的基础流程和原理,详细细节可以多参考相关文档,并多琢磨多实践。

其他参考链接:

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_security_guide/sect-virtualization_security_guide-guest_security-kaslr
LWN介绍KASLR

  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值