├── README.md ├── general ├── POODLEv2 │ ├── README.md │ ├── openssl_bad_tls_padding │ └── t1_enc.c └── README.md └── malware ├── Poison Ivy RAT ├── README.md └── pivy_find_config.py ├── README.md └── Xtreme RAT ├── README.md ├── xtrat_decrypt_config.py ├── xtrat_decrypt_keylog.py ├── xtrat_find_config.py └── xtrat_parse_config.py /README.md: -------------------------------------------------------------------------------- 1 | General purpose and malware-specific analysis tools developed by FireEye Labs 2 | 3 | -------------------------------------------------------------------------------- /general/POODLEv2/README.md: -------------------------------------------------------------------------------- 1 | This is a linux build of OpenSSL 1.0.1j with modified TLS padding to test for POODLE like vulnerabilities in TLS servers. 2 | For details of the changes made, see here: 3 | 4 | https://github.com/jamesoc-feye/openssl/commit/bd769939c3c7b51df8eed02a79c675701a6be3bd 5 | 6 | Example Usage: 7 | ``` 8 | (printf 'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n'; sleep 5) | ./openssl_bad_tls_padding s_client -tls1 -cipher DES-CBC3-SHA -connect 127.0.0.1:443 2>&1 |less 9 | ``` 10 | 11 | Ensure you're using a suitable cipher such as DES-CBC3-SHA which uses TLS padding and not AEAD 12 | 13 | A NON-vulnerable server will look something like: 14 | ``` 15 | 140026524681896:error:140943FC:SSL routines:SSL3_READ_BYTES:sslv3 alert bad record mac:s3_pkt.c:1275:SSL alert number 20 16 | 140026524681896:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:598: 17 | ``` 18 | 19 | A vulnerable server will return a HTTP response, such as: 20 | ``` 21 | HTTP/1.0 200 OK 22 | Server: Generic Web Server 23 | Date: Tue, 26 Aug 1997 22:10:05 GMT 24 | Content-type: text/plain 25 | 26 | ``` 27 | -------------------------------------------------------------------------------- /general/POODLEv2/openssl_bad_tls_padding: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireeye/tools/59a0cb68e25d83ce5cc6600ec30cff9e90a8a965/general/POODLEv2/openssl_bad_tls_padding -------------------------------------------------------------------------------- /general/POODLEv2/t1_enc.c: -------------------------------------------------------------------------------- 1 | /* ssl/t1_enc.c */ 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 | * All rights reserved. 4 | * 5 | * This package is an SSL implementation written 6 | * by Eric Young (eay@cryptsoft.com). 7 | * The implementation was written so as to conform with Netscapes SSL. 8 | * 9 | * This library is free for commercial and non-commercial use as long as 10 | * the following conditions are aheared to. The following conditions 11 | * apply to all code found in this distribution, be it the RC4, RSA, 12 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 | * included with this distribution is covered by the same copyright terms 14 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 | * 16 | * Copyright remains Eric Young's, and as such any Copyright notices in 17 | * the code are not to be removed. 18 | * If this package is used in a product, Eric Young should be given attribution 19 | * as the author of the parts of the library used. 20 | * This can be in the form of a textual message at program startup or 21 | * in documentation (online or textual) provided with the package. 22 | * 23 | * Redistribution and use in source and binary forms, with or without 24 | * modification, are permitted provided that the following conditions 25 | * are met: 26 | * 1. Redistributions of source code must retain the copyright 27 | * notice, this list of conditions and the following disclaimer. 28 | * 2. Redistributions in binary form must reproduce the above copyright 29 | * notice, this list of conditions and the following disclaimer in the 30 | * documentation and/or other materials provided with the distribution. 31 | * 3. All advertising materials mentioning features or use of this software 32 | * must display the following acknowledgement: 33 | * "This product includes cryptographic software written by 34 | * Eric Young (eay@cryptsoft.com)" 35 | * The word 'cryptographic' can be left out if the rouines from the library 36 | * being used are not cryptographic related :-). 37 | * 4. If you include any Windows specific code (or a derivative thereof) from 38 | * the apps directory (application code) you must include an acknowledgement: 39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 | * SUCH DAMAGE. 52 | * 53 | * The licence and distribution terms for any publically available version or 54 | * derivative of this code cannot be changed. i.e. this code cannot simply be 55 | * copied and put under another distribution licence 56 | * [including the GNU Public Licence.] 57 | */ 58 | /* ==================================================================== 59 | * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. 60 | * 61 | * Redistribution and use in source and binary forms, with or without 62 | * modification, are permitted provided that the following conditions 63 | * are met: 64 | * 65 | * 1. Redistributions of source code must retain the above copyright 66 | * notice, this list of conditions and the following disclaimer. 67 | * 68 | * 2. Redistributions in binary form must reproduce the above copyright 69 | * notice, this list of conditions and the following disclaimer in 70 | * the documentation and/or other materials provided with the 71 | * distribution. 72 | * 73 | * 3. All advertising materials mentioning features or use of this 74 | * software must display the following acknowledgment: 75 | * "This product includes software developed by the OpenSSL Project 76 | * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 77 | * 78 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 79 | * endorse or promote products derived from this software without 80 | * prior written permission. For written permission, please contact 81 | * openssl-core@openssl.org. 82 | * 83 | * 5. Products derived from this software may not be called "OpenSSL" 84 | * nor may "OpenSSL" appear in their names without prior written 85 | * permission of the OpenSSL Project. 86 | * 87 | * 6. Redistributions of any form whatsoever must retain the following 88 | * acknowledgment: 89 | * "This product includes software developed by the OpenSSL Project 90 | * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 91 | * 92 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 93 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 95 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 96 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 97 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 98 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 99 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 100 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 101 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 102 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 103 | * OF THE POSSIBILITY OF SUCH DAMAGE. 104 | * ==================================================================== 105 | * 106 | * This product includes cryptographic software written by Eric Young 107 | * (eay@cryptsoft.com). This product includes software written by Tim 108 | * Hudson (tjh@cryptsoft.com). 109 | * 110 | */ 111 | /* ==================================================================== 112 | * Copyright 2005 Nokia. All rights reserved. 113 | * 114 | * The portions of the attached software ("Contribution") is developed by 115 | * Nokia Corporation and is licensed pursuant to the OpenSSL open source 116 | * license. 117 | * 118 | * The Contribution, originally written by Mika Kousa and Pasi Eronen of 119 | * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites 120 | * support (see RFC 4279) to OpenSSL. 121 | * 122 | * No patent licenses or other rights except those expressly stated in 123 | * the OpenSSL open source license shall be deemed granted or received 124 | * expressly, by implication, estoppel, or otherwise. 125 | * 126 | * No assurances are provided by Nokia that the Contribution does not 127 | * infringe the patent or other intellectual property rights of any third 128 | * party or that the license provides you with all the necessary rights 129 | * to make use of the Contribution. 130 | * 131 | * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN 132 | * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA 133 | * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY 134 | * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR 135 | * OTHERWISE. 136 | */ 137 | 138 | #include 139 | #include "ssl_locl.h" 140 | #ifndef OPENSSL_NO_COMP 141 | #include 142 | #endif 143 | #include 144 | #include 145 | #include 146 | #include 147 | #ifdef KSSL_DEBUG 148 | #include 149 | #endif 150 | 151 | /* seed1 through seed5 are virtually concatenated */ 152 | static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec, 153 | int sec_len, 154 | const void *seed1, int seed1_len, 155 | const void *seed2, int seed2_len, 156 | const void *seed3, int seed3_len, 157 | const void *seed4, int seed4_len, 158 | const void *seed5, int seed5_len, 159 | unsigned char *out, int olen) 160 | { 161 | int chunk; 162 | size_t j; 163 | EVP_MD_CTX ctx, ctx_tmp; 164 | EVP_PKEY *mac_key; 165 | unsigned char A1[EVP_MAX_MD_SIZE]; 166 | size_t A1_len; 167 | int ret = 0; 168 | 169 | chunk=EVP_MD_size(md); 170 | OPENSSL_assert(chunk >= 0); 171 | 172 | EVP_MD_CTX_init(&ctx); 173 | EVP_MD_CTX_init(&ctx_tmp); 174 | EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 175 | EVP_MD_CTX_set_flags(&ctx_tmp, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 176 | mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len); 177 | if (!mac_key) 178 | goto err; 179 | if (!EVP_DigestSignInit(&ctx,NULL,md, NULL, mac_key)) 180 | goto err; 181 | if (!EVP_DigestSignInit(&ctx_tmp,NULL,md, NULL, mac_key)) 182 | goto err; 183 | if (seed1 && !EVP_DigestSignUpdate(&ctx,seed1,seed1_len)) 184 | goto err; 185 | if (seed2 && !EVP_DigestSignUpdate(&ctx,seed2,seed2_len)) 186 | goto err; 187 | if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len)) 188 | goto err; 189 | if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len)) 190 | goto err; 191 | if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len)) 192 | goto err; 193 | if (!EVP_DigestSignFinal(&ctx,A1,&A1_len)) 194 | goto err; 195 | 196 | for (;;) 197 | { 198 | /* Reinit mac contexts */ 199 | if (!EVP_DigestSignInit(&ctx,NULL,md, NULL, mac_key)) 200 | goto err; 201 | if (!EVP_DigestSignInit(&ctx_tmp,NULL,md, NULL, mac_key)) 202 | goto err; 203 | if (!EVP_DigestSignUpdate(&ctx,A1,A1_len)) 204 | goto err; 205 | if (!EVP_DigestSignUpdate(&ctx_tmp,A1,A1_len)) 206 | goto err; 207 | if (seed1 && !EVP_DigestSignUpdate(&ctx,seed1,seed1_len)) 208 | goto err; 209 | if (seed2 && !EVP_DigestSignUpdate(&ctx,seed2,seed2_len)) 210 | goto err; 211 | if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len)) 212 | goto err; 213 | if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len)) 214 | goto err; 215 | if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len)) 216 | goto err; 217 | 218 | if (olen > chunk) 219 | { 220 | if (!EVP_DigestSignFinal(&ctx,out,&j)) 221 | goto err; 222 | out+=j; 223 | olen-=j; 224 | /* calc the next A1 value */ 225 | if (!EVP_DigestSignFinal(&ctx_tmp,A1,&A1_len)) 226 | goto err; 227 | } 228 | else /* last one */ 229 | { 230 | if (!EVP_DigestSignFinal(&ctx,A1,&A1_len)) 231 | goto err; 232 | memcpy(out,A1,olen); 233 | break; 234 | } 235 | } 236 | ret = 1; 237 | err: 238 | EVP_PKEY_free(mac_key); 239 | EVP_MD_CTX_cleanup(&ctx); 240 | EVP_MD_CTX_cleanup(&ctx_tmp); 241 | OPENSSL_cleanse(A1,sizeof(A1)); 242 | return ret; 243 | } 244 | 245 | /* seed1 through seed5 are virtually concatenated */ 246 | static int tls1_PRF(long digest_mask, 247 | const void *seed1, int seed1_len, 248 | const void *seed2, int seed2_len, 249 | const void *seed3, int seed3_len, 250 | const void *seed4, int seed4_len, 251 | const void *seed5, int seed5_len, 252 | const unsigned char *sec, int slen, 253 | unsigned char *out1, 254 | unsigned char *out2, int olen) 255 | { 256 | int len,i,idx,count; 257 | const unsigned char *S1; 258 | long m; 259 | const EVP_MD *md; 260 | int ret = 0; 261 | 262 | /* Count number of digests and partition sec evenly */ 263 | count=0; 264 | for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) { 265 | if ((m<s3->server_random,SSL3_RANDOM_SIZE, 301 | s->s3->client_random,SSL3_RANDOM_SIZE, 302 | NULL,0,NULL,0, 303 | s->session->master_key,s->session->master_key_length, 304 | km,tmp,num); 305 | #ifdef KSSL_DEBUG 306 | printf("tls1_generate_key_block() ==> %d byte master_key =\n\t", 307 | s->session->master_key_length); 308 | { 309 | int i; 310 | for (i=0; i < s->session->master_key_length; i++) 311 | { 312 | printf("%02X", s->session->master_key[i]); 313 | } 314 | printf("\n"); } 315 | #endif /* KSSL_DEBUG */ 316 | return ret; 317 | } 318 | 319 | int tls1_change_cipher_state(SSL *s, int which) 320 | { 321 | static const unsigned char empty[]=""; 322 | unsigned char *p,*mac_secret; 323 | unsigned char *exp_label; 324 | unsigned char tmp1[EVP_MAX_KEY_LENGTH]; 325 | unsigned char tmp2[EVP_MAX_KEY_LENGTH]; 326 | unsigned char iv1[EVP_MAX_IV_LENGTH*2]; 327 | unsigned char iv2[EVP_MAX_IV_LENGTH*2]; 328 | unsigned char *ms,*key,*iv; 329 | int client_write; 330 | EVP_CIPHER_CTX *dd; 331 | const EVP_CIPHER *c; 332 | #ifndef OPENSSL_NO_COMP 333 | const SSL_COMP *comp; 334 | #endif 335 | const EVP_MD *m; 336 | int mac_type; 337 | int *mac_secret_size; 338 | EVP_MD_CTX *mac_ctx; 339 | EVP_PKEY *mac_key; 340 | int is_export,n,i,j,k,exp_label_len,cl; 341 | int reuse_dd = 0; 342 | 343 | is_export=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher); 344 | c=s->s3->tmp.new_sym_enc; 345 | m=s->s3->tmp.new_hash; 346 | mac_type = s->s3->tmp.new_mac_pkey_type; 347 | #ifndef OPENSSL_NO_COMP 348 | comp=s->s3->tmp.new_compression; 349 | #endif 350 | 351 | #ifdef KSSL_DEBUG 352 | printf("tls1_change_cipher_state(which= %d) w/\n", which); 353 | printf("\talg= %ld/%ld, comp= %p\n", 354 | s->s3->tmp.new_cipher->algorithm_mkey, 355 | s->s3->tmp.new_cipher->algorithm_auth, 356 | comp); 357 | printf("\tevp_cipher == %p ==? &d_cbc_ede_cipher3\n", c); 358 | printf("\tevp_cipher: nid, blksz= %d, %d, keylen=%d, ivlen=%d\n", 359 | c->nid,c->block_size,c->key_len,c->iv_len); 360 | printf("\tkey_block: len= %d, data= ", s->s3->tmp.key_block_length); 361 | { 362 | int i; 363 | for (i=0; is3->tmp.key_block_length; i++) 364 | printf("%02x", s->s3->tmp.key_block[i]); printf("\n"); 365 | } 366 | #endif /* KSSL_DEBUG */ 367 | 368 | if (which & SSL3_CC_READ) 369 | { 370 | if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC) 371 | s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM; 372 | else 373 | s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM; 374 | 375 | if (s->enc_read_ctx != NULL) 376 | reuse_dd = 1; 377 | else if ((s->enc_read_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL) 378 | goto err; 379 | else 380 | /* make sure it's intialized in case we exit later with an error */ 381 | EVP_CIPHER_CTX_init(s->enc_read_ctx); 382 | dd= s->enc_read_ctx; 383 | mac_ctx=ssl_replace_hash(&s->read_hash,NULL); 384 | #ifndef OPENSSL_NO_COMP 385 | if (s->expand != NULL) 386 | { 387 | COMP_CTX_free(s->expand); 388 | s->expand=NULL; 389 | } 390 | if (comp != NULL) 391 | { 392 | s->expand=COMP_CTX_new(comp->method); 393 | if (s->expand == NULL) 394 | { 395 | SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR); 396 | goto err2; 397 | } 398 | if (s->s3->rrec.comp == NULL) 399 | s->s3->rrec.comp=(unsigned char *) 400 | OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH); 401 | if (s->s3->rrec.comp == NULL) 402 | goto err; 403 | } 404 | #endif 405 | /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */ 406 | if (s->version != DTLS1_VERSION) 407 | memset(&(s->s3->read_sequence[0]),0,8); 408 | mac_secret= &(s->s3->read_mac_secret[0]); 409 | mac_secret_size=&(s->s3->read_mac_secret_size); 410 | } 411 | else 412 | { 413 | if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC) 414 | s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM; 415 | else 416 | s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_STREAM; 417 | if (s->enc_write_ctx != NULL && !SSL_IS_DTLS(s)) 418 | reuse_dd = 1; 419 | else if ((s->enc_write_ctx=EVP_CIPHER_CTX_new()) == NULL) 420 | goto err; 421 | dd= s->enc_write_ctx; 422 | if (SSL_IS_DTLS(s)) 423 | { 424 | mac_ctx = EVP_MD_CTX_create(); 425 | if (!mac_ctx) 426 | goto err; 427 | s->write_hash = mac_ctx; 428 | } 429 | else 430 | mac_ctx = ssl_replace_hash(&s->write_hash,NULL); 431 | #ifndef OPENSSL_NO_COMP 432 | if (s->compress != NULL) 433 | { 434 | COMP_CTX_free(s->compress); 435 | s->compress=NULL; 436 | } 437 | if (comp != NULL) 438 | { 439 | s->compress=COMP_CTX_new(comp->method); 440 | if (s->compress == NULL) 441 | { 442 | SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR); 443 | goto err2; 444 | } 445 | } 446 | #endif 447 | /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */ 448 | if (s->version != DTLS1_VERSION) 449 | memset(&(s->s3->write_sequence[0]),0,8); 450 | mac_secret= &(s->s3->write_mac_secret[0]); 451 | mac_secret_size = &(s->s3->write_mac_secret_size); 452 | } 453 | 454 | if (reuse_dd) 455 | EVP_CIPHER_CTX_cleanup(dd); 456 | 457 | p=s->s3->tmp.key_block; 458 | i=*mac_secret_size=s->s3->tmp.new_mac_secret_size; 459 | 460 | cl=EVP_CIPHER_key_length(c); 461 | j=is_export ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ? 462 | cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl; 463 | /* Was j=(exp)?5:EVP_CIPHER_key_length(c); */ 464 | /* If GCM mode only part of IV comes from PRF */ 465 | if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE) 466 | k = EVP_GCM_TLS_FIXED_IV_LEN; 467 | else 468 | k=EVP_CIPHER_iv_length(c); 469 | if ( (which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) || 470 | (which == SSL3_CHANGE_CIPHER_SERVER_READ)) 471 | { 472 | ms= &(p[ 0]); n=i+i; 473 | key= &(p[ n]); n+=j+j; 474 | iv= &(p[ n]); n+=k+k; 475 | exp_label=(unsigned char *)TLS_MD_CLIENT_WRITE_KEY_CONST; 476 | exp_label_len=TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE; 477 | client_write=1; 478 | } 479 | else 480 | { 481 | n=i; 482 | ms= &(p[ n]); n+=i+j; 483 | key= &(p[ n]); n+=j+k; 484 | iv= &(p[ n]); n+=k; 485 | exp_label=(unsigned char *)TLS_MD_SERVER_WRITE_KEY_CONST; 486 | exp_label_len=TLS_MD_SERVER_WRITE_KEY_CONST_SIZE; 487 | client_write=0; 488 | } 489 | 490 | if (n > s->s3->tmp.key_block_length) 491 | { 492 | SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,ERR_R_INTERNAL_ERROR); 493 | goto err2; 494 | } 495 | 496 | memcpy(mac_secret,ms,i); 497 | 498 | if (!(EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER)) 499 | { 500 | mac_key = EVP_PKEY_new_mac_key(mac_type, NULL, 501 | mac_secret,*mac_secret_size); 502 | EVP_DigestSignInit(mac_ctx,NULL,m,NULL,mac_key); 503 | EVP_PKEY_free(mac_key); 504 | } 505 | #ifdef TLS_DEBUG 506 | printf("which = %04X\nmac key=",which); 507 | { int z; for (z=0; zs3->client_random,SSL3_RANDOM_SIZE, 517 | s->s3->server_random,SSL3_RANDOM_SIZE, 518 | NULL,0,NULL,0, 519 | key,j,tmp1,tmp2,EVP_CIPHER_key_length(c))) 520 | goto err2; 521 | key=tmp1; 522 | 523 | if (k > 0) 524 | { 525 | if (!tls1_PRF(ssl_get_algorithm2(s), 526 | TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE, 527 | s->s3->client_random,SSL3_RANDOM_SIZE, 528 | s->s3->server_random,SSL3_RANDOM_SIZE, 529 | NULL,0,NULL,0, 530 | empty,0,iv1,iv2,k*2)) 531 | goto err2; 532 | if (client_write) 533 | iv=iv1; 534 | else 535 | iv= &(iv1[k]); 536 | } 537 | } 538 | 539 | s->session->key_arg_length=0; 540 | #ifdef KSSL_DEBUG 541 | { 542 | int i; 543 | printf("EVP_CipherInit_ex(dd,c,key=,iv=,which)\n"); 544 | printf("\tkey= "); for (i=0; ikey_len; i++) printf("%02x", key[i]); 545 | printf("\n"); 546 | printf("\t iv= "); for (i=0; iiv_len; i++) printf("%02x", iv[i]); 547 | printf("\n"); 548 | } 549 | #endif /* KSSL_DEBUG */ 550 | 551 | if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE) 552 | { 553 | EVP_CipherInit_ex(dd,c,NULL,key,NULL,(which & SSL3_CC_WRITE)); 554 | EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GCM_SET_IV_FIXED, k, iv); 555 | } 556 | else 557 | EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE)); 558 | 559 | /* Needed for "composite" AEADs, such as RC4-HMAC-MD5 */ 560 | if ((EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER) && *mac_secret_size) 561 | EVP_CIPHER_CTX_ctrl(dd,EVP_CTRL_AEAD_SET_MAC_KEY, 562 | *mac_secret_size,mac_secret); 563 | 564 | #ifdef TLS_DEBUG 565 | printf("which = %04X\nkey=",which); 566 | { int z; for (z=0; zs3->tmp.key_block_length != 0) 598 | return(1); 599 | 600 | if (!ssl_cipher_get_evp(s->session,&c,&hash,&mac_type,&mac_secret_size,&comp)) 601 | { 602 | SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,SSL_R_CIPHER_OR_HASH_UNAVAILABLE); 603 | return(0); 604 | } 605 | 606 | s->s3->tmp.new_sym_enc=c; 607 | s->s3->tmp.new_hash=hash; 608 | s->s3->tmp.new_mac_pkey_type = mac_type; 609 | s->s3->tmp.new_mac_secret_size = mac_secret_size; 610 | num=EVP_CIPHER_key_length(c)+mac_secret_size+EVP_CIPHER_iv_length(c); 611 | num*=2; 612 | 613 | ssl3_cleanup_key_block(s); 614 | 615 | if ((p1=(unsigned char *)OPENSSL_malloc(num)) == NULL) 616 | { 617 | SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE); 618 | goto err; 619 | } 620 | 621 | s->s3->tmp.key_block_length=num; 622 | s->s3->tmp.key_block=p1; 623 | 624 | if ((p2=(unsigned char *)OPENSSL_malloc(num)) == NULL) 625 | { 626 | SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE); 627 | goto err; 628 | } 629 | 630 | #ifdef TLS_DEBUG 631 | printf("client random\n"); 632 | { int z; for (z=0; zs3->client_random[z],((z+1)%16)?' ':'\n'); } 633 | printf("server random\n"); 634 | { int z; for (z=0; zs3->server_random[z],((z+1)%16)?' ':'\n'); } 635 | printf("pre-master\n"); 636 | { int z; for (z=0; zsession->master_key_length; z++) printf("%02X%c",s->session->master_key[z],((z+1)%16)?' ':'\n'); } 637 | #endif 638 | if (!tls1_generate_key_block(s,p1,p2,num)) 639 | goto err; 640 | #ifdef TLS_DEBUG 641 | printf("\nkey block\n"); 642 | { int z; for (z=0; zoptions & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 646 | && s->method->version <= TLS1_VERSION) 647 | { 648 | /* enable vulnerability countermeasure for CBC ciphers with 649 | * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt) 650 | */ 651 | s->s3->need_empty_fragments = 1; 652 | 653 | if (s->session->cipher != NULL) 654 | { 655 | if (s->session->cipher->algorithm_enc == SSL_eNULL) 656 | s->s3->need_empty_fragments = 0; 657 | 658 | #ifndef OPENSSL_NO_RC4 659 | if (s->session->cipher->algorithm_enc == SSL_RC4) 660 | s->s3->need_empty_fragments = 0; 661 | #endif 662 | } 663 | } 664 | 665 | ret = 1; 666 | err: 667 | if (p2) 668 | { 669 | OPENSSL_cleanse(p2,num); 670 | OPENSSL_free(p2); 671 | } 672 | return(ret); 673 | } 674 | 675 | /* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively. 676 | * 677 | * Returns: 678 | * 0: (in non-constant time) if the record is publically invalid (i.e. too 679 | * short etc). 680 | * 1: if the record's padding is valid / the encryption was successful. 681 | * -1: if the record's padding/AEAD-authenticator is invalid or, if sending, 682 | * an internal error occured. 683 | */ 684 | int tls1_enc(SSL *s, int send) 685 | { 686 | SSL3_RECORD *rec; 687 | EVP_CIPHER_CTX *ds; 688 | unsigned long l; 689 | int bs,i,j,k,pad=0,ret,mac_size=0; 690 | const EVP_CIPHER *enc; 691 | 692 | if (send) 693 | { 694 | if (EVP_MD_CTX_md(s->write_hash)) 695 | { 696 | int n=EVP_MD_CTX_size(s->write_hash); 697 | OPENSSL_assert(n >= 0); 698 | } 699 | ds=s->enc_write_ctx; 700 | rec= &(s->s3->wrec); 701 | if (s->enc_write_ctx == NULL) 702 | enc=NULL; 703 | else 704 | { 705 | int ivlen; 706 | enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx); 707 | /* For TLSv1.1 and later explicit IV */ 708 | if (s->version >= TLS1_1_VERSION 709 | && EVP_CIPHER_mode(enc) == EVP_CIPH_CBC_MODE) 710 | ivlen = EVP_CIPHER_iv_length(enc); 711 | else 712 | ivlen = 0; 713 | if (ivlen > 1) 714 | { 715 | if ( rec->data != rec->input) 716 | /* we can't write into the input stream: 717 | * Can this ever happen?? (steve) 718 | */ 719 | fprintf(stderr, 720 | "%s:%d: rec->data != rec->input\n", 721 | __FILE__, __LINE__); 722 | else if (RAND_bytes(rec->input, ivlen) <= 0) 723 | return -1; 724 | } 725 | } 726 | } 727 | else 728 | { 729 | if (EVP_MD_CTX_md(s->read_hash)) 730 | { 731 | int n=EVP_MD_CTX_size(s->read_hash); 732 | OPENSSL_assert(n >= 0); 733 | } 734 | ds=s->enc_read_ctx; 735 | rec= &(s->s3->rrec); 736 | if (s->enc_read_ctx == NULL) 737 | enc=NULL; 738 | else 739 | enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx); 740 | } 741 | 742 | #ifdef KSSL_DEBUG 743 | printf("tls1_enc(%d)\n", send); 744 | #endif /* KSSL_DEBUG */ 745 | 746 | if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) 747 | { 748 | memmove(rec->data,rec->input,rec->length); 749 | rec->input=rec->data; 750 | ret = 1; 751 | } 752 | else 753 | { 754 | l=rec->length; 755 | bs=EVP_CIPHER_block_size(ds->cipher); 756 | 757 | if (EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_AEAD_CIPHER) 758 | { 759 | unsigned char buf[13],*seq; 760 | 761 | seq = send?s->s3->write_sequence:s->s3->read_sequence; 762 | 763 | if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) 764 | { 765 | unsigned char dtlsseq[9],*p=dtlsseq; 766 | 767 | s2n(send?s->d1->w_epoch:s->d1->r_epoch,p); 768 | memcpy(p,&seq[2],6); 769 | memcpy(buf,dtlsseq,8); 770 | } 771 | else 772 | { 773 | memcpy(buf,seq,8); 774 | for (i=7; i>=0; i--) /* increment */ 775 | { 776 | ++seq[i]; 777 | if (seq[i] != 0) break; 778 | } 779 | } 780 | 781 | buf[8]=rec->type; 782 | buf[9]=(unsigned char)(s->version>>8); 783 | buf[10]=(unsigned char)(s->version); 784 | buf[11]=rec->length>>8; 785 | buf[12]=rec->length&0xff; 786 | pad=EVP_CIPHER_CTX_ctrl(ds,EVP_CTRL_AEAD_TLS1_AAD,13,buf); 787 | if (send) 788 | { 789 | l+=pad; 790 | rec->length+=pad; 791 | } 792 | } 793 | else if ((bs != 1) && send) 794 | { 795 | i=bs-((int)l%bs); 796 | 797 | /* Add weird padding of upto 256 bytes */ 798 | 799 | /* we need to add 'i' padding bytes of value j */ 800 | j=i-1; 801 | if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG) 802 | { 803 | if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG) 804 | j++; 805 | } 806 | printf("POODLEv2: %d bytes padding in total\n", (int)(i)); 807 | for (k=(int)l; k<(int)(l+i); k++) 808 | { 809 | if(k == (int)(l+1)) /* mod the second padding byte to test POODLE V2 */ 810 | { 811 | rec->input[k]=j+1; 812 | printf("POODLEv2: padding modified\n"); 813 | } 814 | else 815 | rec->input[k]=j; 816 | } 817 | 818 | l+=i; 819 | rec->length+=i; 820 | } 821 | 822 | #ifdef KSSL_DEBUG 823 | { 824 | unsigned long ui; 825 | printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n", 826 | ds,rec->data,rec->input,l); 827 | printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n", 828 | ds->buf_len, ds->cipher->key_len, 829 | DES_KEY_SZ, DES_SCHEDULE_SZ, 830 | ds->cipher->iv_len); 831 | printf("\t\tIV: "); 832 | for (i=0; icipher->iv_len; i++) printf("%02X", ds->iv[i]); 833 | printf("\n"); 834 | printf("\trec->input="); 835 | for (ui=0; uiinput[ui]); 836 | printf("\n"); 837 | } 838 | #endif /* KSSL_DEBUG */ 839 | 840 | if (!send) 841 | { 842 | if (l == 0 || l%bs != 0) 843 | return 0; 844 | } 845 | 846 | i = EVP_Cipher(ds,rec->data,rec->input,l); 847 | if ((EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_CUSTOM_CIPHER) 848 | ?(i<0) 849 | :(i==0)) 850 | return -1; /* AEAD can fail to verify MAC */ 851 | if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE && !send) 852 | { 853 | rec->data += EVP_GCM_TLS_EXPLICIT_IV_LEN; 854 | rec->input += EVP_GCM_TLS_EXPLICIT_IV_LEN; 855 | rec->length -= EVP_GCM_TLS_EXPLICIT_IV_LEN; 856 | } 857 | 858 | #ifdef KSSL_DEBUG 859 | { 860 | unsigned long i; 861 | printf("\trec->data="); 862 | for (i=0; idata[i]); printf("\n"); 864 | } 865 | #endif /* KSSL_DEBUG */ 866 | 867 | ret = 1; 868 | if (EVP_MD_CTX_md(s->read_hash) != NULL) 869 | mac_size = EVP_MD_CTX_size(s->read_hash); 870 | if ((bs != 1) && !send) 871 | ret = tls1_cbc_remove_padding(s, rec, bs, mac_size); 872 | if (pad && !send) 873 | rec->length -= pad; 874 | } 875 | return ret; 876 | } 877 | 878 | int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out) 879 | { 880 | unsigned int ret; 881 | EVP_MD_CTX ctx, *d=NULL; 882 | int i; 883 | 884 | if (s->s3->handshake_buffer) 885 | if (!ssl3_digest_cached_records(s)) 886 | return 0; 887 | 888 | for (i=0;is3->handshake_dgst[i]&&EVP_MD_CTX_type(s->s3->handshake_dgst[i])==md_nid) 891 | { 892 | d=s->s3->handshake_dgst[i]; 893 | break; 894 | } 895 | } 896 | if (!d) { 897 | SSLerr(SSL_F_TLS1_CERT_VERIFY_MAC,SSL_R_NO_REQUIRED_DIGEST); 898 | return 0; 899 | } 900 | 901 | EVP_MD_CTX_init(&ctx); 902 | EVP_MD_CTX_copy_ex(&ctx,d); 903 | EVP_DigestFinal_ex(&ctx,out,&ret); 904 | EVP_MD_CTX_cleanup(&ctx); 905 | return((int)ret); 906 | } 907 | 908 | int tls1_final_finish_mac(SSL *s, 909 | const char *str, int slen, unsigned char *out) 910 | { 911 | unsigned int i; 912 | EVP_MD_CTX ctx; 913 | unsigned char buf[2*EVP_MAX_MD_SIZE]; 914 | unsigned char *q,buf2[12]; 915 | int idx; 916 | long mask; 917 | int err=0; 918 | const EVP_MD *md; 919 | 920 | q=buf; 921 | 922 | if (s->s3->handshake_buffer) 923 | if (!ssl3_digest_cached_records(s)) 924 | return 0; 925 | 926 | EVP_MD_CTX_init(&ctx); 927 | 928 | for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++) 929 | { 930 | if (mask & ssl_get_algorithm2(s)) 931 | { 932 | int hashsize = EVP_MD_size(md); 933 | EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx]; 934 | if (!hdgst || hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf))) 935 | { 936 | /* internal error: 'buf' is too small for this cipersuite! */ 937 | err = 1; 938 | } 939 | else 940 | { 941 | if (!EVP_MD_CTX_copy_ex(&ctx, hdgst) || 942 | !EVP_DigestFinal_ex(&ctx,q,&i) || 943 | (i != (unsigned int)hashsize)) 944 | err = 1; 945 | q+=hashsize; 946 | } 947 | } 948 | } 949 | 950 | if (!tls1_PRF(ssl_get_algorithm2(s), 951 | str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0, 952 | s->session->master_key,s->session->master_key_length, 953 | out,buf2,sizeof buf2)) 954 | err = 1; 955 | EVP_MD_CTX_cleanup(&ctx); 956 | 957 | if (err) 958 | return 0; 959 | else 960 | return sizeof buf2; 961 | } 962 | 963 | int tls1_mac(SSL *ssl, unsigned char *md, int send) 964 | { 965 | SSL3_RECORD *rec; 966 | unsigned char *seq; 967 | EVP_MD_CTX *hash; 968 | size_t md_size, orig_len; 969 | int i; 970 | EVP_MD_CTX hmac, *mac_ctx; 971 | unsigned char header[13]; 972 | int stream_mac = (send?(ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM):(ssl->mac_flags&SSL_MAC_FLAG_READ_MAC_STREAM)); 973 | int t; 974 | 975 | if (send) 976 | { 977 | rec= &(ssl->s3->wrec); 978 | seq= &(ssl->s3->write_sequence[0]); 979 | hash=ssl->write_hash; 980 | } 981 | else 982 | { 983 | rec= &(ssl->s3->rrec); 984 | seq= &(ssl->s3->read_sequence[0]); 985 | hash=ssl->read_hash; 986 | } 987 | 988 | t=EVP_MD_CTX_size(hash); 989 | OPENSSL_assert(t >= 0); 990 | md_size=t; 991 | 992 | /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */ 993 | if (stream_mac) 994 | { 995 | mac_ctx = hash; 996 | } 997 | else 998 | { 999 | if (!EVP_MD_CTX_copy(&hmac,hash)) 1000 | return -1; 1001 | mac_ctx = &hmac; 1002 | } 1003 | 1004 | if (ssl->version == DTLS1_VERSION || ssl->version == DTLS1_BAD_VER) 1005 | { 1006 | unsigned char dtlsseq[8],*p=dtlsseq; 1007 | 1008 | s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p); 1009 | memcpy (p,&seq[2],6); 1010 | 1011 | memcpy(header, dtlsseq, 8); 1012 | } 1013 | else 1014 | memcpy(header, seq, 8); 1015 | 1016 | /* kludge: tls1_cbc_remove_padding passes padding length in rec->type */ 1017 | orig_len = rec->length+md_size+((unsigned int)rec->type>>8); 1018 | rec->type &= 0xff; 1019 | 1020 | header[8]=rec->type; 1021 | header[9]=(unsigned char)(ssl->version>>8); 1022 | header[10]=(unsigned char)(ssl->version); 1023 | header[11]=(rec->length)>>8; 1024 | header[12]=(rec->length)&0xff; 1025 | 1026 | if (!send && 1027 | EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE && 1028 | ssl3_cbc_record_digest_supported(mac_ctx)) 1029 | { 1030 | /* This is a CBC-encrypted record. We must avoid leaking any 1031 | * timing-side channel information about how many blocks of 1032 | * data we are hashing because that gives an attacker a 1033 | * timing-oracle. */ 1034 | ssl3_cbc_digest_record( 1035 | mac_ctx, 1036 | md, &md_size, 1037 | header, rec->input, 1038 | rec->length + md_size, orig_len, 1039 | ssl->s3->read_mac_secret, 1040 | ssl->s3->read_mac_secret_size, 1041 | 0 /* not SSLv3 */); 1042 | } 1043 | else 1044 | { 1045 | EVP_DigestSignUpdate(mac_ctx,header,sizeof(header)); 1046 | EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length); 1047 | t=EVP_DigestSignFinal(mac_ctx,md,&md_size); 1048 | OPENSSL_assert(t > 0); 1049 | #ifdef OPENSSL_FIPS 1050 | if (!send && FIPS_mode()) 1051 | tls_fips_digest_extra( 1052 | ssl->enc_read_ctx, 1053 | mac_ctx, rec->input, 1054 | rec->length, orig_len); 1055 | #endif 1056 | } 1057 | 1058 | if (!stream_mac) 1059 | EVP_MD_CTX_cleanup(&hmac); 1060 | #ifdef TLS_DEBUG 1061 | printf("seq="); 1062 | {int z; for (z=0; z<8; z++) printf("%02X ",seq[z]); printf("\n"); } 1063 | printf("rec="); 1064 | {unsigned int z; for (z=0; zlength; z++) printf("%02X ",rec->data[z]); printf("\n"); } 1065 | #endif 1066 | 1067 | if (ssl->version != DTLS1_VERSION && ssl->version != DTLS1_BAD_VER) 1068 | { 1069 | for (i=7; i>=0; i--) 1070 | { 1071 | ++seq[i]; 1072 | if (seq[i] != 0) break; 1073 | } 1074 | } 1075 | 1076 | #ifdef TLS_DEBUG 1077 | {unsigned int z; for (z=0; zs3->client_opaque_prf_input != NULL && s->s3->server_opaque_prf_input != NULL && 1096 | s->s3->client_opaque_prf_input_len > 0 && 1097 | s->s3->client_opaque_prf_input_len == s->s3->server_opaque_prf_input_len) 1098 | { 1099 | co = s->s3->client_opaque_prf_input; 1100 | col = s->s3->server_opaque_prf_input_len; 1101 | so = s->s3->server_opaque_prf_input; 1102 | sol = s->s3->client_opaque_prf_input_len; /* must be same as col (see draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) */ 1103 | } 1104 | #endif 1105 | 1106 | tls1_PRF(ssl_get_algorithm2(s), 1107 | TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE, 1108 | s->s3->client_random,SSL3_RANDOM_SIZE, 1109 | co, col, 1110 | s->s3->server_random,SSL3_RANDOM_SIZE, 1111 | so, sol, 1112 | p,len, 1113 | s->session->master_key,buff,sizeof buff); 1114 | #ifdef SSL_DEBUG 1115 | fprintf(stderr, "Premaster Secret:\n"); 1116 | BIO_dump_fp(stderr, (char *)p, len); 1117 | fprintf(stderr, "Client Random:\n"); 1118 | BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE); 1119 | fprintf(stderr, "Server Random:\n"); 1120 | BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE); 1121 | fprintf(stderr, "Master Secret:\n"); 1122 | BIO_dump_fp(stderr, (char *)s->session->master_key, SSL3_MASTER_SECRET_SIZE); 1123 | #endif 1124 | 1125 | #ifdef KSSL_DEBUG 1126 | printf ("tls1_generate_master_secret() complete\n"); 1127 | #endif /* KSSL_DEBUG */ 1128 | return(SSL3_MASTER_SECRET_SIZE); 1129 | } 1130 | 1131 | int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen, 1132 | const char *label, size_t llen, const unsigned char *context, 1133 | size_t contextlen, int use_context) 1134 | { 1135 | unsigned char *buff; 1136 | unsigned char *val = NULL; 1137 | size_t vallen, currentvalpos; 1138 | int rv; 1139 | 1140 | #ifdef KSSL_DEBUG 1141 | printf ("tls1_export_keying_material(%p,%p,%d,%s,%d,%p,%d)\n", s, out, olen, label, llen, context, contextlen); 1142 | #endif /* KSSL_DEBUG */ 1143 | 1144 | buff = OPENSSL_malloc(olen); 1145 | if (buff == NULL) goto err2; 1146 | 1147 | /* construct PRF arguments 1148 | * we construct the PRF argument ourself rather than passing separate 1149 | * values into the TLS PRF to ensure that the concatenation of values 1150 | * does not create a prohibited label. 1151 | */ 1152 | vallen = llen + SSL3_RANDOM_SIZE * 2; 1153 | if (use_context) 1154 | { 1155 | vallen += 2 + contextlen; 1156 | } 1157 | 1158 | val = OPENSSL_malloc(vallen); 1159 | if (val == NULL) goto err2; 1160 | currentvalpos = 0; 1161 | memcpy(val + currentvalpos, (unsigned char *) label, llen); 1162 | currentvalpos += llen; 1163 | memcpy(val + currentvalpos, s->s3->client_random, SSL3_RANDOM_SIZE); 1164 | currentvalpos += SSL3_RANDOM_SIZE; 1165 | memcpy(val + currentvalpos, s->s3->server_random, SSL3_RANDOM_SIZE); 1166 | currentvalpos += SSL3_RANDOM_SIZE; 1167 | 1168 | if (use_context) 1169 | { 1170 | val[currentvalpos] = (contextlen >> 8) & 0xff; 1171 | currentvalpos++; 1172 | val[currentvalpos] = contextlen & 0xff; 1173 | currentvalpos++; 1174 | if ((contextlen > 0) || (context != NULL)) 1175 | { 1176 | memcpy(val + currentvalpos, context, contextlen); 1177 | } 1178 | } 1179 | 1180 | /* disallow prohibited labels 1181 | * note that SSL3_RANDOM_SIZE > max(prohibited label len) = 1182 | * 15, so size of val > max(prohibited label len) = 15 and the 1183 | * comparisons won't have buffer overflow 1184 | */ 1185 | if (memcmp(val, TLS_MD_CLIENT_FINISH_CONST, 1186 | TLS_MD_CLIENT_FINISH_CONST_SIZE) == 0) goto err1; 1187 | if (memcmp(val, TLS_MD_SERVER_FINISH_CONST, 1188 | TLS_MD_SERVER_FINISH_CONST_SIZE) == 0) goto err1; 1189 | if (memcmp(val, TLS_MD_MASTER_SECRET_CONST, 1190 | TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) goto err1; 1191 | if (memcmp(val, TLS_MD_KEY_EXPANSION_CONST, 1192 | TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0) goto err1; 1193 | 1194 | rv = tls1_PRF(ssl_get_algorithm2(s), 1195 | val, vallen, 1196 | NULL, 0, 1197 | NULL, 0, 1198 | NULL, 0, 1199 | NULL, 0, 1200 | s->session->master_key,s->session->master_key_length, 1201 | out,buff,olen); 1202 | 1203 | #ifdef KSSL_DEBUG 1204 | printf ("tls1_export_keying_material() complete\n"); 1205 | #endif /* KSSL_DEBUG */ 1206 | goto ret; 1207 | err1: 1208 | SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL); 1209 | rv = 0; 1210 | goto ret; 1211 | err2: 1212 | SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, ERR_R_MALLOC_FAILURE); 1213 | rv = 0; 1214 | ret: 1215 | if (buff != NULL) OPENSSL_free(buff); 1216 | if (val != NULL) OPENSSL_free(val); 1217 | return(rv); 1218 | } 1219 | 1220 | int tls1_alert_code(int code) 1221 | { 1222 | switch (code) 1223 | { 1224 | case SSL_AD_CLOSE_NOTIFY: return(SSL3_AD_CLOSE_NOTIFY); 1225 | case SSL_AD_UNEXPECTED_MESSAGE: return(SSL3_AD_UNEXPECTED_MESSAGE); 1226 | case SSL_AD_BAD_RECORD_MAC: return(SSL3_AD_BAD_RECORD_MAC); 1227 | case SSL_AD_DECRYPTION_FAILED: return(TLS1_AD_DECRYPTION_FAILED); 1228 | case SSL_AD_RECORD_OVERFLOW: return(TLS1_AD_RECORD_OVERFLOW); 1229 | case SSL_AD_DECOMPRESSION_FAILURE:return(SSL3_AD_DECOMPRESSION_FAILURE); 1230 | case SSL_AD_HANDSHAKE_FAILURE: return(SSL3_AD_HANDSHAKE_FAILURE); 1231 | case SSL_AD_NO_CERTIFICATE: return(-1); 1232 | case SSL_AD_BAD_CERTIFICATE: return(SSL3_AD_BAD_CERTIFICATE); 1233 | case SSL_AD_UNSUPPORTED_CERTIFICATE:return(SSL3_AD_UNSUPPORTED_CERTIFICATE); 1234 | case SSL_AD_CERTIFICATE_REVOKED:return(SSL3_AD_CERTIFICATE_REVOKED); 1235 | case SSL_AD_CERTIFICATE_EXPIRED:return(SSL3_AD_CERTIFICATE_EXPIRED); 1236 | case SSL_AD_CERTIFICATE_UNKNOWN:return(SSL3_AD_CERTIFICATE_UNKNOWN); 1237 | case SSL_AD_ILLEGAL_PARAMETER: return(SSL3_AD_ILLEGAL_PARAMETER); 1238 | case SSL_AD_UNKNOWN_CA: return(TLS1_AD_UNKNOWN_CA); 1239 | case SSL_AD_ACCESS_DENIED: return(TLS1_AD_ACCESS_DENIED); 1240 | case SSL_AD_DECODE_ERROR: return(TLS1_AD_DECODE_ERROR); 1241 | case SSL_AD_DECRYPT_ERROR: return(TLS1_AD_DECRYPT_ERROR); 1242 | case SSL_AD_EXPORT_RESTRICTION: return(TLS1_AD_EXPORT_RESTRICTION); 1243 | case SSL_AD_PROTOCOL_VERSION: return(TLS1_AD_PROTOCOL_VERSION); 1244 | case SSL_AD_INSUFFICIENT_SECURITY:return(TLS1_AD_INSUFFICIENT_SECURITY); 1245 | case SSL_AD_INTERNAL_ERROR: return(TLS1_AD_INTERNAL_ERROR); 1246 | case SSL_AD_USER_CANCELLED: return(TLS1_AD_USER_CANCELLED); 1247 | case SSL_AD_NO_RENEGOTIATION: return(TLS1_AD_NO_RENEGOTIATION); 1248 | case SSL_AD_UNSUPPORTED_EXTENSION: return(TLS1_AD_UNSUPPORTED_EXTENSION); 1249 | case SSL_AD_CERTIFICATE_UNOBTAINABLE: return(TLS1_AD_CERTIFICATE_UNOBTAINABLE); 1250 | case SSL_AD_UNRECOGNIZED_NAME: return(TLS1_AD_UNRECOGNIZED_NAME); 1251 | case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE); 1252 | case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(TLS1_AD_BAD_CERTIFICATE_HASH_VALUE); 1253 | case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY); 1254 | case SSL_AD_INAPPROPRIATE_FALLBACK:return(TLS1_AD_INAPPROPRIATE_FALLBACK); 1255 | #if 0 /* not appropriate for TLS, not used for DTLS */ 1256 | case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return 1257 | (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); 1258 | #endif 1259 | default: return(-1); 1260 | } 1261 | } 1262 | -------------------------------------------------------------------------------- /general/README.md: -------------------------------------------------------------------------------- 1 | General purpose tools developed by FireEye 2 | 3 | -------------------------------------------------------------------------------- /malware/Poison Ivy RAT/README.md: -------------------------------------------------------------------------------- 1 | usage: pivy_find_config.py [-h] [-csv CSV] Input 2 | 3 | finds and prints Poison Ivy RAT configuration details from a process memory 4 | dump 5 | 6 | positional arguments: 7 | Input a path to a process dump or a directory of process dumps 8 | containing Poison Ivy RAT configuration data 9 | 10 | optional arguments: 11 | -h, --help show this help message and exit 12 | -csv CSV write results to CSV in addition to printing to console 13 | 14 | -------------------------------------------------------------------------------- /malware/Poison Ivy RAT/pivy_find_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 FireEye, Inc. All rights reserved. 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 1. Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # 2. Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | # SUCH DAMAGE. 23 | 24 | import sys 25 | import string 26 | import re 27 | import os 28 | import argparse 29 | import binascii 30 | 31 | def getString(buf,pos): 32 | strpattern = r"([^\x00]+)" 33 | match = re.search(strpattern, buf[pos:]) 34 | if match is not None: 35 | return match.group(1) 36 | else: 37 | return "" 38 | 39 | def getPassword(buf,pos): 40 | strpattern = r"([^\x00]+)" 41 | prpattern = r"^[ -~]{4,}\x00" 42 | match = re.search(prpattern, buf[pos:pos+32]) 43 | if match is None: 44 | return "0x%s" % binascii.hexlify(buf[pos:pos+32]) 45 | match = re.search(strpattern, buf[pos:pos+32]) 46 | if match is not None: 47 | return match.group(1) 48 | else: 49 | return "" 50 | 51 | def getConfig(f,buf): 52 | pattern = r"StubPath.SOFTWARE\\Classes\\http\\shell\\open\\command.{22}Software\\Microsoft\\Active Setup\\Installed Components\\" 53 | 54 | match = re.search(pattern, buf) 55 | if match is not None: 56 | print "pivy config located in %s" % f 57 | pos = string.find(buf,match.group(0)) 58 | configpos = pos - 0x40f 59 | id = getString(buf,configpos + 0xafa) 60 | group = getString(buf,configpos + 0xbf9) 61 | if re.search(r"^[ -~]+$",group) is None: 62 | group = "not configured" 63 | 64 | password = getPassword(buf,configpos + 0x145) 65 | mutex = getString(buf,configpos + 0x3fb) 66 | print "ID: %s" % id 67 | print "Group: %s" % group 68 | print "Password: %s" % password 69 | print "Mutex: %s" % mutex 70 | return (id,group,password,mutex) 71 | else: 72 | print "Could not locate pivy config.." 73 | return None 74 | 75 | def getFile(f): 76 | rp = open(f, "rb") 77 | buf = rp.read() 78 | rp.close() 79 | return buf 80 | 81 | if __name__ == "__main__": 82 | parser=argparse.ArgumentParser(description="finds and prints Poison Ivy RAT configuration details from a process memory dump") 83 | parser.add_argument('i', metavar='Input', help='a path to a process dump or a directory of process dumps containing Poison Ivy RAT configuration data') 84 | parser.add_argument('-csv', metavar="CSV", help='write results to CSV instead of printing to console') 85 | 86 | args = parser.parse_args() 87 | 88 | if os.path.isfile(args.i): 89 | f = args.i 90 | buf = getFile(f) 91 | getConfig(f,buf) 92 | elif os.path.isdir(args.i): 93 | if args.csv: 94 | csv = open(args.csv,"w") 95 | headers = "file,id,group,password,mutex\n" 96 | csv.write(headers) 97 | else: 98 | csv = None 99 | 100 | d = args.i 101 | for f in os.listdir(d): 102 | path = os.path.join(d, f) 103 | if os.path.isfile(path): 104 | buf = getFile(path) 105 | res = getConfig(path,buf) 106 | if csv is not None: 107 | if res is not None: 108 | csv.write("%s,%s,%s,%s,%s\n" % (f, res[0], res[1], res[2], res[3])) 109 | 110 | if csv is not None: 111 | csv.close() 112 | 113 | 114 | -------------------------------------------------------------------------------- /malware/README.md: -------------------------------------------------------------------------------- 1 | Malware-specific analysis tools developed by FireEye Labs 2 | 3 | -------------------------------------------------------------------------------- /malware/Xtreme RAT/README.md: -------------------------------------------------------------------------------- 1 | usage: xtrat_parse_config.py [-h] [-csv CSV] Input 2 | 3 | parses Xtreme RAT config and prints config data 4 | 5 | positional arguments: 6 | Input a path to a config dump or directory of config dumps 7 | 8 | optional arguments: 9 | -h, --help show this help message and exit 10 | -csv CSV write results to CSV in addition to printing to console 11 | 12 | 13 | 14 | usage: xtrat_find_config.py [-h] Input 15 | 16 | scans for Xtreme RAT config in memory dumps and writes them to a file of the 17 | same name with '.cfg' appended 18 | 19 | positional arguments: 20 | Input a path to a memory dump or directory of memory dumps 21 | 22 | optional arguments: 23 | -h, --help show this help message and exit 24 | 25 | 26 | 27 | usage: xtrat_decrypt_config.py [-h] [-k] Input 28 | 29 | decrypts and prints an Xtreme RAT config file 30 | 31 | positional arguments: 32 | Input a path to an Xtreme RAT config file 33 | 34 | optional arguments: 35 | -h, --help show this help message and exit 36 | -k try the key CONFIG instead of CYBERGATEPASS 37 | 38 | 39 | 40 | usage: xtrat_decrypt_keylog.py [-h] Input 41 | 42 | decrypts and prints an Xtreme RAT keylog file 43 | 44 | positional arguments: 45 | Input a path to an Xtreme RAT keylog file 46 | 47 | optional arguments: 48 | -h, --help show this help message and exit 49 | 50 | -------------------------------------------------------------------------------- /malware/Xtreme RAT/xtrat_decrypt_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 FireEye, Inc. All rights reserved. 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 1. Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # 2. Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | # SUCH DAMAGE. 23 | 24 | import sys 25 | from Crypto.Cipher import ARC4 26 | import argparse 27 | 28 | if __name__ == "__main__": 29 | 30 | parser=argparse.ArgumentParser(description="decrypts and prints an Xtreme RAT config file") 31 | parser.add_argument('i', metavar='Input', help='a path to an Xtreme RAT config file') 32 | parser.add_argument('-k', action='store_true', help='try the key CONFIG instead of CYBERGATEPASS') 33 | 34 | args = parser.parse_args() 35 | 36 | key = "C\x00Y\x00B\x00E\x00R\x00G\x00A\x00T\x00E\x00P\x00A\x00S\x00S\x00" 37 | if args.k: 38 | key = "C\x00O\x00N\x00F\x00I\x00G\x00" 39 | 40 | #buggy implementation of string length 41 | keylen = len(key) 42 | if key[1] == "\x00" and key[3] == "\x00" and keylen % 2 == 0: 43 | keylen = keylen / 2 44 | key = key[0:keylen] 45 | 46 | f = args.i 47 | rp = open(f, "rb") 48 | ciphertxt = rp.read() 49 | rp.close() 50 | 51 | rc = ARC4.new(key) 52 | print rc.decrypt(ciphertxt) 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /malware/Xtreme RAT/xtrat_decrypt_keylog.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 FireEye, Inc. All rights reserved. 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 1. Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # 2. Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | # SUCH DAMAGE. 23 | 24 | import sys 25 | import os 26 | import struct 27 | import argparse 28 | 29 | def two_byte_xor(buf, key, preserve_unicode=True): 30 | out = '' 31 | for i in range(0,len(buf)/2): 32 | c = struct.unpack(">H", buf[(i*2):(i*2)+2])[0] 33 | if c == 0x0a00 or c == 0x0d00: 34 | pass 35 | else: 36 | c ^= key 37 | out += struct.pack(">H", c) 38 | if preserve_unicode: 39 | return out 40 | else: 41 | return out.replace("\x00","") 42 | 43 | if __name__ == "__main__": 44 | parser=argparse.ArgumentParser(description="decrypts and prints an Xtreme RAT keylog file") 45 | parser.add_argument('i', metavar='Input', help='a path to an Xtreme RAT keylog file') 46 | parser.add_argument('-u', action='store_true', help='Unicode output') 47 | 48 | args = parser.parse_args() 49 | preserve_unicode = args.u 50 | keylog = args.i 51 | if os.path.isfile(keylog): 52 | rp = open(keylog, "rb") 53 | buf = rp.read() 54 | rp.close() 55 | dec = two_byte_xor(buf, 0x3fa5, preserve_unicode) 56 | if "---" in dec.replace("\x00","") or "---" in dec or "
" in dec.replace("\x00","") or "
" in dec: 57 | print dec 58 | else: 59 | dec = two_byte_xor(buf, 0x5500, preserve_unicode) 60 | if "---" in dec.replace("\x00","") or "---" in dec or "
" in dec.replace("\x00","") or "
" in dec: 61 | print dec 62 | else: 63 | dec = two_byte_xor(buf, 0x1300, preserve_unicode) 64 | if "---" in dec.replace("\x00","") or "---" in dec or "
" in dec.replace("\x00","") or "
" in dec: 65 | print dec 66 | else: 67 | print "could not decrypt keylog.." 68 | else: 69 | print "argument supplied is not a file!" 70 | -------------------------------------------------------------------------------- /malware/Xtreme RAT/xtrat_find_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 FireEye, Inc. All rights reserved. 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 1. Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # 2. Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | # SUCH DAMAGE. 23 | 24 | import sys 25 | import string 26 | import re 27 | import os 28 | import argparse 29 | from pprint import pprint 30 | 31 | def getUnicodeString(buf,pos): 32 | out = "" 33 | for i in range(len(buf[pos:])): 34 | if ord(buf[pos+i]) == 0 and ord(buf[pos+i+1]) == 0: 35 | out += "\x00" 36 | break 37 | out += buf[pos+i] 38 | 39 | if out == "": 40 | return None 41 | else: 42 | return out 43 | 44 | def getMutex(buf, exitpos, persistpos): 45 | #do a backwards comparison from PERSIST and EXIT and continue until there is a mismatch or two null bytes, calculate beginning of the mutex this way 46 | cnt = 1 47 | while 1: 48 | exitc = buf[exitpos - cnt] 49 | exitc2 = buf[exitpos - cnt - 1] 50 | persistc = buf[persistpos - cnt] 51 | persistc2 = buf[persistpos - cnt - 1] 52 | if exitc != persistc: 53 | if buf[persistpos - cnt + 1] == "\x00": 54 | out = buf[persistpos - cnt + 2:persistpos] 55 | else: 56 | out = buf[persistpos - cnt + 1:persistpos] 57 | return out 58 | if (exitc == "\x00" and exitc2 == "\x00") or (persistc == "\x00" and persistc2 == "\x00"): 59 | out = buf[persistpos - cnt + 1:persistpos] 60 | return out 61 | cnt+=1 62 | 63 | 64 | 65 | def unicodifyre(s): 66 | return "\\x00".join(s) + "\\x00" 67 | 68 | def unicodify(s): 69 | return "\x00".join(s) + "\x00" 70 | 71 | def getConfig(f,buf): 72 | persistre = unicodifyre("PERSIST") 73 | persist = unicodify("PERSIST") 74 | exit = unicodify("EXIT") 75 | persistpattern = r"((?:[^\x00]\x00){4,})" + persistre 76 | match = re.findall(persistpattern, buf) 77 | if len(match) > 0: 78 | configpos = None 79 | lastfoundoffs = 0 80 | for m in match: 81 | print "possible xtrat config located in %s" % f 82 | persistpos = string.find(buf[lastfoundoffs:],m) 83 | persistoffs = string.find(buf[persistpos + lastfoundoffs:],persist) 84 | persistpos += persistoffs + lastfoundoffs 85 | lastfoundoffs = persistpos + len(persist) 86 | exitpos = string.rfind(buf[:persistpos],exit) 87 | #match last 3 characters of mutex as a sanity check 88 | if exitpos != -1 and buf[exitpos-6:exitpos] == m[-6:]: 89 | if persistpos - exitpos == 0x60: 90 | print "possible version 1.3.6.x config block found.." 91 | mutex = getMutex(buf, exitpos, persistpos) 92 | print "mutex: %s" % mutex 93 | configpos = persistpos - len(mutex) - 0x3c8 94 | configlen = 0xe10 95 | break 96 | 97 | elif persistpos - exitpos == 0x38: 98 | print "possible version 3.x config block found.." 99 | mutex = getMutex(buf, exitpos, persistpos) 100 | print "mutex: %s" % mutex 101 | configpos = persistpos - len(mutex) - 0x33e 102 | configlen = 0x7f0 103 | break 104 | 105 | elif persistpos - exitpos == 0x7a: 106 | print "possible version 2.x config block found.." 107 | mutex = getMutex(buf, exitpos, persistpos) 108 | print "mutex: %s" % mutex 109 | configpos = persistpos - len(mutex) - 0x109e 110 | configlen = 0x1390 111 | break 112 | 113 | if configpos is not None: 114 | print "config located at %08X" % configpos 115 | wp = open(f + ".cfg", "wb") 116 | wp.write(buf[configpos:configpos+configlen]) 117 | wp.close() 118 | 119 | else: 120 | print "could not locate xtrat config" 121 | 122 | def getFile(f): 123 | rp = open(f, "rb") 124 | buf = rp.read() 125 | rp.close() 126 | return buf 127 | 128 | if __name__ == "__main__": 129 | parser=argparse.ArgumentParser(description="scans for Xtreme RAT config in memory dumps and writes them to a file of the same name with '.cfg' appended") 130 | parser.add_argument('i', metavar='Input', help='a path to a memory dump or directory of memory dumps') 131 | 132 | args = parser.parse_args() 133 | 134 | if os.path.isfile(args.i): 135 | f = args.i 136 | buf = getFile(f) 137 | getConfig(f,buf) 138 | elif os.path.isdir(args.i): 139 | d = args.i 140 | for f in os.listdir(d): 141 | path = os.path.join(d, f) 142 | if os.path.isfile(path): 143 | buf = getFile(path) 144 | getConfig(path,buf) 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /malware/Xtreme RAT/xtrat_parse_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 FireEye, Inc. All rights reserved. 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 1. Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # 2. Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | # SUCH DAMAGE. 23 | 24 | import sys 25 | import string 26 | import re 27 | import os 28 | import argparse 29 | 30 | def getString(buf,pos): 31 | out = "" 32 | for c in buf[pos:]: 33 | if ord(c) == 0: 34 | break 35 | out += c 36 | 37 | if out == "": 38 | return None 39 | else: 40 | return out 41 | 42 | def getUnicodeString(buf,pos): 43 | out = "" 44 | for i in range(len(buf[pos:])): 45 | if not (ord(buf[pos+i]) >= 32 and ord(buf[pos+i]) <= 126) and not (ord(buf[pos+i+1]) >= 32 and ord(buf[pos+i+1]) <= 126): 46 | out += "\x00" 47 | break 48 | out += buf[pos+i] 49 | 50 | if out == "": 51 | return None 52 | else: 53 | return out.replace("\x00","") 54 | 55 | def parseConfig(f,buf): 56 | #2.9.x 57 | if len(buf) == 0x1390: 58 | v = 3 59 | #3.x 60 | elif len(buf) == 0x7f0: 61 | v = 2 62 | #1.3.x 63 | elif len(buf) == 0xe10: 64 | v = 1 65 | else: 66 | print "unrecognized config.." 67 | return 68 | ftpserveroffs = None 69 | ftpuseroffs = None 70 | ftppassoffs = None 71 | 72 | if v == 1: 73 | idoffs = 0x1b4 74 | groupoffs = 0x1de 75 | versionoffs = 0x312 76 | mutexoffs = 0x33e 77 | installdiroffs = 0x234 78 | ftpserveroffs = 0x430 79 | ftpuseroffs = 0x4d4 80 | ftppassoffs = 0x526 81 | 82 | elif v == 2: 83 | idoffs = 0x1b4 84 | groupoffs = 0x1ca 85 | versionoffs = 0x2d8 86 | mutexoffs = 0x2f0 87 | installdiroffs = 0x1f8 88 | ftpserveroffs = 0x380 89 | ftpuseroffs = 0x424 90 | ftppassoffs = 0x476 91 | #delayoffs = 0x378 92 | 93 | elif v == 3: 94 | idoffs = 0x9e0 95 | groupoffs = 0xa5a 96 | versionoffs = 0xf2e 97 | mutexoffs = 0xfaa 98 | installdiroffs = 0xb50 99 | 100 | 101 | print f 102 | id = getUnicodeString(buf,idoffs) 103 | group = getUnicodeString(buf,groupoffs) 104 | version = getUnicodeString(buf,versionoffs) 105 | mutex = getUnicodeString(buf,mutexoffs) 106 | installdir = getUnicodeString(buf,installdiroffs) 107 | ftpuser = None 108 | ftppass = None 109 | ftpserver = None 110 | 111 | print "ID: %s" % id 112 | print "Group: %s" % group 113 | print "Version: %s" % version 114 | print "Mutex: %s" % mutex 115 | print "Install Dir: %s" % installdir 116 | if ftpserveroffs != None: 117 | ftpserver = getUnicodeString(buf,ftpserveroffs) 118 | if ftpserver != "ftp.ftpserver.com".join("\x00"): 119 | print "FTP Server: %s" % ftpserver 120 | ftpuser = getUnicodeString(buf,ftpuseroffs) 121 | ftppass = getUnicodeString(buf,ftppassoffs) 122 | print "FTP User: %s" % ftpuser 123 | print "FTP Pass: %s" % ftppass 124 | 125 | print "\n" 126 | return (id,group,version,mutex,installdir,ftpserver,ftpuser,ftppass) 127 | 128 | def getFile(f): 129 | rp = open(f, "rb") 130 | buf = rp.read() 131 | rp.close() 132 | return buf 133 | 134 | if __name__ == "__main__": 135 | parser=argparse.ArgumentParser(description="parses Xtreme RAT config and prints config data") 136 | parser.add_argument('i', metavar='Input', help='a path to a config dump or directory of config dumps') 137 | parser.add_argument('-csv', metavar="CSV", help='write results to CSV in addition to printing to console') 138 | 139 | args = parser.parse_args() 140 | 141 | if os.path.isfile(args.i): 142 | f = sys.argv[1] 143 | buf = getFile(f) 144 | parseConfig(f,buf) 145 | elif os.path.isdir(args.i): 146 | if args.csv: 147 | csv = open(args.csv,"w") 148 | headers = "file,id,group,version,mutex,installdir,ftpserver,ftpuser,ftppass\n" 149 | csv.write(headers) 150 | else: 151 | csv = None 152 | d = args.i 153 | for f in os.listdir(d): 154 | path = os.path.join(d, f) 155 | if os.path.isfile(path): 156 | buf = getFile(path) 157 | res = parseConfig(path,buf) 158 | if csv is not None: 159 | if res is not None: 160 | csv.write("%s,%s,%s,%s,%s,%s,%s,%s,%s\n" % (f, res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7])) 161 | 162 | if csv is not None: 163 | csv.close() 164 | 165 | 166 | 167 | --------------------------------------------------------------------------------