본문 바로가기

리눅스

/etc/passwd, /etc/shadow에 관하여

리눅스에서 중요하게 다뤄지는 두 파일 passwd, shadow에 관하여 포스팅해보겠다.

/etc/passwd

passwd파일은 /etc 디렉토리에 존재하는 설정파일이다. 정확히는 시스템에 로그인하는 사용자 계정을 관리하는 텍스트 파일로 모든 사람들(user, group, others)에게 읽기 권한이 주어져 있다. 이는 다른 유틸리티에서도 참조하기 때문인데 예를 들어 'ls' 명령은 사용자 id(UID)와 이름을 매칭하기 위해 이 파일을 읽는다. 물론 수정은 소유자인 root만이 가능하다.

WSL Ubuntu의 /etc/passwd

파일에 적혀있는 데이터는 다음과 같다.

/etc/passwd 파일 내용

name:password:UID:GID:GECOS:directory:shell

name: 계정명(kwonkyu)

password: 패스워드('x'. shadow 파일로 옮겨짐)

UID: UserID(1000)

GID: GroupID(1000)

GECOS: Commentary. 계정에 대한 설명(,,,)

directory: 계정의 홈 디렉토리(/home/kwonkyu)

shell: 계정의 로그인 쉘(/bin/bash)

워낙 유명한 내용이라 조금이라도 공부했던 사람은 모르는 사람이 없을 것이다. 여기서 중요한 부분은 패스워드 필드로 이에 대해 좀 더 알아보도록 하자.

 

암호화된 패스워드가 그대로 쓰여져 있던 옛 시절에는 패스워드 크래킹을 수행하기에 충분할 만큼 하드웨어 성능이 발전하지 않았고 시스템은 친숙(friendly)한 커뮤니티가 사용할 것이라고 가정했기 때문에 암호화된 비밀번호를 이 파일에 적어두는 것은 큰 문제가 되지 않았다. 하지만 점차 하드웨어가 발전하고 크래킹 기술 역시 발전하면서 아무나 읽을 수 있게 두는 것은 위험해졌기 때문에 비밀번호는 shadow 파일로 옮기고 원래 비밀번호가 적혀있던 필드에는 'x'라는 표식만 남게 되었다.

'x'가 적혀있는 패스워드 필드

이 필드를 수정해서 사용자의 로그인을 막거나 비밀번호를 물어보지 않도록 할 수 있다. 먼저 패스워드 필드가 '*'이라면 이 계정에는 로그인할 수 없다. 로그인하기 위해서는 passwd 명령어를 통해서 비밀번호를 설정해야 한다.

계정 생성, 패스워드 설정, 계정 전환까지 실행한 모습

이제 암호화된 비밀번호 필드를 '*'로 수정한 후 로그인을 시도하면 계정에 접속할 수 없는 것을 볼 수 있다.

Authentication failure가 발생하면서 계정에 접속할 수 없었다.

이렇게 패스워드 필드를 '*'으로 설정하는 것은 직접(direct) 로그인을 막기 위해 자주 사용되는 방법이다. 또는 계정의 비밀번호를 갱신시키기 위해 사용할 수도 있다. 이 경우 passwd로 비밀번호를 재설정해줘야 한다.

 

그렇다면 아예 이 패스워드 필드를 비워버린다면 어떻게 될까? 이는 계정의 비밀번호 인증을 해제시킨다.

비밀번호 인증과정 없이 바로 testaccount로 로그인했다.

이는 보안 결함이기 때문에 PAM(pam_unix.so 등)을 사용해서 이를 비활성화시킬 수 있다. 이를 실습해보기 위해 PAM 모듈 설정파일 디렉토리(/etc/pam.d)에서 common-auth 파일을 확인해보면 다음과 같은 내용이 적혀있다. 이는 WSL Ubuntu 환경이기 때문에 다른 리눅스 배포판에서는 다를 수 있다.

/etc/pam.d/common-auth 파일 내용

여기서 눈여겨 볼 것은 pam_unix.so를 사용하는 라인이다. "pam_unix.so"라는 PAM 모듈에 대하여 실행 옵션으로 "nullok_secure"를 전달함으로써 패스워드 없는 로그인을 허용하고 있는 것을 볼 수 있다.

이 모듈은 유닉스 표준 인증모듈로 시스템 라이브러리를 호출하여 계정 정보를 습득, 인증에 사용한다. 패스워드 섀도잉이 설정됐다면 /etc/passwd, /etc/shadow 파일에서 이를 사용한다. 이에 대한 "nullok_secure" 옵션은 /etc/securetty에 기재되어 있는 터미널을 통해 접속하는 비밀번호 없는 로그인을 허용한다는 의미다. 현재는 /etc/securetty 파일이 존재하지 않기 때문에 어느 곳에서나 로그인할 수 있다. 일반 "nullok" 옵션도 있는데 이는 어떤 유저든 비밀번호 필드가 비어있다면 패스워드 없는 로그인을 허용한다는 옵션이다.

 

아무튼 이 옵션을 제거하면 비밀번호가 설정되어 있지 않아도 비밀번호를 요구하며 로그인이 불가능한 것을 알 수 있다.

nullok_secure가 사라진 common-auth. su testaccount가 실패

