/** * Cracker for PPM (Password Probability Matrix). * * Loads previously-created dictionary (PPMGen) and cracks all * 4-character passwords. PoC only. * * http://2600hacker.stores.yahoo.net/pasprobmat.html **/ import java.security.NoSuchAlgorithmException; import java.math.BigInteger; import java.util.BitSet; import java.io.*; import java.util.Vector; import java.util.Enumeration; public class PPMCrack { private static byte MIN_CHAR = 32; private static byte MAX_CHAR = 126; private static int HASH_SIZE = 16*8192; private static BigInteger MODULUS; static { MODULUS = new BigInteger( "" + HASH_SIZE ); } private static BitSet [] ppm; private static byte [] genHash( String password ) throws NoSuchAlgorithmException { return OneWayHash.hash( password ).getBytes(); } private static int getIndex( byte c1, byte c2 ) { return ( c1 - MIN_CHAR )*95 + ( c2 - MIN_CHAR ); } private static byte getChar1( int index ) { return (byte)( ( index/95 ) + MIN_CHAR ); } private static byte getChar2( int index ) { return (byte)( ( index % 95 ) + MIN_CHAR ); } private static int computeCTIndex( byte [] b ) { // Strip out 17 bits int ret = byteArrayToInt( b, 0 ); return ret & 0x0000FFFF; } private static int byteArrayToInt(byte[] b, int offset) { int value = 0; for (int i = 0; i < 4; i++) { int shift = (4 - 1 - i) * 8; value += (b[i + offset] & 0x000000FF) << shift; } return value; } private static boolean compareArrays( byte [] b1, byte [] b2 ) { boolean ret = true; s: for( int i = 0; i < b1.length; i++ ) { if( b1[ i ] != b2[ i ] ) { ret = false; break s; } } return ret; } public static void main( String [] args ) { try { byte [] plain = new byte[ 4 ]; ObjectInputStream ois = new ObjectInputStream( new FileInputStream( "4char.ppm" ) ); Vector hits = new Vector(); if( args.length != 1 ) { System.out.println( "You must provide a hash to look up." ); System.exit( 1 ); } System.setProperty( "file.encoding", OneWayHash.CHARACTER_ENCODING ); ppm = (BitSet [] )ois.readObject(); ois.close(); System.out.println( "[+] Read PPM" ); System.out.println( " [-] PPM is " + ppm.length + " x " + ppm[ 0 ].length() + " bits." ); for( int i = 0; i < plain.length; i++ ) { plain[ i ] = 32; } byte [] target = Base64Utils.decode( args[ 0 ] ); //int hashIndex = ( target ).mod( MODULUS ).intValue(); int hashIndex = computeCTIndex( target ); System.out.println( " [-] Hash index is: " + hashIndex ); for( int i = 0; i < ppm.length; i++ ) { if( ppm[ i ].get( hashIndex ) == true ) { plain[ 0 ] = getChar1( i ); plain[ 1 ] = getChar2( i ); hits.add( plain.clone() ); } } Enumeration e = hits.elements(); int n = 0; boolean found = false; System.out.println( " [-] Searching " + hits.size() + " vectors." ); search: while( e.hasMoreElements() ) { plain = (byte [])e.nextElement(); n++; /* System.out.print( new String( plain ) + " " ); if( n % 20 == 0 ) { System.out.println( "" ); } */ for( plain[ 2 ] = MIN_CHAR; plain[ 2 ] <= MAX_CHAR; plain[ 2 ]++ ) { for( plain[ 3 ] = MIN_CHAR; plain[ 3 ] <= MAX_CHAR; plain[ 3 ]++ ) { byte [] curr = genHash( new String( plain ) ); if( compareArrays( curr, target ) ) { System.out.println( "\nPassword: " + new String( plain ) ); found = true; break search; } } } } if( !found ) { System.out.println( "\nPassword not found." ); } } catch( Exception e ) { e.printStackTrace(); } } }