自動化檢測CSRF(第一章)
前言:
之前寫過自動化檢測XSS插件,今天來一發自動化檢測CSRF的插件。CSRF有多種情況的出現方式,而本章所說的內容沒有辦法做的那麼全面,就比如JSON Hijacking(第二章或者第三章會寫),本章我們就說說form表單導致的CSRF漏洞。
檢測form表單類型的CSRF漏洞和檢測form表單類型的XSS漏洞最大的不同就是:XSS需要提交才能檢測到,而CSRF只需要分析form表單就行了。
前期的準備工作:
既然要寫,那麼我們就需要demo來幫我們模擬真實環境的下的情況,而0×00節就說明了,本章只針對於form表單,所以我們的demo也就是各式各樣的表單。如下圖:
基本上來說網上常見的表單類別都包含了,當然如果你發現有些表單沒有加入進去,請說明一下,我將會在下一版中修改。
我們先遍歷整個網頁上的form表單。代碼如下:
outerFor:nfor(var i = 0;i < $("form").length;i++){n var formDom = $("form").eq(i); //formDom代表本次循環的form表單元素n var imageFileSuffix = [.jpg,.png,.jpge,.ico,.gif,.bmp]; //圖片後綴白名單,用戶驗證圖片是否為驗證碼n var placeholderFilterKeyword = [跳,搜,查,找,登陸,註冊,search]; //無用表單黑名單,用於驗證這個form表單有沒有用(針對input驗證)n var actionFilterKeyword = [search,find,login,reg]; //無用表單黑名單,用於驗證這個form表單有沒有用(針對form表單驗證)n}n
至於為什麼要加上outerFor:,是因為這只是最外層的for循環,裡面還有for循環,為了方便我們在最裡層的for循環里跳出最外層的本次循環。在最裡層的for循環里我會使用continue outerFor;來跳出最外層for的本次循環。(如果沒有看懂,請返回上一行重新看,這很重要)
去除類似搜索、頁面跳轉等無用的form表單:
首先我們需要假象一下有沒有特殊的form表單,比如沒有action屬性,把請求交給JavaScript來完成。而這種特殊的form表單也很常見,所以這裡我就先使用if判斷action是否存在:
if(formDom.attr("action") != undefined){n //當action不為空的時候,進行下一步的操作n}n
然後就是使用JavaScript的some函數來對action進行判斷,當action里的值滿足於我們之前設置的黑名單里的字元串時,就直接pass,使用continue來跳出初始化表達式變數為i的本次循環。轉化成代碼就是下面這樣:
if(formDom.attr("action") != undefined){n var actionCheck = actionFilterKeyword.some(function(item,index){n return (formDom.attr("action").toLowerCase().indexOf(item) != "-1");n })n if(actionCheck){n continue;n }n}n
如果對some函數不明白的,請移步:Some函數詳解
而在JavaScript里是嚴格區分大小寫的,所以在上面的代碼中我使用了toLowerCase()函數,來把action里的值全部轉化成小寫,然後在其中搜索之前設置的action黑名單,看是否存在。而對比過程如下:
action的值–search(如果此次比對為true,則不會向下進行比對)
action的值–find
……
其返回的結果是布爾型。在《JavaScript高級程序設計》里是這樣說明some函數的: 對數組中的每一項運行給定函數,如果該函數對任意一項返回true,則返回true。
這個時候我們可以看到some前面有一個變數。因為some返回的是布爾型,那麼actionCheck變數也是一個布爾型,假設當前這個form表單里的action的值為」/searchArticle.php」。那麼就會匹配到黑名單里的search字元串,那麼some就會停止向下循環,直接返回true。
如下圖:
然後使用if判斷actionCheck變數。如果為true,那麼就使用continue來跳出當前的循環,不向下運行,直接開始下一個循環。
OK,上面的已經完成對form的action屬性過濾了,那麼下面的將對input進過白名單過濾。
for(var x = 0;x < formDom.find(":text").length;x++){n var inputTextCheck;n var inputText = formDom.find(":text").eq(x);n if(inputText.attr("placeholder") == undefined){n continue;n }n inputTextCheck = placeholderFilterKeyword.some(function(item,index){n return (inputText.attr("placeholder").toLowerCase().indexOf(item) != "-1");n })n if(inputTextCheck){n continue outerFor;n }n}n
首先使用(「:text」)來遍歷當前form表單下所有type為text的input標籤。
inputTextCheck變數是為了存放some函數的布爾結果。而inputText變數代表了當前的input標籤。
然後使用if判斷當前input里的placeholder屬性是否存在,如果不存在,則跳出初始化表達式變數為x的本次循環。不向下運行,且對下一個input標籤進行之前的操作。如果存在且有值的話,if里的表達式會返回false。則這個if判斷不會運行,而是向下運行,而代碼:
inputTextCheck = placeholderFilterKeyword.some(function(item,index){n return (inputText.attr("placeholder").toLowerCase().indexOf(item) != "-1");n})nif(inputTextCheck){n continue outerFor;n}n
和之前判斷action的情況的是一樣的,這裡就不在闡述了。
去除沒有提交按鈕的form表單:
為什麼要寫這個,因為有些form表單不是給用戶使用的,他沒有提交按鈕。對用戶來說也是不可見狀態。而且也不涉及較為核心的操作,那麼我們就需要把這個表單剔除掉。代碼如下:
if(formDom.find(":submit").length < 1){n continue;n}n
這段代碼較為簡單,這裡也不在闡述了。
去除具有token的form表單:
大家都知道對於CSRF來說,具有token的form表單基本是可以斷定是不存在CSRF漏洞的了,當然排除同頁面存在XSS漏洞和CSRF漏洞。
而token,我們應該怎麼樣發現呢?type為hidden?name包含token?,不不不。這些都不準確,沒辦法減少誤報和擴大結果。那我們應該怎麼做呢?判斷type為hidden的input標籤里的value值的長度是否大於10。
具有token功能的input標籤的特殊性:
type為hidden
為了安全起見,token一般是不會小於10位數的。
總是以input標籤為媒介的方式傳輸給後端伺服器中。
OK,那麼我們可以遍歷當前form表單下所有type為hidden的input標籤,再判斷value值是否大於10。如果大於10,說明這個表單很大程度上是具有token驗證的表單,將會被程序丟棄。跳出初始化表達式變數為i的本次循環。把上面的話轉化成代碼就是下面這樣:
for(var j = 0;j < formDom.find(":hidden").length;j++){n if(formDom.find(":hidden").eq(j).val().length > 10){n continue outerFor;n }n}n
程序不複雜,複雜的思路。所以這裡看起來代碼其實也了沒多少,而且相當的簡單。所以這裡就不對代碼進行闡述了。
去除帶有驗證碼的form表單:
有了之前寫自動化檢測XSS項目的經驗,這裡思路就清晰多了。獲取img的src屬性里的值,判斷後綴是否為圖片格式。代碼如下:
if(formDom.find("img").length > 0){n var imageCheck;n for(var z = 0;z < formDom.find("img").length;z++){n var img = formDom.find("img").eq(z);n var imgSrc = img.attr("src")n if(!!imgSrc){n if(imgSrc.indexOf("?") != "-1"){n imgSrc = imgSrc.slice(0,imgSrc.indexOf("?"));n }n imgSrc = imgSrc.substr(imgSrc.lastIndexOf("."),imgSrc.length);n imageCheck = imageFileSuffix.some(function(item,index){n return (imgSrc == item);n })n if(!imageCheck){n continue outerFor;n }n }n }n}n
首先使用formDom.find(「img」).length來判斷當前的form表單里是否存在圖片,如果存在,那麼if判斷會返回true。進入if判斷裡面後,首先是一個變數,而這個變數是存放some函數返回的布爾結果的。
然後就是一個for循環,對當前form表單里的img表單進行遍歷。而變數img代表了當前的img標籤。而imgSrc變數代表了當前img標籤里的src。
下面是一段if代碼if(!!imgSrc)為什麼要這樣寫呢,是強制把imgSrc變數轉成布爾型的,如果當前這個img標籤是不存在src屬性或沒有值的情況下,將會返回false,如果存在src且有值的情況下會返回true。
而下面的代碼的是為了剔除?後面的字元串:
if(imgSrc.indexOf("?") != "-1"){n imgSrc = imgSrc.slice(0,imgSrc.indexOf("?"));n}n
為什麼要寫這樣的代x』z碼呢?原因很簡單,未來防止驗證碼圖片被瀏覽器緩存,需要再後面跟上問號和隨機數字,來達到每刷新一次,就會重新請求這個圖片。防止瀏覽器緩存圖片。
而imgSrc = imgSrc.substr(imgSrc.lastIndexOf(「.」),imgSrc.length);這段代碼是剔除,除了後綴之外所有的字元串。只保留後綴。舉個例子,有段img標籤是這樣寫的:
<img src=」https://wwww.baidu.com/code.php?rand=458711541「>,而運行上面的代碼後,結果只有.php了,剩下的字元串已經被剔除掉了。
而下面的some函數,和之前是一樣的,不做闡述。只是if裡面的表達式里多了一個!取反感嘆號。為什麼要這樣寫呢。因為之前的都是黑名單的形式,而這裡的白名單的形式,既然是相反的,那麼就使用!取反就行了。
其他:
整套代碼如下:
outerFor:nfor(var i = 0;i < $("form").length;i++){n var formDom = $("form").eq(i);n var imageFileSuffix = [.jpg,.png,.jpge,.ico,.gif,.bmp];n var placeholderFilterKeyword = [跳,搜,查,找,登陸,註冊,search];n var actionFilterKeyword = [search,find,login,reg];n //去除類似搜索、頁面跳轉等無用的form表單n if(formDom.attr("action") != undefined){n var actionCheck = actionFilterKeyword.some(function(item,index){n return (formDom.attr("action").toLowerCase().indexOf(item) != "-1");n })n if(actionCheck){n continue;n }n }n for(var x = 0;x < formDom.find(":text").length;x++){n var inputTextCheck;n var inputText = formDom.find(":text").eq(x);n if(inputText.attr("placeholder") == undefined){n continue;n }n inputTextCheck = placeholderFilterKeyword.some(function(item,index){n return (inputText.attr("placeholder").toLowerCase().indexOf(item) != "-1");n })n if(inputTextCheck){n continue outerFor;n }n }n //去除沒有提交按鈕的form表單n if(formDom.find(":submit").length < 1){n continue;n }n //去除具有token的form表單n for(var j = 0;j < formDom.find(":hidden").length;j++){n if(formDom.find(":hidden").eq(j).val().length > 10){n continue outerFor;n }n }n //去除帶有驗證碼的form表單n if(formDom.find("img").length > 0){n var imageCheck;n for(var z = 0;z < formDom.find("img").length;z++){n var img = formDom.find("img").eq(z);n var imgSrc = img.attr("src")n if(!!imgSrc){n if(imgSrc.indexOf("?") != "-1"){n imgSrc = imgSrc.slice(0,imgSrc.indexOf("?"));n }n imgSrc = imgSrc.substr(imgSrc.lastIndexOf("."),imgSrc.length);n imageCheck = imageFileSuffix.some(function(item,index){n return (imgSrc == item);n })n if(!imageCheck){n continue outerFor;n }n }n }n }n console.log(formDom)n}n
這裡的console.log(formDom)可以改為ajax等方式發包,或者alert直接提醒此頁面可能具有csrf漏洞。至於如何使用,需要大夥手工打包成瀏覽器插件的形式。而這裡我為大家附上我之前寫的自動化檢測XSS的插件:網盤。大家可以直接解包,修改裡面的JavaScript代碼為上面完整的代碼,再重新打包就行了。
文章呢,還有很多地方不足。而這套程序還只能說是雛形,所以我沒有附上直接利用的工具給大家,也是第一次這樣。而且有很多地方沒有考慮到,比如JSON Hijacking檢測。當然下一章會完成的,也會放出可以直接利用的工具。第二章或者第三章可能會把之前寫的XSS自動化檢測與本章所說的自動化檢測CSRF相結合起來。畢竟XSS+CSRF的危害是非常大的。
推薦閱讀:
※黑客入侵Edmodo教育平台,竊取超7千萬教師、學生和家長賬戶信息
※滲透測試中搜集AD域信息的常用PS命令
※什麼是對抗攻擊?
※恆星幣也被黑客盯上了,價值40多萬美元的恆星幣被盜
※Bypass WAF:使用Burp插件繞過一些WAF設備