elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Usando Git para manipular el directorio de trabajo, el índice y commits (segunda parte)


  Mostrar Temas
Páginas: 1 [2] 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
11  Seguridad Informática / Criptografía / Implementacion practica Padding Oracle Attack en: 20 Noviembre 2020, 05:29 am
Recientemente me interesa ese tipo de temas otra vez, he aprendido mucho y me gustaría compartirlo con ustedes.

Si no saben de que va el tema aquí dejo unos links.

Block cipher mode of operation
https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation

Wikipedia Padding oracle attack
https://en.wikipedia.org/wiki/Padding_oracle_attack

Padding oracle attack
https://robertheaton.com/2013/07/29/padding-oracle-attack/

Este tipo de Ataque tiene ciertas condiciones iniciales para ser llevado acabo.

  • El cliente solo puede saber si su paquete fue aceptado o no.
Esto es debido al check que hace el servidor sobre el mensaje recibido

  • El servidor no Cambia de KEY utilizada durante el proceso de cifrado y descifrado.
Esto es debido a una mala implementación, ya que el servidor debería de renovar el KEY cada X tiempo y con cada cliente distinto.

  • El servidor tiene algún leak de información ya sea por error o mediante otro tipo de ataque.
  • El cliente solo podrá descifrar Una parte de la información, excepto por el Bloque inicial


Dejo a continuación una imagen de prueba y el código, proximamente subire un video hablando del tema.






Codigo, este codigo ejemplifica el cliente y servidor mediante un hilo distinto, lo hice de esta manera para no complicarme con el protocolo en RED de los mismo, se puede hacer sin hilos, y solo con llamadas a funcion, pero la idea es garantizar que el cliente no tiene acceso al servidor.



