-/*\r
- * rcracki_mt is a multithreaded implementation and fork of the original \r
- * RainbowCrack\r
- *\r
- * Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>\r
- * Copyright Martin Westergaard Jørgensen <martinwj2005@gmail.com>\r
- * Copyright 2009, 2010 Daniël Niggebrugge <niggebrugge@fox-it.com>\r
- * Copyright 2009 James Dickson\r
- * Copyright 2009, 2010 James Nobis <frt@quelrod.net>\r
- * Copyright 2010 uroskn\r
- *\r
- * Modified by Martin Westergaard Jørgensen <martinwj2005@gmail.com> to support * indexed and hybrid tables\r
- *\r
- * Modified by neinbrucke to support multi threading and a bunch of other stuff :)\r
- *\r
- * 2009-01-04 - <james.dickson@comhem.se> - Slightly modified (or "fulhack" as \r
- * we say in sweden) to support cain .lst files.\r
- *\r
- * This file is part of rcracki_mt.\r
- *\r
- * rcracki_mt is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * rcracki_mt is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with rcracki_mt. If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-\r
-#if defined(_WIN32) && !defined(__GNUC__)\r
- #pragma warning(disable : 4786 4267 4018)\r
-#endif\r
-\r
-#include "CrackEngine.h"\r
-#include "lm2ntlm.h"\r
-#include <algorithm>\r
-\r
-#ifdef _WIN32\r
- #include <io.h>\r
-#else\r
- #include <sys/types.h>\r
- #include <sys/stat.h>\r
- #include <unistd.h>\r
- #include <dirent.h>\r
-#endif\r
-\r
-#if defined(_WIN32) && !defined(__GNUC__)\r
- #pragma comment(lib, "libeay32.lib")\r
-#endif\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef _WIN32\r
-void GetTableList(string sWildCharPathName, vector<string>& vPathName)\r
-{\r
- //vPathName.clear();\r
-\r
- string sPath;\r
- string::size_type n = sWildCharPathName.find_last_of('\\');\r
-\r
- if ( n == (sWildCharPathName.size() - 1) )\r
- {\r
- sWildCharPathName = sWildCharPathName.substr(0, n);\r
- n = sWildCharPathName.find_last_of('\\');\r
- }\r
-\r
- if (n != string::npos)\r
- sPath = sWildCharPathName.substr(0, n + 1);\r
-\r
- _finddata_t fd;\r
-\r
- long handle = _findfirst(sWildCharPathName.c_str(), &fd);\r
- if (handle != -1)\r
- {\r
- do\r
- {\r
- string sName = fd.name;\r
- if (sName.size()>3) {\r
- if (sName.substr(sName.size()-3, 3) == ".rt" && !(fd.attrib & _A_SUBDIR))\r
- {\r
- string sPathName = sPath + sName;\r
- vPathName.push_back(sPathName);\r
- }\r
- }\r
- if (sName.size()>4) {\r
- if (sName.substr(sName.size()-4, 4) == ".rti" && !(fd.attrib & _A_SUBDIR))\r
- {\r
- string sPathName = sPath + sName;\r
- vPathName.push_back(sPathName);\r
- }\r
- }\r
- if (sName.size()>5) {\r
- if (sName.substr(sName.size()-5, 5) == ".rti2" && !(fd.attrib & _A_SUBDIR))\r
- {\r
- string sPathName = sPath + sName;\r
- vPathName.push_back(sPathName);\r
- }\r
- }\r
-\r
- if (sName != "." && sName != ".." && (fd.attrib & _A_SUBDIR))\r
- {\r
- string sPath_sub = sPath + sName + '\\';\r
- string sWildCharPathName_sub = sPath_sub + '*';\r
- GetTableList(sWildCharPathName_sub, vPathName);\r
- }\r
-\r
- } while (_findnext(handle, &fd) == 0);\r
-\r
- _findclose(handle);\r
- }\r
- //printf("Found %d rainbowtables (files) in %d sub directories...\n", vPathName.size(), subDir_count);\r
-}\r
-#else\r
-//void GetTableList(int argc, char* argv[], vector<string>& vPathName)\r
-void GetTableList(string sWildCharPathName, vector<string>& vPathName)\r
-{\r
- //vPathName.clear();\r
-\r
- struct stat buf;\r
- if (lstat(sWildCharPathName.c_str(), &buf) == 0)\r
- {\r
- if (S_ISDIR(buf.st_mode))\r
- {\r
- DIR *dir = opendir(sWildCharPathName.c_str());\r
- if(dir)\r
- {\r
- struct dirent *pDir=NULL;\r
- while((pDir = readdir(dir)) != NULL)\r
- {\r
- string filename = "";\r
- filename += (*pDir).d_name;\r
- if (filename != "." && filename != "..")\r
- {\r
- string new_filename = sWildCharPathName + '/' + filename;\r
- GetTableList(new_filename, vPathName);\r
- }\r
- }\r
- closedir(dir);\r
- }\r
- }\r
- else if (S_ISREG(buf.st_mode))\r
- {\r
- if (sWildCharPathName.size()>3)\r
- {\r
- if (sWildCharPathName.substr(sWildCharPathName.size()-3, 3) == ".rt")\r
- {\r
- vPathName.push_back(sWildCharPathName);\r
- }\r
- }\r
- if (sWildCharPathName.size()>4)\r
- {\r
- if (sWildCharPathName.substr(sWildCharPathName.size()-4, 4) == ".rti")\r
- {\r
- //string sPathName_sub = sPath_sub + sName_sub;\r
- vPathName.push_back(sWildCharPathName);\r
- //printf("sPathName_sub: %s\n", sPathName_sub.c_str());\r
- }\r
- }\r
- if ( sWildCharPathName.size() > 5 )\r
- {\r
- if ( sWildCharPathName.substr( sWildCharPathName.size() - 5, 5 ) == ".rti2" )\r
- {\r
- vPathName.push_back( sWildCharPathName );\r
- }\r
- }\r
- }\r
- }\r
-}\r
-#endif\r
-\r
-bool NormalizeHash(string& sHash)\r
-{\r
- string sNormalizedHash = sHash;\r
-\r
- if ( sNormalizedHash.size() % 2 != 0\r
- || sNormalizedHash.size() < MIN_HASH_LEN * 2\r
- || sNormalizedHash.size() > MAX_HASH_LEN * 2)\r
- return false;\r
-\r
- // Make lower\r
- UINT4 i;\r
- for (i = 0; i < sNormalizedHash.size(); i++)\r
- {\r
- if (sNormalizedHash[i] >= 'A' && sNormalizedHash[i] <= 'F')\r
- sNormalizedHash[i] = (char) sNormalizedHash[i] - 'A' + 'a';\r
- }\r
-\r
- // Character check\r
- for (i = 0; i < sNormalizedHash.size(); i++)\r
- {\r
- if ( (sNormalizedHash[i] < 'a' || sNormalizedHash[i] > 'f')\r
- && (sNormalizedHash[i] < '0' || sNormalizedHash[i] > '9'))\r
- return false;\r
- }\r
-\r
- sHash = sNormalizedHash;\r
- return true;\r
-}\r
-\r
-void LoadLMHashFromPwdumpFile(string sPathName, vector<string>& vUserName, vector<string>& vLMHash, vector<string>& vNTLMHash)\r
-{\r
- vector<string> vLine;\r
- if (ReadLinesFromFile(sPathName, vLine))\r
- {\r
- UINT4 i;\r
- for (i = 0; i < vLine.size(); i++)\r
- {\r
- vector<string> vPart;\r
- if (SeperateString(vLine[i], "::::", vPart))\r
- {\r
- string sUserName = vPart[0];\r
- string sLMHash = vPart[2];\r
- string sNTLMHash = vPart[3];\r
-\r
- if (sLMHash.size() == 32 && sNTLMHash.size() == 32)\r
- {\r
- if (NormalizeHash(sLMHash) && NormalizeHash(sNTLMHash))\r
- {\r
- vUserName.push_back(sUserName);\r
- vLMHash.push_back(sLMHash);\r
- vNTLMHash.push_back(sNTLMHash);\r
- }\r
- else\r
- printf("invalid lm/ntlm hash %s:%s\n", sLMHash.c_str(), sNTLMHash.c_str());\r
- }\r
- }\r
- }\r
- }\r
- else\r
- printf("can't open %s\n", sPathName.c_str());\r
-}\r
-\r
-// 2009-01-04 - james.dickson - Added this so we can load hashes from cain .LST files.\r
-void LoadLMHashFromCainLSTFile(string sPathName, vector<string>& vUserName, vector<string>& vLMHash, vector<string>& vNTLMHash)\r
-{\r
- vector<string> vLine;\r
- if (ReadLinesFromFile(sPathName, vLine))\r
- {\r
- UINT4 i;\r
- for (i = 0; i < vLine.size(); i++)\r
- {\r
- vector<string> vPart;\r
- if (SeperateString(vLine[i], "\t\t\t\t\t\t", vPart))\r
- {\r
- string sUserName = vPart[0];\r
- string sLMHash = vPart[4];\r
- string sNTLMHash = vPart[5];\r
-\r
- if (sLMHash.size() == 32 && sNTLMHash.size() == 32)\r
- {\r
- if (NormalizeHash(sLMHash) && NormalizeHash(sNTLMHash))\r
- {\r
- vUserName.push_back(sUserName);\r
- vLMHash.push_back(sLMHash);\r
- vNTLMHash.push_back(sNTLMHash);\r
- }\r
- else\r
- printf("invalid lm/ntlm hash %s:%s\n", sLMHash.c_str(), sNTLMHash.c_str());\r
- }\r
- }\r
- }\r
- }\r
- else\r
- printf("can't open %s\n", sPathName.c_str());\r
-}\r
-\r
-bool NTLMPasswordSeek(unsigned char* pLMPassword, int nLMPasswordLen, int nLMPasswordNext,\r
- unsigned char* pNTLMHash, string& sNTLMPassword)\r
-{\r
- if (nLMPasswordNext == nLMPasswordLen)\r
- {\r
- unsigned char md[MD4_DIGEST_LENGTH];\r
- MD4_NEW(pLMPassword, nLMPasswordLen * 2, md);\r
-\r
- if (memcmp(md, pNTLMHash, MD4_DIGEST_LENGTH) == 0)\r
- {\r
- sNTLMPassword = "";\r
- int i;\r
- for (i = 0; i < nLMPasswordLen; i++)\r
- sNTLMPassword += char(pLMPassword[i * 2]);\r
- return true;\r
- }\r
- else\r
- return false;\r
- }\r
-\r
- if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))\r
- return true;\r
-\r
- if ( pLMPassword[nLMPasswordNext * 2] >= 'A'\r
- && pLMPassword[nLMPasswordNext * 2] <= 'Z')\r
- {\r
- pLMPassword[nLMPasswordNext * 2] = (unsigned char) pLMPassword[nLMPasswordNext * 2] - 'A' + 'a';\r
- if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))\r
- return true;\r
- pLMPassword[nLMPasswordNext * 2] = (unsigned char) pLMPassword[nLMPasswordNext * 2] - 'a' + 'A';\r
- }\r
-\r
- return false;\r
-}\r
-\r
-bool LMPasswordCorrectCase(string sLMPassword, unsigned char* pNTLMHash, string& sNTLMPassword)\r
-{\r
- if (sLMPassword.size() == 0)\r
- {\r
- sNTLMPassword = "";\r
- return true;\r
- }\r
-\r
- unsigned char* pLMPassword = new unsigned char[sLMPassword.size() * 2];\r
- UINT4 i;\r
- for (i = 0; i < sLMPassword.size(); i++)\r
- {\r
- pLMPassword[i * 2 ] = sLMPassword[i];\r
- pLMPassword[i * 2 + 1] = 0x00;\r
- }\r
- bool fRet = NTLMPasswordSeek(pLMPassword, sLMPassword.size(), 0, pNTLMHash, sNTLMPassword);\r
-\r
- delete pLMPassword;\r
-\r
- return fRet;\r
-}\r
-\r
-void Usage()\r
-{\r
- Logo();\r
-\r
- printf("usage: rcracki_mt -h hash rainbow_table_pathname\n");\r
- printf(" rcracki_mt -l hash_list_file rainbow_table_pathname\n");\r
- printf(" rcracki_mt -f pwdump_file rainbow_table_pathname\n");\r
- printf(" rcracki_mt -c lst_file rainbow_table_pathname\n");\r
- printf("\n");\r
- printf("-h hash: use raw hash as input\n");\r
- printf("-l hash_list_file: use hash list file as input, each hash in a line\n");\r
- printf("-f pwdump_file: use pwdump file as input, handles lanmanager hash only\n");\r
- printf("-c lst_file: use .lst (cain format) file as input\n");\r
- printf("-r [-s session_name]: resume from previous session, optional session name\n");\r
- printf("rainbow_table_pathname: pathname(s) of the rainbow table(s)\n");\r
- printf("\n");\r
- printf("Extra options: -t [nr] use this amount of threads/cores, default is 1\n");\r
- printf(" -o [output_file] write (temporary) results to this file\n");\r
- printf(" -s [session_name] write session data with this name\n");\r
- printf(" -k keep precalculation on disk\n");\r
- printf(" -m [megabytes] limit memory usage\n");\r
- printf(" -v show debug information\n");\r
- printf("\n");\r
-#ifdef _WIN32\r
- printf("example: rcracki_mt -h 5d41402abc4b2a76b9719d911017c592 -t 2 [path]\\MD5\n");\r
- printf(" rcracki_mt -l hash.txt [path_to_specific_table]\\*\n");\r
-#else\r
- printf("example: rcracki_mt -h 5d41402abc4b2a76b9719d911017c592 -t 2 [path]/MD5\n");\r
- printf(" rcracki_mt -l hash.txt [path_to_specific_table]/*\n");\r
-#endif\r
- printf(" rcracki_mt -f hash.txt -t 4 -o results.txt *.rti\n");\r
-}\r
-\r
-int main(int argc, char* argv[])\r
-{\r
- if (argc < 2)\r
- {\r
- Usage();\r
- return 0;\r
- }\r
-\r
- vector<string> vPathName;\r
- vector<string> vDefaultRainbowTablePath;\r
- string sWildCharPathName = "";\r
- string sInputType = "";\r
- string sInput = "";\r
- string outputFile = "";\r
- string sApplicationPath = "";\r
- string sIniPathName = "rcracki_mt.ini";\r
- bool writeOutput = false;\r
- string sSessionPathName = "rcracki.session";\r
- string sProgressPathName = "rcracki.progress";\r
- string sPrecalcPathName = "rcracki.precalc";\r
- bool resumeSession = false;\r
- bool useDefaultRainbowTablePath = false;\r
- bool debug = false;\r
- bool keepPrecalcFiles = false;\r
- string sAlgorithm = "";\r
- int maxThreads = 1;\r
- uint64 maxMem = 0;\r
- CHashSet hs;\r
-\r
- // Read defaults from ini file;\r
- bool readFromIni = false;\r
- vector<string> vLine;\r
- if (ReadLinesFromFile(sIniPathName, vLine)) {\r
- readFromIni = true;\r
- }\r
- else if (ReadLinesFromFile(GetApplicationPath() + sIniPathName, vLine)) {\r
- readFromIni = true;\r
- }\r
- if (readFromIni)\r
- {\r
- UINT4 i;\r
- for (i = 0; i < vLine.size(); i++)\r
- {\r
- if (vLine[i].substr(0,1) != "#")\r
- {\r
- vector<string> vPart;\r
- if (SeperateString(vLine[i], "=", vPart))\r
- {\r
- string sOption = vPart[0];\r
- string sValue = vPart[1];\r
- \r
- if (sOption == "Threads") {\r
- maxThreads = atoi(sValue.c_str());\r
- }\r
- else if (sOption == "MaxMemoryUsage" ) {\r
- maxMem = atoi(sValue.c_str()) * 1024 *1024;\r
- }\r
- else if (sOption == "DefaultResultsFile") {\r
- outputFile = sValue;\r
- }\r
- else if (sOption == "AlwaysStoreResultsToFile") {\r
- if (sValue == "1")\r
- writeOutput = true;\r
- }\r
- else if (sOption.substr(0,24) == "DefaultRainbowTablePath.") {\r
- //printf("Default RT path: %s\n", sValue.c_str());\r
- vDefaultRainbowTablePath.push_back(vLine[i]);\r
- }\r
- else if (sOption == "DefaultAlgorithm") {\r
- useDefaultRainbowTablePath = true;\r
- sAlgorithm = sValue;\r
- }\r
- else if (sOption == "AlwaysDebug") {\r
- if (sValue == "1")\r
- debug = true;\r
- }\r
- else if (sOption == "AlwaysKeepPrecalcFiles") {\r
- if (sValue == "1")\r
- keepPrecalcFiles = true;\r
- }\r
- else {\r
- printf("illegal option %s in ini file %s\n", sOption.c_str(), sIniPathName.c_str());\r
- return 0;\r
- }\r
- }\r
- }\r
- }\r
- if (writeOutput && outputFile == "")\r
- {\r
- printf("You need to specify a 'DefaultResultsFile' with 'AlwaysStoreResultsToFile=1'\n");\r
- writeOutput = false;\r
- }\r
- }\r
-\r
- // Parse command line arguments\r
- int i;\r
- for (i = 1; i < argc; i++)\r
- {\r
- string cla = argv[i];\r
- if (cla == "-h") {\r
- sInputType = cla;\r
- i++;\r
- if (i < argc)\r
- sInput = argv[i];\r
- }\r
- else if (cla == "-l") {\r
- sInputType = cla;\r
- i++;\r
- if (i < argc)\r
- sInput = argv[i];\r
- }\r
- else if (cla == "-f") {\r
- sInputType = cla;\r
- i++;\r
- if (i < argc)\r
- sInput = argv[i];\r
- }\r
- else if (cla == "-c") {\r
- sInputType = cla;\r
- i++;\r
- if (i < argc)\r
- sInput = argv[i];\r
- }\r
- else if (cla == "-t") {\r
- i++;\r
- if (i < argc)\r
- maxThreads = atoi(argv[i]);\r
- }\r
- else if ( cla == "-m" ) {\r
- i++;\r
- if ( i < argc )\r
- maxMem = atoi(argv[i]) * 1024 * 1024;\r
- }\r
- else if (cla == "-o") {\r
- writeOutput = true;\r
- i++;\r
- if (i < argc)\r
- outputFile = argv[i];\r
- }\r
- else if (cla == "-r") {\r
- resumeSession = true;\r
- }\r
- else if (cla == "-s") {\r
- i++;\r
- if (i < argc)\r
- {\r
- sSessionPathName = argv[i];\r
- sSessionPathName += ".session";\r
- sProgressPathName = argv[i];\r
- sProgressPathName += ".progress";\r
- sPrecalcPathName = argv[i];\r
- sPrecalcPathName += ".precalc";\r
- }\r
- }\r
- else if (cla == "-v") {\r
- debug = true;\r
- }\r
- else if (cla == "-k") {\r
- keepPrecalcFiles = true;\r
- }\r
- else if (cla == "-a") {\r
- useDefaultRainbowTablePath = true;\r
- i++;\r
- if (i < argc)\r
- sAlgorithm = argv[i];\r
- }\r
- else {\r
- GetTableList(cla, vPathName);\r
- }\r
- }\r
-\r
- if (debug && !readFromIni)\r
- printf("Debug: Couldn't read rcracki_mt.ini, continuing anyway.\n");\r
-\r
- // Load session data if we are resuming\r
- if (resumeSession)\r
- {\r
- vPathName.clear();\r
- vector<string> sSessionData;\r
- if (ReadLinesFromFile(sSessionPathName.c_str(), sSessionData))\r
- {\r
- UINT4 i;\r
- for (i = 0; i < sSessionData.size(); i++)\r
- {\r
- vector<string> vPart;\r
- if (SeperateString(sSessionData[i], "=", vPart))\r
- {\r
- string sOption = vPart[0];\r
- string sValue = vPart[1];\r
- \r
- if (sOption == "sPathName") {\r
- vPathName.push_back(sValue);\r
- }\r
- else if (sOption == "sInputType") {\r
- sInputType = sValue;\r
- }\r
- else if (sOption == "sInput") {\r
- sInput = sValue;\r
- }\r
- else if (sOption == "outputFile") {\r
- writeOutput = true;\r
- outputFile = sValue;\r
- }\r
- else if (sOption == "keepPrecalcFiles") {\r
- if (sValue == "1")\r
- keepPrecalcFiles = true;\r
- }\r
- }\r
- }\r
- }\r
- else {\r
- printf("Couldn't open session file %s\n", sSessionPathName.c_str());\r
- return 0;\r
- }\r
- }\r
-\r
- if (maxThreads<1)\r
- maxThreads = 1;\r
-\r
- // don't load these if we are resuming a session that already has a list of tables\r
- if (useDefaultRainbowTablePath && !resumeSession)\r
- {\r
- UINT4 i;\r
- for (i = 0; i < vDefaultRainbowTablePath.size(); i++)\r
- {\r
- vector<string> vPart;\r
- if (SeperateString(vDefaultRainbowTablePath[i], ".=", vPart))\r
- {\r
- string lineAlgorithm = vPart[1];\r
- string linePath = vPart[2];\r
-\r
- if (lineAlgorithm == sAlgorithm)\r
- GetTableList(linePath, vPathName);\r
- }\r
- }\r
- }\r
-\r
- printf("Using %d threads for pre-calculation and false alarm checking...\n", maxThreads);\r
-\r
- setvbuf(stdout, NULL, _IONBF,0);\r
- if (vPathName.size() == 0)\r
- {\r
- printf("no rainbow table found\n");\r
- return 0;\r
- }\r
- printf("Found %lu rainbowtable files...\n\n",\r
- (unsigned long)vPathName.size());\r
-\r
- bool fCrackerType; // true: hash cracker, false: lm cracker\r
- vector<string> vHash; // hash cracker\r
- vector<string> vUserName; // lm cracker\r
- vector<string> vLMHash; // lm cracker\r
- vector<string> vNTLMHash; // lm cracker\r
- if (sInputType == "-h")\r
- {\r
- fCrackerType = true;\r
-\r
- string sHash = sInput;\r
- if (NormalizeHash(sHash))\r
- vHash.push_back(sHash);\r
- else\r
- printf("invalid hash: %s\n", sHash.c_str());\r
- }\r
- else if (sInputType == "-l")\r
- {\r
- fCrackerType = true;\r
-\r
- string sPathName = sInput;\r
- vector<string> vLine;\r
- if (ReadLinesFromFile(sPathName, vLine))\r
- {\r
- UINT4 i;\r
- for (i = 0; i < vLine.size(); i++)\r
- {\r
- string sHash = vLine[i];\r
- if (NormalizeHash(sHash))\r
- vHash.push_back(sHash);\r
- else\r
- printf("invalid hash: %s\n", sHash.c_str());\r
- }\r
- }\r
- else\r
- printf("can't open %s\n", sPathName.c_str());\r
- }\r
- else if (sInputType == "-f")\r
- {\r
- fCrackerType = false;\r
-\r
- string sPathName = sInput;\r
- LoadLMHashFromPwdumpFile(sPathName, vUserName, vLMHash, vNTLMHash);\r
- }\r
- else if (sInputType == "-c")\r
- {\r
- // 2009-01-04 - james.dickson - Added this for cain-files.\r
- fCrackerType = false;\r
- string sPathName = sInput;\r
- LoadLMHashFromCainLSTFile(sPathName, vUserName, vLMHash, vNTLMHash);\r
- }\r
- else\r
- {\r
- Usage();\r
- return 0;\r
- }\r
-\r
- if (fCrackerType && vHash.size() == 0)\r
- {\r
- printf("no hashes found");\r
- return 0;\r
- }\r
- if (!fCrackerType && vLMHash.size() == 0)\r
- {\r
- return 0;\r
- printf("no hashes found");\r
- }\r
-\r
- if (fCrackerType)\r
- {\r
- UINT4 i;\r
- for (i = 0; i < vHash.size(); i++)\r
- hs.AddHash(vHash[i]);\r
- }\r
- else\r
- {\r
- UINT4 i;\r
- for (i = 0; i < vLMHash.size(); i++)\r
- {\r
- hs.AddHash(vLMHash[i].substr(0, 16));\r
- hs.AddHash(vLMHash[i].substr(16, 16));\r
- }\r
- }\r
-\r
- // Load found hashes from session file\r
- if (resumeSession)\r
- {\r
- vector<string> sSessionData;\r
- if (ReadLinesFromFile(sSessionPathName.c_str(), sSessionData))\r
- {\r
- UINT4 i;\r
- for (i = 0; i < sSessionData.size(); i++)\r
- {\r
- vector<string> vPart;\r
- if (SeperateString(sSessionData[i], "=", vPart))\r
- {\r
- string sOption = vPart[0];\r
- string sValue = vPart[1];\r
- \r
- if (sOption == "sHash") {\r
- vector<string> vPartHash;\r
- if (SeperateString(sValue, "::", vPartHash))\r
- {\r
- string sHash = vPartHash[0];\r
- string sBinary = vPartHash[1];\r
- string sPlain = vPartHash[2];\r
- \r
- hs.SetPlain(sHash, sPlain, sBinary);\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
- // (Over)write session data if we are not resuming\r
- if (!resumeSession)\r
- {\r
- FILE* file = fopen(sSessionPathName.c_str(), "w");\r
- string buffer = "";\r
-\r
- if (file!=NULL)\r
- {\r
- buffer += "sInputType=" + sInputType + "\n";\r
- buffer += "sInput=" + sInput + "\n";\r
-\r
- UINT4 i;\r
- for (i = 0; i < vPathName.size(); i++)\r
- {\r
- buffer += "sPathName=" + vPathName[i] + "\n";\r
- }\r
-\r
- if (writeOutput)\r
- buffer += "outputFile=" + outputFile + "\n";\r
-\r
- if (keepPrecalcFiles)\r
- buffer += "keepPrecalcFiles=1\n";\r
-\r
- fputs (buffer.c_str(), file);\r
- fclose (file);\r
- }\r
- file = fopen(sProgressPathName.c_str(), "w");\r
- fclose (file);\r
- }\r
-\r
- // Run\r
- CCrackEngine ce;\r
- if (writeOutput)\r
- ce.setOutputFile(outputFile);\r
- ce.setSession(sSessionPathName, sProgressPathName, sPrecalcPathName, keepPrecalcFiles);\r
- ce.Run(vPathName, hs, maxThreads, maxMem, resumeSession, debug);\r
-\r
- // Remove session files\r
- if (debug) printf("Debug: Removing session files.\n");\r
-\r
- if (remove(sSessionPathName.c_str()) == 0)\r
- remove(sProgressPathName.c_str());\r
- else\r
- if (debug) printf("Debug: Failed removing session files.\n");\r
-\r
- // Statistics\r
- printf("statistics\n");\r
- printf("-------------------------------------------------------\n");\r
- printf("plaintext found: %d of %d (%.2f%%)\n", hs.GetStatHashFound(),\r
- hs.GetStatHashTotal(),\r
- 100.0f * hs.GetStatHashFound() / hs.GetStatHashTotal());\r
- printf("total disk access time: %.2f s\n", ce.GetStatTotalDiskAccessTime());\r
- printf("total cryptanalysis time: %.2f s\n", ce.GetStatTotalCryptanalysisTime());\r
- printf("total pre-calculation time: %.2f s\n", ce.GetStatTotalPrecalculationTime());\r
- printf("total chain walk step: %d\n", ce.GetStatTotalChainWalkStep());\r
- printf("total false alarm: %d\n", ce.GetStatTotalFalseAlarm());\r
- printf("total chain walk step due to false alarm: %d\n", ce.GetStatTotalChainWalkStepDueToFalseAlarm());\r
-// printf("total chain walk step skipped due to checkpoints: %d\n", ce.GetStatTotalFalseAlarmSkipped()); // Checkpoints not used - yet\r
- printf("\n");\r
-\r
- // Result\r
- printf("result\n");\r
- printf("-------------------------------------------------------\n");\r
- if (fCrackerType)\r
- {\r
- UINT4 i;\r
- for (i = 0; i < vHash.size(); i++)\r
- {\r
- string sPlain, sBinary;\r
- if (!hs.GetPlain(vHash[i], sPlain, sBinary))\r
- {\r
- sPlain = "<notfound>";\r
- sBinary = "<notfound>";\r
- }\r
-\r
- printf("%s\t%s\thex:%s\n", vHash[i].c_str(), sPlain.c_str(), sBinary.c_str());\r
- }\r
- }\r
- else\r
- {\r
- UINT4 i;\r
- for (i = 0; i < vLMHash.size(); i++)\r
- {\r
- string sPlain1, sBinary1;\r
- bool fPart1Found = hs.GetPlain(vLMHash[i].substr(0, 16), sPlain1, sBinary1);\r
- if (!fPart1Found)\r
- {\r
- sPlain1 = "<notfound>";\r
- sBinary1 = "<notfound>";\r
- }\r
-\r
- string sPlain2, sBinary2;\r
- bool fPart2Found = hs.GetPlain(vLMHash[i].substr(16, 16), sPlain2, sBinary2);\r
- if (!fPart2Found)\r
- {\r
- sPlain2 = "<notfound>";\r
- sBinary2 = "<notfound>";\r
- }\r
-\r
- string sPlain = sPlain1 + sPlain2;\r
- string sBinary = sBinary1 + sBinary2;\r
-\r
- // Correct case\r
- if (fPart1Found && fPart2Found)\r
- {\r
- unsigned char NTLMHash[16];\r
- int nHashLen;\r
- ParseHash(vNTLMHash[i], NTLMHash, nHashLen);\r
- if (nHashLen != 16)\r
- printf("debug: nHashLen mismatch\n");\r
- string sNTLMPassword;\r
- if (LMPasswordCorrectCase(sPlain, NTLMHash, sNTLMPassword))\r
- {\r
- sPlain = sNTLMPassword;\r
- sBinary = HexToStr((const unsigned char*)sNTLMPassword.c_str(), sNTLMPassword.size());\r
- }\r
- else\r
- {\r
- printf("%-14s\t%s\thex:%s\n", vUserName[i].c_str(), sPlain.c_str(), sBinary.c_str());\r
- LM2NTLMcorrector corrector;\r
- if (corrector.LMPasswordCorrectUnicode(sBinary, NTLMHash, sNTLMPassword))\r
- {\r
- sPlain = sNTLMPassword;\r
- sBinary = corrector.getBinary();\r
- if (writeOutput)\r
- {\r
- if (!writeResultLineToFile(outputFile, vNTLMHash[i].c_str(), sPlain.c_str(), sBinary.c_str()))\r
- printf("Couldn't write final result to file!\n");\r
- }\r
- }\r
- else {\r
- printf("case correction for password %s failed!\n", sPlain.c_str());\r
- }\r
- }\r
- }\r
-\r
- // Display\r
- printf("%-14s\t%s\thex:%s\n", vUserName[i].c_str(),\r
- sPlain.c_str(),\r
- sBinary.c_str());\r
- \r
- }\r
- }\r
-\r
- return 0;\r
-}\r
+/*
+ * rcracki_mt is a multithreaded implementation and fork of the original
+ * RainbowCrack
+ *
+ * Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+ * Copyright Martin Westergaard Jørgensen <martinwj2005@gmail.com>
+ * Copyright 2009, 2010 Daniël Niggebrugge <niggebrugge@fox-it.com>
+ * Copyright 2009 James Dickson
+ * Copyright 2009, 2010 James Nobis <frt@quelrod.net>
+ * Copyright 2010 uroskn
+ *
+ * Modified by Martin Westergaard Jørgensen <martinwj2005@gmail.com> to support * indexed and hybrid tables
+ *
+ * Modified by neinbrucke to support multi threading and a bunch of other stuff :)
+ *
+ * 2009-01-04 - <james.dickson@comhem.se> - Slightly modified (or "fulhack" as
+ * we say in sweden) to support cain .lst files.
+ *
+ * This file is part of rcracki_mt.
+ *
+ * rcracki_mt 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * rcracki_mt 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 rcracki_mt. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if defined(_WIN32) && !defined(__GNUC__)
+ #pragma warning(disable : 4786 4267 4018)
+#endif
+
+#include "CrackEngine.h"
+#include "lm2ntlm.h"
+#include <algorithm>
+
+#ifdef _WIN32
+ #include <io.h>
+#else
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+ #include <dirent.h>
+#endif
+
+#if defined(_WIN32) && !defined(__GNUC__)
+ #pragma comment(lib, "libeay32.lib")
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN32
+void GetTableList(string sWildCharPathName, vector<string>& vPathName)
+{
+ //vPathName.clear();
+
+ string sPath;
+ string::size_type n = sWildCharPathName.find_last_of('\\');
+
+ if ( n == (sWildCharPathName.size() - 1) )
+ {
+ sWildCharPathName = sWildCharPathName.substr(0, n);
+ n = sWildCharPathName.find_last_of('\\');
+ }
+
+ if (n != string::npos)
+ sPath = sWildCharPathName.substr(0, n + 1);
+
+ _finddata_t fd;
+
+ long handle = _findfirst(sWildCharPathName.c_str(), &fd);
+ if (handle != -1)
+ {
+ do
+ {
+ string sName = fd.name;
+ if (sName.size()>3) {
+ if (sName.substr(sName.size()-3, 3) == ".rt" && !(fd.attrib & _A_SUBDIR))
+ {
+ string sPathName = sPath + sName;
+ vPathName.push_back(sPathName);
+ }
+ }
+ if (sName.size()>4) {
+ if (sName.substr(sName.size()-4, 4) == ".rti" && !(fd.attrib & _A_SUBDIR))
+ {
+ string sPathName = sPath + sName;
+ vPathName.push_back(sPathName);
+ }
+ }
+ if (sName.size()>5) {
+ if (sName.substr(sName.size()-5, 5) == ".rti2" && !(fd.attrib & _A_SUBDIR))
+ {
+ string sPathName = sPath + sName;
+ vPathName.push_back(sPathName);
+ }
+ }
+
+ if (sName != "." && sName != ".." && (fd.attrib & _A_SUBDIR))
+ {
+ string sPath_sub = sPath + sName + '\\';
+ string sWildCharPathName_sub = sPath_sub + '*';
+ GetTableList(sWildCharPathName_sub, vPathName);
+ }
+
+ } while (_findnext(handle, &fd) == 0);
+
+ _findclose(handle);
+ }
+ //printf("Found %d rainbowtables (files) in %d sub directories...\n", vPathName.size(), subDir_count);
+}
+#else
+//void GetTableList(int argc, char* argv[], vector<string>& vPathName)
+void GetTableList(string sWildCharPathName, vector<string>& vPathName)
+{
+ //vPathName.clear();
+
+ struct stat buf;
+ if (lstat(sWildCharPathName.c_str(), &buf) == 0)
+ {
+ if (S_ISDIR(buf.st_mode))
+ {
+ DIR *dir = opendir(sWildCharPathName.c_str());
+ if(dir)
+ {
+ struct dirent *pDir=NULL;
+ while((pDir = readdir(dir)) != NULL)
+ {
+ string filename = "";
+ filename += (*pDir).d_name;
+ if (filename != "." && filename != "..")
+ {
+ string new_filename = sWildCharPathName + '/' + filename;
+ GetTableList(new_filename, vPathName);
+ }
+ }
+ closedir(dir);
+ }
+ }
+ else if (S_ISREG(buf.st_mode))
+ {
+ if (sWildCharPathName.size()>3)
+ {
+ if (sWildCharPathName.substr(sWildCharPathName.size()-3, 3) == ".rt")
+ {
+ vPathName.push_back(sWildCharPathName);
+ }
+ }
+ if (sWildCharPathName.size()>4)
+ {
+ if (sWildCharPathName.substr(sWildCharPathName.size()-4, 4) == ".rti")
+ {
+ //string sPathName_sub = sPath_sub + sName_sub;
+ vPathName.push_back(sWildCharPathName);
+ //printf("sPathName_sub: %s\n", sPathName_sub.c_str());
+ }
+ }
+ if ( sWildCharPathName.size() > 5 )
+ {
+ if ( sWildCharPathName.substr( sWildCharPathName.size() - 5, 5 ) == ".rti2" )
+ {
+ vPathName.push_back( sWildCharPathName );
+ }
+ }
+ }
+ }
+}
+#endif
+
+bool NormalizeHash(string& sHash)
+{
+ string sNormalizedHash = sHash;
+
+ if ( sNormalizedHash.size() % 2 != 0
+ || sNormalizedHash.size() < MIN_HASH_LEN * 2
+ || sNormalizedHash.size() > MAX_HASH_LEN * 2)
+ return false;
+
+ // Make lower
+ UINT4 i;
+ for (i = 0; i < sNormalizedHash.size(); i++)
+ {
+ if (sNormalizedHash[i] >= 'A' && sNormalizedHash[i] <= 'F')
+ sNormalizedHash[i] = (char) sNormalizedHash[i] - 'A' + 'a';
+ }
+
+ // Character check
+ for (i = 0; i < sNormalizedHash.size(); i++)
+ {
+ if ( (sNormalizedHash[i] < 'a' || sNormalizedHash[i] > 'f')
+ && (sNormalizedHash[i] < '0' || sNormalizedHash[i] > '9'))
+ return false;
+ }
+
+ sHash = sNormalizedHash;
+ return true;
+}
+
+void LoadLMHashFromPwdumpFile(string sPathName, vector<string>& vUserName, vector<string>& vLMHash, vector<string>& vNTLMHash)
+{
+ vector<string> vLine;
+ if (ReadLinesFromFile(sPathName, vLine))
+ {
+ UINT4 i;
+ for (i = 0; i < vLine.size(); i++)
+ {
+ vector<string> vPart;
+ if (SeperateString(vLine[i], "::::", vPart))
+ {
+ string sUserName = vPart[0];
+ string sLMHash = vPart[2];
+ string sNTLMHash = vPart[3];
+
+ if (sLMHash.size() == 32 && sNTLMHash.size() == 32)
+ {
+ if (NormalizeHash(sLMHash) && NormalizeHash(sNTLMHash))
+ {
+ vUserName.push_back(sUserName);
+ vLMHash.push_back(sLMHash);
+ vNTLMHash.push_back(sNTLMHash);
+ }
+ else
+ printf("invalid lm/ntlm hash %s:%s\n", sLMHash.c_str(), sNTLMHash.c_str());
+ }
+ }
+ }
+ }
+ else
+ printf("can't open %s\n", sPathName.c_str());
+}
+
+// 2009-01-04 - james.dickson - Added this so we can load hashes from cain .LST files.
+void LoadLMHashFromCainLSTFile(string sPathName, vector<string>& vUserName, vector<string>& vLMHash, vector<string>& vNTLMHash)
+{
+ vector<string> vLine;
+ if (ReadLinesFromFile(sPathName, vLine))
+ {
+ UINT4 i;
+ for (i = 0; i < vLine.size(); i++)
+ {
+ vector<string> vPart;
+ if (SeperateString(vLine[i], "\t\t\t\t\t\t", vPart))
+ {
+ string sUserName = vPart[0];
+ string sLMHash = vPart[4];
+ string sNTLMHash = vPart[5];
+
+ if (sLMHash.size() == 32 && sNTLMHash.size() == 32)
+ {
+ if (NormalizeHash(sLMHash) && NormalizeHash(sNTLMHash))
+ {
+ vUserName.push_back(sUserName);
+ vLMHash.push_back(sLMHash);
+ vNTLMHash.push_back(sNTLMHash);
+ }
+ else
+ printf("invalid lm/ntlm hash %s:%s\n", sLMHash.c_str(), sNTLMHash.c_str());
+ }
+ }
+ }
+ }
+ else
+ printf("can't open %s\n", sPathName.c_str());
+}
+
+bool NTLMPasswordSeek(unsigned char* pLMPassword, int nLMPasswordLen, int nLMPasswordNext,
+ unsigned char* pNTLMHash, string& sNTLMPassword)
+{
+ if (nLMPasswordNext == nLMPasswordLen)
+ {
+ unsigned char md[MD4_DIGEST_LENGTH];
+ MD4_NEW(pLMPassword, nLMPasswordLen * 2, md);
+
+ if (memcmp(md, pNTLMHash, MD4_DIGEST_LENGTH) == 0)
+ {
+ sNTLMPassword = "";
+ int i;
+ for (i = 0; i < nLMPasswordLen; i++)
+ sNTLMPassword += char(pLMPassword[i * 2]);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))
+ return true;
+
+ if ( pLMPassword[nLMPasswordNext * 2] >= 'A'
+ && pLMPassword[nLMPasswordNext * 2] <= 'Z')
+ {
+ pLMPassword[nLMPasswordNext * 2] = (unsigned char) pLMPassword[nLMPasswordNext * 2] - 'A' + 'a';
+ if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))
+ return true;
+ pLMPassword[nLMPasswordNext * 2] = (unsigned char) pLMPassword[nLMPasswordNext * 2] - 'a' + 'A';
+ }
+
+ return false;
+}
+
+bool LMPasswordCorrectCase(string sLMPassword, unsigned char* pNTLMHash, string& sNTLMPassword)
+{
+ if (sLMPassword.size() == 0)
+ {
+ sNTLMPassword = "";
+ return true;
+ }
+
+ unsigned char* pLMPassword = new unsigned char[sLMPassword.size() * 2];
+ UINT4 i;
+ for (i = 0; i < sLMPassword.size(); i++)
+ {
+ pLMPassword[i * 2 ] = sLMPassword[i];
+ pLMPassword[i * 2 + 1] = 0x00;
+ }
+ bool fRet = NTLMPasswordSeek(pLMPassword, sLMPassword.size(), 0, pNTLMHash, sNTLMPassword);
+
+ delete pLMPassword;
+
+ return fRet;
+}
+
+void Usage()
+{
+ Logo();
+
+ printf("usage: rcracki_mt -h hash rainbow_table_pathname\n");
+ printf(" rcracki_mt -l hash_list_file rainbow_table_pathname\n");
+ printf(" rcracki_mt -f pwdump_file rainbow_table_pathname\n");
+ printf(" rcracki_mt -c lst_file rainbow_table_pathname\n");
+ printf("\n");
+ printf("-h hash: use raw hash as input\n");
+ printf("-l hash_list_file: use hash list file as input, each hash in a line\n");
+ printf("-f pwdump_file: use pwdump file as input, handles lanmanager hash only\n");
+ printf("-c lst_file: use .lst (cain format) file as input\n");
+ printf("-r [-s session_name]: resume from previous session, optional session name\n");
+ printf("rainbow_table_pathname: pathname(s) of the rainbow table(s)\n");
+ printf("\n");
+ printf("Extra options: -t [nr] use this amount of threads/cores, default is 1\n");
+ printf(" -o [output_file] write (temporary) results to this file\n");
+ printf(" -s [session_name] write session data with this name\n");
+ printf(" -k keep precalculation on disk\n");
+ printf(" -m [megabytes] limit memory usage\n");
+ printf(" -v show debug information\n");
+ printf("\n");
+#ifdef _WIN32
+ printf("example: rcracki_mt -h 5d41402abc4b2a76b9719d911017c592 -t 2 [path]\\MD5\n");
+ printf(" rcracki_mt -l hash.txt [path_to_specific_table]\\*\n");
+#else
+ printf("example: rcracki_mt -h 5d41402abc4b2a76b9719d911017c592 -t 2 [path]/MD5\n");
+ printf(" rcracki_mt -l hash.txt [path_to_specific_table]/*\n");
+#endif
+ printf(" rcracki_mt -f hash.txt -t 4 -o results.txt *.rti\n");
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2)
+ {
+ Usage();
+ return 0;
+ }
+
+ vector<string> vPathName;
+ vector<string> vDefaultRainbowTablePath;
+ string sWildCharPathName = "";
+ string sInputType = "";
+ string sInput = "";
+ string outputFile = "";
+ string sApplicationPath = "";
+ string sIniPathName = "rcracki_mt.ini";
+ bool writeOutput = false;
+ string sSessionPathName = "rcracki.session";
+ string sProgressPathName = "rcracki.progress";
+ string sPrecalcPathName = "rcracki.precalc";
+ bool resumeSession = false;
+ bool useDefaultRainbowTablePath = false;
+ bool debug = false;
+ bool keepPrecalcFiles = false;
+ string sAlgorithm = "";
+ int maxThreads = 1;
+ uint64 maxMem = 0;
+ CHashSet hs;
+
+ // Read defaults from ini file;
+ bool readFromIni = false;
+ vector<string> vLine;
+ if (ReadLinesFromFile(sIniPathName, vLine)) {
+ readFromIni = true;
+ }
+ else if (ReadLinesFromFile(GetApplicationPath() + sIniPathName, vLine)) {
+ readFromIni = true;
+ }
+ if (readFromIni)
+ {
+ UINT4 i;
+ for (i = 0; i < vLine.size(); i++)
+ {
+ if (vLine[i].substr(0,1) != "#")
+ {
+ vector<string> vPart;
+ if (SeperateString(vLine[i], "=", vPart))
+ {
+ string sOption = vPart[0];
+ string sValue = vPart[1];
+
+ if (sOption == "Threads") {
+ maxThreads = atoi(sValue.c_str());
+ }
+ else if (sOption == "MaxMemoryUsage" ) {
+ maxMem = atoi(sValue.c_str()) * 1024 *1024;
+ }
+ else if (sOption == "DefaultResultsFile") {
+ outputFile = sValue;
+ }
+ else if (sOption == "AlwaysStoreResultsToFile") {
+ if (sValue == "1")
+ writeOutput = true;
+ }
+ else if (sOption.substr(0,24) == "DefaultRainbowTablePath.") {
+ //printf("Default RT path: %s\n", sValue.c_str());
+ vDefaultRainbowTablePath.push_back(vLine[i]);
+ }
+ else if (sOption == "DefaultAlgorithm") {
+ useDefaultRainbowTablePath = true;
+ sAlgorithm = sValue;
+ }
+ else if (sOption == "AlwaysDebug") {
+ if (sValue == "1")
+ debug = true;
+ }
+ else if (sOption == "AlwaysKeepPrecalcFiles") {
+ if (sValue == "1")
+ keepPrecalcFiles = true;
+ }
+ else {
+ printf("illegal option %s in ini file %s\n", sOption.c_str(), sIniPathName.c_str());
+ return 0;
+ }
+ }
+ }
+ }
+ if (writeOutput && outputFile == "")
+ {
+ printf("You need to specify a 'DefaultResultsFile' with 'AlwaysStoreResultsToFile=1'\n");
+ writeOutput = false;
+ }
+ }
+
+ // Parse command line arguments
+ int i;
+ for (i = 1; i < argc; i++)
+ {
+ string cla = argv[i];
+ if (cla == "-h") {
+ sInputType = cla;
+ i++;
+ if (i < argc)
+ sInput = argv[i];
+ }
+ else if (cla == "-l") {
+ sInputType = cla;
+ i++;
+ if (i < argc)
+ sInput = argv[i];
+ }
+ else if (cla == "-f") {
+ sInputType = cla;
+ i++;
+ if (i < argc)
+ sInput = argv[i];
+ }
+ else if (cla == "-c") {
+ sInputType = cla;
+ i++;
+ if (i < argc)
+ sInput = argv[i];
+ }
+ else if (cla == "-t") {
+ i++;
+ if (i < argc)
+ maxThreads = atoi(argv[i]);
+ }
+ else if ( cla == "-m" ) {
+ i++;
+ if ( i < argc )
+ maxMem = atoi(argv[i]) * 1024 * 1024;
+ }
+ else if (cla == "-o") {
+ writeOutput = true;
+ i++;
+ if (i < argc)
+ outputFile = argv[i];
+ }
+ else if (cla == "-r") {
+ resumeSession = true;
+ }
+ else if (cla == "-s") {
+ i++;
+ if (i < argc)
+ {
+ sSessionPathName = argv[i];
+ sSessionPathName += ".session";
+ sProgressPathName = argv[i];
+ sProgressPathName += ".progress";
+ sPrecalcPathName = argv[i];
+ sPrecalcPathName += ".precalc";
+ }
+ }
+ else if (cla == "-v") {
+ debug = true;
+ }
+ else if (cla == "-k") {
+ keepPrecalcFiles = true;
+ }
+ else if (cla == "-a") {
+ useDefaultRainbowTablePath = true;
+ i++;
+ if (i < argc)
+ sAlgorithm = argv[i];
+ }
+ else {
+ GetTableList(cla, vPathName);
+ }
+ }
+
+ if (debug && !readFromIni)
+ printf("Debug: Couldn't read rcracki_mt.ini, continuing anyway.\n");
+
+ // Load session data if we are resuming
+ if (resumeSession)
+ {
+ vPathName.clear();
+ vector<string> sSessionData;
+ if (ReadLinesFromFile(sSessionPathName.c_str(), sSessionData))
+ {
+ UINT4 i;
+ for (i = 0; i < sSessionData.size(); i++)
+ {
+ vector<string> vPart;
+ if (SeperateString(sSessionData[i], "=", vPart))
+ {
+ string sOption = vPart[0];
+ string sValue = vPart[1];
+
+ if (sOption == "sPathName") {
+ vPathName.push_back(sValue);
+ }
+ else if (sOption == "sInputType") {
+ sInputType = sValue;
+ }
+ else if (sOption == "sInput") {
+ sInput = sValue;
+ }
+ else if (sOption == "outputFile") {
+ writeOutput = true;
+ outputFile = sValue;
+ }
+ else if (sOption == "keepPrecalcFiles") {
+ if (sValue == "1")
+ keepPrecalcFiles = true;
+ }
+ }
+ }
+ }
+ else {
+ printf("Couldn't open session file %s\n", sSessionPathName.c_str());
+ return 0;
+ }
+ }
+
+ if (maxThreads<1)
+ maxThreads = 1;
+
+ // don't load these if we are resuming a session that already has a list of tables
+ if (useDefaultRainbowTablePath && !resumeSession)
+ {
+ UINT4 i;
+ for (i = 0; i < vDefaultRainbowTablePath.size(); i++)
+ {
+ vector<string> vPart;
+ if (SeperateString(vDefaultRainbowTablePath[i], ".=", vPart))
+ {
+ string lineAlgorithm = vPart[1];
+ string linePath = vPart[2];
+
+ if (lineAlgorithm == sAlgorithm)
+ GetTableList(linePath, vPathName);
+ }
+ }
+ }
+
+ printf("Using %d threads for pre-calculation and false alarm checking...\n", maxThreads);
+
+ setvbuf(stdout, NULL, _IONBF,0);
+ if (vPathName.size() == 0)
+ {
+ printf("no rainbow table found\n");
+ return 0;
+ }
+ printf("Found %lu rainbowtable files...\n\n",
+ (unsigned long)vPathName.size());
+
+ bool fCrackerType; // true: hash cracker, false: lm cracker
+ vector<string> vHash; // hash cracker
+ vector<string> vUserName; // lm cracker
+ vector<string> vLMHash; // lm cracker
+ vector<string> vNTLMHash; // lm cracker
+ if (sInputType == "-h")
+ {
+ fCrackerType = true;
+
+ string sHash = sInput;
+ if (NormalizeHash(sHash))
+ vHash.push_back(sHash);
+ else
+ printf("invalid hash: %s\n", sHash.c_str());
+ }
+ else if (sInputType == "-l")
+ {
+ fCrackerType = true;
+
+ string sPathName = sInput;
+ vector<string> vLine;
+ if (ReadLinesFromFile(sPathName, vLine))
+ {
+ UINT4 i;
+ for (i = 0; i < vLine.size(); i++)
+ {
+ string sHash = vLine[i];
+ if (NormalizeHash(sHash))
+ vHash.push_back(sHash);
+ else
+ printf("invalid hash: %s\n", sHash.c_str());
+ }
+ }
+ else
+ printf("can't open %s\n", sPathName.c_str());
+ }
+ else if (sInputType == "-f")
+ {
+ fCrackerType = false;
+
+ string sPathName = sInput;
+ LoadLMHashFromPwdumpFile(sPathName, vUserName, vLMHash, vNTLMHash);
+ }
+ else if (sInputType == "-c")
+ {
+ // 2009-01-04 - james.dickson - Added this for cain-files.
+ fCrackerType = false;
+ string sPathName = sInput;
+ LoadLMHashFromCainLSTFile(sPathName, vUserName, vLMHash, vNTLMHash);
+ }
+ else
+ {
+ Usage();
+ return 0;
+ }
+
+ if (fCrackerType && vHash.size() == 0)
+ {
+ printf("no hashes found");
+ return 0;
+ }
+ if (!fCrackerType && vLMHash.size() == 0)
+ {
+ return 0;
+ printf("no hashes found");
+ }
+
+ if (fCrackerType)
+ {
+ UINT4 i;
+ for (i = 0; i < vHash.size(); i++)
+ hs.AddHash(vHash[i]);
+ }
+ else
+ {
+ UINT4 i;
+ for (i = 0; i < vLMHash.size(); i++)
+ {
+ hs.AddHash(vLMHash[i].substr(0, 16));
+ hs.AddHash(vLMHash[i].substr(16, 16));
+ }
+ }
+
+ // Load found hashes from session file
+ if (resumeSession)
+ {
+ vector<string> sSessionData;
+ if (ReadLinesFromFile(sSessionPathName.c_str(), sSessionData))
+ {
+ UINT4 i;
+ for (i = 0; i < sSessionData.size(); i++)
+ {
+ vector<string> vPart;
+ if (SeperateString(sSessionData[i], "=", vPart))
+ {
+ string sOption = vPart[0];
+ string sValue = vPart[1];
+
+ if (sOption == "sHash") {
+ vector<string> vPartHash;
+ if (SeperateString(sValue, "::", vPartHash))
+ {
+ string sHash = vPartHash[0];
+ string sBinary = vPartHash[1];
+ string sPlain = vPartHash[2];
+
+ hs.SetPlain(sHash, sPlain, sBinary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // (Over)write session data if we are not resuming
+ if (!resumeSession)
+ {
+ FILE* file = fopen(sSessionPathName.c_str(), "w");
+ string buffer = "";
+
+ if (file!=NULL)
+ {
+ buffer += "sInputType=" + sInputType + "\n";
+ buffer += "sInput=" + sInput + "\n";
+
+ UINT4 i;
+ for (i = 0; i < vPathName.size(); i++)
+ {
+ buffer += "sPathName=" + vPathName[i] + "\n";
+ }
+
+ if (writeOutput)
+ buffer += "outputFile=" + outputFile + "\n";
+
+ if (keepPrecalcFiles)
+ buffer += "keepPrecalcFiles=1\n";
+
+ fputs (buffer.c_str(), file);
+ fclose (file);
+ }
+ file = fopen(sProgressPathName.c_str(), "w");
+ fclose (file);
+ }
+
+ // Run
+ CCrackEngine ce;
+ if (writeOutput)
+ ce.setOutputFile(outputFile);
+ ce.setSession(sSessionPathName, sProgressPathName, sPrecalcPathName, keepPrecalcFiles);
+ ce.Run(vPathName, hs, maxThreads, maxMem, resumeSession, debug);
+
+ // Remove session files
+ if (debug) printf("Debug: Removing session files.\n");
+
+ if (remove(sSessionPathName.c_str()) == 0)
+ remove(sProgressPathName.c_str());
+ else
+ if (debug) printf("Debug: Failed removing session files.\n");
+
+ // Statistics
+ printf("statistics\n");
+ printf("-------------------------------------------------------\n");
+ printf("plaintext found: %d of %d (%.2f%%)\n", hs.GetStatHashFound(),
+ hs.GetStatHashTotal(),
+ 100.0f * hs.GetStatHashFound() / hs.GetStatHashTotal());
+ printf("total disk access time: %.2f s\n", ce.GetStatTotalDiskAccessTime());
+ printf("total cryptanalysis time: %.2f s\n", ce.GetStatTotalCryptanalysisTime());
+ printf("total pre-calculation time: %.2f s\n", ce.GetStatTotalPrecalculationTime());
+ printf("total chain walk step: %d\n", ce.GetStatTotalChainWalkStep());
+ printf("total false alarm: %d\n", ce.GetStatTotalFalseAlarm());
+ printf("total chain walk step due to false alarm: %d\n", ce.GetStatTotalChainWalkStepDueToFalseAlarm());
+// printf("total chain walk step skipped due to checkpoints: %d\n", ce.GetStatTotalFalseAlarmSkipped()); // Checkpoints not used - yet
+ printf("\n");
+
+ // Result
+ printf("result\n");
+ printf("-------------------------------------------------------\n");
+ if (fCrackerType)
+ {
+ UINT4 i;
+ for (i = 0; i < vHash.size(); i++)
+ {
+ string sPlain, sBinary;
+ if (!hs.GetPlain(vHash[i], sPlain, sBinary))
+ {
+ sPlain = "<notfound>";
+ sBinary = "<notfound>";
+ }
+
+ printf("%s\t%s\thex:%s\n", vHash[i].c_str(), sPlain.c_str(), sBinary.c_str());
+ }
+ }
+ else
+ {
+ UINT4 i;
+ for (i = 0; i < vLMHash.size(); i++)
+ {
+ string sPlain1, sBinary1;
+ bool fPart1Found = hs.GetPlain(vLMHash[i].substr(0, 16), sPlain1, sBinary1);
+ if (!fPart1Found)
+ {
+ sPlain1 = "<notfound>";
+ sBinary1 = "<notfound>";
+ }
+
+ string sPlain2, sBinary2;
+ bool fPart2Found = hs.GetPlain(vLMHash[i].substr(16, 16), sPlain2, sBinary2);
+ if (!fPart2Found)
+ {
+ sPlain2 = "<notfound>";
+ sBinary2 = "<notfound>";
+ }
+
+ string sPlain = sPlain1 + sPlain2;
+ string sBinary = sBinary1 + sBinary2;
+
+ // Correct case
+ if (fPart1Found && fPart2Found)
+ {
+ unsigned char NTLMHash[16];
+ int nHashLen;
+ ParseHash(vNTLMHash[i], NTLMHash, nHashLen);
+ if (nHashLen != 16)
+ printf("debug: nHashLen mismatch\n");
+ string sNTLMPassword;
+ if (LMPasswordCorrectCase(sPlain, NTLMHash, sNTLMPassword))
+ {
+ sPlain = sNTLMPassword;
+ sBinary = HexToStr((const unsigned char*)sNTLMPassword.c_str(), sNTLMPassword.size());
+ }
+ else
+ {
+ printf("%-14s\t%s\thex:%s\n", vUserName[i].c_str(), sPlain.c_str(), sBinary.c_str());
+ LM2NTLMcorrector corrector;
+ if (corrector.LMPasswordCorrectUnicode(sBinary, NTLMHash, sNTLMPassword))
+ {
+ sPlain = sNTLMPassword;
+ sBinary = corrector.getBinary();
+ if (writeOutput)
+ {
+ if (!writeResultLineToFile(outputFile, vNTLMHash[i].c_str(), sPlain.c_str(), sBinary.c_str()))
+ printf("Couldn't write final result to file!\n");
+ }
+ }
+ else {
+ printf("case correction for password %s failed!\n", sPlain.c_str());
+ }
+ }
+ }
+
+ // Display
+ printf("%-14s\t%s\thex:%s\n", vUserName[i].c_str(),
+ sPlain.c_str(),
+ sBinary.c_str());
+
+ }
+ }
+
+ return 0;
+}