Quel est le 6ème caractère du hachage de mot de passe sous Linux, et pourquoi est-ce souvent un slash?

Sous Linux, quel est le sixième caractère du mot de passe stocké dans /etc/shadow ?

Sur ma boîte Linux de style chiot, si j'essaie de générer 100 passwords randoms en utilisant shuf et /dev/urandom , alors le sixième caractère est environ la moitié du time.

Ma question n'est pas à des fins de production, puisque je l'amorce à chaque fois que je viens de CD. Cela signifie-t-il que mon système est mal configuré ou non sécurisé?

J'ai couru le file sur shuf pour voir si c'était un lien busybox .

 file /usr/bin/shuf shuf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, ssortingpped 

Je ne pense pas que shuf soit un lien busybox ici.

 ls -l /usr/bin/shuf -rwxr-xr-x 1 root root 41568 Mar 7 2015 /usr/bin/shuf 

tandis que

 ls -l /bin/wget lrwxrwxrwx 1 root root 14 Apr 29 03:49 wget -> ../bin/busybox 

Voici une idée approximative de ce que j'ai fait:

 # ! / bin / bash ## don't try this on any real computer ## this is not a production script, it is just psuedo code ## with pseudo results to illustrate a point ## for this run of 100 ?random? passwords, ## 46 of the 6th character of the hash stored in ## '/ect/shadow' were '/' function is_this_really_a_random_password () { PERHAPS_RANDOM='' for (( Z=0 ; Z<=8 ; Z++ )) do PERHAPS_RANDOM="$PERHAPS_RANDOM$( shuf --head-count=1 --random-source=/dev/urandom $FILE_OF_SAFE_CHARACTERS )" done echo "$USER_NAME:$PERHAPS_RANDOM" | chpasswd } rm sixth-character-often-forward-slash.txt for (( I=1; I<=100; I++ )) do is_this_really_a_random_password grep --regexp=root /etc/shadow | cut --characters=-40 >> sixth-character-often-forward-slash.txt done 
  root:$5$56YsS//DE$HasM6O8y2mnXbtgeE64zK root:$5$ho8pk/4/A6e/m0eW$XmjA5Up.0Xig1e root:$5$jBQ4f.t1$vY/T/1kX8nzAEK8vQD3Bho root:$5$BJ44S/Hn$CsnG00z6FB5daFteS5QCYE root:$5$Jerqgx/96/HlV$9Wms5n1FEiM3K93A8 root:$5$qBbPLe4zYW$/zXRDqgjbllbsjkleCTB root:$5$37MrD/r0AlIC40n6$8hplf2c3DgtbM1 root:$5$.4Tt5S6F.3K7l7E$dAIZzFvvWmw2uyC root:$5$A4dX4ZlOoE$6axanr4GLPyhDstWsQ9B root:$5$HXAGhryJ/5$40tgmo7q30yW6OF7RUOE root:$5$EzNb9t5d$/nQEbEAQyug7Dk9X3YXCEv root:$5$HHS5yDeSP$LPtbJeTr0/5Z33vvw87bU root:$5$sDgxZwTX5Sm$6Pzcizq4NcKsWEKEL15 root:$5$FK1du/Paf/$hAy8Xe3UQv9HIpOAtLZ2 root:$5$xTkuy/BLUDh/N$/30sESA.5nVr1zFwI root:$5$PV4AX/OjZ$VU8vX651q4eUqjFWbE2b/ root:$5$iDuK0IUGijv4l$cdGh8BlHKJLYxPB8/ root:$5$0DEUp/jz$JBpqllXswNc0bMJA5IFgem root:$5$Wz3og/W3Jra/WKA.$6D7Wd4M1xxRDEp root:$5$ntHWB.mC3x$Kt4DNTjRZZzpbFvxpMxP root:$5$g/uEc/cq$Ptlgu8CXV.vrjrmuok9RRT root:$5$/XAHs/5x$Z9J4Zt4k6NxdjJ27PpLmTt root:$5$mgfbZeWD0h/$UDGz8YX.D85PzeXnd2K root:$5$f4Oh3/bF2Ox/eN$xt/Jkn0LxPnfKP8. root:$5$J0mZZXGJG7/v$e16VxghNvZZKRONown root:$5$SNza9XFl9i$Qq7r/N6Knt2j74no8H0x root:$5$aFCu//xiL$Ocn9mcT2izcnm3rUlBOJg root:$5$kMkyos/SLZ/Mm6$wNYxZ9QeuJ8c8T.o root:$5$ujXKC/Xnj0h/nQ$PUmePvJZr.UXmTGK root:$5$wtEhA/YKaTKH$6VCSXUiIdsfelkCYWV root:$5$I1taRlq59YZUGe$4OyIfByuvJeuwsjM root:$5$N54oH//j4nbiB$K4i6QOiS9iaaX.RiD root:$5$ps8bo/VjPGMP0y4$NTFkI6OeaMAQL7w root:$5$IRUXnXO8tSykA8$NatM5X/kKHHgtDLt root:$5$VaOgL/8V$m45M9glUYnlTKk8uCI7b5P root:$5$/lPDb/kUX73/F3$jJL.QLH5o9Ue9pVa root:$5$/sHNL/tVzuu//cr$QasvQxa02sXAHOl root:$5$hGI.SMi/7I$fYm0rZP0F5B2D1YezqtX root:$5$WsW2iENKA$4HhotPoLRc8ZbBVg4Z5QW root:$5$cN6mwqEl$q5S3U85cRuNHrlxS9Tl/PC root:$5$wwzLR/YMvk5/7ldQ$s3BJhq5LyrtZww root:$5$GUNvr/d15n8/K$CiNHwOkAtxuWJeNy1 root:$5$nGE75/8mEjM/A$pD/84iLunN/ZNI/JK root:$5$77Dn2dHLS$d5bUQhTz.OU4UA.67IGMB root:$5$EWrI//1u$uubkPk3YhAnwYXOYsvwbah root:$5$Hzfw1UCudP/N/U$Rjcdzdbov1YgozSJ root:$5$2y8CKTj.2eTq$7BEIgMWIzAJLl1SWBv root:$5$lcWsD/42g8zEEABA$r/vGxqqUZTkJ0V root:$5$LPJLc/Xz$tnfDgJh7BsAT1ikpn21l76 root:$5$ucvPeKw9eq8a$vTneH.4XasgBIeyGSA root:$5$Fwm2eUR7$ByjuLJRHoIFWnHtvayragS root:$5$yBl7BtMb$KlWGwBL6/WjgHVwXQh9fJS root:$5$1lnnh2kOG$rdTLjJsSpC3Iw4Y6nkPhq root:$5$WfvmP6cSfb066Z$1WvaC9iL11bPCAxa root:$5$qmf/hHvalWa4GE25$m3O2pdu25QBCwU root:$5$4P.oT/9HQ$Ygid4WXi0QCEObLVNsqFZ root:$5$FNr4Bkj56Y$38mG7mKV0mdb1PMCxrVd root:$5$hoNcyURtV$aTidBWHjngc1I0vUTi5bB root:$5$rzHmykYT$ATiXdUDUvUnB2fNMUQgwvE root:$5$o11Yb/ZQv2/k3wg9$5yShpVejDBk6HB root:$5$REPGN//y9H$awpPmUvCqvi6Bd/6bQxF root:$5$HbAEY/djXJx$y56GhMwavd7xTQ.jPg6 root:$5$3T1k5.LZUcy$Cup.LM5AnaBTIaJtBnF root:$5$wXaSC/P8bJ$y/0DoYJVjaP09O6GWiki root:$5$YuFfY8QPqm/dD$IIh0/tyn.18xEBl5Y root:$5$uTTBpjsKG//3Et8$9ibN9mVwSeVyOI4 root:$5$dASlMLzbVbFMnZ$N4uGBwGHhdg93z/V root:$5$03.FA/LnRBb.k7Zl$XOHU2ZlHkV9oz9 root:$5$2zL1p/VDCi$/QRT7Bo3cZ3Rxb8Y7ddo root:$5$0NpZqZs/qt/jIv.$8W/TTM3Gy2UMOWy root:$5$a4SXynoro7ucT$qFM2C79QJ15jQ0ZlL root:$5$RL0Eg/jroH8/ONP$EzceXz.pz74k104 root:$5$O3R5V/n1$U.mmCTbpID8xMXbvtzd4ch root:$5$0T2nVrv/P/xaRwUD$YVm17XF8kTsL0f root:$5$2bRwMNIXobZwn$Q228FJqg6/iRCe9GQ root:$5$PyYgL/axfgj/$uaL5y/kdzU4Kzi.JlB root:$5$A6QtfJdJ4Gwvx4$d4PA5AJ0806NzRnm root:$5$H8Mta5LDgGXp$QGdOJh.bFWgR3L719Z root:$5$H06URjv4BtOAbA$EJs1mZYhdKIVgCmn root:$5$OeB.O/GrmFB/az$SoE759KE9WIE17Uf root:$5$huiB9/sk$el3XMf7SGX81LnD3.SaF8J root:$5$fO7tfM.fjdSHA8G6$s.QIjfNniCzFdU root:$5$32at3SQJAD/xlw$HbXmBLVXTTyZfxQv root:$5$FHBFL/QdFl$FMipxpW0HlEFUIAr7IxF root:$5$sHvKf/M5OPdBuZZ$dz4qLOkTLGeCINX root:$5$hw4Vu/e34$/82lXu7ISrse.Ihk.qbqT root:$5$k1JOy/jRWZ$30YSk7kbhdKOjfDaiWVf root:$5$MnX.LUzqrB/B2$JuwqC.SmKFnMUWkEf root:$5$arRYf/PG$Xw6PpZNFO656p.Eb636iLt root:$5$5op/p8Hqs5$Nj2jA0Qxm80aG4fHW3oz root:$5$VHIT9/8yzZ$CpIK4ODps78GcqcsgiMT root:$5$.AlH7jBJoh/8$sjuVt.PcRH.vyvB3og root:$5$f7Ewinqm$nrJ2p/hKTuiEK//IfCTjth root:$5$N.dv/VCvrCADg$peSXfo35KN1dmbw/n root:$5$PSc4W./54l/SroH$CFFVOHRYK.Jj8Sp root:$5$8UBP3f4IcnAd/N1/$P.ud49qTStQ7Lw root:$5$qnXsZ/NlLZh/$nlaQVTS3FCJg1Jb2QG root:$5$xOpbbBqENR/7$boYJQzkCkZhRf7Uicf root:$5$V93tjZhzT$LrsIZWZmYo4ocRUvCixO6 root:$5$1MVz8/lf5oC/$rUKpnX23MhFx4.y2ZS 

