不管多么強大的系統總會有那么些安全問題,影響小的可能僅僅只會影響用戶體驗,危害性大點的可能會讓攻擊者獲取到服務器權限。這一節重點是怎樣去找到并利用問題去獲取一些有意思的東西。
有MM的地方就有江湖,有程序的地方就有漏洞。現在已經不是SQL注入漫天的年代了,Java的一些優秀的開源框架讓其項目堅固了不少。在一個中大型的Web應用漏洞的似乎永遠都存在,只是在于影響的大小、發現的難易等問題。有很多比較隱晦的漏洞需要在了解業務邏輯甚至是查看源代碼才能揪出來。JavaWeb跟PHP和ASP很大的不同在于其安全性相對來說更高。但是具體體現在什么地方?JavaWeb開發會有那些問題?這些正是我們今天討論的話題。
通過前面幾章的介紹相信已經有不少的朋友對Jsp、Servlet有一定了解了。上一節講MVC的有說的JSP+Servlet構成了性能好但開發效率并不高的Model2。在JavaWeb開發當中一般會分出很多的層去做不同的業務。
1、展現層(View 視圖)
2、控制層(Controller 控制層)
3、服務層(Service)
4、實體層(entity 實體對象、VO(value?object)?值對象?、模型層(bean)。
5、業務邏輯層BO(business?object)?
6、持久層(dao- Data Access Object 數據訪問層、PO(persistant?object)?持久對象)
在了解一個項目之前至少要知道它的主要業務是什么主要的業務邏輯和容易出現問題的環節。其次是了解項目的結構和項目當中的類依賴。再次才是去根據業務模塊去讀對應的代碼。從功能去關聯業務代碼入手往往比逮著段代碼就看效率高無數倍。
前幾天在Iteye看到一款不錯的生成項目依賴圖的工具- Structure101,試用了下Structure101感覺挺不錯的,不過是收費的而且價格昂貴。用Structure101生成Jeebbs的項目架構圖:
Structure101導入jeebss架構圖-包調用: ?
Structure101包調用詳情:
Structure101可以比較方便的去生成類關系圖、調用圖等。Jeebbs項目比較大,邏輯相對復雜,不過可以看下我的半成品的博客系統。
項目圖:
架構圖:
控制層:
調用流程(demo還沒處理異常,最好能try catch下用上面的logger記錄一下): ?
Eclipse采用的是SWT編寫,俗稱萬能IDE擁有各種語言的插件可以寫。Myeclipse是Eclipse的插件版,功能比eclipse更簡單更強大。
導入Web項目到Myeclipse,Myeclipse默認提供了主流的Server可以非常方便的去部署你的Web項目到對應的Server上,JavaWeb容器異常之多,而ASP、 PHP的容器卻相對較少。容器可能除了開發者有更多的選擇外往往意味著需要調試程序在不同的Server半桶的版本的表現,這是讓人一件非常崩潰的事。
調試開源的項目需下載源碼到本地然后導入部署,如果沒有源代碼怎么辦?一般情況下JavaWeb程序不會去混淆代碼,所以通過之前的反編譯工具就能夠比較輕松的拿到源代碼。但是反編譯過來的源代碼并不能夠直接作用于debug。不過對我們了解程序邏輯和結構有了非常大的幫助,根據邏輯代碼目測基本上也能完成debug。 ?
在上一節已經講過了一個客戶端的請求到達服務器端后,后端會去找到這個URL所在的類,然后調用業務相關代碼完成請求的處理,最后返回處理完成后的內容。跟蹤請求的方式一般是先找到對應的控制層,然后深入到具體的邏輯代碼當中。另一種方法是事先到dao或業務邏輯層去找漏洞,然后逆向去找對應的控制層。最直接的如model1、model2并不用那么費勁直接代碼在jsp、servlet代碼里面就能找到一大堆業務邏輯。
普通的測試一般都是按功能和模塊去寫測試的用例,即按照業務一塊一塊去測試對應的功能。這一種方式是順著了Http請求跟蹤到業務邏輯代碼,相對來說比較簡單方便,而且邏輯會更加的清晰。
上面的架構圖和包截圖不知道有沒有同學仔細看,Java里面的包的概念相對來說比較嚴禁。公認的命名方式是com/org.公司名.項目名.業務名全小寫。
如:org.javaweb.ylog.dao
部署到服務器上對應的文件夾應當是/WEB-INF/classes/org/javaweb/ylog/dao/
其中的.意味著一級目錄。
現在知道了包和分層規范要找到控制層簡直就是輕而易舉了,一般來說找到Controller或者Action所在的包的路徑就行了。左邊是jeebbs右邊是我的blog,其中的action下和controller下的都是控制層的方法。@RequestMapping("/top.do")
表示了直接把請求映射到該方法上,Struts2略有不同,需要在xml配置一個action對應的處理類方法和返回的頁面。不過這暫時不是我們討論的話題,我們需要知道隱藏在框架背后的請求入口的類和方法在哪。 ?
用例圖:
用戶邏輯圖:
容易出現的問題:
1、沒有校驗用戶唯一性。
2、校驗唯一性和存儲信息時拼Sql導致Sql注入。
3、用戶信息(用戶名、郵箱等)未校驗格式有效性,可能導致存儲性xss。
4、頭像上傳漏洞。
5、用戶類型注冊時可控導致注冊越權(直接注冊管理員帳號)。
6、注冊完成后的跳轉地址導致xss。
注冊的URL地址是:http://localhost/jeebbs/register.jspx, register.jspx很明顯是控制層映射的URL,第一要務是找到它。然后看他的邏輯。
根據搜索結果找到對應文件:
根據結果找到對應的public class RegisterAct
類,并查看對應邏輯代碼: ?
找到控制層的入口后即可在對應的方法內設上斷點,然后發送請求到控制層的URL進入Debug模式。 注冊發送數據包時用Tamper data攔截并修改請求當中的email為xss攻擊代碼。 ?
?
選擇任意對象右鍵Watch即可查看對應的值(任意完整的,有效的對象包括方法執行)。 F6單步執行。
?
F5進入validateSubmit:
F6跟到125行注冊調用:
F3可以先點開registerMember類看看:
找到接口實現類即最終的注冊邏輯代碼:
Jeebbs的數據庫結構當中用戶名長度過長:
`username` varchar(100) NOT NULL COMMENT '用戶名'
這會讓你想到了什么?
當用戶名的輸入框失去焦點后會發送Ajax請求校驗用戶名唯一性。請輸入一個長度介于 3 和 20 之間的字符串。也就是說滿足這個條件并且用戶名不重復就行了吧?前端是有用戶名長度判斷的,那么后端代碼呢?因為我已經知道了用戶名長度可以存100個字符,所以如果沒有判斷格式的話直接可以注冊100個字符的用戶名。首先輸入一個合法的用戶名完成客戶端的唯一性校驗請求,然后在點擊注冊發送數據包的時候攔截請求修改成需要注冊的xss用戶名,邏輯就不跟了跟上面的郵箱差不多,想像一下用戶名可以xss是多么的恐怖。任何地方只要出現粗線下xss用戶名就可以輕易拿到別人的cookie。 ?
代碼沒有任何加密就直接setCookie了,如果說cookie明文儲存用戶帳號密碼不算漏洞的話等會彈出用戶明文密碼不知道是算不算漏洞。
因為個性簽名會在帖子里顯示,所以回帖或者發帖就會觸發JS腳本了。這里說一下默認不記住密碼的情況下(不設置cookie)不能夠拿到cookie當中的明文密碼,這個漏洞用來打管理員PP挺不錯的。不應該啊,起碼應該過濾下。
積分兌換方法如下:
@RequestMapping(value = "/member/creditExchange.jspx")
public void creditExchange(Integer creditIn, Integer creditOut, Integer creditOutType, Integer miniBalance, String password, HttpServletRequest request, HttpServletResponse response) {}
可以看到這里直接用了SpringMvc注入參數,而這些參數恰恰是控制程序邏輯的關鍵。比如構建如下URL,通過GET或者POST方式都能惡意修改用戶的積分:
http://localhost/jeebbs/member/creditExchange.jspx?creditIn=26&creditOut=-27600&creditOutType=1&miniBalance=-10000000&password=wooyun
因為他的邏輯是這么寫的:
if(user.getPoint()-creditOut>miniBalance){
balance=true;
}else{
flag=1;
}
從User對象里面取出積分的數值,而積分兌換威望具體需要多少是在確定兌換關系后由ajax去后臺計算出來的,提交的時候也沒有驗證計算的結果有沒有被客戶端改過。其中的creditOut和miniBalance都是我們可控的。所以這個等式不管在什么情況下我們都可以讓它成立。
1、用戶名為空。
2、不允許發送消息給自己。
3、用戶名不存在。
在控制層并沒有做過濾: ?
?
在調用com.jeecms.bbs.manager.impl. BbsMessageMngImpl.java的sendMsg方法的時候依舊沒有過濾。到最終的BbsMessageDaoImpl 的save方法還是沒有過濾就直接儲存了; 一般性的做法,關系到用戶交互的地方最好做referer和xss過濾檢測,控制層負責收集數據的同時最好處理下用戶的請求,就算controller不處理起碼在service層做下處理吧。
http://demo.jeecms.com/search.jspx?q=%2F%3E%3Cscript%3Ealert%28document.cookie%29%3B%3C%2Fscript%3Ehello&channelId=
漏洞N………
SQL注入理論上是最容易找的,因為SQL語句的特殊性只要Ctrl+H 搜索select、from 等關鍵字就能夠快速找到項目下所有的SQL語句,然后根據搜索結果基本上都能夠確定是否存在SQL注入。凡是SQL語句中出現了拼SQL(如select * from admin where id=’”+id+”’)那么基本上80%可以確定是SQL注入。但也有特例,比如拼湊的SQL參數并不受我們控制,無法在前臺通過提交SQL注入語句的方式去控制最終的查詢SQL。而采用預編譯?占位方式的一般不存在注入。
比如搜索51javacms項目當中的SQL語句: ?
需要注意的是Hibernate的HQL是對對象進行操作,所以它的SQL可能是:
String hql = "from Emp";
Query q = session.createQuery(hql);
也可以
String hql = "select count(*) from Emp";
Query q = session.createQuery(hql);
甚至是
String hql = "select new Emp(e.empno,e.ename) from Emp e ";
Query q = session.createQuery(hql);
Ibatis、Mybatis的SQL語句可以基于注解的方式寫在類方法上面,更多的是以xml的方式寫到xml文件。
?
在當前項目下搜索SQL語句關鍵字,查找疑似SQL注入的調用:
進入搜索結果的具體邏輯代碼:
最外層的Contrller: ?
“逆向”找到控制層URL以后構建的SQL注入請求:
可能大家關注的代碼審計最核心的怎么去發掘SQL注入這樣高危的漏洞,其次是XSS等類型的漏洞。
學會怎樣Debug。
學會怎樣通過從控制層到最終的數據訪問層的代碼跟蹤和從數據訪問層倒著找到控制層的入口。
學會怎樣去分析功能模塊的用例。
文件上傳漏洞即沒有對上傳的文件的后綴進行過濾,導致任意文件上傳。有的時候就算有后綴判斷,但是由于解析漏洞造成GETSHELL這是比較難避免的。
這一種是不需要任何繞過直接就可以上傳任意腳本威脅性可想而知。
某些時候就算做了后綴驗證我們一樣可以通過查看驗證的邏輯代碼找到繞過方式。第35、36行分別定義了白名單和黑名單后綴列表。41到46行是第一種通過黑名單方式校驗后綴合法性。47到57行代碼是第二種通過白名單方式去校驗后綴合法性。現在來瞧下上訴代碼都有那些方式可以Bypass。
1、假設37行代碼的upload不是在代碼里面寫死了而是從客戶端傳入的參數,那么可以自定義修改path把文件傳到當前server下的任意路徑。
2、第39行犯下了個致命的錯誤,因為文件名里面可以包含多個”.”而”xxxxx”.indexOf(“.”)取到的永遠是第一個”.”,假設我們的文件名是1.jpg.jsp即可繞過第一個黑名單校驗。
3、第42行又是另一個致命錯誤s.equals(fileSuffix)比較是不區分大小寫假設我們提交1.jSP即可突破驗證。
4、第50行同樣是一個致命的錯誤,直接用客戶端上傳的文件名作為最終文件名,可導致多個漏洞包括解析漏洞和上面的1.jpg.jsp上傳漏洞。
1、文件上傳的目錄必須寫死
2、把原來的fileName.indexOf(".")改成fileName.lastIndexOf(".")
3、s.equals(fileSuffix)改成s.equalsIgnoreCase(fileSuffix) 即忽略大小寫或者把前面的fileSuffix字符轉換成小寫s.equals(fileSuffix.toLowerCase())
51JavaCms典型的文件下載漏洞,我們不妨看下其邏輯為什么會存在漏洞。51javacms并沒有用流行的SSH框架而是用了Servlert3.0自行做了各種封裝,實現了各種漏洞。Ctrl+H搜索DownLoadFilePage找到下載的Servlet:
改裝了下51javacms的垃圾代碼: ?
請求不存在的文件:
跨目錄請求一個存在的文件:
JeeCms之前的后臺就存在任意文件編輯漏洞(JEECMS后臺任意文件編輯漏洞and官方漏洞及拿shell :http://wooyun.org/bugs/wooyun-2010-04030)官方的最新的修復方式是把path加了StartWith驗證。
Junit寫單元測試這個難度略高需要對代碼和業務邏輯有比較深入的了解,只是簡單的提下,有興趣的朋友可以自行了解。
JUnit是由 Erich Gamma 和 Kent Beck 編寫的一個回歸測試框架(regression testing framework)。Junit測試是程序員測試,即所謂白盒測試,因為程序員知道被測試的軟件如何(How)完成功能和完成什么樣(What)的功能。Junit是一套框架,繼承TestCase類,就可以用Junit進行自動測試了。
比如直接打開lerxCms的lib目錄:
類型轉換錯誤:
Struts2:
比如修改密保郵箱業務只做了失去焦點唯一性校驗,但是在提交的時候聽沒有校驗唯一性
Select下拉框能有什么漏洞?一般人我不告訴他,最常見的有select框Sql注入、存儲性xss漏洞。搜索注入的時候也許最容易出現注入的地方不是搜索的內容,而是搜索的條件!
Discuz select下拉框存儲也有類型的問題,但Discuz對Xss過濾較嚴未造成xss:
下拉框的Sql注入: ?
小結: 本節不過是漏洞發掘審計的冰山一角,很多東西沒法一次性寫出來跟大家分享。本系列完成后公布ylog博客源碼。本節源代碼暫不發布,如果需要源碼站內。