Enjeux de cette protection

L'accès au setup, le menu de configuration du BIOS, ou l'accès au système d'exploitation peut être protégé par mot de passe.

Desktop

Sur un desktop, un ordinateur de bureau, l'accès au setup est restreint généralement pour éviter qu'un utilisateur modifie les paramètres inconsidérément ou qu'il puisse démarrer sur une disquette.

Laptop

Dans le cas d'un laptop ou portable, le mot de passe a pour but d'interdire l'accès au système d'exploitation. Il est renforcé par un mot de passe protégeant l'accès aux données du disque dur.

Stockage des mots de passe

Cmos NVRAM

Le mot de passe est stocké dans une mémoire NVRAM, Non-Volatile Random Access Memory, de technologie Cmos, Complementary Metal Oxide Semiconductor. Il s'agit généralement d'une mémoire de petite taille, 128 octets, accessible octet par octet, alimenté par une pile au lithium pour maintenir la mémoire. Le composant électronique assurant cette fonction est aussi l'horloge temps réel, la RTC. Une rupture de l'alimentation de la Cmos et son contenu est effacé ainsi que le mot de passe s'y trouvant. Pour cette raison, le stockage du mot de passe dans la Cmos se fait principalement sur les desktops où la sécurité n'est pas primordiale.

Les ancêtres

Voici quelques manipulations pour effacer la mémoire de ces composants, mélant l'horloge RTC et une batterie, devenus assez rares pour certains.

Chips & Technologies P82C206

Ce composant souvent soudé à la carte mère s'efface en connectant les pattes 12 (GND,la masse) et 32 (5.0V) ou 74 (GND) et 75 (5.0V) pendant quelques secondes, l'ordinateur hors-tension. Les connecteurs 12 et 32 sont les premiers et derniers du bas de la puce et les connecteurs 74 et 75 sont les deux connecteurs en haut à droite.

OPTi F82C206

Lui aussi soudé sur la carte mère, il faut relier les connecteurs 3 (troisième à partir de la gauche) et 26 (5ème à partir de la droite) du bas du composant pour effacer son contenu.

Dallas DS1287 & benchmarq bp3287MT

La mémoire ne peut pas être effacer. Il faut soit la reprogrammer, soit changer le composant.

Dallas DS1287A & benchmarq bq3287AMT

La pile intégrée doit durer dix ans. la Cmos peut être effacer en conntectant les pattes 12 (GND) et 21 (RAM Clear). Les connecteurs sont numérotés de 1 à 24 dans le sens inverse des aiguilles d'une montre à partir du bas à gauche. La patte 12 est la première à partir de la droite en bas. Le connecteur 21 est le troisième à partir de la gauche en haut.

Motorola MC146818AP

Ce composant rectangulaire à 24 connecteurs ne possède pas de pile, il suffit de le retirer quelques secondes de son support pour effacer sa mémoire.

Dallas DS12885S and benchmarq bq3258S

Relier les connecteurs 12 (GND) et 20 effacera la mémoire. La patte 12 est la première en bas à droite et la 21 la troisième depuis la gauche en haut.

EEPROM

Pour les portables, les constructeurs ont recherchés assez rapidement un moyen plus fiable de stocker le mot de passe. Ils l'ont trouvé avec les EEPROM, Electronically Erasable Programmable Read Only Memory. Il s'agit d'une mémoire reprogrammable non volatile, elle se programme octet par octet contrairement à une mémoire flash qui fonctionne par bloc. L'information peut se maintenir une dizaine d'année hors tension et supporter 100 000 ecritures. En pratique, vous aurez changer d'ordinateur bien avant. On retrouve plusieurs modèles d'EEPROM allant jusqu'à une capacité de quelques kilo-octets: 24c01 1ko, 24c02 2ko... Pour récupérer son contenu, ignorant le câblage réaliser par le constructeur, il faudrait dessouder l'EEPROM de la carte mère, la placer dans un lecteur d'eeprom et connecter celui-ci à un autre ordinateur. C'est le B.A.BA pour un électronicien mais c'est assez risqué pour un simple particulier ayant perdu son mot de passe... Cela en fait une protection assez efficace. Certains constructeurs vont jusqu'à recommander de changer la carte mère en cas de perte du mot de passe.