Environ la moitié des 6èmes caractères de hachage sont / :

 cat sixth-character-often-forward-slash.txt | cut --character=14 | sort / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / . . . . 2 5 6 8 8 B d D e e E f H I j j j J k k K l L M M n n N q r r r s S S t t T U U U U V w x X X X Z Z Z 

Format et source de hachage

Le format du hash de mot de passe est $<type>$<salt>$<hash> , où <type> 5 est un hachage basé sur SHA-256. Le sel est généralement d'au less 8 caractères, (et est dans les exemples de la question) de sorte que le sixième caractère fait partie du sel.

Ces hachages sont probablement générés par une version de la suite d'outils d'ombre ( shadow packageage src dans Debian, shadow-utils dans CentOS)

J'ai essayé de savoir pourquoi, exactement, le code polarise la barre oblique. (merci à @thrig pour avoir creusé le code à l'origine)

TLDR: C'est un peu intéressant, mais ça n'a pas d'importance.


Le code générant le sel

Dans libmisc/salt.c , nous trouvons la fonction gensalt qui appelle l64a dans une boucle:

 strcat (salt, l64a (random())); do { strcat (salt, l64a (random())); } while (strlen (salt) < salt_size); 

La boucle prend un nombre random de random() , le transforme en un morceau de string, et concatène cela à la string formant le sel. Répétez jusqu'à ce que suffisamment de caractères soient recueillis.

