速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

怎样 Hack Linux 的内核符号?

  • 2020-08-13
  • 本文字数:2726 字

    阅读完需:约 9 分钟

怎样Hack Linux的内核符号?

Linux 内核是不是坚不可摧?答案是 NO!尽管内核中存在诸多限制,但你只需要稍微花点心思,也可以想办法突破它们。下面我们将通过一个例子来展示这趟有趣的旅程。


首先简单介绍一下项目的背景。客户提供了一批嵌入式智能设备给我们,希望能够检测并且修复其中的安全漏洞。我们能够从设备中接触到二进制形式的固件,但却接触不到固件的源码。对于二进制固件的漏扫和加固是一个行业难题。此外为了减少人工成本,客户还希望我们提供一个自动化的漏扫和加固解决方案,这无疑成为了一件不可能完成的任务。


所谓固件,其实就是一个嵌入式操作系统,常见的有定制化的 Linux 和安卓系统。本质上它们都具有相似的结构:Bootloader、Kernel、根文件系统等。根文件系统中又包含了众多用户态程序、脚本、配置等。对于 Kernel 的 CVE 漏洞自动化扫描和修复是我们当前工作的主要内容。而自动化漏扫技术又可单独成文,本文将主要介绍自动化漏洞修复所用到的内核符号 Hack 技术。


所谓内核漏洞,其实就是 Linux 内核中存在的缺陷函数。所谓漏洞利用,就是在用户态通过一系列精巧的传参和调用,最终触发内核缺陷的过程。这里存在两种修复方式:


1)在触发缺陷的必由调用路径上设卡,做参数或调用关系过滤。比如 c 函数是缺陷函数,该漏洞触发的调用关系是 Func a-> Func b-> Func c,那么可以在 a 或 b 函数上做传参检查,一旦参数非法则立刻退出。这种方式的优点是修复过程简单,尤其当 c 函数调用非常深的时候,可以在表层易于打桩的函数中做传参检查;缺点是需要开发者深入理解漏洞的利用原理,同时不同漏洞的利用方式各不相同,修复方式也各异。


2)用与 c 函数功能相同,并且已经打好补丁的 c‘函数替换掉 c 函数。修补时只需要保证每次对 c 函数的调用都会无条件进入到 c’即可。这种方式的优点是修复方法统一,便于自动化,可不必深究不同漏洞的利用原理。


图示展示了方案二技术架构图:中间是 Hook 框架,提供缺陷函数拦截、函数跳板(Trampoline)、修复函数注册、内核代码区修改等基础功能;右侧是包含具体 CVE 漏洞修复业务的模块。 这里有很多核心问题需要解决,其中之一是修复函数使用未导出内核符号问题。



方案二技术架构图


我们都知道 Linux 是宏内核架构(Monolithic Kernel)。为了实现内核功能的动态扩展,Linux 又引入了内核模块。内核模块将不可避免的使用内核函数。正常情况下,Linux 内核代码会将一些基础功能性函数导出。如控制台输出函数 printk 等。所有被导出的函数都会通过 export_symbols 族的宏修饰。最后这些符号会被内核编译到特殊的段中。而针对我们漏洞修复的场景,内核缺陷函数可能存在于内核的任何地方,因此如果仅仅使用内核导出的少量符号,很多缺陷函数或其依赖函数将无法被解析到。


于是我们把目光放到了内核的 Kallsyms 功能上。这个功能是内核为了方便调试而引入的。当内核发生错误时会输出一系列 Stacktrace,后者其实是一系列函数地址。有了 Kallsyms,在输出 Stacktrace 的时候内核可以把地址解析成函数名输出,告诉开发人员错误发生在哪个函数的哪个位置:



export 导出的 printk 函数/kernel 的 stacktrace


由于内核错误可能发生在任何地方,因此 Kallsyms 单独保存了一份函数符号和函数地址的对应关系,其中的符号数量远远多于 export_symbols 宏导出的符号量。即使内核开启了地址随机化(Address Space Layout Randomization)功能,Kallsyms 也能在运行时解析到符号正确地址。如果在内核模块中想使用未导出的符号,可以使用 Kallsyms 提供的 kallsyms_lookup_name 函数将符号名解析到函数地址,再以函数指针的形式调用即可,如:



Kallsyms


普通需求到这里就完事了,但是针对客户的特殊场景,稍微思考一下就会发现有很大缺陷。假如修复补丁中一共涉及到了数百个未导出的函数,我们则要在修复代码中把所有使用到这些函数的地方全部修改成函数指针调用的形式,工作量增加了不少。最简单的解决办法是内核加载修复模块时,单独走 Kallsyms 解析模块符号,而绕过 export_symbols 这个符号子集(前提是不引入新的内核安全风险)。


Linux 内核模块的加载过程其实跟可执行程序加载动态链接库的过程是一样的。举个简单例子,在 printf(“hello world”)中,我们其实并没有实现 printf(由 puts 函数封装而来)。它实际是由 Libc 库实现。当我们运行 HelloWorld 程序的时候,操作系统会解析程序符号,载入依赖的动态链接库(每次加载的基址可能不同),计算重定位符号地址,并把地址填回 HelloWorld 程序中。我们可以通过下图过程来验证:



Linux 内核模块的加载过程


对于 Linux 内核模块而言,它本质上也是动态链接库,因此加载模块时必然存在解析符号地址的函数。于是我们的思路是,动态拦截该函数,重定向到我们的替换函数中,并在替换函数中添加 Kallsyms 查找符号地址的逻辑即可:左图为我们的替换函数,右图为内核原始函数。这样达到的效果是,我们可以在 CVE 修复代码中直接使用诸如 d_absolute_path 这样的未导出函数,而不用做任何函数指针形式的改造,便于漏洞修复过程的自动化。