Código
  1. /*
  2. Desarollado por AlbertoBSD
  3. email alberto.bsd@gmail.com
  4. g++ -O3 -o opk_example opk_example.c -Wint-to-pointer-cast  -pthread
  5. */
  6.  
  7. #include <time.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include<pthread.h>
  12. #include<unistd.h>
  13. #include"ctaes/ctaes.c"
  14.  
  15. #define AES_BLOCKSIZE 16
  16.  
  17. struct timespec tim, tim2,sim,sim2;
  18.  
  19. void crear_server();
  20. char *tohex(char *ptr,int length);
  21. void *process_server(void *vargp);
  22.  
  23. int MyCBCEncrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out);
  24. int MyCBCDecrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out);
  25.  
  26. /* Values between Server and client */
  27. int values_do;
  28. int values_pad;
  29. int values_length;
  30. int values_leaked;
  31. char *values_enc;
  32. char *values_leak;
  33.  
  34. pthread_mutex_t mtx_values;  //Mutex for those values
  35.  
  36. int main(){
  37.  /*
  38.     Set global values;
  39.   */
  40.  tim.tv_sec = 0;
  41.  tim.tv_nsec = 50000;
  42.  
  43.  sim.tv_sec = 0;
  44.  sim.tv_nsec = 50000;
  45.  values_do = 0;
  46.  values_pad = 0;
  47.  values_length = 0;
  48.  values_leaked = 0;
  49.  values_enc = (char*) malloc(48);
  50.  values_leak = (char*) malloc(48);
  51.  crear_server();  //create child "server"
  52.  
  53.  //This main process is the client
  54.  int i,j,k,entrar;
  55.  char *secret,*temp,*try_enc;
  56.  char *decrypted;
  57.  unsigned char GUESS;
  58.  secret = (char*) malloc(48);
  59.  try_enc = (char*) malloc(48);
  60.  decrypted = (char*) malloc(16);
  61.  memset(decrypted,0,16);
  62.  do  {  
  63.    sleep(1);
  64.  }while(values_leaked==0); //We need to wait to the leaked data
  65.  
  66.  memcpy(secret,values_leak,48);
  67.  
  68.  temp = tohex(secret,48);
  69.  printf("process_client: leaked is %s\n",temp);
  70.  free(temp);
  71.  i = 0;
  72.  j = 0;
  73.  while(i < 16)  {
  74.    memcpy(try_enc,secret,32);
  75.  
  76.    pthread_mutex_lock(&mtx_values);
  77.    switch(values_do)  {
  78.      case 0:
  79.        GUESS = j;
  80.        decrypted[15-i] = GUESS;
  81.        for(k = 0; k <= i;k++)  {
  82.          try_enc[15-k] = try_enc[15-k] ^ decrypted[15-k] ^ (unsigned char)(i+1);
  83.        }
  84.  
  85.        values_do = 1;
  86.        values_length = 32;
  87.        memcpy(values_enc,try_enc,32);
  88.      break;
  89.      case 1:
  90.      break;
  91.      case 2:
  92.        if(values_pad)  {
  93.          i++;
  94.          printf("Encontrado valor: %c : %.2x\n",GUESS,GUESS);
  95.          j = 0;
  96.        }
  97.        else  {
  98.          j++;
  99.        }
  100.        values_do = 0;
  101.      break;
  102.    }
  103.    pthread_mutex_unlock(&mtx_values);
  104.    nanosleep(&tim , &tim2);
  105.  }
  106.  printf("Decrypted data: %s\n",decrypted);
  107.  
  108. }
  109.  
  110. void *process_server(void *vargp)  {
  111.  AES256_ctx ctx;
  112.  FILE *urandom;
  113.  const char *secret = "The password is: Ywgo/@g:2$0Qsz<";
  114.  char *key,*dec,*enc,*iv,*temp;
  115.  int length,i,pad_valid,outlen;
  116.  unsigned char pad;
  117.  key = (char*) malloc(32);
  118.  dec = (char*) malloc(48);
  119.  enc = (char*) malloc(48);
  120.  iv  = (char*) malloc(16);
  121.  urandom = fopen("/dev/urandom","rb");
  122.  fread(key,1,32,urandom);
  123.  fread(iv,1,16,urandom);
  124.  fclose(urandom);
  125.  
  126.  AES256_init(&ctx,(const unsigned char*) key);
  127.  
  128.  /* LEAK THE secret */
  129.  pthread_mutex_lock(&mtx_values);
  130.  memset(enc,0,48);
  131.  
  132.  
  133.  outlen = MyCBCEncrypt(&ctx, (const unsigned char*) iv, (const unsigned char*) secret, strlen(secret), true, (unsigned char*) enc);
  134.  
  135.  memcpy(values_leak,enc,outlen);
  136.  values_leaked = 1;
  137.  pthread_mutex_unlock(&mtx_values);
  138.  /*END LEAK*/
  139.  
  140.  do  {
  141.    nanosleep(&sim , &sim2);
  142.    pthread_mutex_lock(&mtx_values);
  143.    if(values_do == 1)  {
  144.      length = values_length;
  145.      pad_valid = 0;
  146.      if(length <= 48)  {
  147.        memcpy(enc,values_enc,length);
  148.  
  149.        outlen = MyCBCDecrypt(&ctx,( const unsigned char*) iv, (const unsigned char*) enc, length, true, (unsigned char*) dec);
  150.        if(outlen > 0)  {
  151.          pad_valid =  1;
  152.          printf("Decrypted data seems legit : %i bytes\n",outlen);
  153.          temp = tohex(dec,length);
  154.          printf("Decrypted data %s\n",temp);
  155.          free(temp);
  156.        }
  157.        else  {
  158.          printf("Decrypted data doesnt seems legit\n",outlen);
  159.          temp = tohex(dec,length);
  160.          printf("Decrypted data %s\n",temp);
  161.          free(temp);
  162.        }
  163.      }
  164.      values_do = 2;
  165.      values_pad = pad_valid;
  166.    }
  167.    pthread_mutex_unlock(&mtx_values);
  168.  }while(1);
  169.  pthread_exit(NULL);
  170. }
  171.  
  172. void crear_server()  {
  173.  int s;
  174.  pthread_t tid;
  175.  pthread_attr_t attr;
  176.  s = pthread_attr_init(&attr);
  177.  if (s != 0)  {
  178.    perror("pthread_attr_init");
  179.    exit(6);
  180.  }
  181.  s = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
  182.  if(s != 0)  {
  183.    perror("pthread_attr_setstacksize");
  184.    exit(8);
  185.  }
  186.  s = pthread_create(&tid,&attr,process_server,NULL);
  187.  if(s != 0)  {
  188.    perror("pthread_create");
  189.  }
  190.  pthread_attr_destroy(&attr);
  191. }
  192.  
  193. char *tohex(char *ptr,int length){
  194.  char *buffer;
  195.  int offset = 0;
  196.  unsigned char c;
  197.  buffer = (char *) malloc((length * 2)+1);
  198.  for (int i = 0; i <length; i++) {
  199.  c = ptr[i];
  200.  sprintf((char*) (buffer + offset),"%.2x",c);
  201.  offset+=2;
  202.  }
  203.  buffer[length*2] = 0;
  204.  return buffer;
  205. }
  206.  
  207.  
  208. int MyCBCDecrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out)
  209. {
  210.  int written = 0;
  211.  bool fail = false;
  212.  const unsigned char* prev = iv;
  213.  if (!data || !size || !out)
  214.    return 0;
  215.  if (size % AES_BLOCKSIZE != 0)
  216.    return 0;
  217.  while (written != size) {
  218.    AES256_decrypt(ctx, 1, out, data + written);
  219.    for (int i = 0; i != AES_BLOCKSIZE; i++)
  220.      *out++ ^= prev[i];
  221.    prev = data + written;
  222.    written += AES_BLOCKSIZE;
  223.  }
  224.  if (pad) {
  225.    unsigned char padsize = *--out;
  226.    fail = !padsize | (padsize > AES_BLOCKSIZE);
  227.    padsize *= !fail;
  228.    for (int i = AES_BLOCKSIZE; i != 0; i--)
  229.      fail |= ((i > AES_BLOCKSIZE - padsize) & (*out-- != padsize));
  230.    written -= padsize;
  231.  }
  232.  return written * !fail;
  233. }
  234.  
  235. int MyCBCEncrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out)
  236. {
  237.  int written = 0;
  238.  int padsize = size % AES_BLOCKSIZE;
  239.  unsigned char mixed[AES_BLOCKSIZE];
  240.  
  241.  if (!data || !size || !out)
  242.    return 0;
  243.  
  244.  if (!pad && padsize != 0)
  245.    return 0;
  246.  
  247.  memcpy(mixed, iv, AES_BLOCKSIZE);
  248.  
  249.  // Write all but the last block
  250.  while (written + AES_BLOCKSIZE <= size) {
  251.    for (int i = 0; i != AES_BLOCKSIZE; i++)
  252.      mixed[i] ^= *data++;
  253.    AES256_encrypt(ctx, 1, out + written, mixed);
  254.    memcpy(mixed, out + written, AES_BLOCKSIZE);
  255.    written += AES_BLOCKSIZE;
  256.  }
  257.  if (pad) {
  258.    // For all that remains, pad each byte with the value of the remaining
  259.    // space. If there is none, pad by a full block.
  260.    for (int i = 0; i != padsize; i++)
  261.      mixed[i] ^= *data++;
  262.    for (int i = padsize; i != AES_BLOCKSIZE; i++)
  263.      mixed[i] ^= AES_BLOCKSIZE - padsize;
  264.    AES256_encrypt(ctx, 1, out + written, mixed);
  265.    written += AES_BLOCKSIZE;
  266.  }
  267.  return written;
  268. }
  269.  