Ce qui se passe en l64a est cependant plus intéressant. La boucle interne génère un caractère à la fois à partir de la valeur d'input (qui provient de random() ):

 for (i = 0; value != 0 && i < 6; i++) { digit = value & 0x3f; if (digit < 2) { *s = digit + '.'; } else if (digit < 12) { *s = digit + '0' - 2; } else if (digit < 38) { *s = digit + 'A' - 12; } else { *s = digit + 'a' - 38; } value >>= 6; s++; } 

La première ligne de la boucle ( digit = value & 0x3f ) sélectionne six bits de la valeur d'input, et les clauses if transforment la valeur formée par celles-ci en un caractère. (pour zéro, / pour un, 0 pour deux, etc.)

l64a prend un long mais les valeurs sorties par random() sont limitées à RAND_MAX , qui semble être 2147483647 ou 2 ^ 31 – 1 sur glibc. Donc, la valeur qui va à l64a est un nombre random de 31 bits. En prenant 6 bits à la fois ou une valeur de 31 bits, nous obtenons cinq caractères dissortingbués raisonnablement uniformément, plus un sixième qui ne vient que d'un bit!

Le dernier caractère généré par l64a ne peut pas être a . , cependant, puisque la boucle a aussi la value != 0 la condition value != 0 , et au lieu de a . en tant que sixième caractère, l64a renvoie seulement cinq caractères. Par conséquent, la moitié du time, le sixième caractère est un / , et la moitié du time l64a renvoie cinq caractères ou less. Dans ce dernier cas, une l64a suivante peut également générer une barre oblique dans les premières positions, de sorte que dans un plein sel, le sixième caractère devrait être une barre oblique un peu plus de la moitié du time.

