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.
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.
[youtube=640,360]https://www.youtube.com/watch?v=GTl4ytJ3jBU[/youtube]
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 (c) [Seleccionar]/*
Desarollado por AlbertoBSD
email alberto.bsd@gmail.com
g++ -O3 -o opk_example opk_example.c -Wint-to-pointer-cast -pthread
*/
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<pthread.h>
#include<unistd.h>
#include"ctaes/ctaes.c"
#define AES_BLOCKSIZE 16
struct timespec tim, tim2,sim,sim2;
void crear_server();
char *tohex(char *ptr,int length);
void *process_server(void *vargp);
int MyCBCEncrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out);
int MyCBCDecrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out);
/* Values between Server and client */
int values_do;
int values_pad;
int values_length;
int values_leaked;
char *values_enc;
char *values_leak;
pthread_mutex_t mtx_values; //Mutex for those values
int main(){
/*
Set global values;
*/
tim.tv_sec = 0;
tim.tv_nsec = 50000;
sim.tv_sec = 0;
sim.tv_nsec = 50000;
values_do = 0;
values_pad = 0;
values_length = 0;
values_leaked = 0;
values_enc = (char*) malloc(48);
values_leak = (char*) malloc(48);
crear_server(); //create child "server"
//This main process is the client
int i,j,k,entrar;
char *secret,*temp,*try_enc;
char *decrypted;
unsigned char GUESS;
secret = (char*) malloc(48);
try_enc = (char*) malloc(48);
decrypted = (char*) malloc(16);
memset(decrypted,0,16);
do {
sleep(1);
}while(values_leaked==0); //We need to wait to the leaked data
memcpy(secret,values_leak,48);
temp = tohex(secret,48);
printf("process_client: leaked is %s\n",temp);
free(temp);
i = 0;
j = 0;
while(i < 16) {
memcpy(try_enc,secret,32);
pthread_mutex_lock(&mtx_values);
switch(values_do) {
case 0:
GUESS = j;
decrypted[15-i] = GUESS;
for(k = 0; k <= i;k++) {
try_enc[15-k] = try_enc[15-k] ^ decrypted[15-k] ^ (unsigned char)(i+1);
}
values_do = 1;
values_length = 32;
memcpy(values_enc,try_enc,32);
break;
case 1:
break;
case 2:
if(values_pad) {
i++;
printf("Encontrado valor: %c : %.2x\n",GUESS,GUESS);
j = 0;
}
else {
j++;
}
values_do = 0;
break;
}
pthread_mutex_unlock(&mtx_values);
nanosleep(&tim , &tim2);
}
printf("Decrypted data: %s\n",decrypted);
}
void *process_server(void *vargp) {
AES256_ctx ctx;
FILE *urandom;
const char *secret = "The password is: Ywgo/@g:2$0Qsz<";
char *key,*dec,*enc,*iv,*temp;
int length,i,pad_valid,outlen;
unsigned char pad;
key = (char*) malloc(32);
dec = (char*) malloc(48);
enc = (char*) malloc(48);
iv = (char*) malloc(16);
urandom = fopen("/dev/urandom","rb");
fread(key,1,32,urandom);
fread(iv,1,16,urandom);
fclose(urandom);
AES256_init(&ctx,(const unsigned char*) key);
/* LEAK THE secret */
pthread_mutex_lock(&mtx_values);
memset(enc,0,48);
outlen = MyCBCEncrypt(&ctx, (const unsigned char*) iv, (const unsigned char*) secret, strlen(secret), true, (unsigned char*) enc);
memcpy(values_leak,enc,outlen);
values_leaked = 1;
pthread_mutex_unlock(&mtx_values);
/*END LEAK*/
do {
nanosleep(&sim , &sim2);
pthread_mutex_lock(&mtx_values);
if(values_do == 1) {
length = values_length;
pad_valid = 0;
if(length <= 48) {
memcpy(enc,values_enc,length);
outlen = MyCBCDecrypt(&ctx,( const unsigned char*) iv, (const unsigned char*) enc, length, true, (unsigned char*) dec);
if(outlen > 0) {
pad_valid = 1;
printf("Decrypted data seems legit : %i bytes\n",outlen);
temp = tohex(dec,length);
printf("Decrypted data %s\n",temp);
free(temp);
}
else {
printf("Decrypted data doesnt seems legit\n",outlen);
temp = tohex(dec,length);
printf("Decrypted data %s\n",temp);
free(temp);
}
}
values_do = 2;
values_pad = pad_valid;
}
pthread_mutex_unlock(&mtx_values);
}while(1);
pthread_exit(NULL);
}
void crear_server() {
int s;
pthread_t tid;
pthread_attr_t attr;
s = pthread_attr_init(&attr);
if (s != 0) {
perror("pthread_attr_init");
exit(6);
}
s = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
if(s != 0) {
perror("pthread_attr_setstacksize");
exit(8);
}
s = pthread_create(&tid,&attr,process_server,NULL);
if(s != 0) {
perror("pthread_create");
}
pthread_attr_destroy(&attr);
}
char *tohex(char *ptr,int length){
char *buffer;
int offset = 0;
unsigned char c;
buffer = (char *) malloc((length * 2)+1);
for (int i = 0; i <length; i++) {
c = ptr[i];
sprintf((char*) (buffer + offset),"%.2x",c);
offset+=2;
}
buffer[length*2] = 0;
return buffer;
}
int MyCBCDecrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out)
{
int written = 0;
bool fail = false;
const unsigned char* prev = iv;
if (!data || !size || !out)
return 0;
if (size % AES_BLOCKSIZE != 0)
return 0;
while (written != size) {
AES256_decrypt(ctx, 1, out, data + written);
for (int i = 0; i != AES_BLOCKSIZE; i++)
*out++ ^= prev[i];
prev = data + written;
written += AES_BLOCKSIZE;
}
if (pad) {
unsigned char padsize = *--out;
fail = !padsize | (padsize > AES_BLOCKSIZE);
padsize *= !fail;
for (int i = AES_BLOCKSIZE; i != 0; i--)
fail |= ((i > AES_BLOCKSIZE - padsize) & (*out-- != padsize));
written -= padsize;
}
return written * !fail;
}
int MyCBCEncrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out)
{
int written = 0;
int padsize = size % AES_BLOCKSIZE;
unsigned char mixed[AES_BLOCKSIZE];
if (!data || !size || !out)
return 0;
if (!pad && padsize != 0)
return 0;
memcpy(mixed, iv, AES_BLOCKSIZE);
// Write all but the last block
while (written + AES_BLOCKSIZE <= size) {
for (int i = 0; i != AES_BLOCKSIZE; i++)
mixed[i] ^= *data++;
AES256_encrypt(ctx, 1, out + written, mixed);
memcpy(mixed, out + written, AES_BLOCKSIZE);
written += AES_BLOCKSIZE;
}
if (pad) {
// For all that remains, pad each byte with the value of the remaining
// space. If there is none, pad by a full block.
for (int i = 0; i != padsize; i++)
mixed[i] ^= *data++;
for (int i = padsize; i != AES_BLOCKSIZE; i++)
mixed[i] ^= AES_BLOCKSIZE - padsize;
AES256_encrypt(ctx, 1, out + written, mixed);
written += AES_BLOCKSIZE;
}
return written;
}
Saludos!