Remarque: sur certains modèles d'eeprom, il est possible d'effacer son contenu en appliquant une tension sur le connecteur adéquat mais cela signifie effacer aussi le numéro de série et d'autres paramètres qui peuvent rendre le portable inutilisable. Il ne faut pas oublier non plus le risque à procéder sans extraire l'eeprom de la carte mère.

CRC pour vérifier l'intégrité

L'intégrité des donnés est validée à l'aide d'un CRC, une somme de contrôle. Lors du démarrage du PC, le BIOS calcule le checksum des donnés, une simple addition sur 16 bits, et le compare à la valeur du CRC stockée dans la mémoire. Si les valeurs sont différentes, le contenu de la mémoire a été corrompu, l'ordinateur ne doit plus en tenir compte.

La somme de contrôle standard des Cmos/RTC couvre la zone 0x10 à 0x2D et est stockée en 0x2E (MSB: partie haute) et 0x2F (LSB: partie basse). C'est pourquoi on trouve souvent comme conseil d'écrire une valeur en 0x2E pour supprimer un mot de passe. Voici comment le faire avec debug sous MS-DOS.

DEBUG   [Enter]
O 70 2E [Enter]
O 71 0  [Enter]
Q       [Enter]

En fait, modifiez n'importe quelle valeur de la configuration ISA entre 0x10 et 0x2F et le CRC ne correspondera plus. Cette méthode va supprimer en conséquence les paramètres du BIOS mais ne supprimera pas le mot de passe si celui-ci est dans une EEPROM.

Disque Dur

Les BIOS des portables permettent de mettre un mot de passe pour protéger le disque dur. Ou est-il stocké ? S'il était stocké dans la Cmos ou dans une EEPROM sur la carte mère, il suffirait de mettre le disque dans un autre portable ou sur un PC avec un adaptateur pour accéder aux données. Pour cette raison, le mot de passe est stocké sur le disque dur. Il est géré directement par celui-ci selon la norme ANSI X3.298-1997, AT Attachment 3 Interface. Comme il y a deux niveaux de mot de passe High et Maximum, le constructeur peut choisir le niveau High et ainsi en cas de perte du mot de passe de l'utilisateur, le constructeur peut débloquer le disque dur avec le Master password. Une attaque par force brute a peu de chance d'aboutir car le disque va se bloquer après un certain nombre de tentative. Il faudra le mettre hors tension puis à nouveau sous tension pour tenter un nouveau mot de passe.

Cependant, certains sociétés proposent de récupérer les données des disques durs protégés par mot de passe. Equipée de salle blanche de classe 100, elles peuvent ouvrir les disques durs sans craindre les poussières et lire directement les données cylindre par cylindre.

Les Backdoors

Alors comment faire pour supprimer un mot de passe ? Quels sont les moyens mis en oeuvre par les constructeurs pour éviter qu'un utilisateur légitime ne se retrouve avec un coûteux presse-papier ?

Reset password jumper/Effacer la Cmos

Lorsque le mot de passe est stocké dans la Cmos, on l'a vu, il suffit de modifier le checksum ou les données de la Cmos pour que le mot de passe soit supprimé. L'inconvénient est que tout les paramètres du BIOS sont aussi effacés, c'est pourquoi certains constructeurs ont trouvés une solution plus élégante. Ils ont disposés un jumper, un cavalier sur la carte mère, à activer pour annuler la demande du mot de passe. L'utilisateur peut alors choisir un nouveau mot de passe ou le supprimer.

Mot de passe universel

Beaucoup de personnes ont entendu parler de mots de passe universels pour chaque BIOS, mais est-ce une légende ou la réalité ? En fait, c'est une ancienne réalité. Sur les Award 4.50 il a effectivement un mot de passe pour débloquer le BIOS. Il s'agit de AWARD_SW. Comme l'algorithme utilisé par les BIOS Award transforme un mot de passe en un entier sur 16 bits (Cette méthode sera vu par la suite), il y a de nombreux autres mots de passe qui fonctionne aussi bien: lkwpeter, Syxz, j256, j262, j322, 01322222, 589589, 589721, 595595, aPAf, ZJAAADC, djonet, Wodj... ou encore d8on qui ne pose pas de difficulté à être tapé sur un clavier AZERTY. Cette profusion de code a été à l'origine de dérives lorsque les différents claviers non US ont été pris en compte, et par déformation, des listes de pseudo mot de passes universels pour Ami, Compaq, Phoenix se sont retrouvés sur Internet, mais il s'agit souvent de mot de passe par défaut.

