La base 64 est une système de comptage qui utilise des nombres mais aussi des lettres et des symboles. Cette base est essentiellement utilisée pour l'échange de pièce jointe dans les mails pour contenir des fichiers binaires dans certain type de conteneur (tel que XHTML, MHTML, ...). Cet article aura pour but de trouver une autre utilité à cette base.





0x01. RECODER L'ENCODAGE


Voici un code non optimisé mais fait par mes soins :


 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
 
 
//-- Constante des chaines de caractères différents plus le  =  du complément ----
#define ERROR_00    "00 : Parametres incorrect."
#define ERROR_01    "01 : Impossible d accéder au fichier en lecture."
#define ERROR_02    "02 : Erreur lors de l ecriture du fichier."
#define ERROR_03    "03 : L ecriture dans le fichier a echoue."
#define ERROR_FF    "FF : Une erreur est apparue."
 
#define DEFAULT_WIDTH 72
#define MINIMAL_WIDTH 4
 
 
//-- Definitiondes chaines de caractères différents plus le  =  du complément ----
#define bool    int
#define true    1
#define false   0
 
 
//-- Constante des chaines de caractères différents plus le symbole du complément ----
  char ConstChar[65]="AQWmzoslVFRBGTYeidZSXED%CH928v7NJUI56+apqkKLOPM04rufjtgyhwnxbc1@3";
//char ConstChar[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
 
 
//-- Encode en base 64 ---------------------------------------------------------
void EncodeBase64(int src[3], int dst[4], short len)
{
    dst[0] = (src[0] & 0xFC) >> 2;
    dst[1] = ((src[0] & 0x03) << 4) | ((src[1] & 0xF0) >> 4);
    if(len==2) dst[2]=64; else dst[2] = ((src[1] & 0x0F) << 2)
          | ((src[2] & 0xC0) >> 6);
    if(len>=1) dst[3]=64; else  dst[3] = src[2] & 0x3F;
}
 
 
 
//-- Lit le fichier et l encode dans le fichier destination --------------------
void EncodeFile(char strSrcFile[256], char strDstFile[256], int iCRLF)
{
    bool loop=true;
    int rep[3]={0,0,0},index=0;
    int cod[4]={0,0,0,0};
 
    // Determine le nombre de mots de 6 bits a codes restants, donc le nombre
    // de = a mettre en fin d encodage
    unsigned short len;
    FILE *o_s, *i_s;
 
    // Test pour une erreur de flux en lecture
    i_s=fopen(strSrcFile,"rb");
    if(!i_s) {printf("\\n\\n\\a+ Erreur : %s",ERROR_01); exit(-1);}
 
    // Test pour une erreur de flux en ecriture
    o_s=fopen(strDstFile,"wb");
    if(!o_s) {printf("\\n\\n\\a+ Erreur : %s",ERROR_02); exit(-1);}
 
    if( strcmp(strSrcFile,"-tmp.-tmp") )
        printf("\\nEncoding %s to %s...",strSrcFile,strDstFile);
 
    do
    {
        len=0;
        rep[0]=fgetc(i_s);
        rep[1]=fgetc(i_s);
        rep[2]=fgetc(i_s);
 
        if( rep[0] < 0 ) { len=0; rep[0] = 0; break; }
        if( rep[1] < 0 ) { len++; rep[1] = 0; loop=false; }
        if( rep[2] < 0 ) { len++; rep[2] = 0; loop=false; }
 
        EncodeBase64(rep,cod,len);
 
            // Une erreur d ecriture > exit.
            if( fputc(ConstChar[cod[0]],o_s) < 0 )
            {
            printf("\\n\\n\\a+ Erreur : %s",ERROR_03);
                exit(-1);
            }
            else
            {
                index++;
            }
 
        if(index==iCRLF)   {fprintf(o_s,"/r\\n");index = 0;}
        fputc(ConstChar[cod[1]],o_s);   index++;
            if(index==iCRLF)   {fprintf(o_s,"/r\\n");index = 0;}
        fputc(ConstChar[cod[2]],o_s);   index++;
            if(index==iCRLF)   {fprintf(o_s,"/r\\n");index = 0;}
        fputc(ConstChar[cod[3]],o_s);   index++;
            if(index==iCRLF)   {fprintf(o_s,"/r\\n");index = 0;}
 
    } while( loop == true );
 
    if( strcmp(strSrcFile,"-tmp.-tmp") )
        printf("done.\\n");
    else
        printf("\\n");
 
    fclose(i_s);
    fclose(o_s);
}
 
 
 
