musl과 PAM 없이 별표 계정에 257~1024바이트 비밀번호를 넣으면 로그인이 뚫리는 sshole 버그
- 빌 조이가 1980년 3BSD /etc/passwd의 daemon 계정에 넣은 별표는 해시가 아니라 어떤 비밀번호와도 매칭되지 않는 값이고, 이 관행이 지금까지 이어짐
- POSIX는 1997년 crypt() 실패 시 NULL 반환을 명시했지만, 많은 프로그램이 NULL 검사를 빼먹어 strcmp가 주소 0을 읽고 세그멘테이션 폴트를 냄
- musl은 2012년 8월 커밋 b3c4cc12에서 crypt()가 실패하면 NULL 대신 별표를 반환하게 바꾸고, 20일 뒤 sha256/sha512 crypt를 추가하면서 비밀번호를 256바이트로 제한함
- glibc는 musl의 별표를 거의 그대로 따라 했지만 한 글자 차이인 별표0이 됐고, 2024년 12월 musl 메일링 리스트에는 257자 비밀번호에 passwd가 크래시한다는 보고가 올라옴
- 결과적으로 musl + PAM 없음 + 별표 계정 + 257~1024바이트 비밀번호 조합으로 로그인이 성립하며, 사이트는 sshd 빌드 12개에서 의심 로그인 약 17,600건을 근거로 제시함
Hacker News 의견들
다른 스레드 소스 보면 PAM 없이 musl 쓰는 환경에서 터지는 버그임. PasswordAuthentication=no로 막거나 그냥 업데이트하면 해결됨.
musl에 PAM 없이 sshd 돌리면서 비밀번호 인증까지 켜둔 데가 실제로 있냐? 이론상 Alpine이 그렇다 치고, 진짜 돌아가는 곳이 있냐는 거임.
Docker 컨테이너가 어마어마하게 많잖아. 소수 비율이라도 전 세계 Alpine 컨테이너 수에 곱하면 절대 숫자는 커짐.
공개 SFTP 서버가 딱 그 경우일 수 있음. 나도 익명 공개 SFTP 만들면서 빈 비밀번호 허용했고 서버는 전부 Alpine인데 shadow 패키지가 기본 설치가 아니라서 위험함. 오늘 테스트용으로 하나 열어뒀으니 놀다 가셈.
요즘 에이전트 샌드박스도 다 그럴 듯.
사이트는 잘 만들었는데 나는 아무 느낌이 안 들더라.
LLM 결과물에 지친 거 아님?
이름은 *sshole인데 도메인은 sshhole.com인 게 계속 걸림. 이 정도로 파고든 사람이 h 개수는 왜 안 맞췄나.
AI가 쓴 느낌은 나는데 그래도 잘 쓴 글임. 한 번에 뽑은 게 아니라 자기 취향에 맞게 다듬은 것 같음.
crypt()가 NULL에서 크래시하는 건 호출자 잘못이라는 게 통설인데, musl이 나쁜 구현까지 감싸줄 필요가 있었나? 이 설명 자체가 AI 추측 아님?
새 구현이 glibc 동작을 다 맞춰주지 않으면 아무도 안 씀. 그냥 트레이드오프임.
musl 커밋 메시지에 대놓고 적혀 있음. crypt 실패를 처리 안 하는 프로그램이 많아서, 항상 성공하되 매칭 불가 해시를 주는 게 낫다고.
FROM scratch로 이미지 만들라는 이유가 하나 더 생겼네.
Alpine 컨테이너에 sshd가 기본으로 깔리는 건 아님. Dockerfile로 직접 깔고 설정을 안 남겨야 그 상태가 됨.
스크롤을 가로채는 사이트는 바로 닫음. 모바일에서는 멀쩡하던데 데스크톱에만 넣은 듯.
핵심 크립토 함수를 편하다는 이유로 바꾼 게 아쉽다. 이 정도 버그를 잡아낼 감사도 없이 바꿨다는 게.
musl은 그냥 농담임. 프로덕션에 왜 쓰는지 모르겠고 경고 신호가 여러 번 있었는데 자업자득임.
각 결정은 나름 말이 됨. 크래시 방지, 타이밍 공격 회피, 비밀번호 없는 계정. 근데 전부 별표는 어차피 거부된다는 전제에 기대고 있음.
musl 초기부터 봤는데 개발자가 이상 동작을 두둔하는 태도 보고 접었음. 나중엔 Python도 제대로 안 돌아갔고.