Depuis les Award 4.51, il n'y a plus de mot de passe générique sauf si le constructeur de la carte mère en configure un. Il s'agit d'une option lors du paramétrage de l'image du BIOS avant de le flasher. A ma connaissance, cela n'a été utilisé que sur les cartes mères SOYO avec comme mot de passe universel SY_MB.

Toshiba: Keydisk

Généralement, les constructeurs de portables ont préférés trouver des solutions obligeant l'utilisateur à passer par eux aussi bien pour s'assurer que le propriétaire du portable était bien légitime que pour lui facturer le service. Les premiers portables Toshiba disposaient d'un système assez sympathique pour limiter les risques d'oubli du mot de passe. Juste après avoir mis un mot de passe, l'utilisateur était convié à créer une disquette de secours qui permettait de supprimer ce mot de passe. Le BIOS modifiait le contenu de la disquette et y stockait la clé équivalente au mot de passe, ce qui rendait cette disquette utilisable uniquement sur cet ordinateur. Cette disquette a pris le nom de Keydisk. Certains utilisateurs ont découverts qu'avec l'aide d' un éditeur hexadécimal, ils pouvait modifier le second secteur de cette disquette pour y écrire KEY suivi de deux zéros, le premier secteur étant le secteur de boot. A ce moment là, la valeur 00 00 étant une valeur spéciale, la disquette devenait universelle, elle permettait de débloquer n'importe quel portable Toshiba.

Toshiba: Loopback

Comme cette backdoor a été rapidement connue, Toshiba en a changée. Les ordinateurs suivants ont intégrées un nouveau moyen permettant au constructeur de supprimer ce mot de passe. Lors du démarrage du portable, le BIOS envoie un signal sur la sortie du port parallèle et vérifie s'il le récupère sur l'entrée, si c'est le cas, aucune vérification du mot de passe n'est effectuée. Quelques fils sont nécessaires pour relier ensemble la sortie et l'entrée afin de boucler le signal de la sortie vers l'entrée. Ce montage en boucle porte le nom de Loopback, on relie les fils 1-5-10, 2-11, 3-17, 4-12, 6-16, 7-13, 8-14, 9-15, 18-25.

DB25

Système par identifiant

Toutes ces méthodes pour supprimer les mots de passe ne restaient pas secrètes très longtemps, alors une autre méthode a été trouvée. Le client n'a qu'à communiquer le numéro de série (du style 12345**-D35B pour un Dell) ou un code affiché par le portable, envoyer par Fax par exemple une preuve d'achat l'identifiant comme propriétaire légitime, passer à la caisse et le service technique peut lui communiquer par téléphone un code permettant de débloquer son portable. Ce code, propre au numéro donné par le client, est généré par un algorithme secret. L'utilisateur n'a plus qu'à l'entrer sur son ordinateur, celui-ci vérifie sa validité et supprime le mot de passe. L'utilisateur est content, il a récupéré l'accès à son portable et le constructeur ne lui a pas pour autant donné le moyen d'accéder à tout les portables de la marque. Ce système se retrouve entre autres sur les portables Hewlett-Packard et Dell.

Accéder à la Cmos

Passons aux choses techniques. Comment un programme peut-il accéder au contenu de la mémoire Cmos ? Si vous avez bonne mémoire, la Cmos est avant tout le composant hébergeant l'horloge temps réel. Ce n'est qu'après que la Cmos a été utilisé pour stocker des paramètres du BIOS puis le mot de passe. L'accès à la Cmos est donc standardisé. On accède à son contenu octet par octet.

Dos

Pour lire un octet de la Cmos ou plus exactement une valeur sur 8 bits de la mémoire connectée à l'horloge temps réel, on envoie sur le port 0x70 l'adresse de la cellule que l'on veut lire. Puis, la valeur est lu sur le port 0x71. Pour écrire un octet dans la Cmos, c'est presque pareil, on envoie l'adresse sur le port 0x70 et la valeur sur le port 0x71. Au niveau de la machine, les instructions assembleurs in et out sont utilisées. C'est ainsi que l'on procède sous DOS. Idem pour Windows 9x et Me, il ne faut pas oublier que ce ne sont que des surcouches du DOS.