符号解析替换函数/符号解析原始函数


可能会有同学感兴趣我们是如何实现内核函数拦截的,即如何从 find_symbol_in_section 跳转到 hook_find_symbol_in_section,这里以 ARM64 架构 CPU 为例简单说明。我们在内核的 find_symbol_in_section 函数开头插入了下图所示的汇编指令(以二进制形式修改内核代码区)。这里借用了 x0 寄存器作远距离跳转(从内核跳转到内核模块)。由于无条件跳转不应该产生任何副作用(即栈帧和寄存器不能改变),因此我们需要先保存 x0 的值到栈上,远跳转后再恢复 x0 内容。


ldr 指令从.addr(low)和.addr(high)中把跳板函数地址装载进 x0,注意到 ARM64 的地址长度为 64 位,而 ARM64 的指令长度为 32 位,因此跳板函数地址被折成低 32 位和高 32 位。进入跳板函数后先恢复 x0 寄存器值,再做近距离跳转(内核模块内部跳转),注意前图 hook_find_symbol_in_section 函数末尾有一行 HOOK_FUNC_TEMPLATE(find_symbol_in_section),即为宏定义的 find_symbol_in_section 的跳板函数。这样经过连续无条件跳转后,执行流被拦截到我们的 HOOK 函数中。



HOOK 函数


此外顺便多提一下,上述使用 Inline Hook 技术的拦截方式跟 CPU 架构是强相关的,如果想实现 ARM32 或 x86 架构的函数拦截,则需要分别单独实现。


作者介绍


刘涛,5 年 Linux 内核开发经历,熟悉操作系统原理,擅长 C 语言、汇编,热爱底层技术,曾在业余时间独立开发过操作系统。目前是 ThoughtWorks 中国安全团队核心成员。我的个人 github 地址是https://github.com/liutgnu


本文转载自 ThoughtWorks 洞见


原文链接


https://insights.thoughtworks.cn/how-to-hack-linux-kernel-symbols/


2020-08-13 14:051519

评论

发布
暂无评论
发现更多内容

中小企业跨境电商“中年危机”来袭,华为云耀云服务器L实例拒绝“洗牌”

平平无奇爱好科技

互联网产品成创业者坟墓?华为云耀云服务器L实例助力创业者逆袭

平平无奇爱好科技

小巧高效的音频录制 Piezo 最新激活版

胖墩儿不胖y

Mac软件 音频处理器 音频录制

List.of() Vs Arrays.asList()

越长大越悲伤

Java

玩转MaxCompute SQL训练营! 数据分析挖掘迅速出师

阿里云大数据AI技术

大数据 数据分析

我与极客时间的故事

穿过生命散发芬芳

我和极客时间的故事

如何从构建到运营?数科公司数智创新研讨会成功举办

用友BIP

数科公司

互联网企业低效愈演愈烈,这款轻量云服务器重建效能!

轶天下事

火爆微信小游戏开发的轻量云服务器,腾讯云、华为云、阿里云三家“避坑”指南来了

轶天下事

“升级是找死,不升级是等死”,GitLab CE 的痛苦升级之路

极狐GitLab

DevOps gitlab postgres CE MySQL、

Servlet、HTTP详细解释!

百度搜索:蓝易云

Java Linux Web HTTP Servlet

SoundSource for mac(音量控制工具)

展初云

Mac软件 音量调节

用友 Fast by BIP引领专业技术服务企业快速迈向数智化创新

用友BIP

Fast by BIP

HTX 与 Zebec Protocol 展开深度合作,并将以质押者的身份参与 ZBC Staking

BlockChain先知

工善其事 先利其器丨华为云耀云服务器L实例成企业数字化助推器

平平无奇爱好科技

跬智信息(Kyligence)成为信创工委会技术活动单位

Kyligence

大数据分析

Linux之进程掩码umask详解。

百度搜索:蓝易云

云计算 Linux 运维 云服务器 umask

Sentinel源码改造,实现Nacos双向通信!

王磊

Java

英语学习工具:Eudic欧路词典 for Mac增强版

展初云

Mac 欧路词典 英语学习工具

轻量应用服务器水太深,这款产品才是实惠好用

轶天下事

企业ERP管理体验两极分化?选择轻量云服务器才能直上“云”霄

轶天下事

B站狂转3500次,火到抖音。阿里P5至P8的java进阶宝典

程序员万金游

#java #程序员 #学习 #框架 #阿里

轻量应用服务器大推荐,最后一个没用绝对后悔

平平无奇爱好科技

iPhone手机维护推荐 PhoneRescue for iOS 最新中文激活

mac大玩家j

Mac软件 手机助手

新手想做跨境电商,是做跨境电商平台好还是做跨境独立站好?

轶天下事

HTX 与 Zebec Protocol 展开深度合作,并将以质押者的身份参与 ZBC Staking

石头财经

这款轻量云服务器解锁中小企业使用ERP正确姿势

平平无奇爱好科技

Youtrack Linux 安装

HoneyMoose

DevOps2023现状报告|注重文化、以用户为中心是成功的关键

SEAL安全

人工智能 DevOps DORA 企业号10月PK榜 技术报告

小程序技术在信创操作系统里的应用趋势

没有用户名丶

QSpace Pro for Mac(多窗文件管理器)

展初云

文件管理 Mac软件

怎样Hack Linux的内核符号?_架构_张凯峰_InfoQ精选文章