├── COPYING ├── kraakengrep ├── kgrep ├── Makefile └── kgrep.cc ├── tests ├── clcache ├── testkf └── genpgpmsgs ├── regexps ├── pgpsym ├── pgparm ├── pgpasym ├── pgp ├── ssl └── all ├── extractblobs.sh ├── README ├── pgp.magic └── keyfind.py /COPYING: -------------------------------------------------------------------------------- 1 | 2014 (c) stf, AGPLv3+ 2 | -------------------------------------------------------------------------------- /kraakengrep/kgrep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stef/cryptokraaken/master/kraakengrep/kgrep -------------------------------------------------------------------------------- /tests/clcache: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # flushes disk cahes before benchmarking 3 | echo 3 > /proc/sys/vm/drop_caches 4 | sync 5 | -------------------------------------------------------------------------------- /regexps/pgpsym: -------------------------------------------------------------------------------- 1 | (\x8c[\r\x0c]\x04[\x01\x02\x03\x04\x07\x08\t\n](\x01[\x01\x02\x03\x08\t\n\x0b].{8}|\x03[\x01\x02\x03\x08\t\n\x0b].{9}))+[\xd2\xc9] 2 | -------------------------------------------------------------------------------- /kraakengrep/Makefile: -------------------------------------------------------------------------------- 1 | OPT=-O3 -Wall 2 | 3 | all: kgrep 4 | 5 | kgrep: 6 | g++ ${OPT} -lre2 kgrep.cc -o kgrep 7 | 8 | clean: 9 | rm -rf *.o kgrep 10 | -------------------------------------------------------------------------------- /regexps/pgparm: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE-----\n\r?(([^\n]+\n\r?)+\n\r?)?([A-Za-z0-9+/]+\s*\n\r?)+([A-Za-z0-9+/]{4})+([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\s*\n\r?(=[A-Za-z0-9+/]{4}\s*\n\r?)?-----END PGP MESSAGE----- 2 | -------------------------------------------------------------------------------- /extractblobs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ksh 2 | # invoke with 3 | # ./kgrep -f regexps/all /usr/bin/openssl | ./extractssl.sh /usr/bin/openssl | less 4 | 5 | while read offset size; do 6 | dd if=$1 bs=1 skip=$offset count=$size | { 7 | openssl rsa -text -inform DER 8 | } 9 | done 10 | -------------------------------------------------------------------------------- /regexps/pgpasym: -------------------------------------------------------------------------------- 1 | (\x84\x8c\x03.{8}[\x01\x02](\x03[\xf9\xfa\xfb\xfc\xfd\xfe\xff]|\x04\x00).{128}|\x85\x01\x0c\x03.{8}[\x01\x02](\x08\x00|\x07[\xf9\xfa\xfb\xfc\xfd\xfe\xff]).{256}|\x85\x01\x8c\x03.{8}[\x01\x02](\x0b[\xf9\xfa\xfb\xfc\xfd\xfe\xff]|\x0c\x00).{384}|\x85\x02\x0c\x03.{8}[\x01\x02](\x10\x00|\x0f[\xf9\xfa\xfb\xfc\xfd\xfe\xff]).{512})+\xd2.(..|.....)?\x01 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | cryptokraaken 2 | 3 | tools to filter cryptographic keymaterial and encrypted messages. 4 | 5 | (also proof that openpgp/rfc4880 is a cheap NSA strong selector) 6 | 7 | - regexps: regexps for various interesting crypto material 8 | - keyfind: python based slowish PoC 9 | - kraakengrep: google re2 - based tool for faster grepping 10 | - pgp.magic: file(1) magic rules for detailed reporting on PGP content 11 | - extractblobs.sh: carves out kraakengrep results 12 | - tests: scripts for benchmarks 13 | -------------------------------------------------------------------------------- /regexps/pgp: -------------------------------------------------------------------------------- 1 | [\x95\x97\x9d]((\x01[\xd8\xeb\xfb\xfd\xf3\xee\xfe\xf4]|\x02[\r\x03\x05\x15\x00\x10\x04\x06\x16])\x04.{4}[\x01\x02](\x03[\xfe\xff]|\x04\x00).{128}|(\x03[\x98\xab\xbb\xbd\xcd\xb3\xc3\xc5\xd5\xae\xbe\xc0\xd0\xb4\xc4\xc6\xd6])\x04.{4}[\x01\x02](\x08\x00|\x07[\xfe\xff]).{256}|(\x05[Xk{}\x8ds\x83\x85\x95n~\x80\x90t\x84\x86\x96])\x04.{4}[\x01\x02](\x0b[\xfe\xff]|\x0c\x00).{384}|(\x07[\x18+;=M3CEU.>@P4DFV])\x04.{4}[\x01\x02](\x10\x00|\x0f[\xfe\xff]).{512})\x00\x11\x01\x00\x01([\x00\x01\x02\x03\x04\x07\x08\t\n]|[\xfe\xff][\x01\x02\x03\x04\x07\x08\t\n][\x00\x01\x03e][\x01\x02\x03\x08\t\n\x0b]) 2 | -------------------------------------------------------------------------------- /tests/testkf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # benchmark python regexps 3 | # invoke with some image that contains stuff 4 | # ./testkf disk.img 5 | 6 | #user\tsystem\telapsed\tcpu\ttext\tdata\tmax\tinput\toutput\tmajor\tminor\tswaps 7 | # 8 | 9 | function check { 10 | echo "${@}" 11 | sudo /bin/sh clcache 12 | /usr/bin/time -f "%U\t%S\t%E\t%P\t%X\t%D\t%M\t%I\t%O\t%F\t%R\t%W" $1 >$2 13 | } 14 | 15 | check "./keyfind.py $1" "test.img.all" 16 | check "./keyfind.py pgpsym pgpasym pgparm $1" "test.img.pgpcipher" 17 | check "./keyfind.py ssl pgp $1" "test.img.keys" 18 | check "./keyfind.py pgpasym $1" "test.img.asym" 19 | check "./keyfind.py pgpsym $1" "test.img.sym" 20 | check "./keyfind.py pgparm $1" "test.img.arm" 21 | check "./keyfind.py ssl $1" "test.img.ssl" 22 | check "./keyfind.py pgp $1" "test.img.pgp" 23 | -------------------------------------------------------------------------------- /tests/genpgpmsgs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # generate all kind of symmetric pgp messages 3 | for cipher_algo in IDEA 3DES CAST5 BLOWFISH AES AES192 AES256 TWOFISH CAMELLIA128 CAMELLIA192 CAMELLIA256; do 4 | gpg -c --passphrase a --s2k-mode 0 --cipher-algo ${cipher_algo} >${cipher_algo}-0.pgp ${cipher_algo}-${s2kmode}-${s2k_digest_algo}-${s2k_cipher_algo}.pgp @P4DFV])\x04.{4}[\x01\x02](\x10\x00|\x0f[\xfe\xff]).{512})\x00\x11\x01\x00\x01([\x00\x01\x02\x03\x04\x07\x08\t\n]|[\xfe\xff][\x01\x02\x03\x04\x07\x08\t\n][\x00\x01\x03e][\x01\x02\x03\x08\t\n\x0b]))|(-----BEGIN PGP MESSAGE-----\n\r?(([^\n]+\n\r?)+\n\r?)?([A-Za-z0-9+/]+\s*\n\r?)+([A-Za-z0-9+/]{4})+([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\s*\n\r?(=[A-Za-z0-9+/]{4}\s*\n\r?)?-----END PGP MESSAGE-----)|((\x84\x8c\x03.{8}[\x01\x02](\x03[\xf9\xfa\xfb\xfc\xfd\xfe\xff]|\x04\x00).{128}|\x85\x01\x0c\x03.{8}[\x01\x02](\x08\x00|\x07[\xf9\xfa\xfb\xfc\xfd\xfe\xff]).{256}|\x85\x01\x8c\x03.{8}[\x01\x02](\x0b[\xf9\xfa\xfb\xfc\xfd\xfe\xff]|\x0c\x00).{384}|\x85\x02\x0c\x03.{8}[\x01\x02](\x10\x00|\x0f[\xf9\xfa\xfb\xfc\xfd\xfe\xff]).{512})+\xd2.(..|.....)?\x01)|((\x8c[\r\x0c]\x04[\x01\x02\x03\x04\x07\x08\t\n](\x01[\x01\x02\x03\x08\t\n\x0b].{8}|\x03[\x01\x02\x03\x08\t\n\x0b].{9}))+[\xd2\xc9])|(0(\x82.{2}|\x83.{3}|\x84.{4}|\x85.{5})\x02[\x01]\x00(\x02(\x82\x01\xff.{511}|\x82\x02\x00.{512}|\x82\x02\x01.{513})\x02[\x03]\x01\x00\x01\x02(\x82\x01\xff.{511}|\x82\x02\x00.{512}|\x82\x02\x01.{513})(\x02(\x81\xff.{255}|\x82\x01\x00.{256}|\x82\x01\x01.{257})){5}|\x02(\x82\x01\x7f.{383}|\x82\x01\x80.{384}|\x82\x01\x81.{385})\x02[\x03]\x01\x00\x01\x02(\x82\x01\x7f.{383}|\x82\x01\x80.{384}|\x82\x01\x81.{385})(\x02(\x81\xbf.{191}|\x81\xc0.{192}|\x81\xc1.{193})){5}|\x02(\x81\xff.{255}|\x82\x01\x00.{256}|\x82\x01\x01.{257})\x02[\x03]\x01\x00\x01\x02(\x81\xff.{255}|\x82\x01\x00.{256}|\x82\x01\x01.{257})(\x02([\x7f].{127}|\x81\x80.{128}|\x81\x81.{129})){5}|\x02([\x7f].{127}|\x81\x80.{128}|\x81\x81.{129})\x02[\x03]\x01\x00\x01\x02([\x7f].{127}|\x81\x80.{128}|\x81\x81.{129})(\x02([?].{63}|[@].{64}|[A].{65})){5}|\x02([?].{63}|[@].{64}|[A].{65})\x02[\x03]\x01\x00\x01\x02([?].{63}|[@].{64}|[A].{65})(\x02([\x1f].{31}|[ ].{32}|[!].{33})){5}))) 2 | -------------------------------------------------------------------------------- /kraakengrep/kgrep.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | using namespace re2; 16 | 17 | typedef unsigned char UCHAR; 18 | typedef unsigned char *UCHARP; 19 | 20 | void grep(char *regexp, int fd, char *name); 21 | void matcher(RE2 &re, UCHARP beg, UCHARP end); 22 | UCHARP get_line_beg(UCHARP p, UCHARP beg); 23 | 24 | void usage(void) { 25 | fprintf(stderr, "usage: grep (regexp|-f regexp-file) file+"); 26 | exit(1); 27 | } 28 | 29 | int main(int argc, char* argv[]) { 30 | int opt, i, fd; 31 | 32 | char buf[1<<14], *regexp = NULL; 33 | 34 | if (argc < 3) { 35 | usage(); 36 | } else { 37 | while ((opt=getopt(argc, argv, "f:")) != -1) { 38 | switch (opt) { 39 | case 'f': 40 | { 41 | FILE *fp = fopen(optarg, "r"); 42 | fgets(buf, sizeof(buf), fp); 43 | regexp = buf; 44 | fclose(fp); 45 | optind--; 46 | } 47 | break; 48 | default: usage(); 49 | } 50 | } 51 | 52 | if (regexp == NULL) { 53 | if (optind > argc) { 54 | usage(); 55 | } 56 | regexp = argv[optind]; 57 | } 58 | 59 | for (i = optind+1; i < argc; i++) { 60 | fd = open(argv[i], O_RDONLY, 0666); 61 | if (fd == 0) { 62 | fprintf(stderr, "can't open %s:", argv[i]); 63 | continue; 64 | } 65 | grep(regexp, fd, argc > 3 ? argv[i] : NULL); 66 | close(fd); 67 | } 68 | } 69 | 70 | return 0; 71 | } 72 | 73 | void grep(char *regexp, int fd, char *name) { 74 | caddr_t file_mmap; 75 | UCHARP end, beg; 76 | off_t size; 77 | struct stat sb; 78 | 79 | if (fstat(fd, &sb)) { 80 | fprintf(stderr, "can't fstat %s\n", name); 81 | exit(0); 82 | } 83 | 84 | size = sb.st_size; 85 | file_mmap = (caddr_t)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, (off_t)0); 86 | 87 | if (file_mmap == (caddr_t)-1) { 88 | fprintf(stderr, "can't mmap %s\n", name); 89 | exit(0); 90 | } 91 | 92 | beg = (UCHARP) file_mmap; 93 | end = beg + size - 1; 94 | 95 | string regex = regexp; 96 | 97 | RE2::Options options; 98 | options.set_dot_nl(true); 99 | options.set_utf8(false); 100 | options.set_max_mem(64<<20); 101 | options.set_log_errors(false); 102 | 103 | RE2 re(regex, options); 104 | re.ok(); 105 | 106 | matcher(re, beg, end); 107 | 108 | munmap(file_mmap, size); 109 | return; 110 | } 111 | 112 | void matcher(RE2 &re, UCHARP beg, UCHARP end) { 113 | string contents = string((const char *)beg, (end - beg)); 114 | StringPiece input(contents); 115 | int i, margc=re.NumberOfCapturingGroups(); 116 | StringPiece word[margc]; 117 | RE2::Arg margv[margc]; 118 | RE2::Arg * margs[margc]; 119 | const map& namedmap = re.CapturingGroupNames(); 120 | std::map::const_iterator it; 121 | long start=(long) input.data(); 122 | for (i = 0; i < margc; i++) { 123 | margv[i] = &word[i]; 124 | margs[i] = &margv[i]; 125 | } 126 | while (RE2::FindAndConsumeN(&input, re, margs, margc)) { 127 | for (int i = 0; i < margc; i++) { 128 | if(word[i].size()==0) continue; 129 | it=namedmap.find(i+1); 130 | if(it!=namedmap.end()) { 131 | cout << it->second << "\t"; 132 | } else { 133 | cout << i << "\t"; 134 | } 135 | cout << ((long) word[i].data()) - start; 136 | cout << "\t" << (long) (word[i].size()) << endl; 137 | } 138 | } 139 | return; 140 | } 141 | -------------------------------------------------------------------------------- /pgp.magic: -------------------------------------------------------------------------------- 1 | # (c) 2014 stf. license AGPLv3+ 2 | # magic signatures to detect PGP crypto material 3 | # detects and extracts metadata from: 4 | # - symmetric encrypted packet header 5 | # - RSA (e=65537) secret (sub-)keys 6 | 7 | # 1024b RSA encrypted data 8 | 9 | 0 string \x84\x8c\x03 PGP RSA encrypted session key - 10 | >3 lelong x keyid: %X 11 | >7 lelong x %X 12 | >11 byte 0x01 RSA (Encrypt or Sign) 1024b 13 | >11 byte 0x02 RSA Encrypt-Only 1024b 14 | >12 string \x04\x00 15 | >12 string \x03\xff 16 | >12 string \x03\xfe 17 | >12 string \x03\xfd 18 | >12 string \x03\xfc 19 | >12 string \x03\xfb 20 | >12 string \x03\xfa 21 | >12 string \x03\xf9 22 | >142 byte 0xd2 . 23 | 24 | # 2048b RSA encrypted data 25 | 26 | 0 string \x85\x01\x0c\x03 PGP RSA encrypted session key - 27 | >4 lelong x keyid: %X 28 | >8 lelong x %X 29 | >12 byte 0x01 RSA (Encrypt or Sign) 2048b 30 | >12 byte 0x02 RSA Encrypt-Only 2048b 31 | >13 string \x08\x00 32 | >13 string \x07\xff 33 | >13 string \x07\xfe 34 | >13 string \x07\xfd 35 | >13 string \x07\xfc 36 | >13 string \x07\xfb 37 | >13 string \x07\xfa 38 | >13 string \x07\xf9 39 | >271 byte 0xd2 . 40 | 41 | # 3072b RSA encrypted data 42 | 43 | 0 string \x85\x01\x8c\x03 PGP RSA encrypted session key - 44 | >4 lelong x keyid: %X 45 | >8 lelong x %X 46 | >12 byte 0x01 RSA (Encrypt or Sign) 3072b 47 | >12 byte 0x02 RSA Encrypt-Only 3072b 48 | >13 string \x0c\x00 49 | >13 string \x0b\xff 50 | >13 string \x0b\xfe 51 | >13 string \x0b\xfd 52 | >13 string \x0b\xfc 53 | >13 string \x0b\xfb 54 | >13 string \x0b\xfa 55 | >13 string \x0b\xf9 56 | >399 byte 0xd2 . 57 | 58 | # 3072b RSA encrypted data 59 | 60 | 0 string \x85\x02\x0c\x03 PGP RSA encrypted session key - 61 | >4 lelong x keyid: %X 62 | >8 lelong x %X 63 | >12 byte 0x01 RSA (Encrypt or Sign) 4096b 64 | >12 byte 0x02 RSA Encrypt-Only 4096b 65 | >13 string \x10\x00 66 | >13 string \x0f\xff 67 | >13 string \x0f\xfe 68 | >13 string \x0f\xfd 69 | >13 string \x0f\xfc 70 | >13 string \x0f\xfb 71 | >13 string \x0f\xfa 72 | >13 string \x0f\xf9 73 | >527 byte 0xd2 . 74 | 75 | # 4096b RSA encrypted data 76 | 77 | 0 string \x85\x04\x0c\x03 PGP RSA encrypted session key - 78 | >4 lelong x keyid: %X 79 | >8 lelong x %X 80 | >12 byte 0x01 RSA (Encrypt or Sign) 8129b 81 | >12 byte 0x02 RSA Encrypt-Only 8129b 82 | >13 string \x20\x00 83 | >13 string \x1f\xff 84 | >13 string \x1f\xfe 85 | >13 string \x1f\xfd 86 | >13 string \x1f\xfc 87 | >13 string \x1f\xfb 88 | >13 string \x1f\xfa 89 | >13 string \x1f\xf9 90 | >1039 byte 0xd2 . 91 | 92 | # crypto algo mapper 93 | 94 | 0 name crypto 95 | >0 byte 0x00 Plaintext or unencrypted data 96 | >0 byte 0x01 IDEA 97 | >0 byte 0x02 TripleDES 98 | >0 byte 0x03 CAST5 (128 bit key) 99 | >0 byte 0x04 Blowfish (128 bit key, 16 rounds) 100 | >0 byte 0x07 AES with 128-bit key 101 | >0 byte 0x08 AES with 192-bit key 102 | >0 byte 0x09 AES with 256-bit key 103 | >0 byte 0x0a Twofish with 256-bit key 104 | 105 | # hash algo mapper 106 | 107 | 0 name hash 108 | >0 byte 0x01 MD5 109 | >0 byte 0x02 SHA-1 110 | >0 byte 0x03 RIPE-MD/160 111 | >0 byte 0x08 SHA256 112 | >0 byte 0x09 SHA384 113 | >0 byte 0x0a SHA512 114 | >0 byte 0x0b SHA224 115 | 116 | # pgp symmetric encrypted data 117 | 118 | 0 byte 0x8c PGP symmetric key encrypted data - 119 | >1 byte 0x0d 120 | >1 byte 0x0c 121 | >2 byte 0x04 122 | >3 use crypto 123 | >4 byte 0x01 salted - 124 | >>5 use hash 125 | >>14 byte 0xd2 . 126 | >>14 byte 0xc9 . 127 | >4 byte 0x03 salted & iterated - 128 | >>5 use hash 129 | >>15 byte 0xd2 . 130 | >>15 byte 0xc9 . 131 | 132 | # encrypted keymaterial needs s2k & can be checksummed/hashed 133 | 134 | 0 name chkcrypto 135 | >0 use crypto 136 | >1 byte 0x00 Simple S2K 137 | >1 byte 0x01 Salted S2K 138 | >1 byte 0x03 Salted&Iterated S2K 139 | >2 use hash 140 | 141 | # all PGP keys start with this prolog 142 | # containing version, creation date, and purpose 143 | 144 | 0 name keyprolog 145 | >0 byte 0x04 146 | >1 beldate x created on %s - 147 | >5 byte 0x01 RSA (Encrypt or Sign) 148 | >5 byte 0x02 RSA Encrypt-Only 149 | 150 | # end of secret keys known signature 151 | # contains e=65537 and the prolog to 152 | # the encrypted parameters 153 | 154 | 0 name keyend 155 | >0 string \x00\x11\x01\x00\x01 e=65537 156 | >5 use crypto 157 | >5 byte 0xff checksummed 158 | >>6 use chkcrypto 159 | >5 byte 0xfe hashed 160 | >>6 use chkcrypto 161 | 162 | # PGP secret keys contain also the public parts 163 | # these vary by bitsize of the key 164 | 165 | 0 name x1024 166 | >0 use keyprolog 167 | >6 string \x03\xfe 168 | >6 string \x03\xff 169 | >6 string \x04\x00 170 | >136 use keyend 171 | 172 | 0 name x2048 173 | >0 use keyprolog 174 | >6 string \x80\x00 175 | >6 string \x07\xfe 176 | >6 string \x07\xff 177 | >264 use keyend 178 | 179 | 0 name x3072 180 | >0 use keyprolog 181 | >6 string \x0b\xfe 182 | >6 string \x0b\xff 183 | >6 string \x0c\x00 184 | >392 use keyend 185 | 186 | 0 name x4096 187 | >0 use keyprolog 188 | >6 string \x10\x00 189 | >6 string \x0f\xfe 190 | >6 string \x0f\xff 191 | >520 use keyend 192 | 193 | # \x00|\x1f[\xfe\xff]).{1024})' 194 | 0 name x8192 195 | >0 use keyprolog 196 | >6 string \x20\x00 197 | >6 string \x1f\xfe 198 | >6 string \x1f\xff 199 | >1032 use keyend 200 | 201 | # depending on the size of the pkt 202 | # we branch into the proper key size 203 | # signatures defined as x{keysize} 204 | 205 | >0 name pgpkey 206 | >0 string \x01\xd8 1024b 207 | >>2 use x1024 208 | >0 string \x01\xeb 1024b 209 | >>2 use x1024 210 | >0 string \x01\xfb 1024b 211 | >>2 use x1024 212 | >0 string \x01\xfd 1024b 213 | >>2 use x1024 214 | >0 string \x01\xf3 1024b 215 | >>2 use x1024 216 | >0 string \x01\xee 1024b 217 | >>2 use x1024 218 | >0 string \x01\xfe 1024b 219 | >>2 use x1024 220 | >0 string \x01\xf4 1024b 221 | >>2 use x1024 222 | >0 string \x02\x0d 1024b 223 | >>2 use x1024 224 | >0 string \x02\x03 1024b 225 | >>2 use x1024 226 | >0 string \x02\x05 1024b 227 | >>2 use x1024 228 | >0 string \x02\x15 1024b 229 | >>2 use x1024 230 | >0 string \x02\x00 1024b 231 | >>2 use x1024 232 | >0 string \x02\x10 1024b 233 | >>2 use x1024 234 | >0 string \x02\x04 1024b 235 | >>2 use x1024 236 | >0 string \x02\x06 1024b 237 | >>2 use x1024 238 | >0 string \x02\x16 1024b 239 | >>2 use x1024 240 | >0 string \x03\x98 2048b 241 | >>2 use x2048 242 | >0 string \x03\xab 2048b 243 | >>2 use x2048 244 | >0 string \x03\xbb 2048b 245 | >>2 use x2048 246 | >0 string \x03\xbd 2048b 247 | >>2 use x2048 248 | >0 string \x03\xcd 2048b 249 | >>2 use x2048 250 | >0 string \x03\xb3 2048b 251 | >>2 use x2048 252 | >0 string \x03\xc3 2048b 253 | >>2 use x2048 254 | >0 string \x03\xc5 2048b 255 | >>2 use x2048 256 | >0 string \x03\xd5 2048b 257 | >>2 use x2048 258 | >0 string \x03\xae 2048b 259 | >>2 use x2048 260 | >0 string \x03\xbe 2048b 261 | >>2 use x2048 262 | >0 string \x03\xc0 2048b 263 | >>2 use x2048 264 | >0 string \x03\xd0 2048b 265 | >>2 use x2048 266 | >0 string \x03\xb4 2048b 267 | >>2 use x2048 268 | >0 string \x03\xc4 2048b 269 | >>2 use x2048 270 | >0 string \x03\xc6 2048b 271 | >>2 use x2048 272 | >0 string \x03\xd6 2048b 273 | >>2 use x2048 274 | >0 string \x05X 3072b 275 | >>2 use x3072 276 | >0 string \x05k 3072b 277 | >>2 use x3072 278 | >0 string \x05{ 3072b 279 | >>2 use x3072 280 | >0 string \x05} 3072b 281 | >>2 use x3072 282 | >0 string \x05\x8d 3072b 283 | >>2 use x3072 284 | >0 string \x05s 3072b 285 | >>2 use x3072 286 | >0 string \x05\x83 3072b 287 | >>2 use x3072 288 | >0 string \x05\x85 3072b 289 | >>2 use x3072 290 | >0 string \x05\x95 3072b 291 | >>2 use x3072 292 | >0 string \x05n 3072b 293 | >>2 use x3072 294 | >0 string \x05\x7e 3072b 295 | >>2 use x3072 296 | >0 string \x05\x80 3072b 297 | >>2 use x3072 298 | >0 string \x05\x90 3072b 299 | >>2 use x3072 300 | >0 string \x05t 3072b 301 | >>2 use x3072 302 | >0 string \x05\x84 3072b 303 | >>2 use x3072 304 | >0 string \x05\x86 3072b 305 | >>2 use x3072 306 | >0 string \x05\x96 3072b 307 | >>2 use x3072 308 | >0 string \x07[ 4096b 309 | >>2 use x4096 310 | >0 string \x07\x18 4096b 311 | >>2 use x4096 312 | >0 string \x07+ 4096b 313 | >>2 use x4096 314 | >0 string \x07; 4096b 315 | >>2 use x4096 316 | >0 string \x07= 4096b 317 | >>2 use x4096 318 | >0 string \x07M 4096b 319 | >>2 use x4096 320 | >0 string \x073 4096b 321 | >>2 use x4096 322 | >0 string \x07C 4096b 323 | >>2 use x4096 324 | >0 string \x07E 4096b 325 | >>2 use x4096 326 | >0 string \x07U 4096b 327 | >>2 use x4096 328 | >0 string \x07. 4096b 329 | >>2 use x4096 330 | >0 string \x07> 4096b 331 | >>2 use x4096 332 | >0 string \x07@ 4096b 333 | >>2 use x4096 334 | >0 string \x07P 4096b 335 | >>2 use x4096 336 | >0 string \x074 4096b 337 | >>2 use x4096 338 | >0 string \x07D 4096b 339 | >>2 use x4096 340 | >0 string \x07F 4096b 341 | >>2 use x4096 342 | >0 string \x07V 4096b 343 | >>2 use x4096 344 | >0 string \x0e[ 8192b 345 | >>2 use x8192 346 | >0 string \x0e\x18 8192b 347 | >>2 use x8192 348 | >0 string \x0e+ 8192b 349 | >>2 use x8192 350 | >0 string \x0e; 8192b 351 | >>2 use x8192 352 | >0 string \x0e= 8192b 353 | >>2 use x8192 354 | >0 string \x0eM 8192b 355 | >>2 use x8192 356 | >0 string \x0e3 8192b 357 | >>2 use x8192 358 | >0 string \x0eC 8192b 359 | >>2 use x8192 360 | >0 string \x0eE 8192b 361 | >>2 use x8192 362 | >0 string \x0eU 8192b 363 | >>2 use x8192 364 | >0 string \x0e. 8192b 365 | >>2 use x8192 366 | >0 string \x0e> 8192b 367 | >>2 use x8192 368 | >0 string \x0e@ 8192b 369 | >>2 use x8192 370 | >0 string \x0eP 8192b 371 | >>2 use x8192 372 | >0 string \x0e4 8192b 373 | >>2 use x8192 374 | >0 string \x0eD 8192b 375 | >>2 use x8192 376 | >0 string \x0eF 8192b 377 | >>2 use x8192 378 | >0 string \x0eV 8192b 379 | >>2 use x8192 380 | 381 | # PGP RSA (e=65537) secret (sub-)key header 382 | 383 | 0 byte 0x95 PGP Secret Key - 384 | >1 use pgpkey 385 | 0 byte 0x97 PGP Secret Sub-key - 386 | >1 use pgpkey 387 | 0 byte 0x9d PGP Secret Sub-key - 388 | >1 use pgpkey -------------------------------------------------------------------------------- /keyfind.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # composes regexps and locates them in supplied image. 3 | # use kraakengrep for more performant scanning. 4 | # exponents in private keys only match with 65537, todo: expand with 5 | # other fermat primes: {3, 5, 17, 257} at least 6 | 7 | import struct, re, sys, mmap, itertools, hashlib 8 | 9 | # common functions for ssl and pgp 10 | def quote(frag): 11 | return ''.join("[%c]" % x if x in '({[.+*?\\' else x for x in frag) 12 | 13 | def _tobin(num,bytes=0): 14 | res = [] 15 | if num==0: 16 | res=['\0'] 17 | while num: 18 | res.append(chr(num&0xff)) 19 | num>>=8 20 | res.reverse() 21 | if bytes and len(res)2 else [item[1]] 33 | else: 34 | res[item[0]].append(item[1:] if len(item)>2 else item[1]) 35 | return res 36 | 37 | def compress(exp): # takes pairs, returns a simplified regex 38 | res = [] 39 | tree = suffixtree(exp) 40 | for k, v in tree.items(): 41 | if set(isinstance(i,str) for i in v) == set([True]): 42 | if len(v)>1: 43 | res.append("%s[%s]" % (k, ''.join(v))) 44 | else: 45 | res.append("%s%s" % (k, v[0])) 46 | return '|'.join(res) 47 | 48 | # ssl related functions 49 | 50 | def pkcs1size(size): 51 | if size<128: 52 | return "[%s]" % chr(size) 53 | for fsize in xrange(1,6): 54 | if size>=(1<<(8*fsize)): 55 | continue 56 | return '%c%s' % (0x80+fsize,tobin(size,fsize)) 57 | 58 | def number(val=None, psize=None, range=1): 59 | if val!=None: 60 | val=tobin(val) 61 | psize=len(val) 62 | return '\x02%s%s' % (pkcs1size(psize), val) 63 | elif psize: 64 | return "\x02(?:%s)" % '|'.join('%s.{%d}' % (pkcs1size(psize+i), psize+i) for i in xrange(-range,range+1)) 65 | 66 | def rsaparam(psize): 67 | f=number(psize=psize) 68 | h="(?:%s){5}" % number(psize=psize/2) 69 | return ''.join(f + number(65537) + f + h) # + h + h + h + h) 70 | 71 | def pkcs1rsa(): # pkcs8 has pkcs1 inside 72 | # finds DER encoded pkcs#1 RSA keys with exponent 65537 and 73 | # [1024,2048,3072,4096] bit keysize 74 | return '\x30(?:%s)%s(?:%s)' % ('|'.join(['%c.{%s}' % (chr(0x80+x),x) # todo calculate more specific sizes 75 | for x in xrange(2,6)]), 76 | number(0), 77 | '|'.join([rsaparam(x) 78 | for x in [512,384,256,128,64]])) 79 | # pgp related functions 80 | 81 | def choice(opts): 82 | return '[%s]' % ''.join(chr(x) for x in opts) 83 | 84 | def tochoice(opts): 85 | return "(?:%s)" % compress([_tobin(x) for x in opts]) 86 | 87 | def size(size, range=2): 88 | return "(?:%s)" % compress([tobin(size+i,2) for i in xrange(-range,1)]) 89 | 90 | #\x95..\x04.{4}[\x01\x02](?:size)(?:[0,1,2,3,4,7,8,9,10]|[254,255][1,2,3,4,7,8,9,10][0,1,3][1,2,3,8,9,10,11] 91 | 92 | # secret (sub) key (5|7) old, 2 byte size 0x95|0x97 93 | # .. length 94 | # version 0x04 95 | # .... creation date 96 | # [\x01\x02] pub key type (rsa sign+enc 1, rsa encrypt only 2) 97 | # size in bits, .... (size+7 //8), n 98 | # size in bits (17) \x01\x00\x01 , exponent 99 | # 0,C, [254, 255]C[0,1,3,101]H - s2k 100 | #C = [1,2,3,4,7,8,9,10] 101 | #H = [1,2,3,8,9,10,11] 102 | 103 | def pktsize(ksize=3072): 104 | base = (1 + # version 105 | 4 + # creation date 106 | 1 + # pub alg 107 | ((ksize+7) // 8) + 2 + # n 108 | 5 + # exponent 109 | ((ksize+7) // 8) + 2 + # d 110 | (((((ksize/2)+7) // 8) +2)*3) + # p, q, u 111 | 1) # s2k 112 | kdf = [(base + # simple 113 | 1 + # symmetric algo 114 | 1 + # simple s2k // 0x00 115 | 1), # hash algo 116 | (base + # salted 117 | 1 + # symmetric algo 118 | 1 + # Salted S2K // 0x01 119 | 1 + # hash algo 120 | 8), # salt 121 | (base + # gnupg 101 122 | 6), # gnu + simple? 123 | (base + # interated and salted 124 | 1 + # symmetric algo 125 | 1 + # Iterated and Salted S2K // 0x03 126 | 1 + # hash algo 127 | 8 + # salt 128 | 1)] # iterations 129 | blocksizes = [16,32] 130 | checkhash = [2,20] 131 | 132 | return [base+2]+[s+c+k for s in kdf for c in checkhash for k in blocksizes] 133 | 134 | def pgprsa(): 135 | sizeopts = "(?:%s)" % '|'.join('%s\x04.{4}%s%s.{%s}' % (tochoice(pktsize(psize)), 136 | choice([1,2]), 137 | size(psize), 138 | (psize+7) // 8) 139 | for psize in [1024, 2048, 3072, 4096, 8192]) 140 | 141 | return '[\x95\x97\x9d]%s\x00\x11\x01\x00\x01(?:%s|%s%s%s%s)' % ( 142 | sizeopts, 143 | choice([0,1,2,3,4,7,8,9,10]), # cipher 144 | choice([254,255]), 145 | choice([1,2,3,4,7,8,9,10]), # cipher 146 | choice([0,1,3,101]), # s2k 147 | choice([1,2,3,8,9,10,11])) 148 | 149 | def pgpsym(): 150 | # - A one-octet version number. The only currently defined version 151 | # is 4. 152 | # 153 | # - A one-octet number describing the symmetric algorithm used. 154 | # 155 | # - A string-to-key (S2K) specifier, length as defined above. 156 | # 157 | # - Optionally, the encrypted session key itself, which is decrypted 158 | # with the string-to-key object. 159 | 160 | h = choice([1,2,3,8,9,10,11]) 161 | c = choice([1,2,3,4,7,8,9,10]) 162 | s2k = '(?:\x01%s.{8}|\x03%s.{9})' % (h,h) 163 | return '(?:\x8c[\x0d\x0c]\x04%s%s)+[\xd2\xc9]' % (c, s2k) 164 | 165 | def pgpasym(): 166 | #Old: Public-Key Encrypted Session Key Packet(tag 1)(524 bytes) 167 | # New version(3) 168 | # Key ID - 0x0123456789abcdef 169 | # Pub alg - RSA Encrypt or Sign(pub 1) 170 | # RSA m^e mod n(4091 bits) - ... 171 | # -> m = sym alg(1 byte) + checksum(2 bytes) + PKCS-1 block type 02 172 | 173 | p = choice([1,2]) 174 | return "(?:%s)+\xd2(?:.|..|.....)\x01" % "|".join( 175 | ["%c%s\x03.{8}%s(?:%s).{%s}" % ('\x84' if len(tobin(((size+7) // 8)+12))==1 else '\x85', 176 | tobin(((size+7) // 8)+12), 177 | p, 178 | compress([_tobin(size+i) for i in xrange(-7,1)]), 179 | ((size+7) // 8)) 180 | for size in [1024,2048,3072,4096,8192] 181 | ]) 182 | 183 | def pgparmor(): 184 | return ''.join(['-----BEGIN PGP MESSAGE-----\x0a\x0d?', # header 185 | '(?:(?:[^\x0a]+\x0a\x0d?)+\x0a\x0d?)?', # version, comment 186 | '(?:[A-Za-z0-9+/]+\s*\x0a\x0d?)+', # base64 data 187 | # last data line, can haz = or == 188 | '(?:[A-Za-z0-9+/]{4})+(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\s*\x0a\x0d?', 189 | # optional last line, can haz =[[:base64:]]{4} 190 | # - if there would be a base64 char class 191 | '(?:=[A-Za-z0-9+/]{4}\s*\x0a\x0d?)?', 192 | '-----END PGP MESSAGE-----']) 193 | 194 | knownkeys = { '6703d04c2c33f79cb27bf73072c91941': 'openssl speed key 4096', 195 | '460ff240ad1b84d9a6fa21db4cf00b0b': 'openssl speed key 2048', 196 | 'ad839da2337b6806979ac3ca8d5c5067': 'openssl speed key 1024', 197 | } 198 | 199 | regexps = {'ssl': pkcs1rsa(), 200 | 'pgp': pgprsa(), 201 | 'pgpsym': pgpsym(), 202 | 'pgpasym': pgpasym(), 203 | 'pgparm': pgparmor(), 204 | } 205 | if __name__ == "__main__": 206 | debug = False 207 | if debug: import traceback 208 | 209 | exp = [] 210 | for k, v in regexps.items(): 211 | if k in sys.argv: 212 | exp.append("(?P<%s>%s)" % (k, v)) 213 | del sys.argv[sys.argv.index(k)] 214 | if len(exp)>0: 215 | exp = '|'.join(exp) 216 | else: 217 | exp = "(?P%s)|(?P%s)|(?P%s)|(?P%s)|(?P%s)" % (pkcs1rsa(), pgprsa(), pgpsym(), pgpasym(), pgparmor()) 218 | 219 | if debug: 220 | print '\n\n'.join(repr(x) for x in (pkcs1rsa(), pgprsa(), pgpsym(), pgpasym(), pgparmor())) 221 | print repr(exp) 222 | sys.exit() 223 | 224 | exp = re.compile(exp, re.S) 225 | stats = {'pgp': 0, 226 | 'pgpsym': 0, 227 | 'pgpasym': 0, 228 | 'pgparm': 0, 229 | 'ssl': 0} 230 | with open(sys.argv[1],'rb') as fd: 231 | mm = mmap.mmap(fd.fileno(), 0, access=mmap.ACCESS_READ) 232 | m = exp.search(mm) 233 | if not m: 234 | print "not found" 235 | sys.exit(1) 236 | while m: 237 | type=[] 238 | for x in ['pgp', 'pgpsym', 'pgpasym', 'pgparm', 'ssl'] : 239 | try: 240 | if not m.group(x): continue 241 | except IndexError: 242 | continue 243 | type.append(x) 244 | if len(type)>1: 245 | print "wtf:", type 246 | sys.exit(1) 247 | type=type[0] 248 | stats[type]+=1 249 | if type in ['pgp','pgpsym','pgpasym']: 250 | if (ord(m.group()[0]) & 0xc0) == 0xc0: 251 | print 'meh unimplemented new pgp pkt' 252 | elif ord(m.group()[0]) & 0x80: # parse old style pgp size 253 | if (ord(m.group()[0]) & 0x3) == 0: 254 | size = ord(m.group()[1]) + 3 255 | elif (ord(m.group()[0]) & 0x3) == 1: 256 | size = struct.unpack('>H', m.group()[1:3])[0] + 3 257 | else: 258 | print 'meh unsupported size type', mm[m.start()] & 0x3 259 | else: 260 | print 'meh first byte of pgp bad', hex(ord(m.group()[0])) 261 | sys.exit(1) 262 | print '###', {'pgp': 'pgp key', 263 | 'pgpsym': 'pgp symmetric encrypted', 264 | 'pgpasym': 'pgp public-key encrypted'}[type], 265 | elif type == 'pgparm': 266 | size = 0 267 | print '### pgp ascii armored message', 268 | elif type == 'ssl': 269 | size = struct.unpack('>H', m.group('ssl')[2:4])[0] 270 | print '### ssl key', 271 | else: 272 | print '! pgp xor ssl' 273 | size = None 274 | 275 | print m.start(), size, 276 | if type in ['pgp','ssl']: 277 | fp=hashlib.md5(m.group()).hexdigest() 278 | if fp in knownkeys: 279 | print knownkeys[fp] 280 | else: 281 | print fp 282 | else: 283 | print 284 | if not size: 285 | if type == 'pgparm': 286 | print m.group() 287 | else: 288 | print repr(m.group()) 289 | else: 290 | print repr(mm[m.start():m.start()+size]) 291 | print 292 | m = exp.search(mm, m.end()+1) 293 | if sum(stats.values()) == 0: 294 | print "nothing found" 295 | else: 296 | print 'stats' 297 | print '\n'.join('%s %4d' % (k, v) for k,v in stats.items()) 298 | --------------------------------------------------------------------------------