Saludos!
12  Seguridad Informática / Seguridad / Como proteger una cartera Bitcoin en: 18 Noviembre 2020, 01:45 am
Como proteger una cartera Bitcoin

No sabemos qué pasará en el futuro, es decir no sabemos si nos robaran la cartera o la perderemos en algún USB y alguien la encontrara. Tampoco sabemos la cantidad de poder de computo que existira.

Pero además de tener cifrada nuestra cartera con un buen passphrase de más de 40 caracteres, se puede lograr una mejor seguridad, para en el caso de que sea robada sea inviable que por medio de fuerza bruta directo contra el passphrase.

Nuestra Cartera está protegida con el resultado de un hash sha512 derivado N veces a partir de nuestro Passphrase y un salt.

Es decir:

Código:
(key,IV) = PBKDF2_algo("sha512",passphrase+salt,N);

Normalmente el cliente bitcoin-core calcula ese N de tal forma que la Operación en total no lleve más de 1 Segundo

¿Por que? ¿Por que ponérsela fácil a los crackers de wallets?

Se puede editar el código fuente del bitcoin-core de tal forma que cuando nosotros cambiemos el passphrase este utilice un número N tal que N el proceso completo de PBKDF2_algo lleve al menos uno o dos minutos por passphare, es un pequeño precio de espera. Y el resultado será sumamente desalentador para quien se robe o encuentre la cartera.

¿Como hacer esta modificacion?

Si revisamos la versión estable y actual al dia de hoy, el bitcoin core 0.20 el archivo wallet.cpp tiene la solución:

https://github.com/bitcoin/bitcoin/blob/0.20/src/wallet/wallet.cpp En la linea 322 tenemos lo siguiente:

Código
  1. bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
  2. {
  3.    bool fWasLocked = IsLocked();
  4.  
  5.    {
  6.        LOCK(cs_wallet);
  7.        Lock();
  8.  
  9.        CCrypter crypter;
  10.        CKeyingMaterial _vMasterKey;
  11.        for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
  12.        {
  13.            if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
  14.                return false;
  15.            if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
  16.                return false;
  17.            if (Unlock(_vMasterKey))
  18.            {
  19.                int64_t nStartTime = GetTimeMillis();
  20.                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
  21.                pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime))));
  22.  
  23.                nStartTime = GetTimeMillis();
  24.                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
  25.                pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
  26.  
  27.                if (pMasterKey.second.nDeriveIterations < 25000)
  28.                    pMasterKey.second.nDeriveIterations = 25000;
  29.  
  30.                WalletLogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
  31.  
  32.                if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
  33.                    return false;
  34.                if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
  35.                    return false;
  36.                WalletBatch(*database).WriteMasterKey(pMasterKey.first, pMasterKey.second);
  37.                if (fWasLocked)
  38.                    Lock();
  39.                return true;
  40.            }
  41.        }
  42.    }
  43.  
  44.    return false;
  45. }

Y solo tendria que quedar de la siguiente manera:

