根據紅日安全寫的文章,學習PHP代碼審計審計的第二節內容,題目均來自PHP SECURITY CALENDAR 2017,講完這個題目,會有一道CTF題目來進行鞏固,外加一個實例來深刻分析,想了解上一篇的內容,能夠點擊這裏:PHP代碼審計01之in_array()函數缺陷
下面咱們開始分析。javascript
下面來看第一題,代碼以下:php
<?php require 'vendor/autoload.php'; class Template{ private $twig; public function __construct() { //這裏是第一次過濾 $indexTemplate = 'img'.'src="https://loremflickr.com/320/240">'. '<a href="{{link|escape}}">Next slide »</a>'; $loader = new Twig\Loader\ArrayLoader([ 'index.html'=>$indexTemplate ]); $this->twig = new Twig\Environment($loader); } public function getNexSlideUrl(){ $nexSlide = $_GET['nexSlide']; //這裏是第二次過濾 return filter_var($nexSlide,FILTER_VALIDATE_URL); } public function render(){ echo $this->twig->render( 'index.html', ['link'=>$this->getNexSlideUrl()] ); } } (new Template())->render(); ?>
這一關用的是PHP的一個模板引擎Twig,考察的是XSS漏洞,也就是跨站腳本攻擊。雖然程序使用了escape和filter_var()兩個過濾方法,可是。仍是能夠被繞過的。下面咱們看第一處過濾,在上面代碼的第10行,使用Twig模板引擎定義的escape過濾器來過濾link。而escape過濾器默認狀況下,它使用HTML轉義策略,也就是escape將PHP本機htmlspecialchars函數用於HTML轉義策略,如今咱們看一下PHP手冊,htmlspecialchars函數是如何定義的。
其實就是把一些預約義字符轉換成HTML實體。具體看下錶:
下面咱們來看第二處過濾,是在上面代碼第20行,是用filter_var()來進行過濾,下面咱們來看看PHP手冊對這個函數的定義:
具體參數設置以下表:
上面代碼是用了FILTER_VALIDATE_URL,把值做爲 URL 來驗證。這個函數過濾其餘的參數設置說明,以下:html
經過對兩個過濾器的瞭解,咱們想一想該如何繞過呢?,其實,這裏能夠經過JavaScript僞協議來繞過,爲了更好的理解,這裏寫一小段簡單的代碼。java
$url = filter_var($_GET['url'],FILTER_VALIDATE_URL); var_dump($url); $url = htmlspecialchars($url); var_dump($url); echo "<a href='$url'>測試一下</a>";
下面咱們構造payload,用JavaScript僞協議來繞過,payload爲:javascript://test%250aalert(1)
,而後執行以下圖:
其實上面payload中,//後面的內容全是註釋的內容,那爲何仍是會被執行呢?由於在上面的payload用了%0a,%進行了編碼,成了%25,這是換行符,因此執行了我們的彈窗。web
經過上面的分析,是否是對filter_var()函數有了必定的瞭解呢,讓我們用一道CTF的題目來鞏固一下吧。這道題也是由於filter_var被繞過,致使命令執行。看下面代碼。正則表達式
<?php $url = $_GET['url']; //檢查是不是合法的URL if (isset($url)&&filter_var($url,FILTER_VALIDATE_URL)) { $site_info = parse_url($url); //正則判斷 if (preg_match('/test.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 test.com.com!</h1></center><br> <center><h3>For example:?url=http://test.com.com</h3></center>"; } ?>
如今分析上面的代碼,GET接收url參數,而後用filter_var檢查是否爲合法的URL,接着走到下面的代碼,正則判斷結尾必須還有test.com。
而後用了exec函數,看到它咱們嘴就有了笑容,由於只要咱們繞過上面兩處檢查,咱們就能夠隨心所欲,命令執行了。而上面咱們分析了,可使用僞協議來繞過filter_var的檢查,至於正則判斷,只要咱們結尾包含test.com,就繞過了正則檢查。
如今咱們設置payload:javascript://123";ls;"test.com
僞協議繞過了filter_var檢查。結尾繞過了正則判斷,當與exec函數拼接後就造成了三條命令數組
javascript://";cat<flag.php;"test.com
//查看目錄 javascript://";dir;"test.com //查看文件 javascript://";type=flag.php;"test.com
經過上面的題目和CTF練習,是否是感受正到勁頭了,下面我們分析實例,是Anchor 0.9.2版本,在這個版本中,當用戶訪問一個不存在的url時,程序會調用404模板,而這個模板存在XSS漏洞。如今我們來仔細分析。下面看代碼:
如今咱們打開themes\default\404.php文件
看第六行,接下來咱們搜索這個函數,發現它在anchor\functions\helpers.php文件中,並看到current_url是由Uri類的current方法實現的,以下圖:安全
下面咱們跟進Uri類,是在system\Uri.php文件中,以下圖:curl
發現這裏調用了static::detect()方法,( static:: 是在PHP5.3版本以後引入的延遲靜態綁定寫法)
detect()方法就在下方,具體代碼以下圖:ide
detect()方法會獲取$_SERVER數組中的REQUEST_URI, PATH_INFO, ORIG_PATH_INFO鍵值,若是存在其中一個鍵,而且符合filter_var($uri, FILTER_SANITIZE_URL)和parse_url($uri, PHP_URL_PATH)則直接將$uri傳入format()方法中。如今咱們跟進這個方法。就在下邊,如圖:
發現程序過濾了三次,看截圖130行到136行。可是沒有對XSS進行過濾。下面咱們來構造payload。
如今咱們構造payload:localhost/anchor/index.php/<script>alert("XSS")</script>
如今結合上面的講解來分析,當咱們訪問這個不存在的url時,程序會調用404模板頁面,而後調用current_url()函數來獲取當前文件名,也就是我們構造的<script>alert("XSS")</script>
,嵌入了進去,找成XSS攻擊。效果以下圖:
經過上面的分析,是否是對filter_var()函數理解更深了呢?下一篇文章會對實例化任意對象漏洞進行學習和分析,一塊兒努力吧!