253 lines
10 KiB
Java
Executable File
253 lines
10 KiB
Java
Executable File
/*
|
|
* PcapCrack 1.0
|
|
* Copyright © 2017 Ben Goldsworthy (rumperuu)
|
|
*
|
|
* A program to attempt to brute-force the key used to encrypt a file
|
|
* in an intercepted network packet.
|
|
*
|
|
* This file is part of PcapCrack.
|
|
*
|
|
* PcapCrack is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* PcapCrack is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with PcapCrack. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
** This class represents a password-cracking thread utilising a given
|
|
** method for generating possible passwords.
|
|
**/
|
|
|
|
import java.io.*;
|
|
import java.net.*;
|
|
import java.security.*;
|
|
import java.util.*;
|
|
import java.util.regex.*;
|
|
|
|
import javax.crypto.*;
|
|
import javax.crypto.spec.*;
|
|
|
|
/**
|
|
** @author Ben Goldsworthy (rumperuu) <me+pcapcrack@bengoldsworthy.net>
|
|
** @version 1.0
|
|
**/
|
|
public class Cracker implements Runnable {
|
|
private static final String ivVal = "1234567891011121";
|
|
private static final char[] leet = {'a', '4', 'e', '3', 'i', '1', 'o', '0', 'l', '|', 't' , '7'};
|
|
private static byte[] file;
|
|
private static boolean found = false;
|
|
|
|
private ArrayList<String> passwords;
|
|
private int mode;
|
|
MessageDigest digest;
|
|
Cipher cipher;
|
|
IvParameterSpec iv;
|
|
|
|
/**
|
|
** Constructor.
|
|
**
|
|
** @param mode The method of password generation the thread will
|
|
** utilise.
|
|
** @param file The encoded file to crack, encoded in Base64.
|
|
** @param dict The `ArrayList` of words from the chosen dictionary.
|
|
**/
|
|
public Cracker(int mode, String file, ArrayList<String> dict){
|
|
this.mode = mode;
|
|
this.file = Base64.getDecoder().decode(file);
|
|
|
|
// Initialises the dictionary to the passed file for all modes except
|
|
// 0...
|
|
if (this.mode > 2) {
|
|
this.passwords = dict;
|
|
// ...in which case, initialises the dictionary to the list of the
|
|
// 10,000 most common passwords included with the .jar.
|
|
} else {
|
|
ArrayList<String> commonPasswords = new ArrayList<String>();
|
|
try {
|
|
InputStream is = getClass().getResourceAsStream("/dat/10000-most-common-passwords.txt");
|
|
InputStreamReader isr = new InputStreamReader(is);
|
|
BufferedReader br = new BufferedReader(isr);
|
|
String line;
|
|
while ((line = br.readLine()) != null) { commonPasswords.add(line); }
|
|
this.passwords = commonPasswords;
|
|
} catch (FileNotFoundException e) {
|
|
System.out.println("File `10000-most-common-passwords.txt` not found in directory `.\\dat`.");
|
|
System.exit(1);
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
System.exit(1);
|
|
}
|
|
}
|
|
|
|
// If the cracker has an even mode, flips the order the password
|
|
// list.
|
|
if ((this.mode % 2)== 0) Collections.reverse(this.passwords);
|
|
|
|
// Halves the cracker's list, to avoid duplicating effort with its
|
|
// even twin.
|
|
this.passwords = new ArrayList<String>(this.passwords.subList(0, this.passwords.size()/2));
|
|
|
|
// Initialises as much of the crypto stuff as can be done at this
|
|
// stage.
|
|
try {
|
|
this.digest = MessageDigest.getInstance("SHA-256");
|
|
this.cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
|
|
this.iv = new IvParameterSpec(this.ivVal.getBytes());
|
|
} catch (Exception e) {
|
|
System.out.println(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
** Runs the cracker process on the thread, and alerts on end.
|
|
**/
|
|
@Override
|
|
public void run() {
|
|
processCommand();
|
|
}
|
|
|
|
/**
|
|
** Tests every key generated using the given method for the thread.
|
|
**
|
|
** Mode 1: 10,000 most common passwords.
|
|
** Mode 3: Dictionary words.
|
|
** Mode 5: Dictionary words, with each letter capitalised in turn.
|
|
** Mode 7: Dictionary words, with ASCII symbols {!-/} appended.
|
|
** Mode 9: Dictionary words, with 'leetspeek' replacements.
|
|
** Mode 11: Dictionary words, capitalised.
|
|
** Mode 13: Dictionary words, with numbers {0-9999} appended
|
|
** and prepended.
|
|
** Mode 15: Dictionary words, combined in pairs.
|
|
** Mode 17: Numbers {0-1,000,000}.
|
|
**
|
|
** Even-numbered modes are the previous mode, with a reversed
|
|
** list. Thus, all modes terminate when halfway through.
|
|
**/
|
|
private void processCommand() {
|
|
int j, k;
|
|
|
|
int tenth = (int)Math.ceil(this.passwords.size()/10);
|
|
int current = 0;
|
|
int percentage = 0;
|
|
// DEBUG: when using the test dictionary, avoids divide be zero
|
|
// exceptions later on.
|
|
if (this.passwords.size() < 10) tenth = 1;
|
|
|
|
for (String password : this.passwords) {
|
|
// If another cracker has found the correct password, stop.
|
|
if (this.found) return;
|
|
|
|
current++;
|
|
switch (this.mode) {
|
|
// Tests the unaltered dictionary word/common password.
|
|
case 1:case 2:case 3:case 4:
|
|
this.crack(password);
|
|
break;
|
|
// Capitalises each letter of each word in turn.
|
|
case 5:case 6:
|
|
for (j = 1; j < password.length() - 1; j++) {
|
|
password = password.substring(0,j) + password.substring(j,j+1).toUpperCase() + password.substring(j+1);
|
|
this.crack(password);
|
|
}
|
|
break;
|
|
// Appends the symbols represented by ASCII values 33-47.
|
|
case 7:case 8:
|
|
for (j = 33; j < 48; j++) {
|
|
password = password + (char)j;
|
|
this.crack(password);
|
|
}
|
|
break;
|
|
// Replaces each leet character in turn.
|
|
case 9:case 10:
|
|
for (j = 0; j < password.length() - 1; j++) {
|
|
for (k = 0; k < this.leet.length; k+=2) {
|
|
if (password.charAt(j) == this.leet[k]) {
|
|
StringBuilder newPassword = new StringBuilder(password);
|
|
newPassword.setCharAt(j, this.leet[k+1]);
|
|
this.crack(newPassword.toString());
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
// Capitalises the first letter of every word.
|
|
case 11:case 12:
|
|
password = password.substring(0,1).toUpperCase() + password.substring(1);
|
|
this.crack(password);
|
|
break;
|
|
// Appends and prepends the numbers 1-9,999 to every word.
|
|
case 13:case 14:
|
|
for (j = 0; j < 9999 - 1; j++) {
|
|
this.crack(password + j);
|
|
this.crack(j + password);
|
|
}
|
|
break;
|
|
// Appends and prepends the next word.
|
|
case 15:case 16:
|
|
for (j = 0; j < this.passwords.size() - 1; j++) {
|
|
this.crack(password + this.passwords.get(j));
|
|
}
|
|
break;
|
|
// Attempts the numbers 0-1,000,000.
|
|
case 17:case 18:
|
|
for (j = k = 0; (j <= 500000) && (k >= 500000); j++, k--) {
|
|
this.crack(""+j);
|
|
this.crack(""+k);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Displays the current progress.
|
|
if ((current % tenth) == 0) {
|
|
tenth += tenth;
|
|
percentage += 10;
|
|
System.out.println("Cracker "+mode+" at "+percentage+"%");
|
|
}
|
|
}
|
|
|
|
// If there's been no return, none of the attempted passwords have
|
|
// worked.
|
|
System.out.println("Cracker " + this.mode + " end, no result.");
|
|
}
|
|
|
|
/**
|
|
** Tests a given password to see if it cracks the payload.
|
|
**
|
|
** @param password The given password.
|
|
** @return Whether the file was cracked or not.
|
|
**/
|
|
private boolean crack(String password) {
|
|
try {
|
|
// Sets up the cipher with the given password.
|
|
byte[] keyVal = digest.digest(password.getBytes("UTF-8"));
|
|
keyVal = Arrays.copyOfRange(keyVal, 0, keyVal.length/2);
|
|
SecretKeySpec key = new SecretKeySpec(keyVal, "AES");
|
|
cipher.init(Cipher.DECRYPT_MODE, key, iv);
|
|
|
|
// Decrypts the file using the cipher.
|
|
String decryptedFile = new String(cipher.doFinal(this.file));
|
|
if (decryptedFile.startsWith("DECRYPTED:")) {
|
|
// Must be outputted in a single command, or lines will be
|
|
// broken up by output from other cracker threads.
|
|
System.out.println("Cracker "+this.mode+" end, successful crack!\n==========\nDecrypted file: " + decryptedFile.split(":",2)[1] + "\nPassword: " + password + "\n==========\n");
|
|
this.found = true;
|
|
return true;
|
|
}
|
|
} catch (BadPaddingException e) {
|
|
// If the password is incorrect, do nothing and move on to
|
|
// returning "false".
|
|
} catch (Exception e) {
|
|
System.out.println(e);
|
|
} finally {
|
|
return false;
|
|
}
|
|
}
|
|
}
|