Le code a aussi une fonction pour randomiser la longueur du sel, c'est 8 à 16 octets. Le même parti pris pour le caractère slash se produit également avec d'autres appels à l64a qui feraient que le 11ème et le 12ème caractère aient aussi une barre oblique plus souvent qu'autre chose. Les 100 sels présentés dans la question ont 46 barres en sixième position et 13 et 15 en 11ème et 12ème position respectivement. (un peu less de la moitié des sels sont plus courts que 11 caractères).

Sur Debian

Sur Debian, je ne pouvais pas reproduire cela avec un chpasswd droit comme indiqué dans la question. Mais chpasswd -c SHA256 montre le même comportement. Selon le manuel, l'action par défaut, sans -c , est de laisser PAM gérer le hachage, donc apparemment PAM sur Debian utilise au less un code différent pour générer le sel. Je n'ai pas regardé le code PAM sur n'importe quelle dissortingbution, cependant.

(La version précédente de cette réponse indiquait que l'effet n'apparaissait pas sur Debian, ce qui n'était pas correct.)

Importance et exigences pour les sels

Est-ce important? Comme l'a commenté @RemcoGerlich, ce n'est qu'une question d'enencoding. Il corrige effectivement certains bits du sel à zéro, mais il est probable que cela n'aura pas d'effet significatif dans ce cas, puisque l'origine de ces bits est cet appel à srandom dans seedRNG :

 srandom (tv.tv_sec ^ tv.tv_usec ^ getpid ()); 

Ceci est une variante de l'ancienne coutume de semer un RNG avec l'heure actuelle. ( tv_sec et tv_usec sont les secondes et les microsecondes de l'heure courante, getpid() donne l'identifiant du process si le process est en cours). Le time et les PID ne sont pas très imprévisibles. peut tenir.

Le time et le PID ne sont pas quelque chose que vous souhaitez créer des keys avec, mais peuvent être assez imprévisibles pour les sels. Les sels doivent être distincts pour empêcher les tests de force brute de multiples hachages de mot de passe avec un seul calcul, mais ils doivent également être imprévisibles afin d'éviter ou de ralentir le calcul de précompilation ciblé pour raccourcir le time d'obtention des passwords .

Même avec les légers problèmes, tant que l'algorithm ne génère pas le même sel pour les différents passwords, ça devrait aller. Et il ne semble pas, même en générant quelques douzaines dans une boucle, comme le montre la list de la question.

En outre, le code en question n'est utilisé que pour générer des sels pour les passwords, il n'y a donc aucune implication sur les problèmes ailleurs.

Pour les sels, voir aussi, par exemple, sur Stack Overflow et ceci sur security.SE .

Conclusion

En conclusion, il n'y a rien de mal dans votre système. Assurez-vous que vos passwords sont bons et qu'ils ne sont pas utilisés sur des systèmes non apparentés.

Ce caractère fait partie du manuel de la crypt(3) . Étant donné que la longueur du sel (la string entre le $5$ ID et le $ subséquent) varie pour les hachages exposés, je ne suis pas sûr de ce que représente un personnage random de cette colonne pour quelques passwords.

D'autre part, le / est plutôt plus répandu (102 fois) dans le sel entier par rapport aux autres caractères possibles (environ 18), de sorte que quelque chose dans chpasswd semble favoriser ce caractère dans le sel;

 for x in `seq 1 100000`; do echo testacct:asdfasdfasdf | chpasswd -c SHA256 awk -F: '/testacct/{print $2}' /etc/shadow | awk -F\$ '{print $3}' >> salts done perl -nle 'print for m/(.)/g' salts | sort | uniq -c | sort -nr | head -5 

sur un système RedHat EL 6, il se présente:

  1006 / 195 X 193 U 193 q 193 e 

Et, oui, le code dans shadow-utils-4.1.5.1-5.el6 présente un biais vers / qui pourrait faciliter les attaques de dictionary:

 #include <sys/time.h> #include <stdio.h> #include <stdlib.h> #include <ssortingng.h> #include <unistd.h> // these next two borrowed from libmisc/salt.c of shadow-4.1.5.1 from // Centos 6.8 RPM at http://vault.centos.org/6.8/os/Source/SPackages/shadow-utils-4.1.5.1-5.el6.src.rpm char *l64a(long value) { static char buf[8]; char *s = buf; int digit; int i; if (value < 0) { abort(); } for (i = 0; value != 0 && i < 6; i++) { digit = value & 0x3f; if (digit < 2) { *s = digit + '.'; } else if (digit < 12) { *s = digit + '0' - 2; } else if (digit < 38) { *s = digit + 'A' - 12; } else { *s = digit + 'a' - 38; } value >>= 6; s++; } *s = '\0'; return (buf); } static void seedRNG(void) { struct timeval tv; static int seeded = 0; if (0 == seeded) { (void) gettimeofday(&tv, NULL); srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); seeded = 1; } } int main(void) { seedRNG(); for (int x = 0; x < 1000; x++) { printf("%s\n", l64a(random())); } exit(0); } 

Ce qui entraîne:

 % ./salttest | perl -nle 'print for m/(.)/g' | sort | uniq -c | sort -nr | head -3 593 / 96 8 93 3 

Et puis en utilisant les mêmes routines de la dernière https://github.com/shadow-maint/shadow/blob/master/libmisc/salt.c nous trouvons qu'il y a encore un biais vers / . Donc euh ouais c'est un bug qui devrait être patché donc / n'est pas favorisé autant, idéalement les caractères de sel doivent être pondérés de manière égale.

mkpasswd(1) pourrait être un frontal de crypt(3) , mais ce n'est pas la même chose que d'exécuter chpasswd(1) , qui fait partie du packageage shadow-utils sur CentOS et "passwd" sur Debian. Au lieu de cela, vous devriez comparer les pommes aux pommes. Considérez le script suivant:

 #!/bin/bash # This repeatedly changes a `saltuser' password # and grabs the salt out of /etc/shadow. # Requires root and the existence of `saltuser' user. if [ $EUID -ne 0 ]; then echo "This script requires root access to read /etc/shadow." exit 1 fi grep -q saltuser /etc/passwd if [ $? -ne 0 ]; then echo "This script requires the 'saltuser' to be present." exit 2 fi : > /tmp/salts.txt for i in {1..1000}; do PW=$(tr -cd '[[:print:]]' < /dev/urandom | head -c 64) echo "saltuser:${PW}" | chpasswd -c SHA256 -s 0 2> /dev/urandom awk -F '$' '/^saltuser/ {print $3}' /etc/shadow >> /tmp/salts.txt done while read LINE; do # 6th character in the salt echo ${LINE:5:1} done < /tmp/salts.txt | sort | uniq -c | sort -rn 

Sortie de Debian Sid:

 512 / 14 T 13 W 13 v 13 t 12 x 12 m 12 d 11 p 11 L 11 F 11 4 10 s 10 l 10 g 10 f 10 7 10 6 9 Z 9 w 9 N 9 H 9 G 9 E 9 A 8 Y 8 X 8 r 8 O 8 j 8 c 8 B 8 b 8 9 7 u 7 R 7 q 7 P 7 M 7 k 7 D 6 z 6 y 6 U 6 S 6 K 6 5 5 V 5 Q 5 o 5 J 5 I 5 i 5 C 5 a 5 3 4 n 4 h 4 e 4 2 4 0 4 . 3 8 3 1 

Sortie de CentOS 7:

 504 / 13 P 13 B 12 s 12 Z 11 e 11 Y 11 O 11 L 11 G 10 w 10 u 10 q 10 i 10 h 10 X 10 I 10 E 9 x 9 g 9 f 9 W 9 F 9 C 9 9 9 8 8 v 8 t 8 c 8 b 8 S 8 H 8 D 8 0 7 z 7 y 7 o 7 k 7 U 7 T 7 R 7 M 7 A 7 6 7 4 7 1 6 p 6 d 6 a 6 Q 6 J 6 5 6 . 5 r 5 m 5 j 5 V 5 3 5 2 4 n 4 l 4 N 4 K 3 7 

Donc, le problème n'est pas propre à CentOS, mais il provient probablement de l'amont, d'où proviennent les deux projets.