byte read_cmos(const int cell)
{
  outportb(0x70,cell);
  return inportb(0x71);
}

void write_cmos(const int cell, const byte value)
{
  outportb(0x70,cell);
  outportb(0x71,value);
}

Windows

Sous Windows, entendons par là Windows NT, W2K ou XP, les choses sont plus complexes car le système d'exploitation ne laisse pas n'importe qui dialoguer directement avec le hardware. Les instructions in et out sont des instructions privilégiées, elles sont interdites dans un programme utilisateur. En tant qu'administrateur, il faut installer un driver qui autorisera explicitement le programme à accéder à certains ports.

Linux

Sous Linux, c'est plus simple, il n'y a pas besoin de driver. En tant qu'utilisateur root, l'équivalent d'administrateur sous Unix, le programme n'a qu'à demander l'autorisation d'accès à ces ports avec la fonction ioperm.

  if (ioperm(0x70,2,IO_READ|IO_WRITE))
  {
    printf("Need to be run as root to access the Cmos.\n");
    exit(1);
  }
Il est aussi possible de passer par un device sous Linux.

BSD

Sous BSD, la Cmos est accessible une fois le device /dev/io ouvert.

    cmos_fd = fopen("/dev/io", "r");

Gestion du clavier

Maintenant que l'on sait comment accéder à la Cmos, il est tant de se poser une question de base: Comment sont lus les caractères que l'on tape sur son clavier ? Chaque touche est numéroté. Cette valeur s'appelle le ScanCode. Sur un clavier AZERTY, 'A' vaut 0x10, 'Z' vaut 0x11, 'E' 0x12 et ainsi de suite. Il faut donc connaître le type de clavier (QWERTY, AZERTY...) pour convertir un ScanCode en une valeur ASCII, ainsi on peut utiliser une table de correspondance.

  static const byte tbl_fr[255]=
  { ' ',' ','1','2','3','4','5','6',
    '7','8','9','0',')','=',' ',' ',
    'A','Z','E','R','T','Y','U','I',
    'O','P',' ','$',' ',' ','Q','S',
    'D','F','G','H','J','K','L','M',
    '%','ý',' ','*','W','X','C','V',
    'B','N',',',';',':','/',' ','*',
    ' ',' ',' ','f','f','f','f','f',
    'f','f','f','f','f',' ',' ','7',
    '8','9','-','4','5','6','+','1',
    '2','3','0','.',' ',' ','>',' '};

Par exemple, la suite de ScanCodes 0x19 0x2C 0x20 entrée sur un clavier français devient, en utilisant cette table de convertion, la chaîne ASCII PWD.

Selon les BIOS, le mot de passe est soit utilisé sous sa forme d'une chaîne ASCII, soit sous la forme d'une suite de ScanCode.

Ordre et positions des données

Certains champs (date, heure, siecle...) sont standardisés.

00: Secondes
01: Secondes, Alarme
02: Minutes
03: Minutes, Alarme
04: Heures,
05: Heures, Alarme
06: Jour de la semaine   (01-07 Dimanche=1)
07: Jour du mois
08: Mois
09: Année

Les champs présentées dans cette table sont au format BCD Binary Coded Decimal. S'il est 10 heures, la position 4 de la Cmos contiendra la valeur hexadécimal 0x10.

Un constructeur peut stocker le mot de passe à peu près n'importe où dans la Cmos en dehors de ces champs et n'importe comment: soit le mot de passe est stocké de façon linéaire: chaque caractère du mot de passe se suit dans la mémoire Cmos, soit le mot de passe est stocké sous forme d'entier de 16 bit, le mot de passe ABCD devient BADC, ou encore le mot de passe est stocké de façon non linéaire, il est éparpillé dans la Cmos.

Cryptage/codage des mots de passe

Quelques exemples sans codage

Certains BIOS sauvegardent le mot de passe directement dans la Cmos. Voici un exemple pour le BIOS Phoenix 110A03 des Dell Optiplex GXi. Le mot de passe administrateur est QWERTYU et le mot de passe utilisateur ASDFGHJ.

Une image brute de la Cmos ne révèle rien à première vu.

