Jump to content

Minitut: Virtual Methods / Final Methods / Cracking Safes


Botre

Recommended Posts

Intro
 
Hello, today we are going to be cracking safes while learning a bit about virtual methods and how they are potentially exposing your code to exploits.
 
Definition
 
The wikipedia definition of  "virtual method":
 
In object-oriented programming, in languages such as C++, a virtual function or virtual method is an inheritable and overridable function or method for which dynamic dispatch is facilitated. This concept is an important part of the (runtime) polymorphism portion of object-oriented programming (OOP).
 
Java
 
In Java, methods are virtual by default, all methods are overridable unless any of the following criteria is met:

  • A method is declared final.
  • A method is declared static.
  • The method's class is declared final (since the parent can not be sublcassed, an alternate implementation can not be provided).
  • Annotations can be used in certain frameworks to devirtualize methods.

The "Safe" class
 
In order to point out some of the most basic vulnerabilities virtual methods can create, let's create a very simple POJO safe:
 
This safe can be locked, unlocked with a password, and if unlocked: retrieve a treasure.


public class Safe {

	private String password = "maldesto69";
	private String treasure = "Treasure";
	private boolean unlocked = false;
	
	/**
	 * Unlocks the safe if the correct password is supplied.
	 * @param password
	 */
	public void unlock(String password) {
		if(this.password.equals(password)) {
			unlocked = true;
		}
		else {
			throw new SecurityException();
		}
	}
	
	/**
	 * Locks the safe.
	 */
	public void lock() {
		unlocked = false;
	}
	
	/**
	 * Checks whether the safe is unlocked.
	 */
	public boolean isUnlocked() {
		return unlocked;
	}
	
	/**
	 * Returns the treasure if the safe is unlocked.
	 */
	public String getTreasure() {
		if(isUnlocked()) {
			return treasure;
		}
		else {
			throw new SecurityException();
		}
	}
	
}

Here's how the designer intended the class to work:

	public static void main(String[] args) {
		// Create a new safe.
		Safe safe = new Safe();
		// Print whether the safe is unlocked.
		System.out.println(safe.isUnlocked());
		// Unlock the safe.
		safe.unlock("maldesto69");
		// Print whether the safe is unlocked.
		System.out.println(safe.isUnlocked());
		// Get the treasure.
		System.out.println(safe.getTreasure());
	} 
false
true
Treasure

Everything goes well and the treasure remain safe, until someone discovers the designer forgot protecting some of his methods, by anonymously sub-classing the treasure class (the class was not declared final) and overriding the isUnlocked method (which was also not declared final), the safecracker managed to entirely bypass the password system by simply making the lock getter return true unconditionally. 

	public static void main(String[] args) {
		// Create a new safe, exploit the fact that isUnlocked is virtual.
		Safe safe = new Safe(){
			@Override
			public boolean isUnlocked() {
				return true;
			}
		};
		// Print whether the safe is unlocked.
		System.out.println(safe.isUnlocked());
		// Get the treasure.
		System.out.println(safe.getTreasure());
	} 
true
Treasure

There are plenty of solutions here:

  • Make isUnlocked final so it can not be overriden.
  • Make getTreasure use the variable instead of its getter.
  • Make  Safe final.

Our designer opts to simply make isUnlocked final (something he will regret sooner rather than later), a new treasure is put in to the safe and everything is dandy.

A couple of days later however, the programmer gets some reports about people finding odd items in their safe (panties, slimey socks, you name it (or don't)). 

	public static void main(String[] args) {
		// Create a new safe, exploit the fact that getTreasure is virtual.
		Safe safe = new Safe(){
			@Override
			public String getTreasure() {
				return "Fake treasure";
			}
		};
		// Print whether the safe is unlocked.
		System.out.println(safe.isUnlocked());
		// Get the treasure.
		System.out.println(safe.getTreasure());
	} 
false
Fake treasure

isUnlocked was secured, but getTreasure, a vital method of the class, remained untouched and allowed the nasty hacker to spoof fake treasure return values. The safe was sabotaged, customers panicked, the programmer's client faced multiple law suits and our designer was of course fired, never to work a programming job in his life again.

 

The end.

  • Like 8
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...