2 RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
4 Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
6 Modified by Martin Westergaard Jørgensen <martinwj2005@gmail.com> to support indexed and hybrid tables
10 #pragma warning(disable : 4786)
13 #include "CrackEngine.h"
18 #include <sys/types.h>
24 //////////////////////////////////////////////////////////////////////
27 void GetTableList(string sWildCharPathName, vector<string>& vPathName)
32 int n = sWildCharPathName.find_last_of('\\');
34 sPath = sWildCharPathName.substr(0, n + 1);
37 long handle = _findfirst(sWildCharPathName.c_str(), &fd);
42 string sName = fd.name;
43 if (sName != "." && sName != ".." && !(fd.attrib & _A_SUBDIR))
45 string sPathName = sPath + sName;
46 vPathName.push_back(sPathName);
48 } while (_findnext(handle, &fd) == 0);
54 void GetTableList(int argc, char* argv[], vector<string>& vPathName)
59 for (i = 1; i <= argc - 3; i++)
61 string sPathName = argv[i];
64 if (lstat(sPathName.c_str(), &buf) == 0)
66 if (S_ISREG(buf.st_mode))
67 vPathName.push_back(sPathName);
73 bool NormalizeHash(string& sHash)
75 string sNormalizedHash = sHash;
77 if ( sNormalizedHash.size() % 2 != 0
78 || sNormalizedHash.size() < MIN_HASH_LEN * 2
79 || sNormalizedHash.size() > MAX_HASH_LEN * 2)
84 for (i = 0; i < sNormalizedHash.size(); i++)
86 if (sNormalizedHash[i] >= 'A' && sNormalizedHash[i] <= 'F')
87 sNormalizedHash[i] = sNormalizedHash[i] - 'A' + 'a';
91 for (i = 0; i < sNormalizedHash.size(); i++)
93 if ( (sNormalizedHash[i] < 'a' || sNormalizedHash[i] > 'f')
94 && (sNormalizedHash[i] < '0' || sNormalizedHash[i] > '9'))
98 sHash = sNormalizedHash;
102 void LoadLMHashFromPwdumpFile(string sPathName, vector<string>& vUserName, vector<string>& vLMHash, vector<string>& vNTLMHash)
104 vector<string> vLine;
105 if (ReadLinesFromFile(sPathName, vLine))
108 for (i = 0; i < vLine.size(); i++)
110 vector<string> vPart;
111 if (SeperateString(vLine[i], "::::", vPart))
113 string sUserName = vPart[0];
114 string sLMHash = vPart[2];
115 string sNTLMHash = vPart[3];
117 if (sLMHash.size() == 32 && sNTLMHash.size() == 32)
119 if (NormalizeHash(sLMHash) && NormalizeHash(sNTLMHash))
121 vUserName.push_back(sUserName);
122 vLMHash.push_back(sLMHash);
123 vNTLMHash.push_back(sNTLMHash);
126 printf("invalid lm/ntlm hash %s:%s\n", sLMHash.c_str(), sNTLMHash.c_str());
132 printf("can't open %s\n", sPathName.c_str());
135 bool NTLMPasswordSeek(unsigned char* pLMPassword, int nLMPasswordLen, int nLMPasswordNext,
136 unsigned char* pNTLMHash, string& sNTLMPassword)
138 if (nLMPasswordNext == nLMPasswordLen)
140 unsigned char md[16];
141 MD4_NEW(pLMPassword, nLMPasswordLen * 2, md);
142 if (memcmp(md, pNTLMHash, 16) == 0)
146 for (i = 0; i < nLMPasswordLen; i++)
147 sNTLMPassword += char(pLMPassword[i * 2]);
154 if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))
157 if ( pLMPassword[nLMPasswordNext * 2] >= 'A'
158 && pLMPassword[nLMPasswordNext * 2] <= 'Z')
160 pLMPassword[nLMPasswordNext * 2] = pLMPassword[nLMPasswordNext * 2] - 'A' + 'a';
161 if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))
163 pLMPassword[nLMPasswordNext * 2] = pLMPassword[nLMPasswordNext * 2] - 'a' + 'A';
169 bool LMPasswordCorrectCase(string sLMPassword,
170 unsigned char* pNTLMHash, string& sNTLMPassword)
172 if (sLMPassword.size() == 0)
178 unsigned char* pLMPassword = new unsigned char[sLMPassword.size() * 2];
180 for (i = 0; i < sLMPassword.size(); i++)
182 pLMPassword[i * 2 ] = sLMPassword[i];
183 pLMPassword[i * 2 + 1] = 0x00;
185 bool fRet = NTLMPasswordSeek(pLMPassword, sLMPassword.size(), 0, pNTLMHash, sNTLMPassword);
195 printf("usage: rcracki rainbow_table_pathname -h hash\n");
196 printf(" rcracki rainbow_table_pathname -l hash_list_file\n");
197 printf(" rcracki rainbow_table_pathname -f pwdump_file\n");
198 printf("rainbow_table_pathname: pathname of the rainbow table(s), wildchar(*, ?) supported\n");
199 printf("-h hash: use raw hash as input\n");
200 printf("-l hash_list_file: use hash list file as input, each hash in a line\n");
201 printf("-f pwdump_file: use pwdump file as input, this will handle lanmanager hash only\n");
203 printf("example: rcracki *.rti -h 5d41402abc4b2a76b9719d911017c592\n");
204 printf(" rcracki *.rti -l hash.txt\n");
205 printf(" rcracki *.rti -f hash.txt\n");
208 int main(int argc, char* argv[])
216 string sWildCharPathName = argv[1];
217 string sInputType = argv[2];
218 string sInput = argv[3];
221 vector<string> vPathName;
222 GetTableList(sWildCharPathName, vPathName);
229 string sInputType = argv[argc - 2];
230 string sInput = argv[argc - 1];
233 vector<string> vPathName;
234 GetTableList(argc, argv, vPathName);
236 if (vPathName.size() == 0)
238 printf("no rainbow table found\n");
242 // fCrackerType, vHash, vUserName, vLMHash
243 bool fCrackerType; // true: hash cracker, false: lm cracker
244 vector<string> vHash; // hash cracker
245 vector<string> vUserName; // lm cracker
246 vector<string> vLMHash; // lm cracker
247 vector<string> vNTLMHash; // lm cracker
248 if (sInputType == "-h")
252 string sHash = sInput;
253 if (NormalizeHash(sHash))
254 vHash.push_back(sHash);
256 printf("invalid hash: %s\n", sHash.c_str());
258 else if (sInputType == "-l")
262 string sPathName = sInput;
263 vector<string> vLine;
264 if (ReadLinesFromFile(sPathName, vLine))
267 for (i = 0; i < vLine.size(); i++)
269 string sHash = vLine[i];
270 if (NormalizeHash(sHash))
271 vHash.push_back(sHash);
273 printf("invalid hash: %s\n", sHash.c_str());
277 printf("can't open %s\n", sPathName.c_str());
279 else if (sInputType == "-f")
281 fCrackerType = false;
283 string sPathName = sInput;
284 LoadLMHashFromPwdumpFile(sPathName, vUserName, vLMHash, vNTLMHash);
292 if (fCrackerType && vHash.size() == 0)
294 if (!fCrackerType && vLMHash.size() == 0)
302 for (i = 0; i < vHash.size(); i++)
303 hs.AddHash(vHash[i]);
308 for (i = 0; i < vLMHash.size(); i++)
310 hs.AddHash(vLMHash[i].substr(0, 16));
311 hs.AddHash(vLMHash[i].substr(16, 16));
317 ce.Run(vPathName, hs);
320 printf("statistics\n");
321 printf("-------------------------------------------------------\n");
322 printf("plaintext found: %d of %d (%.2f%%)\n", hs.GetStatHashFound(),
323 hs.GetStatHashTotal(),
324 100.0f * hs.GetStatHashFound() / hs.GetStatHashTotal());
325 printf("total disk access time: %.2f s\n", ce.GetStatTotalDiskAccessTime());
326 printf("total cryptanalysis time: %.2f s\n", ce.GetStatTotalCryptanalysisTime());
327 printf("total chain walk step: %d\n", ce.GetStatTotalChainWalkStep());
328 printf("total false alarm: %d\n", ce.GetStatTotalFalseAlarm());
329 printf("total chain walk step due to false alarm: %d\n", ce.GetStatTotalChainWalkStepDueToFalseAlarm());
330 // printf("total chain walk step skipped due to checkpoints: %d\n", ce.GetStatTotalFalseAlarmSkipped()); // Checkpoints not used - yet
335 printf("-------------------------------------------------------\n");
339 for (i = 0; i < vHash.size(); i++)
341 string sPlain, sBinary;
342 if (!hs.GetPlain(vHash[i], sPlain, sBinary))
344 sPlain = "<notfound>";
345 sBinary = "<notfound>";
348 printf("%s %s hex:%s\n", vHash[i].c_str(), sPlain.c_str(), sBinary.c_str());
354 for (i = 0; i < vLMHash.size(); i++)
356 string sPlain1, sBinary1;
357 bool fPart1Found = hs.GetPlain(vLMHash[i].substr(0, 16), sPlain1, sBinary1);
360 sPlain1 = "<notfound>";
361 sBinary1 = "<notfound>";
364 string sPlain2, sBinary2;
365 bool fPart2Found = hs.GetPlain(vLMHash[i].substr(16, 16), sPlain2, sBinary2);
368 sPlain2 = "<notfound>";
369 sBinary2 = "<notfound>";
372 string sPlain = sPlain1 + sPlain2;
373 string sBinary = sBinary1 + sBinary2;
376 if (fPart1Found && fPart2Found)
378 unsigned char NTLMHash[16];
380 ParseHash(vNTLMHash[i], NTLMHash, nHashLen);
382 printf("debug: nHashLen mismatch\n");
383 string sNTLMPassword;
384 if (LMPasswordCorrectCase(sPlain, NTLMHash, sNTLMPassword))
386 sPlain = sNTLMPassword;
387 sBinary = HexToStr((const unsigned char*)sNTLMPassword.c_str(), sNTLMPassword.size());
390 printf("case correction for password %s fail!\n", sPlain.c_str());
394 printf("%-14s %s hex:%s\n", vUserName[i].c_str(),