KAP 意在对 Linux ELF 在构建之后到上线运行的过程中对应用进行保护,可以通过加密的方式来保护 ELF 泄漏后无法被执行,还可以保护 ELF 在运行过程中不会被调试,也能监控被保护的 ELF 被篡改。且解密校验后运行是采用无文件的方式来运行,保证了解密后的 ELF 不落盘,且可以自定义运行前基线检查。相比于 Linux 默认方式,KAP 对完整性和保密性上进行了大幅度提升,并且还有一个未完全完成的Linux驱动来从内核态来保护 ELF。
1
目标
我 https://github.com/AlkenePan 和 Will https://github.com/EBWi11 参加了2019 GoHack,编写的项目KAP https://github.com/AlkenePan/KAP 很荣幸获得了第一名,这里和大家聊聊关于 KAP 和这次比赛。
由于时间紧任务重,一开始又没有太多沟通。我们后来选了一个相对实现难度简单的小项目。项目的主要目的是帮助企业保护自己较为敏感的ELF文件。
我们的目标很明确,要在不信任的 Linux 服务器上完成对可执行程序的保护,我们觉得要能对抗以下风险:
⽣产环境可执⾏行行⽂文件窃取
⾮可靠⽣生产环境
可执⾏⽂件被调试
过⾼的执⾏权限
可执⾏程序被篡改
2
设计
我们首先简要回顾程序的一生: Code -> Compile -> Exec(Load) 。当然,现代化的程序员早已全副武装,每个步骤都有自动或是半自动的工具辅助完成:代码编辑器 -> CI/CD -> 进程管理器。
我们盯准在构建之后的产出物到 Linux 加载可执行程序的环节,进行以下设计:
要对构建出的 ELF 进行粉碎式加密并重新打包,不可执行,手工不可恢复。
要自己完成 Linux 装载动作,解密后的可执行程序不可落盘。
通过 APPID 分发公私钥,研发人员在构建后不能手工执行程序。
生产服务器必须与 Server 通信才能完成装载,不正确的执行装载会触发告警,通信还会做一些校验如特定的基线检查。
3
实现
为了在规定时间内完成比赛,我们选择使用 Irsi 作为 API 的框架,Gorm 读写 SQLie,使用 Go 提供的 RSA 库完成加解密,当然如果需要无论是 API 的性能还是存储方案都能够更好的去修改或是替换。
加密可执行文件的部分本想对 ELF 文件头进行加密,但是这样依旧会被手动补充,我们选择了更粗暴的方案:对整个 ELF 文件的区间块进行加密,尽可能的不引起产出物过于膨胀。APPID 和 源文件 Hash 会被添加到头部。并且 Will 给加密后的文件起了 Magic Number: ELF -> 31F
。
正常的ELF:
粉碎加密:
最后对比一下:
加载部分,为了实现可执行程序不落盘,我们在解密可执行文件之后,会创建内存文件:memfd,我们执行使用 Syscall(MFD_CREATE, ...)
,并将解密后的文件写入。
一切准备就绪,使用 syscall.StartProcess
启动进程。
整个过程不会对程序的性能或是之后对进程的操作造成影响,同时无论是内鬼还是***拷贝这个加密后的程序或是打包整个执行环境都无法启动。
为了达到其他的安全特性,我们增加了执行程序的权限控制(也可以在注册APPID时填写,默认nobody)。
Will 在这里使用了特别的 Ptrace 技巧防止执行中的程序被调试:通过提前进行不影响进程的Ptrace来保护进程不会被其他进程进行Ptrace。
此外我们增加了额外的 DNS 校验,尽可能的确定在我们期望的环境中执行。
并且还增加了通过fsnotify来监控我们的加密后的二进制文件是否被write/remove。
然后还抓紧时间用很久都不用的bootstrap画了个前端,用来查看我们的一些基本信息:
APP INFO:
ALERT INFO:
这里我们可以看到我们保护的ELF是否正常启动,是否有异常操作等等。
4
进阶
看似一切都符合我们的期待,此时比赛还剩下大约12小时时间,功能已经都实现,然而这时 Will 发现 memfd 依旧可能会被读取,我们的一番操作可能只是提高了***者的门槛。为了保护在内存中的可执行程序,Will 决定增加一个 Agent 保护 /proc/ 文件树,并自制内核模块利用 fsnotify 确保可执行程序在装载后不会被探测或是破坏。
主要思路是通过一个内核驱动来Hook fsnotify,如果发现有进程读去我们需要保护的目录,则从Kernel来kill掉他。
这里坑还是很多的,小BUG不断,虽然勉强达到了我们预期的功能,但是很遗憾的是最后路演阶段出了BUG没有演示成功。这里是效果图:
经过一宿奋战后,具备更强保护能力的 KAP 诞生了,我们顺利完成了比赛的其他要求,包括写一个说明 slide 和准备演示环境,并在路演之后,意外的获得了一等奖,抱着一等奖牌的 Will 暂时忘记了困倦。比赛结束,我们结束了我们第一次 hackathon。
KAP 的项目地址:KAP: https://github.com/AlkenePan/KAP ,目前 KAF 还处在原型阶段,欢迎与我们一起完善这个项目,也欢迎其他项目借鉴我们。
最后非常感谢Go中国社区举办的这次Hackathon!看到了许许多多充满想法的Gopher的精彩的项目,我们收获良多。
有疑问加站长微信联系(非本文作者)