00: 20 36 56 13 12 05 05 19 01 99 26 02 50 80 00 00  | 6V      O& P   |
10: 40 9F F0 00 03 80 02 00 FC 37 00 00 00 1E 1F 20  |@        7      |
20: 21 22 23 24 E7 11 02 25 00 00 00 00 00 00 05 8D  |!"#$   %       i|
30: 00 FC 19 80 10 10 A6 19 10 11 12 13 14 15 16 85  |               a|
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |                |
50: 00 00 F0 39 00 8E 00 40 00 00 00 00 00 00 00 00  |   9 A @        |
60: 00 00 00 00 00 00 00 4D 31 51 42 57 68 FE 09 A0  |       M1QBWh  a|
70: 01 82 00 80 00 01 04 00 00 00 00 00 00 00 00 17  | e              |

Mais si on demande un affichage avec une convertion des ScanCodes, le mot de passe apparait:

00: 20 36 56 13 12 05 05 19 01 99 26 02 50 80 00 00  |D">RE44P  L12   |
10: 40 9F F0 00 03 80 02 00 FC 37 00 00 00 1E 1F 20  |f   2 1  *   ASD|
20: 21 22 23 24 E7 11 02 25 00 00 00 00 00 00 05 8D  |FGHJ W1K      4 |
30: 00 FC 19 80 10 10 A6 19 10 11 12 13 14 15 16 85  |  P QQ PQWERTYU |
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |                |
50: 00 00 F0 39 00 8E 00 40 00 00 00 00 00 00 00 00  |       f        |
60: 00 00 00 00 00 00 00 4D 31 51 42 57 68 FE 09 A0  |       6N3f   8 |
70: 01 82 00 80 00 01 04 00 00 00 00 00 00 00 00 17  |      3        I|

On peut obtenir ce double affichage avec la commande cmospwd /d. CmosPwd est disponible à l'adresse http://www.cgsecurity.org/cmospwd.html.

A titre d'exercice, vous pouvez retrouver la date à laquelle cette image du BIOS a été prise.

Award

Les BIOS Award sont parmi les plus fréquents. Ils utilisent tous le même algorithme pour convertir un mot de passe en une valeur sur 16 bits.

u16 award(const char*password)
{
  int i;
  u16 crc=0;
  for(i=0;password[i];i++)
  {
    crc=(crc<<2)| ((crc & 0xC000) >> 14);
    crc+=password[i];
  }
  return crc;
}

La somme de contrôle, le CRC, est initialisé à zéro. A chaque caractère du mot de passe correspond une itération. A chaque itération, le CRC sur 16 bits subit une rotation vers la gauche de deux bits, c'est l'instruction rol en assembleur. Puis, on additionne au CRC le caractère du mot de passe avant de recommencer.

Que ce soit un mot de passe utilisateur ou un mot de passe superviseur, il subit la même transformation. Le CRC correspondant est stocké dans la Cmos dans une zone variant selon les versions du BIOS Award. Du fait de la réduction du mot de passe en un nombre de 16 bits, il y a de multiples mots de passe ayant la même valeur cryptée. Par exemple, si vous prenez test comme mot de passe, vous pouvez aussi entrer eludez ou quel, faites juste attention à l'interprétation du clavier, le BIOS validera votre accès!

Comme différents mots de passe peuvent avoir la même somme de contrôle, il est impossible de retrouver à coût sûr le mot de passe d'origine. Une attaque par force brute permet de trouver un mot de passe équivalent à celui protégeant la machine. L'algorithme étant très simple, le résultat est immédiat.

Voici le programme qui m'a permis de trouver des mots de passe équivalents au mot de passe test et de vérifier les équivalents à AWARD_SW:

#include <stdio.h>
typedef short int Bit16u;
#define LINE_SIZE 500

Bit16u rol(Bit16u n)
{
  return (n<<2)| ((n & 0xC000) >> 14);
}


int award(const char* chaine)
{
  int i;
  Bit16u res=0;
  for(i=0;(chaine[i]!=0) && (i<8);i++)
   res=(rol(res) + chaine[i])&0xFFFF;
  return res;
}

int test_liste(const char* nom_wordlist, Bit16u valref)
{
  FILE *f_in;
  char ligne[LINE_SIZE];
  printf("Val2crack %04X\n", valref);
  if((f_in=fopen(nom_wordlist,"r"))==NULL)
  { printf("\nUnable to open %s", nom_wordlist); return 1; }
  while(!feof(f_in) && (fscanf(f_in, "%s", ligne)!=0))
  {
    if(award(ligne)==valref) printf("%s\n", ligne);
  }
  return fclose(f_in);
}