//-- Encode en base 2 ----------------------------------------------------------
void DecToBin(int n, int *CODE, int NbrBitsLength)
{
    int i,nb=NbrBitsLength;
    for(i=nb-1;i>=0;i--)
    {
        CODE[i]=n%2;
        n/=2;
            if(n<0) break;
    }
}
 
 
 
//-- Fonction puissance --------------------------------------------------------
int powa(int x, int n)
{
    int i=0,r=1;
    for(i=0;i<n;i++)
    {
        r*=x;
    }
    return(r);
}
 
 
/*-- Encode en base 10 depuis la base 2 ----------------------------------------
 
                             2 ^ 7 = 128 * 1 = 128
  8 - i + Start - 1                + 2 ^ 6 = 64  * 1 = 192
                           + 2 ^ 5 = 32  * 1 = 224
  8 -  8 +  8 - 1 = 7                  + 2 ^ 4 = 16  * 1 = 240
  8 -  9 +  9 - 1 = 6                  + 2 ^ 3 = 8   * 1 = 248
  8 - 16 + 16 - 1 = 7                  + 2 ^ 2 = 4   * 1 = 252
  8 - 17 + 17 - 1 = 6                  + 2 ^ 1 = 2   * 1 = 254
  on revient en 7 à chaque fois...         + 2 ^ 0 = 1   * 1 = 255
 
  Donc on a bien un octet code sur 8 bits (0 -> 255 => 0 -> FF)
*/
int BinToDec(int *CODE, int Start, int Last)
{
    int i,R=0;
    for(i=Start;i<=Last;i++)
    {
        R+=CODE[i]*(int)powa(2,8-i+Start-1);
    }
    return(R);
}
 
 
 
//-- Decode en base 64 ---------------------------------------------------------
void DecodeBase64(int src[4], int dst[3])
{
    int i,j,k,step=-6;
    int tmp[6],buff[24];
 
    for(j=0;j<4;j++)            // Dans nos quatres mots de 8 bits...
    {                   // on cherche la correspondance
        step+=6;                        // avec l alphabet base 64
        for(i=0;i<65;i++)               // et on rempli le buffer 6 bits par 6
        {                       
            if(src[j]==ConstChar[i])
                {
                if(i==64)               // Si on est sur le caractère de
                    {                   // complément  =  alors on est sur
                    src[j]=0;           // le dernier octet
                    }
                        else
                        {
                            DecToBin(i,tmp,6);      // On met en binaire l équivalent du
                            for(k=step;k<step+6;k++)    // caractère lu et trouvé dans la base
                            {               // puis on le sauvegarde par mots
                        buff[k]=tmp[k%6];   // de 6 bits dans une variable
                            }               // temporaire pour ensuite regrouper
                        }                   // les quatres mots de 6 bits en
                }                       // un seul buffer de 24 bits
        }
    }
 
    dst[0]=BinToDec(buff,0,7);  // qu on pourra ici décomposer
    dst[1]=BinToDec(buff,8,15); // en 3 mots de 8 bits
    dst[2]=BinToDec(buff,16,23);    //
 
}
 
 
 