[출처 | https://linux.die.net/man/5/passwd]

[출처 | https://wiki.kldp.org/Translations/html/PAM_admin-KLDP/configuration.html]

[출처 | https://www.redhat.com/archives/pam-list/2005-September/msg00001.html]

[출처 | https://wiki.kldp.org/Translations/html/PAM_admin-KLDP/configuration.html]

[출처 | http://manpages.ubuntu.com/manpages/xenial/man8/pam_unix.8.html]

/etc/shadow

/etc/passwd와 더불어 또다른 중요한 파일인 shadow 파일은 계정의 패스워드 정보와 에이징(aging) 정보를 담고 있다.

에이징 정보란 계정의 만료기간, 비밀번호의 변경 일자 등을 관리하는 것이다. 이 파일은 passwd 파일과 달리 일반적인 사용자들이 절대 읽을 수 없도록 하여 비밀번호 관리 보안에 힘쓰고 있다.

 

이렇게 암호화된 비밀번호를 따로 분리하여 파일에 저장한 이유는 암호화된 패스워드, 즉 패스워드 해시값에 대한 브루트-포스 공격을 방지하기 위함이다. 제일 좋은 방법은 passwd 파일을 root 권한으로만 읽을 수 있도록 하는 것이겠지만 위에서 언급했듯이 다른 유틸리티들이 사용자명에 대해 UID를 매핑하는 등의 이유로 passwd 파일을 읽어야 하기 때문에 "shadow" 파일을 만들어 패스워드 해시값만 따로 보관하는 방법을 선택한 것이다.

 

물론 이 역시 네트워크를 통해 유출되거나 시스템 파일 백업본을 통해 악의적인 사용자의 손에 들어간다면 오프라인 환경에서 레인보우 테이블 등을 이용한 공격에 노출될 수 있다. 그래도 모두가 읽을 수 있는 passwd 파일에 저장된 모든 계정의 비밀번호 해시값을 악의적인 사용자가 몽땅 훔쳐가는 것보다는 안전한 방법이라 할 수 있다.

 

파일의 내용은 다음과 같다.

길게 표시된 문자열이 암호화된 비밀번호를 의미한다.

name:encrypted_password:last_password_change:minimum:maximum:warning:inactivity:expiration

name: 계정명(kwonkyu)

encrypted_password: 암호화된 패스워드($6$lrGFlng...). crypt() 함수가 사용한다.

last_password_change: 마지막으로 비밀번호를 변경한 날(18411). 1970/01/01부터 일수로 계산.

minimum: 최소 비밀번호 사용 일수(0)

maximum: 최대 비밀번호 사용 일수(99999)

warning: 비밀번호 만료 전 경고 일수(7)

inactivity: 비밀번호가 만료된 후 유예기간(비어있음 - 유예기간 없음).

expiration: 계정 자체의 만료 기간(비어있음 - 영원히 만료되지 않음). 1970/01/01부터 일수로 계산.

이런 필드들을 조작하면 여러 동작을 할 수 있다.

최근 비밀번호를 변경한 날인 last_password_change 필드를 0으로 설정할 경우 로그인 시 비밀번호 재설정을 강제한다. 

유예기간, inactivity 필드는 말 그대로 패스워드가 만료된 후 패스워드가 변경되어야 할 기간이며 이 기간마저 만료된다면 사용자는 더이상 해당 비밀번호로 로그인을 할 수 없으며 관리자에게 문의하여야 한다. 즉 maximum 기간을 넘겨도 비밀번호는 여전히 사용 가능하지만 로그인 시 비밀번호를 변경하라는 메시지를 받게 된다.

계정의 만료 기간을 나타내는 expiration 필드는 해당 비밀번호로 로그인할 수 없게 되는 비밀번호 만료와는 달리 계정에 아예 로그인할 수가 없게 된다. 이를 해제하려고 필드를 0으로 설정할 경우 1970/01/01에 만료되는 것인지 만료기간이 없는 것인지 구분할 수가 없기 때문에 필드를 비워놓는 방식으로 설정해야 한다.

 

이 중 제일 긴 문자열인 암호화된 패스워드를 살펴보면 '$'으로 구분된 몇가지 세부 필드가 보이는데 이는 다음과 같은 포맷을 가지고 있다.

$id$salt$hashed

$id: 해싱 알고리즘

$salt: 해싱에 사용된 솔트(salt)값

$hashed: 해싱된 비밀번호 값

비밀번호를 암호화하는 방법은 암호기술이 발전함에 따라, 그리고 암호에 대한 공격기술이 발전함에 따라 계속 변화해왔다. 전통적으로는 DES에 기반한 암호 계획(scheme)을 사용했으나 취약점이 발견되면서 MD5, Blowfish 등이 사용되어 왔고 현재는 SHA 알고리즘을 많이 사용하고 있다. 비밀번호 해시값은 crypt() 함수에 의해 생성되는데 어떤 해싱 알고리즘을 사용했는지는 id 필드를 통해 확인할 수 있다.

  • $1$: MD5
  • $2a$: Blowfish
  • $2y$: Eksblowfish
  • $5$: SHA-256
  • $6$: SHA-512

위의 shadow 파일에서는 비밀번호가 SHA-512($6$)로 해시되어 저장된 것을 알 수 있다. 이때 shadow 파일에는 솔트값과 해싱된 비밀번호 값이 원본이 아니라 Base64-like로 인코딩된 결과가 적혀있다. 이외에도 해싱 알고리즘은 BSDi, bcrypt, NTHASH, SolarisMD5 등이 있으며 이는 리눅스 배포판에 따라 지원여부에 차이가 있다.

 

비밀번호가 잠기거나 이를 이용하여 로그인할 수 없는 경우 '!', '*' 같은 문자들이 앞에 붙는다. 후자의 경우 콘솔로 로그인은 불가능할 지 몰라도 ssh 등을 통하여 로그인이 허용되는 경우도 있다.

passwd의 l 옵션을 이용하여 잠근 계정의 패스워드 필드

 

[출처 | https://en.wikipedia.org/wiki/Passwd]

[출처 | https://linux.die.net/man/5/shadow]

 

'리눅스' 카테고리의 다른 글

심볼릭 링크란 무엇일까  (2) 2019.07.20
데몬(daemon)이란?  (4) 2019.01.10