시스템 보안 · 취약점 › B. 계정 · 인증 보안 강화 · 12/50편 (전체 062/450)
학습 단계: 2단계 · 설정 및 점검
실습 표기: 이 글의 명령어·출력·로그는 로컬 VMware 테스트 VM(Rocky Linux 9 / Ubuntu 22.04) 기준의 「실습 예시」이며, IP·계정·호스트명은 가상의 값입니다.
PAM(Pluggable Authentication Modules)은 "로그인·인증을 어떻게 검사할지"를 모듈을 쌓아(stack) 결정합니다. 각 줄은 타입 control flag 모듈 [인자] 구조입니다.
auth required pam_faillock.so preauth
auth sufficient pam_unix.so try_first_pass nullok
auth required pam_faillock.so authfail
auth required pam_deny.so
│ │ │
타입 control 모듈
| 타입 | 언제 동작 |
|---|---|
auth | 신원 확인(비밀번호·키) |
account | 계정 유효성(만료·잠금·접근 제어) |
password | 비밀번호 변경 시 검증 |
session | 세션 시작/종료(환경·로그·limits) |
| control flag | 의미 |
|---|---|
required | 실패해도 스택은 계속 진행하되 최종 실패(실패 사실을 숨기지 않음) |
requisite | 실패 즉시 중단·실패 반환 |
sufficient | 성공하면 즉시 성공(앞의 required 실패가 없을 때) |
optional | 결과가 다른 모듈에 거의 영향 없음 |
[success=.. default=..] | 세밀한 분기 제어(최신 스택에서 많이 사용) |
sufficient pam_unix가 성공하면 뒤 모듈을 보지 않습니다.pam_faillock preauth가 pam_unix 앞에 있어야 잠금이 인증보다 먼저 적용됩니다.| 파일 | 역할 |
|---|---|
/etc/pam.d/system-auth, password-auth (Rocky) | 공통 인증 스택(다른 서비스가 include) |
/etc/pam.d/common-auth, common-* (Ubuntu) | 공통 인증 스택 |
/etc/pam.d/sshd, login, sudo, su | 서비스별 스택(공통을 include) |
authselect current (Rocky) | 현재 적용 프로파일·커스텀 여부 |
pam_tally2/faillock, pam_unix, pam_pwquality, pam_pwhistory | 주요 모듈 |
# 1) sshd 인증 경로 전체 펼쳐 보기 (include 따라가며)
grep -vE '^\s*(#|$)' /etc/pam.d/sshd
echo '--- system-auth ---'; grep -vE '^\s*(#|$)' /etc/pam.d/system-auth # Ubuntu: common-auth
# 2) Rocky: authselect로 표준 대비 커스텀 변경 확인
authselect current 2>/dev/null
authselect check 2>/dev/null
# 3) 위험 패턴 탐색: nullok(빈 비밀번호 허용), pam_permit(무조건 통과)
grep -rnE 'nullok|pam_permit\.so' /etc/pam.d/
nullok은 빈 비밀번호 로그인을 허용하는 인자라 운영 서버에서는 제거 대상입니다. pam_permit.so가 auth/account에 쓰이면 사실상 인증 우회입니다.
auth required pam_env.so
auth required pam_faillock.so preauth silent deny=5 unlock_time=900
auth sufficient pam_unix.so try_first_pass
auth required pam_faillock.so authfail deny=5 unlock_time=900
auth required pam_deny.so
$ authselect check
Current configuration is valid.
faillock이 pam_unix 앞뒤로 올바르게 배치되고, 마지막이 pam_deny.so로 닫히며, authselect가 "valid"인 상태가 정상입니다.
auth sufficient pam_unix.so try_first_pass nullok
auth sufficient pam_permit.so
$ authselect check
Current configuration was manually modified.
nullok 추가 → 빈 비밀번호 로그인 허용auth ... sufficient pam_permit.so → 앞 모듈이 실패해도 무조건 인증 성공(완전한 우회)faillock·pam_deny 제거 → 잠금·최종 거부 없음PAM 동작은 인증 로그의 grantors/op 필드로 어떤 모듈이 관여했는지 보입니다(가상의 예시 로그).
[정상]
type=USER_AUTH ... msg='op=PAM:authentication grantors=pam_faillock,pam_unix acct=devops ... res=success'
[우회 설정 후]
type=USER_AUTH ... msg='op=PAM:authentication grantors=pam_permit acct=devops ... res=success'
Oct 2 03:00:11 rocky9-web01 sshd[12301]: Accepted password for devops from 192.168.56.77 port 50240 ssh2
| 필드 | 분석 |
|---|---|
grantors=pam_faillock,pam_unix | 정상: 잠금 검사 + 비밀번호 검사 |
grantors=pam_permit | 비정상: 통과시킨 모듈이 pam_permit → 인증 우회 |
| 성공했지만 비밀번호 검증 흔적 없음 | 인증 로직이 바뀌었다는 강한 신호 |
grantors에 기대하지 않은 모듈이 보이면 PAM 스택 변조를 의심합니다(013편에서 탐지).
grantors를 기준선과 비교해 관여 모듈이 바뀌었는지 봅니다.nullok, pam_permit(auth/account)은 스택에 있어서는 안 되는 패턴으로 관리합니다.authselect check의 "manually modified"를 변경 지표로 삼습니다.PAM 스택 자체의 탐지는 다음 편(013)에서 다루고, 여기서는 인증 결과의 grantors 이상을 보는 관점을 둡니다.
# Kibana(KQL): 인증 성공인데 pam_unix가 관여하지 않은 이벤트
data.audit.op : "PAM:authentication" and data.audit.res : "success" and not data.audit.grantors : *pam_unix*
디코더가 grantors를 필드로 추출하지 않으면 전체 메시지 문자열 검색(full_log)으로 대체합니다.
| 타입 | auth(신원) · account(유효성) · password(변경) · session(세션) |
|---|---|
| 주요 flag | required(계속·실패) · requisite(즉시 실패) · sufficient(즉시 성공) · optional |
| 위험 패턴 | nullok(빈 비밀번호), pam_permit(무조건 통과) |
| 판독 | 인증 로그의 grantors = 실제 관여 모듈 |
| 면접 포인트 | "sufficient가 성공하면 뒤 모듈을 보지 않는다 — 순서가 결과를 바꾼다" |
다음 편 063. 계정 · 인증 보안 — PAM 설정 변조 탐지 에서는 이 스택을 노리는 PAM 설정 변조 탐지를 다룹니다.
이전 편: 061. 계정 · 인증 보안 — 비밀번호 이력·재사용 제한(pam_pwhistory)
📚 시리즈 전체 보기: 시스템 보안 · 취약점