浅析php的正则表达式

Posted 网络空间安全社

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅析php的正则表达式相关的知识,希望对你有一定的参考价值。


在日常的代码审计中,最常见的就是一般的漏洞语句和一些正则表达式,因此在水平达到了一定境界后,我们需要对正则表达式进行一个理解,尝试突破正则这层防线,在百度后发现很少会有实战方面的正则表达式浅析,因此开下这篇,也算为新手在代码审计路上作一个指引!

一、php正则基础

这部分基本是参照的别人的文章,由于是基础,因此不做赘述,但是这是正则匹配的基础!


1.元字符

$ 匹配输入字符串的结尾位置。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \)。
* 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。
. 匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列 ‘\\’ 匹配 “\”,而 ‘\(‘ 则匹配 “(“。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。

2.限定符

限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有*或+或?或{n}或{n,}或{n,m}共6种。

3.字符描述

* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,’zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,”do(es)?” 可以匹配 “do” 或 “does” 中的”do” 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,’o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,’o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。’o{1,}’ 等价于 ‘o+’。’o{0,}’ 则等价于 ‘o*’。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,”o{1,3}” 将匹配 “fooooood” 中的前三个 o。’o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。

4.字符

用来描述字符串或单词的边界,^和$分别指字符串的开始与结束,\b描述单词的前或后边界,\B表示非单词边界。不能对定位符使用限定符。

可以使用字符类指定字符列表以匹配正则表达式中的一个位置。使用方括号([ 和 ])定义字符类。例如,下面的正则表达式定义了匹配 bag、beg、big、bog 或 bug 的字符类:


1

/b[aeiou]g/

使用连字符指定字符的范围,例如 A-Z、a-z 或 0-9。这些字符必须在字符类中构成有效的范围。例如,下面的字符类匹配 a-z 范围内的任何一个字符或任何数字:


1

/[a-z0-9]/

如果在字符类的开头使用尖号 (^) 字符,则将反转该集合的意义,即未列出的任何字符都认为匹配。下面的字符类匹配除小写字母 (a-z) 或数字以外的任何字符:


1

/[^a-z0-9]/

最后附上一些特殊方式


1

2

3

4

5

6

7

. 匹配除换行符以外的任意字符

\w 匹配字母或数字或下划线或汉字 等价于 '[^A-Za-z0-9_]'

\s 匹配任意的空白符

\d 匹配数字

\b 匹配单词的开始或结束

匹配中文字符的正则表达式: [\u4e00-\u9fa5]

匹配双字节字符(包括汉字在内)[^\x00-\xff]

二、php正则匹配实例


1

2

3

4

5

6

<?php

$str = 'a1234';

if (preg_match("^[a-zA-Z0-9]{4,16}$", $str)) {

echo "验证成功";} else {

echo "验证失敗";}

?>

这里匹配的原则:只含数字和字母(大小写均可),并且长度为4-16。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

评注:匹配形式如 0511-4405222 021-87888822

 

匹配腾讯QQ号:[1-9][0-9]{4,}

评注:腾讯QQ号从10000开始

 

匹配中国邮政编码:[1-9]\d{5}(?!\d)

评注:中国邮政编码为6位数字

 

匹配身份证:\d{15}|\d{18}

评注:中国的身份证为15位或18

 

三、代码审计中的正则表达式


1

$pregs = '/select|insert|update|CR|document|LF|eval|delete|script|alert|\'|\/\*|\#|\--|\ --|\/|\*|\-|\+|\=|\~|\*@|\*!|\$|\%|\^|\&|\(|\)|\/|\/\/|\.\.\/|\.\/|union|into|load_file|outfile/';

这是一个最常见的防sql注入的正则,现在我们可以来对这个正则进行分析。

首先是’/注入代码/’这种格式,我们下面来对注入代码进行分析,首先是select、insert等常见的注入语句,这里解释一下CR,这个是回车控制符,这里就不得不说CRLF注入漏洞,因此过滤CR也是非常有必要的!

下面来看到|\’|,这里|起的是或者的作用,这个不多说,如果看过前面的基础教学,那么就一定知道这里的\起的是转义作用,因为’是特殊字符,对于这些特殊字符的匹配,需要使用转义字符\来进行转义!

那么下面很多的匹配模式都是如此,就比如说\/\*,这里在匹配的时候除去转义字符,那么就剩下/*,这里最常见的可能就是内联注释/*!50000*/,因此通过这种硬匹配也能作一层过滤。

这里提到防注入,不得不从攻击者的角度来思考,那就是如何绕过,而其中一种最为常见的绕过手法就是大小写的混淆,但是上面的防注入似乎没有考虑大小写的问题,下面本地搭建环境来测试是否存在问题!


1

2

3

4

5

6

7

<?php

$str = 'sElect';

if (preg_match('/select|insert|update|CR|document|LF|eval|delete|script|alert|\'|\/\*|\#|\--|\ --|\/|\*|\-|\+|\=|\~|\*@|\*!|\$|\%|\^|\&|\(|\)|\/|\/\/|\.\.\/|\.\/|union|into|load_file|outfile/', $str)) {

echo "验证成功";

} else {

echo "验证失敗";}

?>

可以看到的确可以进行大小写的绕过!

那么从开发的角度来写,在正则匹配的时候需要无视大小写,而正则匹配也提供了这个功能:/i


1

2

3

4

$text = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-";

$res = preg_match('/[a-z0-9-]+/i', $text);

echo $res;

//输出1

在匹配模式末尾加入/i,那么就会不区分大小写

下面来分析一个稍微复杂点的正则表达式


1

$getfilter="'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";

首先来看第一个||里的正则,(and|or)\\b.+?(>|<|=|in|like)

这里对应的应该是and 1=1、and 1=2这种案例,(and|or)对应and语句或者or语句,\\b.+?则是匹配的任意数字,后面则是(>|<|=|in|like)这种语句,那么拆分下来其实就是匹配三段内容,第一段就是使用and或者or语句,第二段就是任意数字,第三段就是像<、>或者in、like等判断语句

再举一个例子\\/\\*.+?\\*\\/,这里首先将\\理解为转义字符,那么这里其实就是/*.+?*/,是不是很熟悉?其实就是内联注释/*!50000and*/这种样式。

四、总结

最后作个总结,正则匹配表达式看似很复杂,但是每个符号的应用都是十分固定的,也有一些常见的搭配样式,对于一些十分长的表达式,也不用感到害怕,慢慢看,慢慢学,沉下心来认真看总是会看懂的,!

上述如有不当之处,敬请指出~

 

参考文章:

1.http://www.jb51.net/article/36172.htm

2.http://blog.csdn.net/langjian2012/article/details/28234589


以上是关于浅析php的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式lastIndex属性浅析

浅析正则表达式模式匹配的 String 方法

浅析正则表达式基本语法及应用详解

浅析ReDoS

浅析L2参数正则化的数学含义

PHP 正则表达式总结