Código
  1. bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
  2. {
  3.    bool fWasLocked = IsLocked();
  4.  
  5.    {
  6.        LOCK(cs_wallet);
  7.        Lock();
  8.  
  9.        CCrypter crypter;
  10.        CKeyingMaterial _vMasterKey;
  11.        for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
  12.        {
  13.            if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
  14.                return false;
  15.            if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
  16.                return false;
  17.            if (Unlock(_vMasterKey))
  18.            {
  19.                pMasterKey.second.nDeriveIterations = 133707331;
  20.  
  21.                WalletLogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
  22.  
  23.                if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
  24.                    return false;
  25.                if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
  26.                    return false;
  27.                WalletBatch(*database).WriteMasterKey(pMasterKey.first, pMasterKey.second);
  28.                if (fWasLocked)
  29.                    Lock();
  30.                return true;
  31.            }
  32.        }
  33.    }
  34.  
  35.    return false;
  36. }

Si quitamos todo lo relacionado con el calculo del tiempo y agregamos la linea:

Código
  1. pMasterKey.second.nDeriveIterations = 133707331;

En mi caso con el bitcoin-core oficial recompilado y con un procesador Intel Xeon CPU E3-1271 v3 @ 3.60GHz cambiar el passphrase toma alrededor de un minuto

Saludos!

13  Seguridad Informática / Criptografía / Como crackear una cartera bitcoin. Teoria y practica en: 4 Noviembre 2020, 19:42 pm

Como crackear una cartera bitcoin. (Teoria y practica).

