/CVE 분석/CVE-2024-6387
CriticalCVSS 9.82024-07-01

CVE-2024-6387: regreSSHion — OpenSSH 레이스 컨디션 RCE (CVSS 9.8)

18년 전 수정된 OpenSSH 시그널 핸들러 버그가 다시 돌아왔다. 수백만 대의 리눅스 서버에 영향을 미치는 Pre-auth RCE이며, Qualys가 발견한 'regreSSHion'.

#OpenSSH#Race Condition#RCE#Linux#regreSSHion

개요

항목 내용
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는 전 세계 서버 인프라의 핵심
   - 하나의 버그가 수천만 대에 영향
   - 의존성 관리와 신속한 패치 적용 체계 필수