//-- Lit le fichier et le décode dans le fichier destination -------------------
void DecodeFile(char strSrcFile[256], char strDstFile[256])
{
    bool loop=true;
    int rep[4]={0,0,0,0};
    int dcd[3]={0,0,0},tmp;
    unsigned short len;
    FILE *i_s=fopen(strSrcFile,"rb");
    FILE *o_s=fopen(strDstFile,"wb");
    if(!i_s) {printf("\\n\\n\\a+ Erreur : %s",ERROR_01); exit(-1);}
    if(!o_s) {printf("\\n\\n\\a+ Erreur : %s",ERROR_02); exit(-1);}
 
    if( strcmp(strSrcFile,"-tmp.-tmp") )
        printf("\\nDecoding %s to %s...",strSrcFile,strDstFile);
    else
        printf("\\n");
 
    do
    {
        len=0;
 
            // Un caractere est mis dans une variable temporaire pour tester si on
            // est sur un saut de ligne, si c est le cas on lit le caractere suivant
            // et on sauvegarde le caractere d apres dans notre tampon REP, autrement
            // on sauvegarde directement dans le tampon REP
 
        tmp=fgetc(i_s); if(tmp==0xD) { fgetc(i_s); rep[0]=fgetc(i_s); }
                    else rep[0]=tmp;
        tmp=fgetc(i_s); if(tmp==0xD) { fgetc(i_s); rep[1]=fgetc(i_s); }
                    else rep[1]=tmp;
        tmp=fgetc(i_s); if(tmp==0xD) { fgetc(i_s); rep[2]=fgetc(i_s); }
                    else rep[2]=tmp;
        tmp=fgetc(i_s); if(tmp==0xD) { fgetc(i_s); rep[3]=fgetc(i_s); }
                    else rep[3]=tmp;
 
        if( rep[0] < 0 ) { rep[0] = 0; break; }
        if( rep[1] < 0 ) { rep[1] = 0; loop=false; }    // Si le caractere est
        if( rep[2] < 0 ) { rep[2] = 0; loop=false; }    // celui de fin de fichier
        if( rep[3] < 0 ) { rep[2] = 0; loop=false; }    // EOF == -1
 
        DecodeBase64(rep,dcd);              // On decode les 4 mots
                                                // en 3 octets
        // Une erreur d ecriture > exit.        // Puis on les ecrits en
            if(fputc(dcd[0],o_s)<0) {printf("\\n\\n\\a+ Erreur : %s",ERROR_03); exit(-1);}
        if( rep[2] > 0 ) fputc(dcd[1],o_s);         // verifiant bien qu ils
        if( rep[3] > 0 ) fputc(dcd[2],o_s);     // ne proviennent pas de =
 
                                // le saut de ligne
    } while( loop == true );                // Tout ceci tant que
                                // on est pas a la fin.
 
    if( strcmp(strSrcFile,"-tmp.-tmp") ) printf("done.\\n");
 
    fclose(i_s);
    fclose(o_s);
}
 
 
 
//-- Synopsis ------------------------------------------------------------------
void Usage(int more)
{
    if(more)
    printf("\\nConvertisseur Base64Encoded (par Nicolas@secureinfo.free.fr)"
          "\\nB64 [-f|-s] [-e|-d] [input_file|chaine_de_caractere] [output_file] [[-l 80]]"
          "\\n                                              "
          "\\n-f : specifie le traitement de fichier        "
          "\\n-s : specifie une chaine de caractere         "
          "\\n-e : encodage en base 64                      "
          "\\n-d : decodage en base 64                      "
          "\\n-l : (optionel) longueur de la ligne encodee  \\n"
 
          "\\nEncodage d un fichier ............: b64 -f -e test.txt code.txt"
          "\\nDecodage d un fichier ............: b64 -f -d code.txt decode.txt"
          "\\nLigne de 50 caracteres ...........: b64 -f -e test.txt code.txt -l 50"
          "\\nPar defaut le programme encodera un fichier sur une ligne de 72 caracteres"
          "\\nle minimum de caractere sur une ligne est de 4 caracteres (24bits, 3octets)"
          "\\nEncodage d une chaine de caractere: b64 -s -e ABCD"
          "\\nDecodage d une chaine de caractere: b64 -s -d QUJDRA==\\n");
    else
    printf("\\nConvertisseur Base64Encoded"
          "\\nB64 [-f|-s] [-e|-d] [input_file|chaine_de_caractere] [output_file] [[-l 80]]\\n"
          "\\nPar defaut le programme encodera un fichier sur une ligne de 72 caracteres"
          "\\nle minimum de caractere sur une ligne est de 4 caracteres (24bits, 3octets)\\n");
}
 
 
 
//-- Ecriture du fichier temporaire --------------------------------------------
void WriteInFile(char *Buffer, char *FileName)
{
    FILE *flux;
    flux=fopen(FileName,"wb");
    if(!flux) {printf("\\n\\n\\a+ Erreur : %s",ERROR_02); exit(-1);}
    fprintf(flux,"%s",Buffer);
    fclose(flux);
}
 
 
 
//-- Affichage du fichier temporaire -------------------------------------------
void ViewFile(char *FileName)
{
    int rep;
    FILE *flux;
    flux=fopen(FileName,"rb");
    if(!flux) {printf("\\n\\n\\a+ Erreur : %s",ERROR_01); exit(-1);}
    while( (rep=fgetc(flux)) != EOF ) printf("%c",rep);
    fclose(flux);
    unlink("-tmp.-tmp");
    unlink("_tmp._tmp");
}
 
 
 
//-- Determine l operation a effectuer (encodage, decodage) --------------------
#define is_ok      strlen(argv[3])>=1   /
        && strlen(argv[3])<=256 /
        && strlen(argv[4])>=1   /
        && strlen(argv[4])<=256 
 
#define is_ok_s    strlen(argv[3])>=1   /
        && strlen(argv[3])<=1024/
 