Bueno esta investigación comenzó a manera de broma y solo por hobby. En las platicas que tenemos en la comunidad de elhacker.net en Telegram ( https://t.me/elhackerdotnet )

Se menciono hace tiempo la existencia de una  cartera de bitcoin con 69 Mil BTC, al tipo de cambio actual hoy 4 de Noviembre de 2020 serian unos 995 millones de dólares, entre bromas se menciono que teníamos que crackearla con algún computador cuántico.

En fin, el proceso "normal" para abrir una cartera cifrada utilizando las aplicaciones oficiales de Bitcoin-Core es el siguiente.

Primero cargamos la cartera

Código:
bitcoin-cli loalwallet "wallet.dat"

"wallet.dat" es un archivo que debe de existir en el directorio ~/.bitcoin/wallets/

Se puede llamar de otro modo, el punto es que debe de exisitir en ese path

Segundo desbloqueamos la cartera con nuestra passphrase o mas comúnmente contraseña

Código:
bitcoin-cli walletpassphrase "passphrase o password" 60

Entre comillas tenemos nuestro password y el 60 a continuación indica que desbloqueamos la cartera por 60segundos

Si el password es correcto no marcara error, de lo contrario lo indicará.

Código:
error code: -14
error message:
Error: The wallet passphrase entered was incorrect.

Ahora la forma lenta e ineficiente de intentar crackearla por fuerza fruta probando directamente distintos passphrase desde la misma terminal.
Sigue siendo lento incluso aunque se utilice algún script bash por que pasar del bash al programa y de regreso es ineficiente.

Necesitamos saber que hace internamente la aplicación, para tratar de reproducirlo en un programa en C y ejecutarlo por aparte posiblemente con multihilo para mejorar la eficiencia

¿Que hace el bitcoin core con nuestro passphrase?

Nuestro passphrase es combinado con un salt que se encuentra almacenado en el archivo, mediante un algoritmo estilo PBKDF y con mas de 25000 iteraciones generan un hash sha512.

De estos 64 bytes generados mediante PBKDF, se utilizan los primeros 32 bytes como KEY para inicializar el contexto de AES y los siguientes 16 bytes como IV para el algoritmo CBC

A este algoritmo AES256CBC se le pasa como parámetro para descifrar el mKey (master KEY) cifrado y se obtiene un mKey Descifrado

El master key ya descifrado se le hacen varias pruebas, se utiliza este valor como KEY para otros descifrados y en este caso como IV en todas las pruebas se utilizan 16 bytes del public Key de la cartera bitcoin obtenidos por una función interna llamada GetHash que desconozco que valores devuelva exactamente, solamente me limite a llamarla.

Y si el master key ya descifrado pasa todas las pruebas se almacena en memoria para sea utilizado en el futuro.

Fin de la triste Historia.  :silbar:

Resumen en pseudo codigo

El siguiente codigo en Pseudo C esta solo para representare que hace la aplicación internamente.

Código
  1. prekey = PBKDF(passphrase,IV, N Iteraciones,"sha512");
  2. memcpy(KEY,prekey,32);
  3. memcpy(IV,prekey+32,16);
  4. aesctx = AES256_init(KEY);
  5. if( AES256CBC_decrypt(aesctx,IV,ENC_mKey,DEC_mKEY) > 0) {
  6. foreach(OthersENC as oENC) {
  7. oCtx = AES256_init(DEC_mKEY);
  8. if(!AES256CBC_decrypt(oCtx,IV_fromPublickey,oENC,dummy) > 0) {
  9. return false;
  10. }
  11. }
  12. return true;
  13. }

Entonces si nuestro plan es un ataque por fuerza bruta podemos saltarnos el PBKDF que se ejecuta N Iteraciones (Mínimo 25000) y saltar directamente al Decrypt de AES.

Tenemos 2 opciones:

1.- Generar un par (KEY,IV) 48 bytes random o secuencial y empezar con el primer AES256CBC_decrypt y utilizar el valor generado para continuar con los AES256CBC_decrypt dentro del for.

2.- O generar solamente un KEY de 32 bytes random o secuencial y pasar directamente a los AES256CBC_decrypt dentro del For.

Asi con 32 bytes solo tenemos 1 de 115792089237316195423570985008687907853269984665640564039457584007913129639936 posibilidades de dar con la KEY correcto.
xD xD xD

Resultados vistos en la práctica.

Con la opción 1 solamente el 0.4% de los valores aleatorios generados pasaban el primer AES256CBC_decrypt posteriormente solo el 0.4% de esos valores pasaban el primer AES256CBC_decrypt dentro del FOR

Para la cartera que cree con el propósito de realizar las pruebas los challenge dentro del FOR eran sobre 500.

Sin embargo para la cartera lackeada con 69K BTC solo está disponible un solo challenge dentro del FOR, al ser solo dos AES256CBC_decrypt me dio bastantes KEY "Falsos positivos" aproximadamente uno de cada millón de valores random generados (KEY,IV) pasaban ambas pruebas

En conclusión

La aproximación por Fuerza Bruta a AES256CBC es improbable que funcione ojo, improbable no imposible, Tal vez en el futuro con mejor poder de computo disponible, o tal vez con Múltiples equipos trabajando de forma sincronizada con alguna RED tipo BOINC o algún tipo de BOTNET

Tengo el código utilizado para realizar este proceso, un poco de manera hardcodeada Ya que los Valores cifrados los saque directamente mediante Hexedit, si alguien esta interesado en la estructura del archivo no dude en comentarlo.

Saludos

Posdata
La cartera de 69K BTC fue vaciada por alguien el dia de ayer. 3 de Noviembre a las 3PM
https://twitter.com/albertobsd/status/1323752623510446080
https://decrypt.co/es/47133/wallet-de-bitcoin-con-955-millones-famosa-entre-hackers-se-acaba-de-vaciar?amp=1
14  Seguridad Informática / Criptografía / El patron de padding en la data descifrada es normal? en: 4 Noviembre 2020, 03:14 am
Anteriormente no me había fijado la salida del descifrado por AES 256 CBC con Pad habilitado.

Normalmente uno solo espera la data original descifrada, vamos que si ciframos la palabra "hola" esperamos de vuelta la misma palabra "hola" ya descifrada.

Cuando encriptas sin padding cada bloque del tamaño  "AES_BLOCKSIZE" devuelve la misma cantidad de bloques. Pero el cifrar con Padding agrega cierta cantidad mas de datos.

Por ejemplo si ciframos 32 bytes con AES256CBC con Padding nos devuelve un buffer con 48 bytes de data

Y cuando desciframos esos 48 bytes, nos devuelve la data original de 32 bytes + un buffer "sucio" es decir que hay mas datos en el buffer, en mi caso he comprobado que para este ejemplo siempre devuelve un buffer sucio de 16 bytes y cada uno de esos bytes tiene valor de uno.

Mi pregunta es ¿Es normal esto, o solo es la forma en la que trabaja la librería ctaes?

hice un programa que muestra que independientemente del key y del IV utilizados  siempre pasa lo mismo

Código:
albertobsd $ ./test_aes256cbc
key: fd792d4458dbc9bfee589482273ae061a37e24a72e95a0a5fba17109e4cb1daf
iv: 7d5559d5e50e340bb66618ceaad7ed1b
Data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
len 48
cipher data 1117fcb2cbb27ee2f735ce4083d0aea743b51f6b7f61f59ce5a27a78bb5d454eab8b6a1733a5ad1d07b0b08ba1732e04
len 32
decipher data 414141414141414141414141414141414141414141414141414141414141414110101010101010101010101010101010
albertobsd $ ./test_aes256cbc
key: 1049354727fa2affd4410da40870f1757e211efeb96349b8576157c101fe5ab0
iv: 49547b6aac189b8487f60157d13185df
Data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
len 48
cipher data e980ef82804a6fe5bec15dda0ad50064457c65259cd810055c38eb7c55e1d40071646c7c792e6d5a7ac6597057868267
len 32
decipher data 414141414141414141414141414141414141414141414141414141414141414110101010101010101010101010101010
albertobsd $ ./test_aes256cbc
key: 6d40ce0be48da5fcc7ede6531dae1b3613e5931a808e1ae99928ab74f74f3685
iv: ec1cebfa7894563a8329aa797610841c
Data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
len 48
cipher data 395976ca9f00ace59ba64e8a1ee5dbaf55f45e786fada6520148d82a84c298e15b2854763a2fc82e7a62164936bf8f1f
len 32
decipher data 414141414141414141414141414141414141414141414141414141414141414110101010101010101010101010101010



De ser normal esto se podría tomar ese buffer sucio como una comprobación de que la key y el iv utilizados son los correctos?


Saludos
15  Seguridad Informática / Seguridad / Extraer MasterKey de cartera Bitcoin en: 29 Octubre 2020, 16:35 pm
Publico este tema aquí, ya que no se en qué sección queda mejor publicarlo.

Estoy intentando extraer la información Cifrada de una cartera bitcoin, en específico la información del Key para posteriormente intentar descifrarlo por algún ataque de fuerza bruta.

Quiero extraerla por que no quiero depender del bitcoin core ya que si se realiza el ataque por fuerza bruta mediante algún script bash o algun otro metodo NO compilado, el ataque puede ser realmente ineficiente.

También quiero brincarme algunos pasos innecesarios de funciones tipo rehash o PBKDF2 (key derivation) ya que aunque no consumen mucho CPU si quitan algunos miles de ciclos de procesamiento que a la larga pueden hacer aun mas eterno el proceso de crackeo.

Segun he leido la informacion del Key cifrado el salt y el numero de iteraciones esta contenida en un campo de 64 bytes del wallet.dat llamado mkey.

Segun vi en el siguiente Link:

Código:
https://bitcoin.stackexchange.com/questions/48070/format-of-mkey-field-in-encrypted-wallet-dat-file

La data contiene los siguientes campos:

mkey, nID, encrypted_key, salt, derivation_method, derivation_rounds, other_derivation_parameters

Citar
  • mkey - a size prefixed string denoting the start of the master key data.
  • nID - an integer whose purpose I have been unable to determine.
  • encrypted_key - a size prefixed buffer containing the encrypted master key.
  • salt - a size prefixed buffer containing the salt data used when encrypting the key.
  • derivation_method - an integer containing either 0 or 1 for the method used to encrypt the master key using the wallet password.
  • derivation_rounds – an integer containing the number of rounds used to encrypt the master key.
  • other_derivation_parameters
mkey es solo el ascii "mkey", se que el encrypted_key debe de ser de 32 bytes y el salt de 16, restando solo 12 bytes para los otros datos, sin embargo no estoy seguro del orden de los mismos.

Si vemos la siguiente imagen:





Vemos que ahí esta la data, escribí un pequeño programa que la encuentra y la extrae, pero no se en que orden este, con ver los datos de esta cartera y otras me doy cuenta de algunos datos que pueden ser números como los primeros 8 bytes después del mkey, pueden ser números, al igual que los últimos 4 antes de ckey.


Edit

Solucionado el master key cifrado son 48 bytes que se encuentran a un offset de -72 bytes de la primera coincidencia del string mkey.

Para esta cartera en cuestión el Master Key Cifrado es:

CEC646179A7F947349A0AA99EC7122B01F72BF18FFA4FDC760635D8C13109DA196D3DC802D5AABB23FA6C6AABA9A1DBB

Saludos

16  Seguridad Informática / Criptografía / Funcion BytesToKeySHA512AES en el bitcoin en: 29 Octubre 2020, 15:26 pm
Recientemente publique el tema:Como determina la función AES256CBCDecrypt una correcta desencriptación El cual esta relacionado con este de forma algo indirecta.

Todo esto viene del análisis que estoy realizando al código fuente del Bitcoin Core.

Hoy hablaré sobre la función BytesToKeySHA512AES la cual es una de las primeras que se utilizan cuando intentas desbloquear una cartera bitcoin protegida con un passphrase.

BytesToKeySHA512AES básicamente toma las passphrase ingresada + un salt proporcionado por el mismo archivo wallet.dat y los transforma en un (key, iv) para posteriormente utilizarlos como material para descifrar la llave cifrada.

El código fuente de BytesToKeySHA512AES, lo pueden encontrar en

Código:
https://github.com/bitcoin/bitcoin/blob/master/src/wallet/crypter.cpp
 

Tiene 3 parámetros de entrada y 2 de salida
Entrada:
Salt
Passphrase
Count

Salida:
Key
IV

La parte interesante del código es la siguiente:

Código
  1.    for(int i = 0; i != count - 1; i++)
  2.        di.Reset().Write(buf, sizeof(buf)).Finalize(buf);

Básicamente obtiene el hash sha512 de si mismo (count -1) veces ya la que primera vez fue el hash sha512 de (passphrase + IV) como muestra el siguiente código:

Código
  1.    di.Write((const unsigned char*)strKeyData.data(), strKeyData.size());
  2.    di.Write(chSalt.data(), chSalt.size());
  3.    di.Finalize(buf);

Posteriormente copia los primeros 32 bytes al Key y los siguientes 16 bytes al Vector IV

Si no están familiarizados con la sintaxis  del codigo anterior dejare un código en PHP ejemplificando lo que hace la función:

Código
  1. <?php
  2. $salt = "BBBBBBBBBBBBBBBB";
  3. $passphrase = "AAAAA";
  4. $key_ ="";
  5. $iv_ = "";
  6. BytesToKeySHA512AES($salt ,$passphrase,2,$key_, $iv_ );
  7.  
  8. echo "Key:\n";
  9. var_dump($key_);
  10. echo "IV:\n";
  11. var_dump($iv_);
  12.  
  13. function BytesToKeySHA512AES($chSalt,$strKeyData,$count,&$key,&$iv) {
  14. $ctx = hash_init('sha512');
  15. hash_update($ctx,$strKeyData);
  16. hash_update($ctx,$chSalt);
  17. $buf = hash_final($ctx,true);
  18. $i = 0;
  19. while($i != $count -1) {
  20.  
  21. /* //Estas tres líneas básicamente se transforman en una simple llamada a hash
  22. $ctx = hash_init('sha512');
  23. hash_update($ctx,$buf);
  24. $buf = hash_final($ctx,true);
  25. */
  26. $buf = hash('sha512',$buf,true);
  27. $i++;
  28. }
  29. echo "hash:\n";
  30. var_dump($buf);
  31. $key = mb_substr($buf,0,32);
  32. $iv = mb_substr($buf,32,16);
  33. }
  34. ?>

Lo escribí en PHP ya que es mas fácil darle seguimiento a las funciones hash, solo que no estoy 100% seguro de como manejar las copia de los bytes del hash resultante al key y al IV respectivamente.

Saludos
17  Seguridad Informática / Criptografía / Como determina la función AES256CBCDecrypt una correcta desencriptación en: 28 Octubre 2020, 15:00 pm
Muy buena dia, estoy con una pequeña duda ya que estoy tratando de automatizar un proceso de crackeo por fuerza bruta de una key de 256 bits (Se que es improbable, sin embargo la clave esta ahi del 0 al 2^256)  :rolleyes: :rolleyes: :rolleyes:

La función original recibe 2 parametros un un KeyCifrada, y el candidato a Key como segundo parametro:

Código
  1. Decrypt(KeyCifrada,KeyCandidato);

Dicha función realiza un llamado internamente a AES256CBCDecrypt


Código:
   AES256CBCDecrypt dec(Key.data(), IV.data(), true);
    nLen = dec.Decrypt(KeyCifrada.data(), KeyCifrada.size(), KeyCandidato);
    if(nLen == 0)
        return false;

y si nLen es igual a 0 entonces retorna false indicando que Key Candidato no es un Key valido.

Mi duda es la siguiente como determina internamente AES256CBCDecrypt  que la KeyCandidato es valida.

Saludos


Edit
Platicando con Kub0x me corrigio el KeyCandidato no es parámetro de entrada si no de salida

Si vemos el link
Código:
https://fabcoin.pro/aes_8cpp_source.html#l00176

en la linea 112 hay se muestra que las comprobaciones las hace directamente sobre el texto descifrado y si alguna de ellas no pasa simplemente regresa 0.

Me comenta kub0x que  existen varios valores Key y IV de entrada que podrian dar una salida valida, siendo esto un falso positivo, sin embargo me gustaría investigar cuantas veces pasa eso en realidad.

Saludos



Edit 2
Tal como menciono Kub0x, el proceso arroja muchos falsos positivos.

Programe un programa multihilo para crackear un key

Código:
albertobsd $ g++ -o crack_wallet_mt crack_wallet_mt.c -Wint-to-pointer-cast  -pthread
albertobsd $ ./crack_wallet_mt
OK
Thread 3, count: 142
key_material: 6120fbf417fcf689ce5ef35f8094d2e4ff584f2652fff824c94c23dae07633e7
iv_material: 226fe385941a98f5fa0274f2917793c7
decipher_key: 01f970cde83114aef95f5bda80866249053b3067a25cd551fa87d57e9a1406be72496a13439c363ee317b478966891
OK
Thread 2, count: 296
key_material: 4c167299eabda7932ce63d2ca44045a45f00316a45ca72a4acfca3bdd73fd2a5
iv_material: fc238b78db6d6d3c3ebc4cdb4075ccef
OK
Thread 1, count: 443
decipher_key: 0053614707620edd364dfd688249bcf316ba2973df40fa6fa70df7bb532bbc483de465c8e9336c2ef66dc51a7633d4
key_material: 609615afd2c0714b603d077cae58b8561e1fae8445a87cf0c1e8847be0c9acca
iv_material: 36b905f01e1b898b3cd3efa298db88da
decipher_key: a7333cf2484dbc21158b25600a131d707bbb38d4f6dd2fff92e6c2dae3d8c053499ffa19532a99b3c48a59d2574ecc
OK
Thread 0, count: 773
key_material: 93cb1954410e9676fbbf3cd6b17ccfaae4d8e874b6f577e32b9bbbd1c37ea0c3
iv_material: 5fd321427cd14a9ae2c9a2f95f14d629
decipher_key: fdfebebeb779e4df9aa76746f02cd000d93c6e69d7b4fad30214369a2dab84295716a30dc585efcd6a22a16235

Con solo 4 Hilos y solo probando 1554 hashes random me dio 4 resultados que la función AES256CBCDecrypt considera válidos, pense que serian mucho menos el ratio de falsos positivos, pero asi no me da tiempo de probarlos manualmente, tendrás que optimizar ese proceso también.


18  Programación / Programación C/C++ / Por que motivos se cierra un programa con sockets hecho en C? en: 31 Julio 2020, 01:30 am
Muy buenos días compañeros.

Por algun momento pense en colar el titulo de "ayuda mi programa se cierra sin motivo", pero no es demasiado genérico y solo un novato lo haría

Quiero explorar los diversos motivos por los que un programa en C se cierra. De momento vienen a mi mente los siguientes motivos:

  • llamaa explicita a exit o variantes
  • bufferoverflow y variantes de segment fault
  • NULL pointer... (parecido al anterior)
  • No poder asignar mas memoria
  • No poder crear mas threads

Algunos son salidas explícitamente programadas y otras son por bugs.

Tengo un proyecto en C, es un servidor WEB multihilo:

https://github.com/albertobsd/chttpserv

De momento funciona bien cuando hago peticiones mediante  curl incluso soporta un ciclo sin fin de peticiones:

Código
  1. while true; do curl -i http://localhost:3002/ ; done

Sin embargo cuando le hago las peticiones desde cualquier otro navegador que procese todos los archivos y CIERRO el navegador a media carga el programa simplemente se sale sin mensaje de error.

OJO que solo es cuando cierro a media carga, si espero a que termine de cargar la pagina por completo esto no sucede.

Consideraciones:
  • Estoy totalmente seguro de que la mayoría de las funciones que pueden dar error están correctamente procesadas y muestran el error correspondiente:
Código
  1. s = pthread_create(&tid,&attr,thread_process,(void *)tothread);
  2. if(s != 0) {
  3. perror("pthread_create");
  4. }
  5.  

  • Todas las funciones de lectura y escritura en el socket se valida si leyeron o escribieron los datos y no devolvio error:
Código
  1. while(sended >= 0  && readed >= 0 && !feof(fd)  ) {
  2. readed = fread(buffer,1,128,fd);
  3. if(readed > 0)
  4. sended = send(hsc->client_fd,buffer,readed,0);
  5. }
  6. if(sended ==  -1) {
  7. perror("send");
  8. }
  9. if(readed == -1) {
  10. perror("fread");
  11. }
  12.  

  • También estoy seguro que no es un problema de memoria ya que tengo una libreria propia con la que me he asegurado tras varias pruebas de que todos los apuntadores asignados con malloc/calloc son liberados y no se vuelven a utilizar, ademas de indicarme la cantidad de memoria dinamica actualmente utilizada.
  • De igual manera todos los sockets son cerrados mediante:
Código
  1. shutdown(hsc->client_fd,SHUT_RDWR);
  2. close(hsc->client_fd);

Se que el problema tiene que ver con Sockets ya que solo cuando cierro el navegador a media carga el programa termina.

Me he quedado un poco estancado, ya que siento que no avanzo si no soluciono ese error.

No les pido que depuren mi codigo, ya que no esta 100% documentado.

Pregunto: ¿Alguien a tenido el mismo problema?, ¿Que otros motivos hacen que el programa se cierre y no caiga error en ninguna función?

Saludos
19  Seguridad Informática / Bugs y Exploits / Video: Infiltrating Corporate Intranet Like NSA: Pre-Auth RCE On Leading SSL VPN en: 21 Enero 2020, 05:02 am
20  Programación / Desarrollo Web / [Resuelto] ¿Cual es la mejor forma de depurar un JS semiofuscado? en: 17 Enero 2020, 02:42 am
Seguramente muchos de ustedes han visto esos códigos javascript Semiofucados ejemplo:

Código
  1. !function(a){function k(k){for(var n,a,f=k[0],d=k[1],u=k[2],l=0,b=[];l<f.length;l++)o[a=f[l]]&&b.push(o[a][0])
  2. ....

Y asi le sigue por unos cuantos Kilobytes de codigo minificado.

Entonces esa es la pregunta, cual es la mejor forma de depurar que es lo que esta haciendo, pregunto por que javascript es bastante permisivo con la sintaxis.

Obvio primer paso:
-- Utilizar alguna de esas paginas para que el código se vea indentado y tabulado

Saludos!
Páginas: 1 [2] 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines