近期對平臺安全滲透測試中遇到有JAVA+mysql架構(gòu)的網(wǎng)站,針對此架構(gòu)我們Sine安全滲透工程師整理了下具體的漏洞檢測方法和防護修復方法,很多像執(zhí)行框架漏洞獲取到系統(tǒng)權(quán)限,以及跨權(quán)限寫入木馬后門等等操作,希望大家在滲透測試的道路中發(fā)現(xiàn)更多的知識和經(jīng)驗。
4.2.1. 格式化字符串
在Python中,有兩種格式化字符串的方式,在Python2的較低版本中,格式化字符串的方式為 "this is a %s" % "test" ,之后增加了format的方式, 語法為 "this is a {}".format('test') 或者 "this is a {test}".format(test='test')
當格式化字符串由用戶輸入時,則可能會造成一些問題,下面是一個最簡單的例子
>>> 'class of {0} is {0.__class__}'.format(42)
"class of 42 is "
從上面這個簡單的例子不難知道,當我們可以控制要format的字符串時,則可以使用 __init__ / __globals__ 等屬性讀取一些比較敏感的值,甚至任意執(zhí)行代碼。
4.2.2. 反序列化
4.2.2.1. pickle
>>> class A(object):
... a = 1
... b = 2
... def __reduce__(self):
... return (subprocess.Popen, (('cmd.exe',),))
>>> cPickle.dumps(A())
"csubprocess\nPopen\np1\n((S'cmd.exe'\np2\ntp3\ntp4\nRp5\n."
4.2.2.2. 其他
PyYAML
marshal
shelve
4.2.3. 沙箱
4.2.3.1. 常用函數(shù)
eval / exec / compile
dir / type
globals / locals / vars
getattr / setattr
4.2.3.2. 繞過
最簡單的思路是在已有的模塊中import,如果那個模塊中已經(jīng) import 可以利用的模塊就可以使用了
在父類中尋找可用的模塊,最常見payload是 ().__class__.__bases__[0].__subclasses__() 或者用魔術(shù)方法獲取全局作用域 __init__.__func__.__globals__
有些網(wǎng)站沒有過濾 pickle 模塊,可以使用 pickle 實現(xiàn)任意代碼執(zhí)行,生成 payload 可以使用
有的沙箱把相關(guān)的模塊代碼都被刪除了,則可以使用libc中的函數(shù),Python 中調(diào)用一般可以使用 ctypes 或者 cffi。
"A""B" == "AB"
4.2.3.3. 防御
Python官方給出了一些防御的建議
使用Jython并嘗試使用Java平臺來鎖定程序的權(quán)限
使用fakeroot來避免
使用一些rootjail的技術(shù)
4.2.4. 框架
4.2.4.1. Django
4.2.4.1.1. 歷史漏洞
CVE-2016-7401 CSRF Bypass
CVE-2017-7233/7234 Open redirect vulnerability
CVE-2017-12794 debug page XSS
4.2.4.1.2. 配置相關(guān)
Nginx 在為 Django 做反向代理時,靜態(tài)文件目錄配置錯誤會導致源碼泄露。訪問 /static.. 會 301 重定向到 /static../
4.2.4.2. Flask
Flask默認使用客戶端session,使得session可以被偽造
4.2.5. 危險函數(shù) / 模塊列表
4.2.5.1. 命令執(zhí)行
os.popen
os.system
os.spawn
os.fork
os.exec
popen2
commands
subprocess
exec
execfile
eval
timeit.sys
timeit.timeit
platform.os
platform.sys
platform.
popen
pty.spawn
pty.os
bdb.os
cgi.sys
…
4.2.5.2. 危險第三方庫
Template
subprocess32
4.2.5.3. 反序列化
marshal
PyYAML
pickle
cPickle
shelve
PIL
Java
4.3.1. 基本概念
JVM是Java平臺的核心,以機器代碼來實現(xiàn),為程序執(zhí)行提供了所需的所有基本功能,例如字節(jié)碼解析器、JIT編譯器、垃圾收集器等。由于它是機器代碼實現(xiàn)的,其同樣受到二進制文件受到的攻擊。
JCL是JVM自帶的一個標準庫,含有數(shù)百個系統(tǒng)類。默認情況下,所有系統(tǒng)類都是可信任的,且擁有所有的特權(quán)。
4.3.1.2. JNDI
JNDI(Java Naming and Directory Interface,JAVA命名和目錄接口)是為JAVA應(yīng)用程序提供命名和目錄訪問服務(wù)的API(Application Programing Interface,應(yīng)用程序編程接口)。
4.3.1.3. OGNL
OGNL(Object-Graph Navigation Language,對象導航語言)是一種功能強大的表達式語言,通過簡單一致的表達式語法,提供了存取對象的任意屬性、調(diào)用對象的方法、遍歷整個對象的結(jié)構(gòu)圖、實現(xiàn)字段類型轉(zhuǎn)化等功能。
Struts2中使用了OGNL,提供了一個ValueStack類。ValueStack分為root和context兩部分。root中是當前的action對象,context中是ActionContext里面所有的內(nèi)容。
4.3.1.4. RMI
RMI(Remote Method Invocation,遠程方法調(diào)用)能夠讓在客戶端Java虛擬機上的對象像調(diào)用本地對象一樣調(diào)用服務(wù)端java虛擬機中的對象上的方法。
RMI遠程調(diào)用步驟:
客戶調(diào)用客戶端輔助對象stub上的方法
客戶端輔助對象stub打包調(diào)用信息(變量,方法名),通過網(wǎng)絡(luò)發(fā)送給服務(wù)端輔助對象skeleton
服務(wù)端輔助對象skeleton將客戶端輔助對象發(fā)送來的信息解包,找出真正被調(diào)用的方法以及該方法所在對象
調(diào)用真正服務(wù)對象上的真正方法,并將結(jié)果返回給服務(wù)端輔助對象skeleton
服務(wù)端輔助對象將結(jié)果打包,發(fā)送給客戶端輔助對象stub
客戶端輔助對象將返回值解包,返回給調(diào)用者
客戶獲得返回值
4.3.2. 框架
4.3.2.1. Servlet
4.3.2.1.1. 簡介
Servlet(Server Applet)是Java Servlet的簡稱,稱為小服務(wù)程序或服務(wù)連接器,是用Java編寫的服務(wù)器端程序,主要功能在于交互式地瀏覽和修改數(shù)據(jù),生成動態(tài)Web內(nèi)容。
狹義的Servlet是指Java語言實現(xiàn)的一個接口,廣義的Servlet是指任何實現(xiàn)了這個Servlet接口的類,一般情況下,人們將Servlet理解為后者。Servlet運行于支持Java的應(yīng)用服務(wù)器中。從原理上講,Servlet可以響應(yīng)任何類型的請求,但絕大多數(shù)情況下Servlet只用來擴展基于HTTP協(xié)議的Web服務(wù)器。
4.3.2.1.2. 生命周期為
客戶端請求該 Servlet
加載 Servlet 類到內(nèi)存
實例化并調(diào)用init()方法初始化該
Servlet service()(根據(jù)請求方法不同調(diào)用 doGet() / doPost() / … / destroy()
4.3.2.1.3. 接口
init()
在 Servlet 的生命期中,僅執(zhí)行一次 init() 方法,在服務(wù)器裝入 Servlet 時執(zhí)行。
service()
service() 方法是 Servlet 的核心。每當一個客戶請求一個HttpServlet對象,該對象的 service() 方法就要被調(diào)用,而且傳遞給這個方法一個”請求”(ServletRequest)對象和一個”響應(yīng)”(ServletResponse)對象作為參數(shù)。
4.3.2.2. Struts 2
4.3.2.2.1. 簡介
Struts2是一個基于MVC設(shè)計模式的Web應(yīng)用框架,它本質(zhì)上相當于一個servlet,在MVC設(shè)計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數(shù)據(jù)交互。
4.3.2.2.2. 請求流程
客戶端發(fā)送請求的tomcat服務(wù)器
請求經(jīng)過一系列過濾器
FilterDispatcher調(diào)用ActionMapper來決定這個請求是否要調(diào)用某個Action
ActionMppaer決定調(diào)用某個ActionFilterDispatcher把請求給ActionProxy
ActionProxy通過Configuration Manager查看structs.xml,找到對應(yīng)的Action類
ActionProxy創(chuàng)建一個ActionInvocation對象
ActionInvocation對象回調(diào)Action的execute方法
Action執(zhí)行完畢后,ActionInvocation根據(jù)返回的字符串,找到相應(yīng)的result,通過HttpServletResponse返回給服務(wù)器
4.3.2.2.3. 相關(guān)CVE
CVE-2016-3081 (S2-032)
CVE-2016-3687 (S2-033)
CVE-2016-4438 (S2-037)
CVE-2017-5638
CVE-2017-7672
CVE-2017-9787
CVE-2017-9793
CVE-2017-9804
CVE-2017-9805
CVE-2017-12611
CVE-2017-15707
CVE-2018-1327
CVE-2018-11776
4.3.2.3. Spring MVC
4.3.2.3.1. 請求流程
用戶發(fā)送請求給服務(wù)器
服務(wù)器收到請求,使用DispatchServlet處理
Dispatch使用HandleMapping檢查url是否有對應(yīng)的Controller,如果有,執(zhí)行
如果Controller返回字符串,ViewResolver將字符串轉(zhuǎn)換成相應(yīng)的視圖對象
DispatchServlet將視圖對象中的數(shù)據(jù),輸出給服務(wù)器 服務(wù)器將
數(shù)據(jù)輸出給客戶端
4.3.3. 容器
常見的Java服務(wù)器有Tomcat、Weblogic、JBoss、GlassFish、Jetty、Resin、IBM Websphere等,這里對部分框架做一個簡單的說明。
4.3.3.1. Tomcat
Tomcat是一個輕量級應(yīng)用服務(wù)器,在中小型系統(tǒng)和并發(fā)訪問用戶不是很多的場合下被普遍使用,用于開發(fā)和調(diào)試JSP程序。
在收到請求后,Tomcat的處理流程如下:
客戶端訪問Web服務(wù)器,發(fā)送HTTP請求
Web服務(wù)器接收到請求后,傳遞給Servlet容器
Servlet容器加載Servlet,產(chǎn)生Servlet實例后,向其傳遞表示請求和響應(yīng)的對象
Servlet實例使用請求對象得到客戶端的請求信息,然后進行相應(yīng)的處理
Servlet實例將處理結(jié)果通過響應(yīng)對象發(fā)送回客戶端,容器負責確保響應(yīng)正確送出,同時將控制返回給Web服務(wù)器
Tomcat服務(wù)器是由一系列可配置的組件構(gòu)成的,其中核心組件是Catalina Servlet容器,它是所有其他Tomcat組件的頂層容器。
4.3.3.1.1. 相關(guān)CVE
CVE-2019-0232
CVE-2017-12615
CVE-2013-2067
CVE-2012-4534
CVE-2012-4431
CVE-2012-3546
CVE-2012-3544
CVE-2012-2733
CVE-2011-3375
CVE-2011-3190
CVE-2008-2938
4.3.3.2. Weblogic
4.3.3.2.1. 簡介
WebLogic是美國Oracle公司出品的一個Application Server,是一個基于Java EE架構(gòu)的中間件,WebLogic是用于開發(fā)、集成、部署和管理大型分布式Web應(yīng)用、網(wǎng)絡(luò)應(yīng)用和數(shù)據(jù)庫應(yīng)用的Java應(yīng)用服務(wù)器。其將Java的動態(tài)功能和Java Enterprise標準的安全性引入大型網(wǎng)絡(luò)應(yīng)用的開發(fā)、集成、部署和管理之中。
WebLogic對業(yè)內(nèi)多種標準的全面支持,包括EJB、JSP、Servlet、JMS、JDBC等。
4.3.3.2.2. 相關(guān)CVE
CVE-2019-2658
CVE-2019-2650
CVE-2019-2649
CVE-2019-2648
CVE-2019-2647
CVE-2019-2646
CVE-2019-2645
CVE-2019-2618
CVE-2019-2615
CVE-2019-2568
CVE-2018-3252
CVE-2018-3248
CVE-2018-3245
CVE-2018-3201
CVE-2018-3197
CVE-2018-3191
CVE-2018-1258
CVE-2017-10271
CVE-2017-3248
CVE-2016-3510
CVE-2015-4852
4.3.3.3. JBoss
4.3.3.3.1. 簡介
JBoss是一個基于J2EE的管理EJB的容器和服務(wù)器,但JBoss核心服務(wù)不包括支持servlet/JSP的WEB容器,一般與Tomcat或Jetty綁定使用。
4.3.3.3.2. 相關(guān)CVE
CVE-2017-12149
4.3.4. 沙箱
4.3.4.1. 簡介
Java實現(xiàn)了一套沙箱環(huán)境,使遠程的非可信代碼只能在受限的環(huán)境下執(zhí)行。
4.3.4.2. 相關(guān)CVE
CVE-2012-0507
CVE-2012-4681
CVE-2017-3272
CVE-2017-3289
4.3.5. 反序列化
4.3.5.1. 簡介
序列化就是把對象轉(zhuǎn)換成字節(jié)流,便于保存在內(nèi)存、文件、數(shù)據(jù)庫中;反序列化即逆過程,由字節(jié)流還原成對象。Java中的 ObjectOutputStream 類的 writeObject() 方法可以實現(xiàn)序列化,類 ObjectInputStream類的readObject() 方法用于反序列化。
如果要實現(xiàn)類的反序列化,則是對其實現(xiàn) Serializable 接口。
4.3.5.2. 序列數(shù)據(jù)結(jié)構(gòu)
0xaced 魔術(shù)頭
4.3.5.3. 序列化流程
ObjectOutputStream實例初始化時,將魔術(shù)頭和版本號寫入bout (BlockDataOutputStream類型) 中
調(diào)用ObjectOutputStream.writeObject()開始寫對象數(shù)據(jù)
○ObjectStreamClass.lookup()封裝待序列化的類描述 (返回ObjectStreamClass類型) ,獲取包括類名、自定義serialVersionUID、可序列化字段 (返回ObjectStreamField類型) 和構(gòu)造方法,以及writeObject、readObject方法等
○writeOrdinaryObject()寫入對象數(shù)據(jù)
■寫入對象類型標識
■writeClassDesc()進入分支writeNonProxyDesc()寫入類描述數(shù)據(jù)
寫入類描述符標識
寫入類名
寫入SUID (當SUID為空時,會進行計算并賦值)
計算并寫入序列化屬性標志位
寫入字段信息數(shù)據(jù)
寫入Block Data結(jié)束標識
寫入父類描述數(shù)據(jù)
■writeSerialData()寫入對象的序列化數(shù)據(jù)
若類自定義了writeObject(),則調(diào)用該方法寫對象,否則調(diào)用defaultWriteFields()寫入對象的字段數(shù)據(jù) (若是非原始類型,則遞歸處理子對象)
4.3.5.4. 反序列化流程
ObjectInputStream實例初始化時,讀取魔術(shù)頭和版本號進行校驗
調(diào)用ObjectInputStream.readObject()開始讀對象數(shù)據(jù)
○讀取對象類型標識
○readOrdinaryObject()讀取數(shù)據(jù)對象
■readClassDesc()讀取類描述數(shù)據(jù)
讀取類描述符標識,進入分支readNonProxyDesc()
讀取類名
讀取SUID
讀取并分解序列化屬性標志位
讀取字段信息數(shù)據(jù)
resolveClass()根據(jù)類名獲取待反序列化的類的Class對象,如果獲取失敗,則拋出ClassNotFoundException
skipCustomData()循環(huán)讀取字節(jié)直到Block Data結(jié)束標識為止 讀取父類描述數(shù)據(jù)
initNonProxy()中判斷對象與本地對象的SUID和類名 (不含包名) 是否相同,若不同,則拋出InvalidClassException
ObjectStreamClass.newInstance()獲取并調(diào)用離對象最近的非■Serializable的父類的無參構(gòu)造方法 (若不存在,則返回null) 創(chuàng)建對象實例
■readSerialData()讀取對象的序列化數(shù)據(jù)
若類自定義了readObject(),則調(diào)用該方法讀對象,否則調(diào)用defaultReadFields()讀取并填充對象的字段數(shù)據(jù)
4.3.5.5. 相關(guān)函數(shù)
ObjectInputStream.readObject
ObjectInputStream.readUnshared
XMLDecoder.readObject
Yaml.load
XStream.fromXML
ObjectMapper.readValue
JSON.parseObject
4.3.5.6. 主流JSON庫
4.3.5.6.1. GSON
Gson默認只能反序列化基本類型,如果是復雜類型,需要程序員實現(xiàn)反序列化機制,相對比較安全。
4.3.5.6.2. Jackson
除非指明@jsonAutoDetect,Jackson不會反序列化非public屬性。在防御時,可以不使用enableDefaultTyping方法。
相關(guān)CVE有
CVE-2017-7525
CVE-2017-15095
4.3.5.6.3. Fastjson
相關(guān)CVE有
CVE-2017-18349
4.3.5.7. 存在危險的基礎(chǔ)庫
commons-fileupload 1.3.1
commons-io 2.4
commons-collections 3.1
commons-logging 1.2
commons-beanutils 1.9.2
org.slf4j:slf4j-api 1.7.21
com.mchange:mchange-commons-java 0.2.11
org.apache.commons:commons-collections 4.0
com.mchange:c3p0 0.9.5.2
org.beanshell:bsh 2.0b5
org.codehaus.groovy:groovy 2.3.9
org.springframework:spring-aop 4.1.4.RELEASE
4.3.5.8. 網(wǎng)站漏洞修復和防護
4.3.5.8.1. Hook resolveClass
在使用 readObject() 反序列化時會調(diào)用 resolveClass 方法讀取反序列化的類名,可以通過hook該方法來校驗反序列化的類,一個Demo如下
以上的Demo就只允許序列化 SerialObject ,通過這種方式,就可以設(shè)置允許序列化的白名單
4.3.5.8.2. ValidatingObjectInputStream
Apache Commons IO Serialization包中的 ValidatingObjectInputStream 類提供了 accept 方法,可以通過該方法來實現(xiàn)反序列化類白/黑名單控制,一個demo如下
4.3.5.8.3. ObjectInputFilter
Java 9提供了支持序列化數(shù)據(jù)過濾的新特性,可以繼承 java.io.ObjectInputFilter 類重寫 checkInput方法來實現(xiàn)自定義的過濾器,并使用 ObjectInputStream 對象的 setObjectInputFilter 設(shè)置過濾器來實現(xiàn)反序列化類白/黑名單控制,對JAVA漏洞滲透測試有想進一步了解的可以咨詢專業(yè)的網(wǎng)站安全公司,國內(nèi)推薦Sinesafe,綠盟,啟明星辰等等專業(yè)的安全維護公司。
申請創(chuàng)業(yè)報道,分享創(chuàng)業(yè)好點子。點擊此處,共同探討創(chuàng)業(yè)新機遇!