Hey guys,
Now that you have known enough Java to write simple programs that do the calculation for you, let's get to know some basic input/output. Today I'll show you how to read data from text files to write a simple dictionary attack program.
In Java every input/output task is handled using streams. In the previous programs, actually I have used 2 streams: System.in, which is an InputStream, and System.out, an OutputStream.
To read/write from streams it is easiest to use a reader/writer. When you are working with text streams it's even more convenient to use BufferedReader and BufferedWriter. These classes allow you to read/write the data on a line-by-line basis.
Here's how you read a text file:
// You need to import this package for the IO classes
import java.io.*;
...
// Most IO methods throw IOExceptions,
// you don't need to worry about them for now,
// so just use this throws clause
public static void main(String[] args) throws IOException {
// Create a FileReader to read the file
FileReader fr = new FileReader("path/to/file");
// Use a BufferedReader for the convenient readLine() method
BufferedReader br = new BufferedReader(fr);
// Declare a string to store every line read from the file
String s;
// Read the file until the end of file is reached
// i.e. until the readLine() method returns null
while ((s = br.readLine()) != null) {
// Do something with the string
System.out.println(s);
}
// Close the reader to release the system resource
br.close();
}
Now let's get some practice!
In the last post I have shown you how to write a brute-force program. However, that method only works when the password is brute-forcable, probably no more than 8 characters. When the password is longer, brute-forcing will take days, or even months, or years :P Another common technique is dictionary attack.
Most passwords are based on common words to be easily memorized. Therefore instead of trying all character combination, you can use a wordlist, manipulate the words, and check them. This method is generally more effective than brute-forcing, and takes less time.
If you Google for wordlist, you can find many of them. I myself prefer the argon wordlists at
http://www.theargon.com/achilles/wordlists. For quick cracking, you can use english.txt. Or you can use the huge wordlists in
theargonlists/, which are 245 megs and 2 gigs when uncompressed.
Now let's pwnzor
this little crackme.
If you decompile it, you'll get something like this:
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)
// Source File Name: CrackMe2.java
import java.io.PrintStream;
import java.util.Scanner;
public class CrackMe2
{
public CrackMe2()
{
}
public static int crc(String s)
{
byte bytes[] = s.getBytes();
int crc = 0;
byte abyte0[];
int j = (abyte0 = bytes).length;
for(int i = 0; i < j; i++)
{
byte b = abyte0[i];
crc = crc >>> 8 ^ table[(crc ^ b) & 0xff];
}
return crc;
}
public static void main(String args[])
{
System.out.print("Enter password: ");
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
if(crc(s) == 38983)
System.out.println("Good job!");
else
System.out.println("Go to hell!");
}
private static final int table[] = {
0, 49345, 49537, 320, 49921, 960, 640, 49729, 50689, 1728,
1920, 51009, 1280, 50625, 50305, 1088, 52225, 3264, 3456, 52545,
3840, 53185, 52865, 3648, 2560, 51905, 52097, 2880, 51457, 2496,
2176, 51265, 55297, 6336, 6528, 55617, 6912, 56257, 55937, 6720,
7680, 57025, 57217, 8000, 56577, 7616, 7296, 56385, 5120, 54465,
54657, 5440, 55041, 6080, 5760, 54849, 53761, 4800, 4992, 54081,
4352, 53697, 53377, 4160, 61441, 12480, 12672, 61761, 13056, 62401,
62081, 12864, 13824, 63169, 63361, 14144, 62721, 13760, 13440, 62529,
15360, 64705, 64897, 15680, 65281, 16320, 16000, 65089, 64001, 15040,
15232, 64321, 14592, 63937, 63617, 14400, 10240, 59585, 59777, 10560,
60161, 11200, 10880, 59969, 60929, 11968, 12160, 61249, 11520, 60865,
60545, 11328, 58369, 9408, 9600, 58689, 9984, 59329, 59009, 9792,
8704, 58049, 58241, 9024, 57601, 8640, 8320, 57409, 40961, 24768,
24960, 41281, 25344, 41921, 41601, 25152, 26112, 42689, 42881, 26432,
42241, 26048, 25728, 42049, 27648, 44225, 44417, 27968, 44801, 28608,
28288, 44609, 43521, 27328, 27520, 43841, 26880, 43457, 43137, 26688,
30720, 47297, 47489, 31040, 47873, 31680, 31360, 47681, 48641, 32448,
32640, 48961, 32000, 48577, 48257, 31808, 46081, 29888, 30080, 46401,
30464, 47041, 46721, 30272, 29184, 45761, 45953, 29504, 45313, 29120,
28800, 45121, 20480, 37057, 37249, 20800, 37633, 21440, 21120, 37441,
38401, 22208, 22400, 38721, 21760, 38337, 38017, 21568, 39937, 23744,
23936, 40257, 24320, 40897, 40577, 24128, 23040, 39617, 39809, 23360,
39169, 22976, 22656, 38977, 34817, 18624, 18816, 35137, 19200, 35777,
35457, 19008, 19968, 36545, 36737, 20288, 36097, 19904, 19584, 35905,
17408, 33985, 34177, 17728, 34561, 18368, 18048, 34369, 33281, 17088,
17280, 33601, 16640, 33217, 32897, 16448
};
}
The crackme checks the password using the CRC16 algorithm, which is a pretty weak one. Let's crack it using dictionary attack. For simplicity you can skip the string manipulation for now and use it as is. With everything you have learned, hopefully you'll end up with the following code:
import java.io.*;
public class CrackMe2Solver {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader("path/to/english.txt"));
String s;
while ((s = reader.readLine()) != null)
if (CrackMe2.crc(s) == 38983) System.out.println(s);
reader.close();
}
}
I guess that's good enough for now. Maybe you can try and crack some TBS challs and get the smiley now :)