黑客与宕机-阿里云开发者社区

开发者社区> 声东> 正文

黑客与宕机

简介: 宕机问题有一种比较少见的pattern,就是看起来完全不相关的机器同时出现宕机。处理这个pattern的问题,我们需要找到,在这些机器上能同时触发问题的条件。 通常,这些机器要么几乎在同一时间点出现问题,要么从某一个时间点开始,相继出现问题。
+关注继续查看

宕机问题有一种比较少见的pattern,就是看起来完全不相关的机器同时出现宕机。处理这个pattern的问题,我们需要找到,在这些机器上能同时触发问题的条件。

通常,这些机器要么几乎在同一时间点出现问题,要么从某一个时间点开始,相继出现问题。对于前一种情况,比较常见的情形是,物理机故障导致运行在其上的所以虚拟机宕机,或者一个远程管理软件同时杀死了所有被管理的系统里的关键进程;对于后一种情况,可能的一个原因是,用户在所有实例上部署了同一个有问题的模块(软件、驱动)。

而实例被大范围的hack,则是另一个常见的原因。在WannaCry病毒肆虐的时候,经常出现一些公司,或者一些部门的机器全部蓝屏的情形。今天跟大家分享一例这样的问题。

坏掉的内核栈

使用crash工具sys命令,我们可以看到系统的一些基本信息,和宕机的直接原因。对于这个问题来说,宕机的直接原因是"Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffffffa02987eb"。关于这条信息,我们必须逐字解读。"Kernel panic - not syncing:"这部分内容在内核函数panic里输出,凡是调用到panic函数,必然会有这一部分输出,所以这一部分内容和问题没有直接关系。而"stack-protector: Kernel stack is corrupted in:"这部分内容,在内核函数__stack_chk_fail,这个函数是一个堆栈检查函数,它会检查堆栈,同时在发现问题的时候调用panic函数产生core dump报告问题。而它报告的问题是堆栈损坏。关于这个函数,后续我们会跟进一步分析。
d67a97d54e5ea127575203dd3e7e9a30e65812c0
而ffffffffa02987eb这个地址,是函数__builtin_return_address(0)的返回值。当这个函数的参数是0的时候,这个函数的输出值是调用它的函数的返回地址。这句话现在有点绕,但是后续分析完调用栈,会很清楚。

函数调用栈

分析宕机问题的核心,就是分析panic的调用栈。下边的调用栈,乍看起来是system_call_fastpath调用了__stack_chk_fail,然后__stack_chk_fail调用了panic,报告了堆栈损坏的问题。但是稍微和类似的堆栈做一点比较的话,就会发现,事实并非这么简单。
b3ca37db8a7985d926e6366417f489049611a673
下边是一个类似的,以system_call_fastpath函数开始的调用栈,不知道大家有没有看出来这个调用栈和上边调用栈的不同。实际上,以system_call_fastpath函数开始的调用栈,表示这是一次系统调用(system call)的内核调用栈。下图中的调用栈,表示用户模式的进程,有一次epoll的系统调用,然后这个调用进入了内核模式。而上图中的调用栈显然是有问题的,因为我们就算查遍所有的文档,也不会找到一个系统调用,会对应于内核__stack_chk_fail函数。
5bbb1deb2cab3847046ee0e31474dc14007bccdd
提示:这边引出另外一个,在分析core dump的时候需要注意的问题,就是用bt打印出来的调用栈有的时候是错误的。

Raw stack

所谓的调用栈,其实不是一种数据结构。用bt打印出来的调用栈,其实是从真正的数据结构,线程(内核)堆栈中,根据一定的算法重构出来的。而这个重构过程,其实是函数调用过程的一个逆向工程。相信大家都知道堆栈的特性,先进后出。关于函数调用,以及堆栈的使用,可以参考一下下边这张图。大家可以看到,每个函数调用,都会在堆栈上分配到一定的空间。而CPU执行每个函数调用指令(call),都会顺便把这条call指令的下一条指令压栈。这些“下一条指令”,就是所谓的函数返回地址。
35cb5f4c6ce21eb56aaf0e26381a90aa8ccbb85e
这个时候,我们再回头看Panic的直接原因那一部分,函数__builtin_return_address(0)的返回值。这个返回值,其实就是调用__stack_chk_fail的call指令的下一条指令,这条指令属于调用者函数。这条指令地址被记录为ffffffffa02987eb。我们用sym命令查看这个地址临近的函数名,显然这个地址不属于函数system_call_fastpath,也不属于内核任何函数。这也再次验证了,panic调用栈是错误的这个结论。
5dd11af2785cfbeedc00942f32653af09f0c0940
关于raw stack,我们可以用bt -r命令来查看。因为raw stack往往有几个页面,这里只截图和__stack_chk_fail相关的这一部分内容。
a352affae36645207f80e86c3b339593d637eef3
这部分内容,有三个重点数据需要注意,panic调用__crash_kexec函数的返回值,这个值是panic函数的一条指令的地址;__stack_chk_fail调用panic函数的返回值,同样的,它是__stack_chk_fail函数的一条指令的地址;ffffffffa02987eb这个指令地址,属于另外一个未知函数,这个函数调用了__stack_chk_fail。

