]> git.sesse.net Git - freerainbowtables/blob - Client Applications/rcracki/RainbowCrack.cpp
a6ec66e037c1aa9f1691bf0db7c847e2271cdf64
[freerainbowtables] / Client Applications / rcracki / RainbowCrack.cpp
1 /*
2    RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
3
4    Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
5
6    Modified by Martin Westergaard Jørgensen <martinwj2005@gmail.com> to support indexed and hybrid tables
7 */
8
9 #ifdef _WIN32
10         #pragma warning(disable : 4786)
11 #endif
12
13 #include "CrackEngine.h"
14
15 #ifdef _WIN32
16         #include <io.h>
17 #else
18         #include <sys/types.h>
19         #include <sys/stat.h>
20         #include <unistd.h>
21 #endif
22 #include "md4.h"
23
24 //////////////////////////////////////////////////////////////////////
25
26 #ifdef _WIN32
27 void GetTableList(string sWildCharPathName, vector<string>& vPathName)
28 {
29         vPathName.clear();
30
31         string sPath;
32         int n = sWildCharPathName.find_last_of('\\');
33         if (n != -1)
34                 sPath = sWildCharPathName.substr(0, n + 1);
35
36         _finddata_t fd;
37         long handle = _findfirst(sWildCharPathName.c_str(), &fd);
38         if (handle != -1)
39         {
40                 do
41                 {
42                         string sName = fd.name;
43                         if (sName != "." && sName != ".." && !(fd.attrib & _A_SUBDIR))
44                         {
45                                 string sPathName = sPath + sName;
46                                 vPathName.push_back(sPathName);
47                         }
48                 } while (_findnext(handle, &fd) == 0);
49
50                 _findclose(handle);
51         }
52 }
53 #else
54 void GetTableList(int argc, char* argv[], vector<string>& vPathName)
55 {
56         vPathName.clear();
57
58         int i;
59         for (i = 1; i <= argc - 3; i++)
60         {
61                 string sPathName = argv[i];
62
63                 struct stat buf;
64                 if (lstat(sPathName.c_str(), &buf) == 0)
65                 {
66                         if (S_ISREG(buf.st_mode))
67                                 vPathName.push_back(sPathName);
68                 }
69         }
70 }
71 #endif
72
73 bool NormalizeHash(string& sHash)
74 {
75         string sNormalizedHash = sHash;
76
77         if (   sNormalizedHash.size() % 2 != 0
78                 || sNormalizedHash.size() < MIN_HASH_LEN * 2
79                 || sNormalizedHash.size() > MAX_HASH_LEN * 2)
80                 return false;
81
82         // Make lower
83         int i;
84         for (i = 0; i < sNormalizedHash.size(); i++)
85         {
86                 if (sNormalizedHash[i] >= 'A' && sNormalizedHash[i] <= 'F')
87                         sNormalizedHash[i] = sNormalizedHash[i] - 'A' + 'a';
88         }
89
90         // Character check
91         for (i = 0; i < sNormalizedHash.size(); i++)
92         {
93                 if (   (sNormalizedHash[i] < 'a' || sNormalizedHash[i] > 'f')
94                         && (sNormalizedHash[i] < '0' || sNormalizedHash[i] > '9'))
95                         return false;
96         }
97
98         sHash = sNormalizedHash;
99         return true;
100 }
101
102 void LoadLMHashFromPwdumpFile(string sPathName, vector<string>& vUserName, vector<string>& vLMHash, vector<string>& vNTLMHash)
103 {
104         vector<string> vLine;
105         if (ReadLinesFromFile(sPathName, vLine))
106         {
107                 int i;
108                 for (i = 0; i < vLine.size(); i++)
109                 {
110                         vector<string> vPart;
111                         if (SeperateString(vLine[i], "::::", vPart))
112                         {
113                                 string sUserName = vPart[0];
114                                 string sLMHash   = vPart[2];
115                                 string sNTLMHash = vPart[3];
116
117                                 if (sLMHash.size() == 32 && sNTLMHash.size() == 32)
118                                 {
119                                         if (NormalizeHash(sLMHash) && NormalizeHash(sNTLMHash))
120                                         {
121                                                 vUserName.push_back(sUserName);
122                                                 vLMHash.push_back(sLMHash);
123                                                 vNTLMHash.push_back(sNTLMHash);
124                                         }
125                                         else
126                                                 printf("invalid lm/ntlm hash %s:%s\n", sLMHash.c_str(), sNTLMHash.c_str());
127                                 }
128                         }
129                 }
130         }
131         else
132                 printf("can't open %s\n", sPathName.c_str());
133 }
134
135 bool NTLMPasswordSeek(unsigned char* pLMPassword, int nLMPasswordLen, int nLMPasswordNext,
136                                           unsigned char* pNTLMHash, string& sNTLMPassword)
137 {
138         if (nLMPasswordNext == nLMPasswordLen)
139         {
140                 unsigned char md[16];
141                 MD4_NEW(pLMPassword, nLMPasswordLen * 2, md);
142                 if (memcmp(md, pNTLMHash, 16) == 0)
143                 {
144                         sNTLMPassword = "";
145                         int i;
146                         for (i = 0; i < nLMPasswordLen; i++)
147                                 sNTLMPassword += char(pLMPassword[i * 2]);
148                         return true;
149                 }
150                 else
151                         return false;
152         }
153
154         if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))
155                 return true;
156
157         if (   pLMPassword[nLMPasswordNext * 2] >= 'A'
158                 && pLMPassword[nLMPasswordNext * 2] <= 'Z')
159         {
160                 pLMPassword[nLMPasswordNext * 2] = pLMPassword[nLMPasswordNext * 2] - 'A' + 'a';
161                 if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))
162                         return true;
163                 pLMPassword[nLMPasswordNext * 2] = pLMPassword[nLMPasswordNext * 2] - 'a' + 'A';
164         }
165
166         return false;
167 }
168
169 bool LMPasswordCorrectCase(string sLMPassword,
170                                                    unsigned char* pNTLMHash, string& sNTLMPassword)
171 {
172         if (sLMPassword.size() == 0)
173         {
174                 sNTLMPassword = "";
175                 return true;
176         }
177
178         unsigned char* pLMPassword = new unsigned char[sLMPassword.size() * 2];
179         int i;
180         for (i = 0; i < sLMPassword.size(); i++)
181         {
182                 pLMPassword[i * 2    ] = sLMPassword[i];
183                 pLMPassword[i * 2 + 1] = 0x00;
184         }
185         bool fRet = NTLMPasswordSeek(pLMPassword, sLMPassword.size(), 0, pNTLMHash, sNTLMPassword);
186         delete pLMPassword;
187
188         return fRet;
189 }
190
191 void Usage()
192 {
193         Logo();
194
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");
202         printf("\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");
206 }
207
208 int main(int argc, char* argv[])
209 {
210 #ifdef _WIN32
211         if (argc != 4)
212         {
213                 Usage();
214                 return 0;
215         }
216         string sWildCharPathName = argv[1];
217         string sInputType        = argv[2];
218         string sInput            = argv[3];
219
220         // vPathName
221         vector<string> vPathName;
222         GetTableList(sWildCharPathName, vPathName);
223 #else
224         if (argc < 4)
225         {
226                 Usage();
227                 return 0;
228         }
229         string sInputType        = argv[argc - 2];
230         string sInput            = argv[argc - 1];
231
232         // vPathName
233         vector<string> vPathName;
234         GetTableList(argc, argv, vPathName);
235 #endif
236         if (vPathName.size() == 0)
237         {
238                 printf("no rainbow table found\n");
239                 return 0;
240         }
241
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")
249         {
250                 fCrackerType = true;
251
252                 string sHash = sInput;
253                 if (NormalizeHash(sHash))
254                         vHash.push_back(sHash);
255                 else
256                         printf("invalid hash: %s\n", sHash.c_str());
257         }
258         else if (sInputType == "-l")
259         {
260                 fCrackerType = true;
261
262                 string sPathName = sInput;
263                 vector<string> vLine;
264                 if (ReadLinesFromFile(sPathName, vLine))
265                 {
266                         int i;
267                         for (i = 0; i < vLine.size(); i++)
268                         {
269                                 string sHash = vLine[i];
270                                 if (NormalizeHash(sHash))
271                                         vHash.push_back(sHash);
272                                 else
273                                         printf("invalid hash: %s\n", sHash.c_str());
274                         }
275                 }
276                 else
277                         printf("can't open %s\n", sPathName.c_str());
278         }
279         else if (sInputType == "-f")
280         {
281                 fCrackerType = false;
282
283                 string sPathName = sInput;
284                 LoadLMHashFromPwdumpFile(sPathName, vUserName, vLMHash, vNTLMHash);
285         }
286         else
287         {
288                 Usage();
289                 return 0;
290         }
291         
292         if (fCrackerType && vHash.size() == 0)
293                 return 0;
294         if (!fCrackerType && vLMHash.size() == 0)
295                 return 0;
296
297         // hs
298         CHashSet hs;
299         if (fCrackerType)
300         {
301                 int i;
302                 for (i = 0; i < vHash.size(); i++)
303                         hs.AddHash(vHash[i]);
304         }
305         else
306         {
307                 int i;
308                 for (i = 0; i < vLMHash.size(); i++)
309                 {
310                         hs.AddHash(vLMHash[i].substr(0, 16));
311                         hs.AddHash(vLMHash[i].substr(16, 16));
312                 }
313         }
314
315         // Run
316         CCrackEngine ce;
317         ce.Run(vPathName, hs);
318
319         // Statistics
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
331         printf("\n");
332
333         // Result
334         printf("result\n");
335         printf("-------------------------------------------------------\n");
336         if (fCrackerType)
337         {
338                 int i;
339                 for (i = 0; i < vHash.size(); i++)
340                 {
341                         string sPlain, sBinary;
342                         if (!hs.GetPlain(vHash[i], sPlain, sBinary))
343                         {
344                                 sPlain  = "<notfound>";
345                                 sBinary = "<notfound>";
346                         }
347
348                         printf("%s  %s  hex:%s\n", vHash[i].c_str(), sPlain.c_str(), sBinary.c_str());
349                 }
350         }
351         else
352         {
353                 int i;
354                 for (i = 0; i < vLMHash.size(); i++)
355                 {
356                         string sPlain1, sBinary1;
357                         bool fPart1Found = hs.GetPlain(vLMHash[i].substr(0, 16), sPlain1, sBinary1);
358                         if (!fPart1Found)
359                         {
360                                 sPlain1  = "<notfound>";
361                                 sBinary1 = "<notfound>";
362                         }
363
364                         string sPlain2, sBinary2;
365                         bool fPart2Found = hs.GetPlain(vLMHash[i].substr(16, 16), sPlain2, sBinary2);
366                         if (!fPart2Found)
367                         {
368                                 sPlain2  = "<notfound>";
369                                 sBinary2 = "<notfound>";
370                         }
371
372                         string sPlain = sPlain1 + sPlain2;
373                         string sBinary = sBinary1 + sBinary2;
374
375                         // Correct case
376                         if (fPart1Found && fPart2Found)
377                         {
378                                 unsigned char NTLMHash[16];
379                                 int nHashLen;
380                                 ParseHash(vNTLMHash[i], NTLMHash, nHashLen);
381                                 if (nHashLen != 16)
382                                         printf("debug: nHashLen mismatch\n");
383                                 string sNTLMPassword;
384                                 if (LMPasswordCorrectCase(sPlain, NTLMHash, sNTLMPassword))
385                                 {
386                                         sPlain = sNTLMPassword;
387                                         sBinary = HexToStr((const unsigned char*)sNTLMPassword.c_str(), sNTLMPassword.size());
388                                 }
389                                 else
390                                         printf("case correction for password %s fail!\n", sPlain.c_str());
391                         }
392
393                         // Display
394                         printf("%-14s  %s  hex:%s\n", vUserName[i].c_str(),
395                                                                                   sPlain.c_str(),
396                                                                                   sBinary.c_str());
397                 }
398         }
399
400         return 0;
401 }