红日代码审计项目
今天跟着红日团队的php审计项目,试着做了一下anchor的代码审计,整体还算比较简单,漏洞触发点是在404.php里面.
<!--more-->
大概算是黑盒的东西
也就是当网站访问一个不存在的连接时,404页面会直接将错误回显在页面上,如下图:
那么既然输入的错误信息能够直接回显在页面上,那么又是否存在xss?接下来进行验证:
大概算是白盒的东西
发现存在xss,我们下一步就是看看问题出在哪,首先找到回显404.php的代码
通过猜测名,以及黑盒的实际效果来看,似乎这个current_url()函数是获得我们当前url中最后的路径,然后回显在页面上,这才导致了代码注入的问题.
接着追踪current_url()这个函数:
这个函数调用了url类里的current()方法,下面这个是类中current()方法的源码:
而这个方法则是主要调用了detect()方法,这个方法首先创建了$server对象,其实就是获得$_SERVER数组,然后将需要获得参数,以数组的形式,用foreach循环控制查询,随后获得数组中每个值,所对应的$_SERVER键值的内容,然后进行过滤.首先利用filter_var()函数进行初步过滤,这个函数是通过php本身已经定义好的内,进行过滤,第一步过滤的是
如果我们注入了script标签,这里会保留所有的内容,接着利用parse_url()进行解析,并指定了返回的内容,举个例子:
<?php
$a=parse_url("http://example.com/index.php/<script>alert('xss')</script>",PHP_URL_PATH);
var_dump($a);
?>
//回显为:string(40) "/index.php/<script>alert('xss')</script>"
也就是说这里只是将我们的相对路径,传递给format()函数,进行格式化,format函数代码及其所调用的其他函数如下:
format()又进行了一次过滤,但这个过滤和第一次过滤是类似的,并没有过滤'>','<'这两个xss常用的符号,因此脏数据依然得以保留,随后开始remove_script_name(),然而我们传入的url会因为含有index.php,是的判断if条件成立,因此使用substr()进行index.php之后的截取,然后再传入remove_relative_uri(),这个函数作用,在这里只是过滤首位的'\'而已,因此xss标签被保留下来,从而成功注入页面上.
有关遗留的ctf题,源码奉上:
index.php
<?php
$url = $_GET['url'];
if(isset($url) && filter_var($url, FILTER_VALIDATE_URL)){
$site_info = parse_url($url);
var_dump($site_info);
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{
show_source(__FILE__);
echo "<center><h1>Just curl sec-redclub.com!</h1></center><br>
<center><h3>For example:?url=http://sec-redclub.com</h3></center>";
}
flagi3hEre.php:
<?php
$flag = "HRCTF{f1lt3r_var_1s_s0_c00l}"
?>
这道题做的时候原本以为和之前的博客写的一样是利用parse_url()和curl()不同的解析顺序用两个@@绕过的,后来发现不是,即使我知道flag文件的名字,但如果直接运行一样是得不到flag的,因此需要绕过校验,进行命令执行.
这里首先是通过filter_var()函数的校验,这个函数后面跟的关键词是看是不是有效的url,按照url的格式去解析,举个例子,加深一下对这个函数的理解吧:
返回为true
返回为true
返回为false
也就意味着filter_var()函数,设置参数为'FILTER_VALIDATE_URL',只对http://进行简单校验,其余未知协议校验则不会那么严格.
--->filter_var()透过构造除http以外的内容进行绕过
第二个是正则匹配的问题,前面首先会经过parse_url()的拆分,这个函数会将url的各部分拆解开返回一个数组,该函数只是简单的对每个部分的标志进行分隔,举个例子,大家就知道了,再奇怪的url,parse_url()也会尽可能的去解析.
就这么一个奇怪的url,parse_url也是照样解析,注意parse_url()判断的标志,分别是'/'和'?',因此可以构造恶意数据进行绕过,我们只需要在'//'后带上sec-redclub.com,即可绕过正则;
接着就是最关键的一步命令执行了,可以参考命令执行的各种姿势这篇文章,大致提炼一下这里需要的内容就是,linux下,命令间可以用';'进行分隔,因此,这里构造payload
?url=hello://";ls;"sec-redclub.com
经过拼接后,exec()里的内容就变成了
curl "";ls;"sec-redclub.com"
curl执行的url为空,随后执行ls命令,最后又因为"sec-redclub.com" /bash中不存在该命令是不会执行的,最后回显结果为:
接着我们来读flag文件,这里cat不能使用' '分隔,因为这样不能通过filter_var()的校验,需要改成"<"
最后结果:
----------------the end-------------