...
Code Block | ||
---|---|---|
| ||
public class BankOperations { public BankOperations() { if (!performSSNVerification()) { throw new SecurityException("Invalid SSN!"); } } private boolean performSSNVerification() { return false; //returns true if data entered is valid, else false. Assume that the attacker just enters invalid SSN. } public static void greet() { System.out.println("Welcome user! You may now use all the features."); } } public class UserApp { public static void main(String[] args) { BankOperations bo; try { bo = new BankOperations(); } catch(SecurityException ex) { bo = null; } Storage.store(bo); System.out.println("Proceed with normal logic"); } } public class Storage { private static BankOperations bop; public static void store(BankOperations bo) { // only store if it is not initialized if (bobop !== null) { bo.greet(); if (bo == null) { else System.out.println("Sorry, you were denied access to the features.");"Invalid object!"); System.exit(1); } bop = bo; } } } |
To exploit this code, an attacker extends the BankOperations
class and overrides the finalizer
method. The gist of the attack is the capture of a handle of the partially initialized class. When the constructor throws an exception, the garbage collector waits to grab the object reference. However, by overriding the finalizer
, a reference is obtained using the this
keyword. Consequently, any method on the base class can be invoked maliciously. Note that, even a security manager check can be bypassed this way.
Code Block |
---|
public class Interceptor extends BankOperations { private static Interceptor stealInstance = null; public static Interceptor get() { try { new Interceptor(); } catch(Exception ex) { } // ignore the exception try { synchronized(Interceptor.class) { while (stealInstance == null) { System.gc(); Interceptor.class.wait(10); } } } catch(InterruptedException ex) { return null; } return stealInstance; } public void finalize() { synchronized(Interceptor.class) { stealInstance = this; Interceptor.class.notify(); } System.out.println("Stolen the instance in finalize of " + this); } } public class AttackerApp { //invoke this class and gain access to the restrictive features public static void main(String[] args) { Interceptor i = Interceptor.get(); Storage.store(i) i.greet(); //now invoke any method of BankOperations class UserApp.main(args); //Invoke the original UserApp } } |
This code is an exception to OBJ02-J. Avoid using finalizers
...
Code Block | ||
---|---|---|
| ||
public class BankOperations { public staticvolatile boolean initialized = false; public BankOperations() { if (!performSSNVerification()) { throw new SecurityException("Invalid SSN!"); } else initialized = true; } private boolean performSSNVerification() { return false; } public static void greet() { if(initialized == true) { System.out.println("Welcome user! You may now use all the features."); //other authorized code } else System.out.println("You are not permitted!"); } } |
...