int main(int argc, char **argv)
{
  if(argc<3)
  { printf("Usage : award wordlist password\n"); return 1; }
  return test_liste(argv[1], award(argv[2]));
}
Et voila le résultat:

./award bigdico test
Val2crack 2590
test
doutez
eludez
grogginess
quel
rood
test

AMI

Les BIOS AMI chiffrent le mot de passe. Les anciennes versions utilisaient le code ascii de chaque touche et les versions récentes (AMI WinBIOS) utilisent le ScanCode. L'algorithme est initialisé avec une valeur précédent le mot de passe dans la Cmos ou avec la valeur 0x80 selon les versions.

Voici comment le décrypter:

int generic_ami(unsigned char *value, const int lng, const int methode,const int val_stop)
{
  int pos;
  unsigned char old_val,new_val;
  switch(methode)
  {
    case ALGO_AMI_F0: 	new_val=value[0] & 0xF0; break;
    case ALGO_AMI: 	new_val=value[0]; break;
    case ALGO_AMI_80: 	new_val=0x80; break;
  }
  for(pos=1;pos<lng;pos++)
  {
    int i;
    old_val=new_val;
    new_val=value[pos];
    if (new_val==val_stop) break;
    for (i=0;i<=255;i++)
    {
      if (new_val==old_val) break;
      if (parity_test(0xE1&new_val)) new_val=(new_val<<1)|1; else new_val<<=1;
    }
    new_val=value[pos];
    if(i>255)
      value[pos-1]=UNKNOWN_CAR;
    else
      value[pos-1]=i;
    value[pos]=val_stop;
  }
  return 0;
}

Le décryptage du mot de passe doit prendre en compte la forme cryptée du caractère précédent (variable old_val). Il modifie la valeur new_val lu dans la Cmos par un succession de shift (décalage) et d'incrémentation selon sa parité avec le masque binaire 0xE1 jusqu'à ce qu'elle prenne la valeur de old_val. Tester la parité d'un nombre revient à compter le nombre de 1 dans son écriture sous forme binaire:

byte parity_test(byte val)
{
  int res=0;
  int i;
  for(i=0;i<8;i++)
  {
    if(val&1)
      res^=1;
    val>>=1;
  }
  return res;
}

En assembleur Intel, c'est plus simple, il suffit de tester le nombre test al,0xE1 et de réagir selon la partition avec un saut conditionneljp label_partite_ok. L'utilisation d'instructions assembleur n'ayant pas d'équivalent direct en C est une des difficultés dans le décryptage des mots de passe des BIOS.

DTK

Le codage utilisé par le BIOS DTK est assez amusant: chaque caractère du mot de passe est codé sur 6 bits. Ainsi un mot de passe de 4 caractères n'utilisera que 3 octets de la Cmos (4*6=3*8=24).

Le mot de passe 11111111 est ainsi codé par 04 10 41 04 10 41. Sous forme binaire, cela donne 0000 0100 0001 0000 0100 0001. Le codage sur 6 bits est facile à voir. Les chiffres de 0 à 9 sont codés par 0x01 à 0x0A, suivi par les lettres de l'alphabet.

Phoenix

Les BIOS Phoenix ont la particularité d'avoir un algorithme pour coder les mots de passe différemment pour quasiment chaque version. C'est ainsi que l'on a un algorithme qui ajoute la constante 0x20 à chaque caractère, un autre qui effectue sur chacun un XOR 0xF0 puis ajoute la valeur du rang.

void generic_phoenix_add(unsigned char *value, const int lng,const unsigned char value_stop)
{
  int i;
  for(i=0;(i<lng)&&(value[i]!=value_stop);i++)
    value[i]+=0x20;
}

void generic_phoenix_xor(unsigned char *value, const int lng,const unsigned char value_stop)
{
  int i;
  for(i=0;(i<lng)&&(value[i]!=value_stop);i++)
    value[i]=(value[i] ^ 0xF0) + i;
}

Etudions un autre algorithme utilisé sur certains Phoenix 4.0 release 6.

Une comparaison entre deux images de la Cmos avec deux mots de passe différents permet de localiser le mot de passe codé.

