Linux에서 비밀번호 해시의 여섯 번째 문자는 무엇 /etc/shadow
입니까?
내 강아지 스타일의 리눅스 상자에서 shuf
and를 사용하여 100 개의 임의의 암호를 생성하려고 /dev/urandom
하면 여섯 번째 문자는 /
약 절반입니다.
내 질문은 CD에서 새로 시작할 때마다 부팅하기 때문에 프로덕션 목적이 아닙니다. 이것은 시스템이 잘못 구성되었거나 안전하지 않다는 것을 의미합니까?
파일 shuf
이 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, stripped
나는 생각하지 않는다 shuf
A는 busybox
여기 링크.
ls -l /usr/bin/shuf
-rwxr-xr-x 1 root root 41568 Mar 7 2015 /usr/bin/shuf
동안
ls -l /bin/wget
lrwxrwxrwx 1 root root 14 Apr 29 03:49 wget -> ../bin/busybox
내가 한 일에 대한 대략적인 아이디어는 다음과 같습니다.
# ! / b i n / b a s h
## 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
6 번째 해시 문자의 대략 절반은 다음과 /
같습니다.
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
답변
해시 형식 및 소스
비밀번호 해시의 형식은입니다 $<type>$<salt>$<hash>
. 여기서 <type>
5
SHA-256 기반 해시입니다. 소금은 일반적으로 8 자 이상이며 문제의 예에서 6 번째 문자는 소금의 일부입니다.
이러한 해시는 섀도우 도구 모음 ( CentOS의 shadow
데비안의 src 패키지) 버전에 의해 생성 될 수 있습니다.shadow-utils
정확히 코드가 슬래시를 바이어스하는 이유를 찾으려고 노력했습니다. (원래 코드를 파낸 @thrig 덕분에.)
TLDR : 약간 흥미롭지 만 중요하지 않습니다.
소금을 생성하는 코드
에서 libmisc/salt.c
, 우리는 찾을 gensalt
함수 호출 l64a
루프를 :
strcat (salt, l64a (random()));
do {
strcat (salt, l64a (random()));
} while (strlen (salt) < salt_size);
루프는에서 임의의 숫자를 가져 와서 random()
문자열로 변환하여 소금을 형성하는 문자열에 연결합니다. 충분한 문자가 수집 될 때까지 반복하십시오.
l64a
그래도 더 흥미로운 일 이 있습니다. 내부 루프는 입력 값 (에서 온 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++;
}
루프의 첫 번째 줄 ( digit = value & 0x3f
)은 입력 값에서 6 비트를 선택하고 if
절은 해당 값으로 구성된 값을 문자로 바꿉니다. ( .
0, /
1, 0
2 등)
l64a
a를 사용 long
하지만로 출력되는 값 random()
은으로 제한 RAND_MAX
되며 glibc에서 2147483647 또는 2 ^ 31-1로 나타납니다. 따라서 값 l64a
은 31 비트의 난수입니다. 한 번에 6 비트 또는 31 비트 값을 취함으로써 합리적으로 분포 된 5 개의 문자와 1 비트에서만 나오는 6 개의 문자를 얻습니다!
에 의해 생성 된 마지막 문자는 l64a
수 없습니다 .
루프는 조건이 있기 때문에,하지만 value != 0
, 대신에의 .
같은 여섯 번째 문자, l64a
다섯 문자를 반환합니다. 따라서 시간의 절반, 여섯 번째 문자는 a /
이고 시간의 절반 l64a
은 5 자 이하의 문자를 반환합니다. 후자의 경우 다음 l64a
은 첫 번째 위치에서 슬래시를 생성 할 수 있으므로 전체 소금에서 여섯 번째 문자는 절반보다 약간 긴 슬래시 여야합니다.
이 코드에는 소금의 길이를 무작위로 추출하는 기능이 있으며 8 ~ 16 바이트입니다. 슬래시 문자에 대한 동일한 편향이 발생하여 추가 호출 l64a
이 발생하여 11 번째 및 12 번째 문자도 다른 것보다 더 자주 슬래시를 갖습니다. 이 질문에 제시된 100 개의 소금은 각각 6 위에 46 슬래시, 11 위와 12 위에 13과 15가 있습니다. (소금의 절반 미만이 11 자보다 짧습니다).
데비안에서
데비안에서는 chpasswd
질문에 표시된 것처럼 똑바로 이것을 재현 할 수 없었습니다 . 그러나 chpasswd -c SHA256
같은 행동을 보여줍니다. 매뉴얼에 따르면,없는 기본 동작 -c
은 PAM이 해싱을 처리하도록하는 것이므로 Debian의 PAM은 적어도 다른 코드를 사용하여 소금을 생성합니다. 그러나 배포판에서 PAM 코드를 보지 않았습니다.
(이 답변의 이전 버전은 그 효과가 데비안에 나타나지 않았다고 언급했습니다. 정확하지 않습니다.)
염의 중요성 및 요구 사항
그래도 문제가 되나요? @RemcoGerlich가 언급했듯이 인코딩의 문제 일뿐입니다. 그것은 소금의 일부 비트를 0으로 효과적으로 고정시킬 것이지만,이 비트의 원점이 다음에서 호출되기 때문에이 경우에는 큰 영향을 미치지 않을 것 srandom
입니다 seedRNG
.
srandom (tv.tv_sec ^ tv.tv_usec ^ getpid ());
이것은 현재 시간으로 RNG를 파종하는 오래된 관습의 변형입니다. ( tv_sec
하고 tv_usec
초와 현재 시간의 마이크로이며, getpid()
시간으로. 실행중인 프로세스의 경우 프로세스 ID를 제공)와 PID를 매우 예측할 수없는, 여기 난수의 양이 인코딩에 저장할 수있는 것보다 더 큰 가능성이있다.
시간과 PID는 키 를 만들려 는 것이 아니지만 소금에 대해 예측할 수 없을 수도 있습니다. 솔트 는 단일 계산으로 여러 암호 해시를 무차별 테스트하는 것을 방지하기 위해 구별 되어야 하지만 예측 된 예측할 수 없어 대상 사전 계산을 방지하거나 느리게 해야 합니다. .
약간의 문제가 있더라도 알고리즘이 다른 암호에 대해 동일한 소금을 생성하지 않는 한 괜찮습니다. 그리고 질문 목록에 나와 있듯이 루프에서 수십 개를 생성 할 때조차 보이지 않습니다.
또한 문제의 코드는 암호에 대한 염분을 생성하는 것 외에 다른 용도로 사용되지 않으므로 다른 문제에 대한 영향은 없습니다.
소금에 대해서는 스택 오버플로 및 보안 에 대한 예도 참조하십시오 .
결론
결론적으로 시스템에는 아무런 문제가 없습니다. 암호가 올바른지 확인하고 관련없는 시스템에서 사용하지 않는 것이 더 유용합니다.
답변
그 특성은 crypt(3)
매뉴얼 에 따라 소금의 일부입니다 . 소금의 길이 ( $5$
ID와 후속 문자열 사이의 문자열 $
)가 표시된 해시에 따라 다르므로 몇 가지 암호에 대해 특정 열에서 임의의 문자를 선택하는 것이 무엇인지 정확히 알 수 없습니다.
한편,이 /
입니다 오히려 더에서 (102 개 인스턴스) 널리 전체 에 이렇게 뭔가 (18 정도) 다른 가능한 문자에 비해 소금 chpasswd
소금에 그 문자를 선호하는 것처럼 보인다;
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
RedHat EL 6 시스템에서 다음이 실행됩니다.
1006 /
195 X
193 U
193 q
193 e
그렇습니다.이 코드는 사전 공격을보다 쉽게 만들 수 shadow-utils-4.1.5.1-5.el6
있는 편견을 나타냅니다 /
.
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.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);
}
결과 :
% ./salttest | perl -nle 'print for m/(.)/g' | sort | uniq -c | sort -nr | head -3
593 /
96 8
93 3
그리고 최신 https://github.com/shadow-maint/shadow/blob/master/libmisc/salt.c 와 동일한 루틴을 사용하면 여전히에 대한 편견이 있음을 알 수 /
있습니다. 그렇습니다. /
이것은 패치되어야하는 버그입니다. 이상적으로는 소금 문자의 가중치가 동일해야하기 때문에 많이 선호되지는 않습니다.
답변
mkpasswd(1)
에 대한 프론트 엔드 crypt(3)
일 수 있지만 chpasswd(1)
centOS의 “shadow-utils”패키지와 Debian의 “passwd”의 일부인 running 과 는 다릅니다 . 대신, 사과와 사과를 비교해야합니다. 다음 스크립트를 고려하십시오.
#!/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
데비안 시드의 출력 :
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
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
따라서이 문제는 CentOS에만 국한된 것이 아니라 두 프로젝트가 모두 끌어 오는 업스트림에서 비롯된 것일 수 있습니다.