Skip to content

Latest commit

 

History

History
128 lines (99 loc) · 6.46 KB

File metadata and controls

128 lines (99 loc) · 6.46 KB

util-linux wall 이스케이프 시퀀스 주입 (CVE-2024-28085)

메타데이터

항목 내용
CVE ID CVE-2024-28085
영향 버전 util-linux 2.40 이하 전 버전 (2013년 도입, 약 11년간 존재)
CVSS v3.1 5.5 (Medium) 전후 (배포판별 상이)
공개일 2024-03-27 (oss-security 공개)
별칭 WallEscape

개요

wall 은 로그인해 있는 다른 사용자들의 터미널에 메시지를 broadcast 하는 유틸리티다. Ubuntu/Debian 계열에서는 기본적으로 setgid tty 로 설치되어 있고, mesgy 로 설정된 사용자라면 누구나 이 명령을 실행해 남의 터미널에 메시지를 띄울 수 있다. CVE-2024-28085는 wall표준입력으로 받은 메시지는 이스케이프 시퀀스를 걸러내면서, 명령행 인자(argv)로 받은 메시지는 걸러내지 않는 불일치 때문에, 권한 없는 로컬 사용자가 다른 사용자의 터미널에 임의의 터미널 이스케이프 시퀀스를 주입할 수 있게 되는 취약점이다.

사전 지식

터미널 이스케이프 시퀀스

터미널은 화면에 그냥 텍스트만 찍는 게 아니라, 특정 바이트 시퀀스(예: ESC 로 시작하는 시퀀스)를 "커서 이동", "색상 변경", "제목 변경" 같은 명령으로 해석한다. 문제는 일부 터미널 에뮬레이터가 이 시퀀스 중 일부를 "클립보드에 텍스트 쓰기"나 "임의 문자열을 터미널에 다시 입력된 것처럼 흉내내기(키 입력 인젝션)" 같은 위험한 동작까지 지원한다는 점이다. 즉 터미널에 "텍스트를 출력하는 것"만으로도, 상대방의 클립보드를 바꾸거나 상대방이 다음에 칠 명령을 조작하는 것과 비슷한 효과를 낼 수 있다.

wall 이 메시지를 받는 두 가지 경로

wall 은 메시지를 두 가지 방식으로 받을 수 있다.

  1. 표준입력(stdin): wall < message.txt 처럼 파일이나 파이프로 메시지를 준다.
  2. 명령행 인자(argv): wall "안녕하세요" 처럼 메시지 자체를 인자로 준다.

두 경로 모두 결국 같은 "터미널에 메시지를 출력하는" 목적지로 가지만, 각 경로에서 메시지 문자열이 어떤 함수를 거쳐 출력되는지가 서로 달랐다는 것이 이 취약점의 핵심이다.

취약점 분석

근본 원인: 경로에 따라 다른 출력 함수를 사용

wall 개발자는 이전에 이미 "이스케이프 시퀀스를 걸러내고 출력하는" 안전한 함수 (fputs_careful, 위험한 바이트를 ^ 로 escape 하고 표시 폭을 제한)를 만들어 두었다. 그런데 이 함수는 표준입력으로 받은 메시지에만 적용되고 있었다. 명령행 인자로 받은 메시지는 그냥 일반 fputs() 로 그대로(필터링 없이) 출력되고 있었다.

// term-utils/wall.c — makemsg() 의 argv 처리 부분 (패치 전)
for (i = 0; i < mvecsz; i++) {
    fputs(mvec[i], fs);           // 필터링 없이 그대로 출력
    if (i < mvecsz - 1)
        fputc(' ', fs);
}

즉 코드베이스 안에 "안전한 출력 함수"와 "안전하지 않은 출력 함수"가 공존했고, 어느 경로가 어느 함수를 쓰는지의 일관성이 깨져 있었던 것이 근본 원인이다. 두 경로를 박스로 그리면:

사용자 입력
   │
   ├─ stdin 경로 ──▶ fputs_careful() ──▶ 이스케이프 문자를 '^X' 형태로 안전하게 변환 ──▶ 출력
   │                  (필터링 있음)
   │
   └─ argv 경로  ──▶ fputs() ─────────▶ 아무 변환 없이 그대로 ──▶ 출력
                      (필터링 없음)  ↑
                                     여기가 취약점: 같은 목적지인데 다른 관문을 통과

공격이 성립하는 경로

  1. 대상 시스템에서 wall 이 setgid tty 로 설치되어 있고(다수 배포판 기본값), 피해자의 mesg 설정이 y 다(다수 배포판 기본값).
  2. 권한 없는 로컬 공격자가 wall명령행 인자로 호출하며, 인자 안에 터미널 이스케이프 시퀀스를 포함시킨다.
  3. wall 은 이 인자를 필터링 없이 그대로 로그인 중인 모든 사용자의 터미널에 broadcast 한다.
  4. 피해자의 터미널 에뮬레이터가 해당 이스케이프 시퀀스를 지원하면, 클립보드 내용이 공격자가 원하는 문자열로 바뀌거나 그 외 터미널 조작이 발생할 수 있다.

수정 방법

수정 커밋(404b0781f52f7c045ca811b2dceec526408ac253, "wall: fix escape sequence Injection [CVE-2024-28085]")은 argv 경로도 동일하게 fputs_careful() 을 쓰도록 바꿔서, 두 입력 경로가 같은 필터링 관문을 통과하게 만들었다.

--- a/term-utils/wall.c
+++ b/term-utils/wall.c
@@ makemsg() argv 처리 부분
 		for (i = 0; i < mvecsz; i++) {
-			fputs(mvec[i], fs);
+			fputs_careful(mvec[i], fs, '^', true, TERM_WIDTH);
 			if (i < mvecsz - 1)
 				fputc(' ', fs);
 		}

패치 후 그림으로 다시 그리면:

사용자 입력
   │
   ├─ stdin 경로 ──▶ fputs_careful() ──▶ 이스케이프 문자를 '^X' 형태로 안전하게 변환 ──▶ 출력
   │
   └─ argv 경로  ──▶ fputs_careful() ──▶ 이스케이프 문자를 '^X' 형태로 안전하게 변환 ──▶ 출력
                      (이제 같은 함수, 같은 필터링)

두 경로가 동일한 함수를 쓰게 되면서, "어느 경로로 들어왔느냐"에 따라 필터링 여부가 달라지는 불일치 자체가 사라졌다.

참고 자료

미해결/불확실 지점

  • "클립보드를 바꾸는 이스케이프 시퀀스"의 정확한 바이트열과, 어떤 터미널 에뮬레이터가 이를 지원하는지의 목록은 이번에는 다루지 않았다(공개 PoC/Full Disclosure 게시물에 있을 것으로 보이나, 정적 분석 범위상 직접 대조하지 않았다).