A        30: 00 FC 20 CC CA 0F 00 00 00 00 00 00 12 10 00 A0  |               a|
QQQQQQQ: 30: 00 FC 20 CC CA 08 04 02 01 80 40 20 12 10 00 A0  |          @    a|

Le mot de passe est stocké en 0x35, il peut faire jusqu'à 7 caractères et il est suivi de zéro. Vous pouvez remarquer que le caractère Q n'est pas codé de la même manière suivant son rang: 08 04 02 01 80 40 20. Regardons la représentation binaire de ces nombres:

08  0000 1000
04  0000 0100
02  0000 0010
01  0000 0001
80  1000 0000
40  0100 0000
20  0010 0000

Le nombre subit une rotation vers la droite supplémentaire lorsque le rang augmente! Pour retrouver le mot de passe dans son intégralité, il ne reste plus qu'à savoir comment décoder le premier caractère.

Le premier caractère Q est codé par la valeur 08. En ASCII, il vaut 51 et le scan code pour un clavier QWERTY 10. Eureka, 10 est le double de 08 (On est en hexa). Les caractères du mot de passe sont lu en scan code et subissent une rotation à droite dès le premier caractère. L'algorithme de décryptage est donc:

void generic_phoenix_dec(unsigned char *value, const int lng,const unsigned char value_stop)
{
  int i;
  for(i=0;(i<lng)&&(value[i]!=value_stop);i++)
    value[i]=rcl8n(value[i],i+1);
}

Toshiba

Sur les Toshiba, l'algorithme utilisé est assez complexe. Comme pour les BIOS Award, le mot de passe est transformé en une somme de contrôle sur 16 bits. Le checksum est initialisé à zéro puis chaque caractère du mot de passe est mêlé à celui-ci par une succession de XOR, ou exclusif, et de shift, décalage binaire.

Bit16u toshiba(Bit16u valcrc, byte car)
{
    byte ah,al,dh,dl;
    al=(byte)valcrc;
    ah=valcrc>>8;
    ah^=car;
    dl=ah;
    dl<<=4;
    ah^=dl;
    dl=ah;
    dl>>=5;
    dl^=ah;
    dh=ah;
    ah<<=3;
    ah^=al;
    dh>>=4;
    ah^=dh;
    al=dl;
    return (ah<<8)|al;
}

Cet algorithme était utilisé à l'époque des Keydisks. Une copie du checksum ainsi calculé était copié dans la Cmos.

Compaq

En dehors de certains BIOS Compaq qui stockent le mot de passe en clair (ScanCode ou code ASCII), j'ai été confronté en 1998 à un algorithme assez redoutable. En utilisant de nombreuses images de la Cmos avec des mots de passe connus, il a été facile de déduire où étaient stockés les mots de passe utilisateur et administrateur en vérifiant les différences entre les sauvegardes.

12345678 70: 9E 02 23 00 00 04 93 2C 04 05 DD 21 08 09 E7 2B  |  #   o,   !   +|
ABCDEFGH 70: 9E 02 23 00 00 04 93 20 2E 20 7B 2A 22 23 35 8D  |  #   o . {*"#5i|

Un changement du mot de passe du setup modifie 9 caractères à partir de la position 0x77, le mot de passe utilisateur modifie lui aussi 9 caractères à partir de la position 0x37.

Certains caractères du mot de passe apparaissent parfois après une convertion ScanCode vers ASCII du contenu de la Cmos.

12345678 70: 9E 02 23 00 00 04 93 2C 04 05 DD 21 08 09 E7 2B  | 1H  3 Z34 F78 *|

Il a fallu l'aide de nombreuses personnes sur Internet pour en venir à bout finalement en mai 2001. On s'est rendu compte que les mots de passe était codés par bloc de 4 caractères, le neuvième caractère étant peut-être un checksum du mot de passe.

11111111 70: 9E 02 23 00 00 04 93 2D 02 02 DD 2D 02 02 DD 1C  | 1H  3 X11 X11  |

La découverte suivante a été de trouver que les 3,4,7 et 8ème caractères étaient codés sur 7 bits.

KILLPWD 30: 00 7C 19 80 00 00 00 3D 26 A6 C4 1B 20 80 32 BA  |  P    fL  $D M |

