當這個《Struts2 Tomcat class.classLoader.resources.dirContext.docBase賦值造成的DoS及遠程代碼執行利用!》在Tomcat下的利用出來以后,它其實秒殺的不是一個框架,而是所有表單數據綁定功能不安全實現的J2EE MVC模式框架(因為國內運營商共享協議的限制,遠程代碼執行漏洞在國內難以大規模實現.但DoS漏洞還是存在的!).
稍微列一下清單:
2013年已經停止更新了,所以不會有補丁,出于節操,報了一下官方,Struts2項目leader?波蘭小胖子 Lukasz Lenar 是這樣回復的:
如圖:
struts2框架的前身,由于與struts2框架合并,所以不會有補丁!
前面文章已經介紹了(不過發現,到現在很多重要廠商都沒修復!)
已經在cve-2010-1622中,補丁對class.classLoader的限制.但利用從此可以簡化!
還有就是,自己早年學習java時,寫的簡易框架,也可以打(只是表單填充需要多寫一行代碼手動調用填充,而其他常規框架是自動的)
就以自己寫的框架說明問題:
表單參數綁定功能是MVC模式的框架一項非常重要的功能,比如:
沒有表單參數綁定功能的時代,我們填充javabean的屬性都需要:
#!java
...
dto.setUserName(request.getParameter("userName"));
dto.setPassWord(request.getParameter("passWord"));
....
框架表單參數綁定出現以后,就節約了很多硬編碼(這是框架的主要作用之一!)
通常實現表單參數綁定需要用到Java的兩個重要機制:
內省(introspector)與反射(reflection)
而Apache?commons-beanutils組件就提供了javaBean的內省與反射操作簡化API
哥的框架使用commons-beanutils,實現表單參數綁定的部分代碼塊:
#!java
...
public static Object parseRequest(HttpServletRequest request, Object bean) throws ServletException, IOException {
Enumeration enums = request.getParameterNames();
while (enums.hasMoreElements()) {
Object obj = enums.nextElement();
try {
Class cls = PropertyUtils.getPropertyType(bean, obj.toString());
Object beanValue = ConvertUtils.convert(request.getParameter(obj.toString()), cls);
HashMap map = new HashMap();
BeanUtils.populate(bean, map);
PropertyUtils.setProperty(bean, obj.toString(), beanValue);
} catch (Exception e) {
// e.printStackTrace();
}
}
return bean;
}
...
這里不會框架的可以用servlet測試一下漏洞!
這里有一個重要的問題,就是為什么能訪問到基類Object.class ?
看內省機制,內省是?Java?語言對?Bean?類屬性、事件的一種缺省處理方法。例如類?A?中有屬性?name,?那我們可以通過?getName,setName?來得到其值或者設置新的值。通過?getName/setName?來訪問?name?屬性,這就是默認的規則(*但是只要有?getter/setter?方法中的其中一個,那么?Java?的內省機制就會認為存在一個屬性)。
本身就業務邏輯講,訪問javaBean的屬性就夠了,是不需要訪問其他基類的Object.class,但是內省機制使用不當,就會造成這個問題.
問題非常簡單,在內省機制獲取javaBean屬性的一個小細節,測試代碼:
#!java
public class TestBean {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) throws IntrospectionException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
TestBean dto = new TestBean();
BeanInfo bi = Introspector.getBeanInfo(dto.getClass());
// BeanInfo bi = Introspector.getBeanInfo(dto.getClass(),Object.class);
PropertyDescriptor[] props = bi.getPropertyDescriptors();
for (int i = 0; i < props.length; i++) {
System.out.println(props[i].getName());
}
BeanInfo bi = Introspector.getBeanInfo(dto.getClass());
}
}
獲取包括父類的所有屬性,如圖:
如果不想獲取父類的屬性.可以使用
#!java
Introspector.getBeanInfo(dto.getClass(),Object.class);
其中第二個參數就是終止遍歷到的父類(如:終止到基類Object),如圖(這才是表單綁定實現正確的做法):
然后只要屬性有set器,參數就會被填充,以及后面的Tomcat的一些屬性被掛載到class.classLoader下等原因,然后Tomcat的屬性被訪問到并且賦值.然后才是發生上面的利用!
任何使用commons-beanutils組件或內省(及反射)不安全實現表單參數綁定功能的框架,都會受影響(當然,我這里只測試了Tomcat,其他web容器感興趣的也可以測試一下利用思路!).
J2EE規范在現今使用極廣了,但如果不是Struts2漏洞,或許很少有人關注Java安全,這點很是奇怪!
Author:?Nebula, HelloWorld security team