Syscall number & Syscall table

因为带有system_call_fastpath函数的调用栈,对应着一次系统调用,而panic的调用栈是坏的,所以这个时候我们自然而然会疑问,到底这个调用栈对应的是什么系统调用。在linux操作系统实现中,系统调用被实现为异常。而操作系统通过这次异常,把系统调用相关的参数,通过寄存器传递到内核。在我们使用bt命令打印出调用栈的时候,我们同时会输出,发生在这个调用栈上的异常上下文,也就是保存下来的,异常发生的时候,寄存器的值。对于系统调用(异常),关键的寄存器是RAX,它保存的是系统调用号。我们先找一个正常的调用栈验证一下这个结论。0xe8是十进制的232。
872193cd4e392c1de1560312346e14bef4338f03
使用crash工具,sys -c命令可以查看内核系统调用表。我们可以看到,232对应的系统调用号,就是epoll。
a045a18309bdf445f8f8cb5e7d54700c6d5a2f34
这个时候我们再回头看“函数调用栈”这节的插图,我们会发现异常上下文中RAX是0。正常情况下这个系统调用号对应read函数,如下图。
52ae282e637a316ecc0da7b767f3d1c13517173b

如下图,有问题的系统调用表显然是被修改过的。修改系统调用表(system call table)这种事情,常见的有两种代码会做(这个相当辩证),一种是杀毒软件,而另外一种是hack程序。当然还有另外一种情况,就是某个蹩脚的内核驱动,无意识的改写了系统调用表。

f151564d12e20dea33380e97fb969f3bc8c2418e

另外我们可以看到,被改写过的函数的地址,显然和最初被__stack_chk_fail函数报出来的地址,是非常邻近的。这也可以证明,系统调用确实是走进了错误的read函数,最终踩到了__stack_chk_fail函数。

Raw data

基于上边的数据,来下结论,总归还是有点经验主义。更何况,我们甚至不能区分,问题是由杀毒软件导致的,还是木马导致的。这个时候我们花费了比较多的时间,尝试从core dump里挖掘出ffffffffa02987eb这个地址更多的信息。有一些最基本的尝试,比如尝试找出这个地址对应的内核模块等,但是都无功而返。这个地址既不属于任何内核模块,也不被已知的内核函数所引用。这个时候,我们做了一件事情,就是把这个地址前后连续的,所有已经落实(到物理页面)的页面,用rd命令打印出来,然后看看有没有什么奇怪的字符串可以用来作为特征串定位问题。

5d46eb66186531d078c52503563d2ea6fc274996

就这样,我们在邻近地址发现了下边这些字符串。很明显这些字符串应该是函数名。我们可以看到hack_open和hack_read这两个函数,对应被hacked的0和2号系统调用。还有函数像disable_write_protection等等。这些函数名,显然说明这是一段“不平凡”的代码。公网搜索这些函数会发现很多rootkit的示例。

后记

宕机问题的core dump分析,需要我们非常的耐心。我个人的一条经验是:every bit matters,就是不要放过任何一个bit的信息。core dump因为机制本身的原因,和生成过程中一些随机的因素,必然会有数据不一致的情况,所以很多时候,一个小的结论,需要从不同的角度去验证。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
使用NAT网关轻松为单台云服务器设置多个公网IP
在应用中,有时会遇到用户询问如何使单台云服务器具备多个公网IP的问题。 具体如何操作呢,有了NAT网关这个也不是难题。
26788 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10072 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13882 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
9157 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
4659 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
4502 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
7363 0
+关注
声东
来自阿里云售后技术团队,系统专家,专注操作系统调试,内核调试。
9
文章
0
问答
来源圈子
更多
作为全球云计算的领先者,阿里云为全球230万企业提供着云计算服务,服务范围覆盖200多个国家和地区。我们致力于为企业、政府等组织机构提供安全可靠的云计算服务,给用户带来极速愉悦的服务体验。
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载