Dans la forme cryptée du mot de passe KILLPWD, les deux L deviennent 26 A6, la valeur 26 correspond bien à un L en ScanCode mais que vient faire là le A6 ? En supprimant le bit de poids fort, on retrouve la valeur 26 (0xA6 & 0x7F = 0x26) et donc le second L. Cela a permis de déduire le codage sur 7 bits.

La moitié du mot de passe a été obtenue ainsi.

A force de tâtonnement, il est apparu que le 2ème et donc aussi le 6ème caractère était codé par un XOR avec une valeur dépendante du caractère précédent.

AA 70: 9E 02 23 00 00 04 93 0E 00 00 7B 00 00 00 00 89  | 1H  3          |
AB 70: 9E 02 23 00 00 04 93 20 00 00 7B 00 00 00 00 9B  | 1H  3 D        |
AC 70: 9E 02 23 00 00 04 93 3E 00 00 7B 00 00 00 00 B9  | 1H  3 f        |

En ScanCode, un A vaut 0x1E, B 0x30 et C 0x2E. L'égalité 0x0E ^ 0x1E = 0x20 ^ 0x30 = 0x3E ^ 0x2E = 0x10 permet de supposer que le deuxième caractère du mot de passe est codé par un XOR, ici avec la valeur 0x10 si le premier caractère est un A. Une table de correspondance a été établie sur la correspondance entre le premier caractère et sa forme codée et elle donne aussi la valeur avec laquelle il faut effectuer un XOR pour décoder le second caractère. Ainsi, l'intégralité du mot de passe est décryptée alors même que l'algorithme exacte de codage reste inconnu.

CmosPwd

Un programme regroupe ces différentes techniques de décodage, il s'agit de CmosPwd, http://www.cgsecurity.org/cmospwd.html. Sous Windows NT/2000/XP, il faut installer un driver en tant qu'administrateur pour autoriser l'accès aux ports 0x70 et 0x71 controlant la Cmos puis utiliser la version NT de CmosPwd cmospwd_nt. Sous Dos ou Win9x, utiliser la version dos cmospwd. Enfin, sous Linux ou BSD, il vous faut compiler CmosPwd puis l'utiliser en tant qu'utilisateur root.

CmosPwd - BIOS Cracker 4.0, February 7 2002, Copyright 1996-2002
GRENIER Christophe, grenier@cgsecurity.org
http://www.cgsecurity.org/

Keyboard : US
Acer/IBM                     []
AMI BIOS                     [ ]
AMI WinBIOS (12/15/93)       [ ]
AMI WinBIOS 2.5              [ ][  3]
Award 4.5x                   [000100][000033][31000002]
Award 4.5x                   [33][320033][000110]
Award Medallion 6.0          [1200030][000100]
Compaq (1992)                [ ]
Compaq DeskPro               [? 1][]
Compaq                       [][ ]
DTK                          [``0"][x R7t`]
Phoenix A08, 1993            [][]
IBM (PS/2, Activa ...)       [][ ]
IBM Thinkpad boot pwd        [ ]
IBM Thinkpad 765 EEPROM      [][]
IBM 300 GL                   []
Press a key to continue
Pour obtenir un affichage ASCII de la Cmos ainsi qu'un affichage après une converion ScanCode vers ASCII pour un clavier AZERTY français, utiliser cmospwd /d /kfr. Il est aussi possible de sauvegarder la Cmos avec cmospwd /w cmos_backup afin d'étudier son contenu par la suite cmospwd /l cmos_backup ou de recharger une sauvegarde de la Cmos par la suite cmospwd /r cmos_backup.

Conclusion

Les mots de passe du BIOS sont codés avec des algorithmes plus ou moins simples propre au constructeur et parfois même à la version. De plus, il est fréquent que l'emplacement de la sauvegarde de la forme cryptée change avec les versions. En somme, retrouver le mot de passe d'un BIOS n'est pas chose évidente, il est souvent plus simple de l'effacer. Si par hazard, vous rencontrez un BIOS que CmosPwd ne gère pas, je ne peux que vous encourager à rechercher l'algorithme de codage. Cela peut soumettre vos meninges à rude épreuve, croyez mon expérience.


Christophe GRENIER, Auteur de CmosPwd, Consultant Sécurité chez Global Secure.
grenier@cgsecurity.org http://www.cgsecurity.org