NOW Briefing
*인 계정에 로그인할 수 있습니다.
musl libc 환경 OpenSSH 패스워드 인증 우회 취약점 (CVE-2026-123158)
■ 개요
OpenSSH는 리눅스·유닉스 서버의 원격 접속 표준 구현이고, musl libc는 Alpine Linux 같은 경량 배포판이 glibc 대신 쓰는 표준 C 라이브러리입니다. 2026년 11월 5일 공개된 CVE-2026-123158(*sshole)은 이 musl libc 환경에서 빌드·실행된 sshd의 패스워드 인증을 우회하는 취약점입니다. Alpine의 기본 openssh-server 패키지는 musl 기반이고 플러그형 인증 모듈(PAM) 없이 빌드되므로, 영향은 Alpine에 집중됩니다.
벤더 공지와 연구자 분석 기준으로 영향을 받으려면 네 가지 조건이 모두 충족돼야 합니다. sshd가 musl libc로 빌드돼 PAM 없이 동작하고, 패스워드 인증이 켜져 있으며(기본값), 계정 해시 저장 파일 /etc/shadow에 패스워드가 설정되지 않은 계정(*)이 있고, 같은 시스템의 다른 계정에 SHA-crypt($5$·$6$) 형식의 실제 패스워드 해시가 하나 이상 남아 있어야 합니다. 유효한 패스워드나 공개키는 필요하지 않습니다. glibc 기반 배포판(Debian·Ubuntu·Fedora 등), PAM이 활성화된 빌드, 경량 SSH 서버 Dropbear, OpenBSD는 영향을 받지 않습니다. Alpine 외에 OpenWrt·Buildroot·Yocto 등 musl을 쓰는 임베디드·컨테이너 환경도 나머지 조건이 충족되면 영향을 받습니다.
우회가 성립하면 공격자는 유효한 자격증명 없이 원격 셸을 얻을 수 있으며, 접근 범위는 우회한 계정에 부여된 권한으로 한정됩니다. 연구자는 Alpine의 기본 root 계정과 클라우드 이미지의 기본 사용자 계정, 키 전용 계정, LDAP 연동 계정을 전형적인 표적으로 꼽았습니다. root 계정이 대상이고 sshd가 root의 패스워드 로그인을 허용하는 구성이라면 영향은 시스템 전체로 확대됩니다.
CVSS v3.1 점수는 8.1이고, 패치는 공개와 같은 날 OpenSSH 10.6p2로 배포됐습니다. 보안업체 분석 정리 기준으로 Alpine은 3.16부터 edge까지 각 브랜치에 패치 패키지를 배포했으며, 3.16보다 오래된 브랜치에는 패치 패키지가 제공되지 않습니다. 실제 공격에 악용됐다는 관측 보고는 현재 공개 정보에 없습니다. 다만 연구자가 점검 스크립트와 PoC를 함께 공개했습니다.
■ 요약
| 항목 | 내용 |
|---|---|
| CVE ID | CVE-2026-123158 (musl libc 환경 sshd의 패스워드 인증 우회, *sshole) |
| CVSS 점수 | CVSS v3.1 8.1 |
| 취약점 유형 | CWE-394, 예상치 못한 반환값 오해석에 따른 인증 우회 |
| 영향/위험 | • 유효한 패스워드·키 없이 패스워드가 설정되지 않은 계정(*)으로 원격 로그인 가능• 우회한 계정에 부여된 권한 범위의 원격 셸 획득 가능 • root가 *이고 sshd가 root 패스워드 로그인을 허용하는 구성에서는 root 접근까지 성립 가능(연구자 분석 기준)• 연구자 공개 PoC 존재(실제 악용 관측 보고는 없음) |
| 취약 버전 | • OpenSSH 10.6p2 이전 (musl libc 빌드 + PAM 비활성 + 패스워드 인증 활성 조건) • Alpine Linux 3.16~edge의 패치 이전 openssh 패키지 • OpenWrt·Buildroot·Yocto 등 musl 기반 빌드 (동일 조건) |
| 패치 버전 | • OpenSSH 10.6p2 • Alpine edge: 10.6_p2-r0 • Alpine 3.24: 10.3_p1-r2 / 3.23: 10.2_p1-r1 / 3.22: 10.0_p1-r11 • Alpine 3.21~3.16: 각 브랜치 백포트판(9.9_p2-r1 ~ 9.0_p1-r6) |
■ 기술 분석
PAM 없이 패스워드 인증을 처리할 때 sshd는 입력된 패스워드를 시스템의 해시 생성 함수 crypt()로 해시한 뒤, /etc/shadow에 저장된 값과 문자열을 그대로 비교합니다. musl의 crypt()는 SHA-crypt 계열에서 키 길이 상한(KEY_MAX) 256바이트를 넘는 입력을 실패로 처리하는데, 2012년 설계에 따라 NULL이 아니라 문자열 "*"를 반환합니다. 반환값을 검사하지 않는 프로그램의 비정상 종료를 막으려는 선택이었습니다. 그런데 *는 1980년대부터 "유효한 해시가 없는 계정"을 뜻하는 관례 표기로 /etc/shadow에 저장되는 값과 똑같아서, 길이 초과로 생긴 실패값과 패스워드가 설정되지 않은 계정의 저장값이 같은 한 글자가 되면서 비교가 성립합니다. sshd 자체가 패스워드 길이를 1024바이트(MAX_PASSWORD_LEN)로 제한하므로, CVE 레코드 기준으로 우회가 성립하는 입력 구간은 257~1024바이트입니다.
다른 계정의 실제 해시가 필요한 이유는 솔트 선택 경로에 있습니다. 인증 처리 코드 auth-passwd.c의 sys_auth_passwd()는 계정이 유효하고 저장값의 첫 두 바이트가 모두 존재할 때만 그 값을 솔트로 넘기므로, 저장값이 * 한 글자면 솔트가 NULL로 전달됩니다. 이때 호환 계층의 xcrypt()는 pick_salt()로 시스템의 다른 계정 해시에서 해시 방식을 골라 씁니다. 연구자 분석 기준으로 이 경로에서 SHA-crypt($5$·$6$)가 선택돼야 musl의 256바이트 상한이 적용됩니다. 존재하지 않는 사용자명에도 동일한 해시 연산을 수행하도록 만든 2016년의 사용자 열거 방지 설계(CVE-2016-6210 대응)가 이 조건의 배경입니다.
아래는 openssh-portable 공식 패치 커밋 4353fdc의 auth-passwd.c 변경분 가운데 sys_auth_passwd()의 최종 비교 부분입니다. 같은 커밋은 상수 MIN_PASSWORD_HASH_LEN을 4로 정의하고, 저장된 값이 유효한 해시로 보기에 너무 짧으면 비교 결과와 무관하게 인증을 거부하는 조건을 추가했습니다. 그 결과 *나 ! 같은 한 글자 표기는 더 이상 인증 성공 조건이 되지 못합니다. OpenSSH 측은 릴리스 노트에서 근본 원인이 sshd 외부에 있다고 보면서도 sshd에서 회피할 수 있다고 밝혔습니다.
@@ -221,7 +227,10 @@ sys_auth_passwd(struct ssh *ssh, const char *password)
* Authentication is accepted if the encrypted passwords
* are identical.
*/
- return encrypted_password != NULL &&
+ ret = encrypted_password != NULL &&
+ strlen(pw_password) >= MIN_PASSWORD_HASH_LEN &&
strcmp(encrypted_password, pw_password) == 0;
+ freezero(pw_password, strlen(pw_password));
+ return ret;
}
패치는 xstrdup()으로 저장값 복사본을 만들고 freezero()로 지우도록 메모리 처리도 바꿨습니다. 호환 계층 openbsd-compat/xcrypt.c의 shadow_pw()와 pick_salt(), openbsd-compat/port-uw.c에도 동일한 정리 로직을 적용했습니다.
■ PoC
연구자 저장소에는 취약한 Alpine 환경을 만드는 Dockerfile과, 특정 계정에 정상적으로 거부되는 패스워드를 먼저 시도한 뒤 길이를 늘린 패스워드로 인증 성공 여부를 판정하는 파이썬 스크립트가 포함돼 있습니다. 인증이 통과하면 원격 명령 실행 결과를 출력해 우회 성공을 확인합니다. 실행하려면 sshd에 네트워크로 도달할 수 있어야 하고, 대상 계정명과 영향 버전 환경도 필요합니다.
PoC 코드는 본문에 싣지 않았습니다. 원문은 참고 자료의 링크에서 확인할 수 있습니다.
⚠️ WARN
공개된 재현 코드가 있으므로, 위 영향 조건에 해당하는 sshd가 외부에 노출돼 있었다면 패치와 함께 노출 경로를 차단하고 로그를 점검해야 합니다.
■ 탐지 및 점검
• sshd -T | grep -i -E 'passwordauthentication|usepam'로 패스워드 인증과 PAM 설정 상태를 확인합니다. 패스워드 인증이 꺼져 있거나 PAM이 켜져 있으면 영향을 받지 않습니다.
• 베이스 이미지와 호스트의 libc가 musl인지 확인하고, Alpine·OpenWrt·Buildroot·Yocto 기반 자산을 별도 목록으로 분류해 영향 조건을 점검합니다.
• /etc/shadow에서 패스워드 필드가 *인 계정과 $5$·$6$ 해시를 가진 계정이 함께 존재하는지 점검합니다. 두 조건이 함께 충족돼야 우회가 성립합니다.
• 시스템 로그(Alpine 기본 구성에서는 /var/log/messages)에서 패스워드가 설정되지 않은 계정에 대한 Accepted password for 기록을 검색합니다. 공개 분석 권고 기준으로 해당 기록이 있으면 침해를 전제로 조사해야 합니다.
• 연구자가 공개한 점검 스크립트 check.sh로 libc·버전·PAM·계정 조건 충족 여부를 한 번에 확인합니다.
✅ CHECK
glibc 기반 배포판(Debian·Ubuntu·Fedora 등), PAM이 활성화된 sshd 빌드, Dropbear를 쓰는 환경은 점검 대상에서 제외할 수 있습니다.
■ 대응 방안
• Alpine 자산은 apk update && apk upgrade openssh로 브랜치별 패치 버전 이상으로 올립니다. 3.16~edge 브랜치에 패치 패키지가 제공됩니다.
• 직접 빌드한 sshd는 OpenSSH 10.6p2 이상으로 업그레이드하거나, 구버전을 유지해야 한다면 공개된 업스트림 패치(커밋 4353fdc)를 적용해 재빌드합니다.
• 즉시 업그레이드가 어려운 자산은 PasswordAuthentication no로 패스워드 인증을 비활성화합니다. Alpine 기본 패키지는 PAM 없이 빌드되므로, PAM 활성화 전환보다 패스워드 인증 차단이 현실적인 임시 대응입니다.
• 컨테이너는 패키지 업그레이드만으로 끝내지 말고 갱신된 베이스 이미지로 재빌드해 재배포합니다. 기존 이미지가 남아 있으면 재기동 시 취약 버전이 다시 올라옵니다.
• 로그에서 비정상 로그인이 확인된 호스트는 세션을 종료하고 우회한 계정의 권한으로 접근할 수 있었던 SSH 키·서비스 자격증명을 재발급합니다. 외부 노출 이력만 있는 호스트는 침해 가능성을 전제로 조사 우선순위를 높입니다.
[참고 자료]
• openssh-portable 패치 커밋 — avoid password authn bypass
• GitHub 보안 권고 — CVE-2026-123158
• musl libc 소스 — crypt_sha256.c
• 연구자 공개 저장소 — 점검 스크립트 및 PoC 원문
• OX Security 분석 — OpenSSH Password Authentication Bypass on Alpine Linux
• Cycode 분석 — Alpine 브랜치별 패치 버전 정리
• BleepingComputer 보도 — OpenSSH flaw lets attackers log into password-disabled Linux accounts