개요
| 항목 | 내용 |
|---|---|
| CVE ID | CVE-2024-6387 |
| 별칭 | regreSSHion |
| CVSS 점수 | 9.8 (Critical) |
| 영향 제품 | OpenSSH 8.5p1 ~ 9.7p1 (glibc 기반 Linux) |
| 취약점 유형 | Race Condition (Signal Handler) |
| 인증 필요 | ❌ Pre-auth RCE |
| 발견 | Qualys, 2024년 7월 |
| 패치 | OpenSSH 9.8p1 |
기본 원리: 시그널과 레이스 컨디션
UNIX 시그널이란
시그널은 프로세스에게 보내는 비동기 알림이다. 키보드 Ctrl+C를 누르면 SIGINT가 전송되고, 타이머가 만료되면 SIGALRM이 전송된다.
프로세스 실행 흐름:
메인 코드 실행 중...
↓ 언제든지 시그널 도착 가능
→ 현재 실행 중인 코드 중단
→ 시그널 핸들러 함수 실행
→ 핸들러 완료 후 중단된 위치로 복귀
시그널 핸들러의 제약:
POSIX 표준: 핸들러 안에서는 async-signal-safe 함수만 호출해야 함
async-signal-safe 함수: write(), read(), _exit(), kill() 등 (약 100개)
unsafe 함수: malloc(), free(), syslog(), printf() 등
이유: 메인 코드가 malloc()을 실행하는 도중에 SIGALRM이 도착하면
핸들러에서도 malloc()을 호출하면 힙 내부 데이터 구조가 망가짐
힙 메모리와 malloc의 내부 구조
malloc()이 관리하는 힙 메모리 구조:
[청크 헤더 | 실제 데이터 | 청크 헤더 | 실제 데이터 ...]
prev_size size flags prev_size size flags
malloc() 실행 중:
1. 가용 청크 목록(bin) 검색
2. 적절한 청크 찾으면 헤더 수정 (in-use 표시)
3. 메모리 포인터 반환
레이스 컨디션:
메인: malloc() 진행 중 (bin 수정 중)
↓ SIGALRM 도착
핸들러: syslog() 호출 → 내부적으로 malloc() 다시 호출
결과: 이미 수정 중인 bin 구조에 또다시 쓰기 → 힙 손상
취약점 메커니즘
"Regression"의 의미
CVE-2006-5051는 2006년 OpenSSH에서 발견된 시그널 핸들러 레이스 컨디션이다. 2006년에 패치됐지만, 2020년 OpenSSH 8.5p1에서 코드 리팩토링 중 실수로 재도입됐다. 이를 회귀 버그(Regression Bug) 라고 한다.
CVE-2006-5051 → 2006년 발견 → 패치
→ 2020년 8.5p1에서 실수로 재도입 ← regreSSHion
CVE-2024-6387 → 2024년 Qualys가 재발견
취약한 코드 위치
/* OpenSSH sshd.c — 취약한 시그널 핸들러 */
static void
sshd_sigalrm(int sig)
{
/* LoginGraceTime 타임아웃 시 호출 */
/* ❌ syslog()는 async-signal-unsafe!
내부에서 malloc() → fprintf() → 기타 unsafe 함수 호출 */
syslog(LOG_INFO, "Timeout before authentication for %s port %d",
ssh_remote_ipaddr(the_active_state),
ssh_remote_port(the_active_state));
cleanup_exit(255);
}
/* LoginGraceTime 설정: 기본값 120초
클라이언트가 120초 안에 인증하지 않으면 SIGALRM 발생 */
공격 흐름
1. 공격자가 SSH 연결 시작 (인증은 하지 않음)
2. sshd가 LoginGraceTime(120초) 타이머 시작
3. 공격자가 SSH 프로토콜 상 일부 데이터 교환으로
sshd의 malloc/free를 특정 상태로 유도 (힙 그루밍)
4. 120초 후 SIGALRM 발생
5. sshd_sigalrm() 핸들러에서 syslog() 호출
6. syslog() 내부의 malloc()이 이미 조작된 힙 구조에 쓰기
7. 힙 손상 → 정밀 조작으로 RCE 가능
성공까지 수천~수십만 번 반복 시도 필요 (확률적 공격)
공격 난이도와 현실성
32비트 x86 시스템:
ASLR 엔트로피: 16비트 (65536 경우의 수)
→ 현실적으로 수백~수천 번 시도로 성공 가능
→ Qualys 연구팀이 실험적 익스플로잇 성공 확인
64비트 x86_64 시스템:
ASLR 엔트로피: 40비트 (약 1조 경우의 수)
→ 평균 수백만 번 시도 필요
→ 이론적으로 가능하나 실용적 익스플로잇은 아직 미공개
→ 단, 클라우드 환경에서 동일 이미지로 배포된 서버는
ASLR 시드가 같을 수 있어 병렬 공격 가능성
주목할 점:
각 시도마다 새 TCP 연결 (sshd가 새 프로세스 fork)
연결 수가 많으면 타겟 서버 로그에 기록됨
단, 자동화 공격이라 실제 시간은 짧을 수 있음
영향 범위
취약: OpenSSH 8.5p1 이상, 9.7p1 이하 (glibc 기반 Linux)
안전: OpenSSH 4.4p1 미만 (CVE-2006-5051 패치 포함)
안전: OpenSSH 9.8p1 이상 (CVE-2024-6387 패치)
안전: OpenBSD (다른 시그널 처리 메커니즘)
안전: macOS (다른 syslog 구현체 사용)
안전: musl libc 기반 Alpine Linux (musl의 malloc은 동작 다름)
# 버전 확인
ssh -V
# OpenSSH_9.6p1 Ubuntu-3ubuntu13.3, OpenSSL 3.0.13
# 모든 인터넷 노출 OpenSSH 서버 규모 (2024년 7월 기준)
# Shodan: ~1,400만 개 인스턴스
# 취약 버전: 그 중 약 700만 개 이상 추정
탐지 및 대응
# 즉시 패치
sudo apt update && sudo apt upgrade openssh-server # Debian/Ubuntu
sudo dnf update openssh-server # RHEL/Fedora/Rocky
sudo zypper update openssh # openSUSE/SLES
# 패치 후 버전 확인
sshd -V # OpenSSH_9.8p1 이상이어야 함
# 패치 불가 시 임시 완화 (/etc/ssh/sshd_config)
LoginGraceTime 0
# 타임아웃 비활성화 → SIGALRM 발생 안 함 → 공격 벡터 제거
# 주의: DoS 가능성 있음 (타임아웃 없으면 미완성 연결이 계속 유지)
# sudo systemctl reload sshd # 설정 적용
# 추가 완화: 연결 속도 제한
MaxStartups 10:30:100
# 미인증 연결이 10개 이상이면 30% 확률로 거절, 100개 이상이면 전부 거절
# → 공격에 필요한 대량 연결 시도 차단
# 공격 탐지: 짧은 시간에 다수의 SSH 연결 시도
grep "sshd.*Connection from" /var/log/auth.log | \
awk '{print $NF}' | sort | uniq -c | sort -rn | head
# SIGALRM 관련 로그 (공격 시도 흔적)
grep "Timeout before authentication" /var/log/auth.log | tail -20
시사점
1. 회귀 버그(Regression Bug)의 위험성
- 한 번 수정된 버그가 리팩토링/업그레이드 중 재도입될 수 있음
- 자동화된 회귀 테스트(Regression Test)가 보안에도 필수
- 수정 커밋 메시지에 "fixes CVE-XXXX" 명시해야 추적 가능
2. async-signal-safety 원칙
- 시그널 핸들러에서는 async-signal-safe 함수만 사용
- POSIX 표준 문서의 safe 함수 목록 참조
- 핸들러를 최소화: 플래그 설정만 하고 실제 처리는 메인 루프에서
3. 오픈소스 소프트웨어의 대규모 영향
- OpenSSH는 전 세계 서버 인프라의 핵심
- 하나의 버그가 수천만 대에 영향
- 의존성 관리와 신속한 패치 적용 체계 필수