1 #if !defined (_MSC_VER)
2 /* Modified by Dhiru Kholia for JtR in August, 2012
3  *
4  * dmg.c
5  *
6  * hashkill - a hash cracking tool
7  * Copyright (C) 2010 Milen Rangelov <gat3way@gat3way.eu>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
22 
23 #if AC_BUILT
24 #include "autoconfig.h"
25 #endif
26 
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <math.h>
30 #if (!AC_BUILT || HAVE_UNISTD_H) && !_MSC_VER
31 #include <unistd.h>
32 #endif
33 #include <string.h>
34 #if (!AC_BUILT || HAVE_FCNTL_H)
35 #include <fcntl.h>
36 #endif
37 #include <stdlib.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 
41 #include "arch.h"
42 #include "filevault.h"
43 #include "misc.h"
44 #include "jumbo.h"
45 #include "memory.h"
46 
47 #ifndef ntohl
48 #if ARCH_LITTLE_ENDIAN
49 #define htonl(x) ((((x)>>24) & 0xffL) | (((x)>>8) & 0xff00L) | \
50 		(((x)<<8) & 0xff0000L) | (((x)<<24) & 0xff000000L))
51 
52 #define ntohl(x) ((((x)>>24) & 0xffL) | (((x)>>8) & 0xff00L) | \
53 		(((x)<<8) & 0xff0000L) | (((x)<<24) & 0xff000000L))
54 #else
55 #define htonl(x) (x)
56 #define ntohl(x) (x)
57 #endif
58 #endif
59 
60 #ifndef ntohll
61 #define ntohll(x) (((uint64_t) ntohl((x) >> 32)) | (((uint64_t) ntohl((uint32_t) ((x) & 0xFFFFFFFF))) << 32))
62 #endif
63 
64 #define LARGE_ENOUGH 8192
65 
header_byteorder_fix(cencrypted_v1_header * hdr)66 static void header_byteorder_fix(cencrypted_v1_header *hdr)
67 {
68 	hdr->kdf_iteration_count = htonl(hdr->kdf_iteration_count);
69 	hdr->kdf_salt_len = htonl(hdr->kdf_salt_len);
70 	hdr->len_wrapped_aes_key = htonl(hdr->len_wrapped_aes_key);
71 	hdr->len_hmac_sha1_key = htonl(hdr->len_hmac_sha1_key);
72 	hdr->len_integrity_key = htonl(hdr->len_integrity_key);
73 }
74 
header2_byteorder_fix(cencrypted_v2_header * header)75 static void header2_byteorder_fix(cencrypted_v2_header *header)
76 {
77 	header->version = ntohl(header->version);
78 	header->enc_iv_size = ntohl(header->enc_iv_size);
79 	header->encMode = ntohl(header->encMode);
80 	header->encAlg = ntohl(header->encAlg);
81 	header->keyBits = ntohl(header->keyBits);
82 	header->prngalg = ntohl(header->prngalg);
83 	header->prngkeysize = ntohl(header->prngkeysize);
84 	header->blocksize = ntohl(header->blocksize);
85 	header->datasize = ntohll(header->datasize);
86 	header->dataoffset = ntohll(header->dataoffset);
87 	header->keycount = ntohl(header->keycount);
88 }
89 
v2_key_header_pointer_byteorder_fix(cencrypted_v2_key_header_pointer * key_header_pointer)90 static void v2_key_header_pointer_byteorder_fix(cencrypted_v2_key_header_pointer *key_header_pointer)
91 {
92 	key_header_pointer->header_type = ntohl(key_header_pointer->header_type);
93 	key_header_pointer->header_offset = ntohl(key_header_pointer->header_offset);
94 	key_header_pointer->header_size = ntohl(key_header_pointer->header_size);
95 }
96 
v2_password_header_byteorder_fix(cencrypted_v2_password_header * password_header)97 static void v2_password_header_byteorder_fix(cencrypted_v2_password_header *password_header)
98 {
99 	password_header->algorithm = ntohl(password_header->algorithm);
100 	password_header->prngalgo = ntohl(password_header->prngalgo);
101 	password_header->itercount = ntohl(password_header->itercount);
102 	password_header->salt_size = ntohl(password_header->salt_size);
103 	password_header->iv_size = ntohl(password_header->iv_size);
104 	password_header->blob_enc_keybits = ntohl(password_header->blob_enc_keybits);
105 	password_header->blob_enc_algo = ntohl(password_header->blob_enc_algo);
106 	password_header->blob_enc_padding = ntohl(password_header->blob_enc_padding);
107 	password_header->blob_enc_mode = ntohl(password_header->blob_enc_mode);
108 	password_header->keyblobsize = ntohl(password_header->keyblobsize);
109 }
110 
print_hex(unsigned char * str,int len)111 static void print_hex(unsigned char *str, int len)
112 {
113 	int i;
114 	for (i = 0; i < len; ++i)
115 		printf("%02x", str[i]);
116 }
117 
118 // Remove these duplicated strnXYZ functions after refactoring misc.c. Trying
119 // to link dmg2john.o with misc.o results in linking errors, as parts of misc.o
120 // depends on other parts of JtR jumbo. These linking problems are not easily
121 // solvable without refactoring misc.c file.
strnzcpyn(char * dst,const char * src,int size)122 int strnzcpyn(char *dst, const char *src, int size)
123 {
124 	char *dptr;
125 	if (!size) return 0;
126 
127 	dptr = dst;
128 
129 	while (--size)
130 		if (!(*dptr++ = *src++)) return (dptr-dst)-1;
131 	*dptr = 0;
132 
133 	return (dptr-dst);
134 }
135 
strnzcat(char * dst,const char * src,int size)136 char *strnzcat(char *dst, const char *src, int size)
137 {
138 	char *dptr = dst;
139 
140 	if (size) {
141 		while (size && *dptr) {
142 			size--; dptr++;
143 		}
144 		if (size)
145 			while (--size)
146 				if (!(*dptr++ = *src++)) break;
147 	}
148 	*dptr = 0;
149 
150 	return dst;
151 }
152 
hash_plugin_parse_hash(char * in_filepath)153 static void hash_plugin_parse_hash(char *in_filepath)
154 {
155 	int fd;
156 	char buf8[8];
157 	uint32_t i = 0;
158 	int64_t cno = 0;
159 	int64_t data_size = 0;
160 	int64_t count = 0;
161 	unsigned char *chunk1 = NULL;
162 	unsigned char chunk2[4096];
163 	char filepath[LARGE_ENOUGH];
164 	char name[LARGE_ENOUGH];
165 	char *filename;
166 	int is_sparsebundle = 0;
167 	int headerver;
168 	cencrypted_v1_header header;
169 	cencrypted_v2_header header2;
170 	cencrypted_v2_password_header v2_password_header;
171 
172 	int filepath_length = strnzcpyn(filepath, in_filepath, LARGE_ENOUGH);
173 
174 	memset(&header, 0, sizeof(cencrypted_v2_header));
175 	memset(&header2, 0, sizeof(cencrypted_v2_header));
176 	memset(&v2_password_header, 0, sizeof(cencrypted_v2_password_header));
177 	strnzcpyn(name, in_filepath, LARGE_ENOUGH);
178 	if (!(filename = basename(name))) {
179 	    filename = filepath;
180 	}
181 
182 	if (strstr(filepath, ".sparsebundle")) {
183 		// The filepath given indicates this is a sparsebundle
184 		// A sparsebundle is simply a directory with contents.
185 		// Let's check to see if that is the case.
186 		struct stat file_stat;
187 		char *token_path;
188 		if (stat(filepath, &file_stat) != 0) {
189 			fprintf(stderr, "Can't stat file: %s\n", filename);
190 			return;
191 		}
192 
193 		// Determine if the filepath given is a directory.
194 		if (!(file_stat.st_mode & S_IFDIR)) {
195 			fprintf(stderr, "%s claims to be a sparsebundle but isn't a directory\n", filename);
196 			return;
197 		}
198 
199 		// Let's look to see if the token file exists.
200 		fprintf(stderr, "filepath = %s path_length = %d\n", filepath, filepath_length);
201 		if (filepath_length + 6 + 1 >= LARGE_ENOUGH) {
202 			fprintf(stderr, "Can't create token path. Path too long.\n");
203 			return;
204 		}
205 
206 		is_sparsebundle = 1;
207 
208 		token_path = strnzcat(filepath, "/token", LARGE_ENOUGH);
209 		strnzcpyn(filepath, token_path, LARGE_ENOUGH);
210 		strnzcpyn(name, filepath, LARGE_ENOUGH);
211 		if (!(filename = basename(name))) {
212 		    filename = filepath;
213 		}
214 
215 	}
216 
217 	headerver = 0;
218 	fd = open(filepath, O_RDONLY);
219 	if (fd < 0) {
220 		fprintf(stderr, "Can't open file: %s\n", filename);
221 		return;
222 	}
223 
224 	if (read(fd, buf8, 8) <= 0) {
225 		fprintf(stderr, "%s is not a DMG file!\n", filename);
226 		goto bailout;
227 	}
228 
229 	if (strncmp(buf8, "encrcdsa", 8) == 0) {
230 		headerver = 2;
231 	} else {
232 		if (lseek(fd, -8, SEEK_END) < 0) {
233 			fprintf(stderr, "Unable to seek in %s\n", filename);
234 			goto bailout;
235 		}
236 		if (read(fd, buf8, 8) <= 0) {
237 			fprintf(stderr, "%s is not a DMG file!\n", filename);
238 			goto bailout;
239 		}
240 		if (strncmp(buf8, "cdsaencr", 8) == 0) {
241 			headerver = 1;
242 		}
243 	}
244 
245 	if (headerver == 0) {
246 		fprintf(stderr, "%s is not an encrypted DMG file!\n", filename);
247 		goto bailout;
248 	}
249 
250 	// fprintf(stderr, "Header version %d detected\n", headerver);
251 	if (headerver == 1) {
252 		if (lseek(fd, -(off_t)sizeof(cencrypted_v1_header), SEEK_END) < 0) {
253 			fprintf(stderr, "Unable to seek in %s\n", filename);
254 			goto bailout;
255 		}
256 		if (read(fd, &header, sizeof(cencrypted_v1_header)) < 1) {
257 			fprintf(stderr, "%s is not a DMG file!\n", filename);
258 			goto bailout;
259 		}
260 		header_byteorder_fix(&header);
261 		if (header.kdf_salt_len > sizeof(header.kdf_salt)) {
262 			fprintf(stderr, "%s has bad kdf_salt_len value!\n", filename);
263 			goto bailout;
264 		}
265 		if (header.len_wrapped_aes_key > sizeof(header.wrapped_aes_key)) {
266 			fprintf(stderr, "%s has bad len_wrapped_aes_key value!\n", filename);
267 			goto bailout;
268 		}
269 		if (header.len_hmac_sha1_key > sizeof(header.wrapped_hmac_sha1_key)) {
270 			fprintf(stderr, "%s has bad len_hmac_sha1_key value!\n", filename);
271 			goto bailout;
272 		}
273 
274 		fprintf(stderr, "%s (DMG v%d) successfully parsed, iterations "
275 		        "count %u\n", name, headerver,
276 		        header.kdf_iteration_count);
277 
278 		printf("%s:$dmg$%d*%d*", name, headerver, header.kdf_salt_len);
279 		print_hex(header.kdf_salt, header.kdf_salt_len);
280 		printf("*%d*", header.len_wrapped_aes_key);
281 		print_hex(header.wrapped_aes_key, header.len_wrapped_aes_key);
282 		printf("*%d*", header.len_hmac_sha1_key);
283 		print_hex(header.wrapped_hmac_sha1_key, header.len_hmac_sha1_key);
284 		printf("*%u::::%s\n", header.kdf_iteration_count, filename);
285 	} else {
286 		cencrypted_v2_key_header_pointer header_pointer;
287 		int password_header_found = 0;
288 
289 		if (lseek(fd, 0, SEEK_SET) < 0) {
290 			fprintf(stderr, "Unable to seek in %s\n", filename);
291 			goto bailout;
292 		}
293 		if (read(fd, &header2, sizeof(cencrypted_v2_header)) < 1) {
294 			fprintf(stderr, "%s is not a DMG file!\n", filename);
295 			goto bailout;
296 		}
297 
298 		header2_byteorder_fix(&header2);
299 
300 		// If this is a sparsebundle then there is no data to seek
301 		// to in this file so we skip over this particular check.
302 		if (!is_sparsebundle) {
303 			if (lseek(fd, header2.dataoffset, SEEK_SET) < 0) {
304 				fprintf(stderr, "Unable to seek in %s\n", filename);
305 				goto bailout;
306 			}
307 		}
308 
309 		if (strstr(name, ".sparseimage") || is_sparsebundle) {
310 			// If this file is a sparseimage then we want one of the first chunks as the other chunks could be empty.
311 			cno = 1;
312 			data_size = 8192;
313 		} else {
314 			cno = ((header2.datasize + 4095ULL) / 4096) - 2;
315 			data_size = header2.datasize - cno * 4096ULL;
316 		}
317 
318 		if (data_size < 0) {
319 			fprintf(stderr, "%s is not a valid DMG file!\n", filename);
320 			goto bailout;
321 		}
322 
323 		for (i = 0; i < header2.keycount; i++) {
324 			// Seek to the start of the key header pointers offset by the current key which start immediately after the v2 header.
325 			if (lseek(fd, (sizeof(cencrypted_v2_header) + (sizeof(cencrypted_v2_key_header_pointer)*i)), SEEK_SET) < 0) {
326 				fprintf(stderr, "Unable to seek to header pointers in %s\n", filename);
327 				goto bailout;
328 			}
329 
330 			// Read in the key header pointer
331 			count = read(fd, &header_pointer, sizeof(cencrypted_v2_key_header_pointer));
332 			if (count < 1 || count != sizeof(cencrypted_v2_key_header_pointer)) {
333 				fprintf(stderr, "Unable to read required data from %s\n", filename);
334 				goto bailout;
335 			}
336 
337 			v2_key_header_pointer_byteorder_fix(&header_pointer);
338 
339 			// We, currently, only care about the password key header. If it's not the password header type skip over it.
340 			if (header_pointer.header_type != 1) {
341 				continue;
342 			}
343 
344 			// Seek to where the password key header is in the file.
345 			if (lseek(fd, header_pointer.header_offset, SEEK_SET) < 0) {
346 				fprintf(stderr, "Unable to seek to password header in %s\n", filename);
347 				goto bailout;
348 			}
349 
350 			// Read in the password key header but avoid reading anything into the keyblob.
351 			count = read(fd, &v2_password_header, sizeof(cencrypted_v2_password_header) - sizeof(unsigned char *));
352 			if (count < 1 || count != (sizeof(cencrypted_v2_password_header) - sizeof(unsigned char *))) {
353 				fprintf(stderr, "Unable to read required data from %s\n", filename);
354 				goto bailout;
355 			}
356 
357 			v2_password_header_byteorder_fix(&v2_password_header);
358 
359 			// Allocate the keyblob memory
360 			if (v2_password_header.keyblobsize > 1024) {
361 				fprintf(stderr, "Unusual keyblobsize found in %s\n", filename);
362 				goto bailout;
363 			}
364 			v2_password_header.keyblob = malloc(v2_password_header.keyblobsize);
365 			if (!v2_password_header.keyblob) {
366 				fprintf(stderr, "Error allocating memory while processing %s\n", filename);
367 				goto bailout;
368 			}
369 
370 			// Seek to the keyblob in the header
371 			if (lseek(fd, header_pointer.header_offset + sizeof(cencrypted_v2_password_header) - sizeof(unsigned char *), SEEK_SET) < 0) {
372 				fprintf(stderr, "Unable to seek to password header in %s\n", filename);
373 				free(v2_password_header.keyblob);
374 				goto bailout;
375 			}
376 
377 			// Read in the keyblob
378 			count = read(fd, v2_password_header.keyblob, v2_password_header.keyblobsize);
379 			if (count < 1 || count != (v2_password_header.keyblobsize)) {
380 				fprintf(stderr, "Unable to read required data from %s\n", filename);
381 				free(v2_password_header.keyblob);
382 				goto bailout;
383 			}
384 
385 			password_header_found = 1;
386 
387 			// We only need one password header. Don't search any longer.
388 			break;
389 		}
390 
391 		if (!password_header_found) {
392 			fprintf(stderr, "Password header not found in %s\n", filename);
393 			free(v2_password_header.keyblob);
394 			goto bailout;
395 		}
396 
397 		if (v2_password_header.salt_size > 32) {
398 			fprintf(stderr, "%s is not a valid DMG file, salt length is too long!\n", filename);
399 			free(v2_password_header.keyblob);
400 			goto bailout;
401 		}
402 
403 		fprintf(stderr, "%s (DMG v%d) successfully parsed, iterations "
404 		        "count %u\n", name, headerver,
405 		        v2_password_header.itercount);
406 
407 		if (is_sparsebundle) {
408 			// If this is a sparsebundle then we need to get the chunks
409 			// of data out of 0 from the bands directory. Close the
410 			// previous file and open bands/0
411 			char *bands_path;
412 			if (close(fd) != 0) {
413 				fprintf(stderr, "Failed closing file %s\n", filename);
414 				free(v2_password_header.keyblob);
415 				goto bailout;
416 			}
417 
418 			filepath_length = strnzcpyn(filepath, in_filepath, LARGE_ENOUGH);
419 
420 			strnzcpyn(name, in_filepath, LARGE_ENOUGH);
421 
422 			// See if we have enough room to append 'bands/0' to the path.
423 			if (filepath_length + 8 + 1 >= LARGE_ENOUGH) {
424 				fprintf(stderr, "Can't create bands path. Path too long.\n");
425 				free(v2_password_header.keyblob);
426 				goto bailout;
427 			}
428 
429 			bands_path = strnzcat(filepath, "/bands/0", LARGE_ENOUGH);
430 			strnzcpyn(filepath, bands_path, LARGE_ENOUGH);
431 			strnzcpyn(name, filepath, LARGE_ENOUGH);
432 			if (!(filename = basename(name))) {
433 			    filename = filepath;
434 			}
435 
436 			// Open the file for reading.
437 			close(fd);
438 			fd = open(filepath, O_RDONLY);
439 			if (fd < 0) {
440 				fprintf(stderr, "Can't open file: %s\n", filename);
441 				return;
442 			}
443 
444 			// Since we are in a different file, so we can ignore the dataoffset
445 			header2.dataoffset = 0;
446 		}
447 
448 		/* read starting chunk(s) */
449 		chunk1 = (unsigned char *)malloc(data_size);
450 		if (lseek(fd, header2.dataoffset + cno * 4096LL, SEEK_SET) < 0) {
451 			fprintf(stderr, "Unable to seek in %s\n", filename);
452 			free(chunk1);
453 			free(v2_password_header.keyblob);
454 			goto bailout;
455 		}
456 		count = read(fd, chunk1, data_size);
457 		if (count < 1 || count != data_size) {
458 			fprintf(stderr, "Unable to read required data from %s\n", filename);
459 			free(chunk1);
460 			free(v2_password_header.keyblob);
461 			goto bailout;
462 		}
463 		/* read last chunk */
464 		if (lseek(fd, header2.dataoffset, SEEK_SET) < 0) {
465 			fprintf(stderr, "Unable to seek in %s\n", filename);
466 			free(chunk1);
467 			free(v2_password_header.keyblob);
468 			goto bailout;
469 		}
470 		count = read(fd, chunk2, 4096);
471 		if (count < 1 || count != 4096) {
472 			fprintf(stderr, "Unable to read required data from %s\n", filename);
473 			free(chunk1);
474 			free(v2_password_header.keyblob);
475 			goto bailout;
476 		}
477 
478 		/* output hash */
479 		printf("%s:$dmg$%d*%d*", name, headerver, v2_password_header.salt_size);
480 		print_hex(v2_password_header.salt, v2_password_header.salt_size);
481 		printf("*32*");
482 		print_hex(v2_password_header.iv, 32);
483 		printf("*%d*", v2_password_header.keyblobsize);
484 		print_hex(v2_password_header.keyblob, v2_password_header.keyblobsize);
485 		printf("*%d*%d*", (int)cno, (int)data_size);
486 		print_hex(chunk1, data_size);
487 		printf("*1*");
488 		print_hex(chunk2, 4096);
489 		printf("*%u::::%s\n", v2_password_header.itercount, filename);
490 
491 		free(chunk1);
492 		free(v2_password_header.keyblob);
493 	}
494 
495 bailout:
496 	close(fd);
497 }
498 
499 #ifdef HAVE_LIBFUZZER
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)500 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
501 {
502 	int fd;
503 	char name[] = "/tmp/libFuzzer-XXXXXX";
504 
505 	fd = mkstemp(name);
506 	if (fd < 0) {
507 		fprintf(stderr, "Problem detected while creating the input file, %s, aborting!\n", strerror(errno));
508 		exit(-1);
509 	}
510 	write(fd, data, size);
511 	close(fd);
512 	hash_plugin_parse_hash(name);
513 	remove(name);
514 
515 	return 0;
516 }
517 #else
main(int argc,char ** argv)518 int main(int argc, char **argv)
519 {
520 	int i;
521 
522 	if (argc < 2) {
523 		puts("Usage: dmg2john [DMG files]");
524 		return -1;
525 	}
526 	for (i = 1; i < argc; i++)
527 		hash_plugin_parse_hash(argv[i]);
528 
529 	return 0;
530 }
531 #endif  // HAVE_LIBFUZZER
532 
533 #endif
534