void SelectOperation(int argc, char *argv[])
{
    // Traitement d une chaine de caractere
    if( argc == 4 )
    {
            if( ! strcmp(argv[1],"-s") )
            {
                if( ! strcmp(argv[2],"-e") )    // -> Encode
            {                               // la chaine de caractere
                    if( is_ok_s )
                        {       
                            // Ecriture dans un fichier temporaire
                            WriteInFile(argv[3],"-tmp.-tmp");
                    EncodeFile( "-tmp.-tmp" , "_tmp._tmp" , DEFAULT_WIDTH );
                            ViewFile("_tmp._tmp");
                    printf("\\n\\n");
                        }
                }
                if( ! strcmp(argv[2],"-d") )    // -> Decode
            {                               // la chaine de caractere
                    if( is_ok_s )
                        {
                            WriteInFile(argv[3],"-tmp.-tmp");
                    DecodeFile( "-tmp.-tmp" , "_tmp._tmp" );
                            ViewFile("_tmp._tmp");
                    printf("\\n\\n");
                        }
                }
            }
            return;
    }
 
    // Il s agit d encoder ou de decoder un fichier
    if( argc == 5 )
    {
            if(!strcmp(argv[1],"-f"))               // Fichier
            {
                if(is_ok)
                {
                    if( ! strcmp(argv[2],"-e") )            // -> Encode le fichier
                        EncodeFile( argv[3] , argv[4] , DEFAULT_WIDTH );
                    if( ! strcmp(argv[2],"-d") )            // -> Decode le fichier
                        DecodeFile( argv[3] , argv[4] );
                }
            }
            return;
    }
 
 
    // Il s agit d encoder avec une largeur specifiee
    if( argc == 7 )
    {
            if( ! strcmp(argv[1],"-f") )
            {
                if( is_ok )
                {
                    if( ! strcmp(argv[2],"-e") )
                    if( ! strcmp(argv[5],"-l") )
                                if( atoi(argv[6]) > 4)
                                    EncodeFile( argv[3] , argv[4] , atoi(argv[6]));
                                else
                                    {Usage(0);return;}
            }
            }
            return;
    }
 
    // Affiche l aide en complet selon le cas
    if( argc == 2 )
        if( ! strcmp(argv[1],"-h") )
        {Usage(1);return;}
    Usage(0);
}
 
 
 
//-- Programme principal -------------------------------------------------------
int main(int argc, char *argv[])
{
    // Selectionne l operation a effectue selon les arguments
    SelectOperation(argc, argv);
}
 




0x02. UTILITE DANS LES SCRIPTS



Tout simplement de la manière suivante :


 
#!/bin/bash
 
 
b64e="/usr/local/bin/b64e"
 
# Decode la chaine base 64 encodée
password=$($b64e -s -d "GS8wT5zuGSVjTSVgGSGrYgt0vsd+8sof8gXxG58fTSGuYSVhT5z4TSA4" |cut -d ';' -f2)
 
# Exemple : connexion via MySQL 
mysql -uroot -hlocalhost -p$password
 


Après, on peut renforcer le mot de passe en multipliant les encodage ou en changeant les 8 en _ par exemple.
La source étant présente on peut en faire ce qu'on veut.





0x03. ATTAQUER UNE BASE 64 ALTEREE



Pas compliqué, il suffit de substituer à une base 64 normale. Le but de cet article n'est pas d'attaquer une base 64 décalée, mais de protéger du "shoulder hacking", ou de l'attaque qui consiste à regarder par dessus l'épaule.

De plus "GS8wT5zuGSVjTSVgGSGrYgt0vsd+8sof8gXxG58fTSGuYSVhT5z4TSA4" est plus long à retenir que "password"

Exemple :


# b64 -s -e 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLz0=

# b64e -s -e 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
iXFmdzEsdjUFZ6PGSXweXooZXtdEE+vCDEkUCaT6HDHp9s+K9grP2ac48%FfvlEgvyUw75ArG5GjTSCyYm6LBfj3

# On peut déduire que : 
Q = i 
U = X 
...

Alphabet_norm="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
Alphabet_code="AQWmzoslVFRBGTYeidZSXED%CH928v7NJUI56+apqkKLOPM04rufjtgyhwnxbc1@3"


   =>   Écrit par : Nicolas, le 26 octobre 2010


 
Mots clés :  
  c 
  
  encoding 
    >   Articles connexes :

Comment gagner du temps sur Internet



/tmp et /var/log en noexec sur macOS



1105251