2P by neo 2달전 | ★ favorite | 댓글 1개

WorstFit: Windows ANSI의 숨겨진 변환기 공개

TL;DR

  • Windows의 내부 문자 집합 변환 기능인 Best-Fit을 악용하여 새로운 공격 표면을 발견함.
  • 이 기능을 경로 탐색, 인수 주입, 원격 코드 실행(RCE) 등의 실질적인 공격으로 변환함.
  • 문제의 근본 원인은 컴파일러 동작, C/C++ 런타임, 개발자의 실수에 있음.
  • 오픈 소스 생태계에서의 수정 도입의 어려움도 논의함.

Windows 인코딩 해독

초기: ANSI와 코드 페이지

  • Windows는 처음에 ANSI 인코딩을 사용했으며, 이는 특정 언어에 효과적이었지만 혼합 문자 집합을 처리할 수 없었음.
  • 다양한 코드 페이지가 존재하며, 각 코드 페이지는 특정 언어를 지원함.

유니코드 시대: UTF-16

  • Windows는 1990년대 중반에 유니코드로 전환하여 거의 모든 언어의 문자를 단일 표준으로 표현할 수 있게 됨.
  • 초기에는 UCS-2를 사용했으나, 곧 UTF-16으로 업그레이드됨.

이중 인코딩 시대

  • Windows는 이전의 ANSI 코드 페이지를 지원하기 위해 두 가지 API 버전을 구현함.
  • ANSI API유니코드 API가 있으며, 개발자는 원하는 데이터 형식을 쉽게 얻을 수 있음.

Best-Fit의 장점

  • Windows의 "Best-Fit" 문자 변환은 UTF-16에서 ANSI로 변환할 때 대상 코드 페이지에 없는 문자를 처리하는 방법임.
  • 예를 들어, 기호는 Windows-1252 코드 페이지에 없으므로 Microsoft는 이를 8로 매핑함.

WorstFit: Windows의 새로운 공격 표면

🔥 동아시아의 악몽 - CVE-2024-4577

  • CVE-2024-4577은 중국어 또는 일본어 코드 페이지로 구성된 PHP-CGI 서버를 간단한 ?%ADs 요청으로 손상시킬 수 있는 취약점임.
  • Best-Fit 동작으로 인해 U+00AD(소프트 하이픈)가 대시(-)로 매핑되어 우회가 가능함.

🔥 파일 이름 밀수

  • 파일 이름 처리에서 WorstFit을 악용하여 경로 탐색 페이로드로 변환할 수 있음.
  • 예를 들어, Chrome V8의 Developer Shell(d8.exe)은 ANSI API를 사용하여 현재 작업 디렉토리를 얻음.

🔥 인수 분할

  • GetCommandLineA의 출력을 조작하여 WorstFit 동작을 명령줄 구문 분석에 악용할 수 있음.
  • 예를 들어, " --use-askpass=calc " 입력은 시스템에서 calc.exe를 실행할 수 있음.

결론

  • Best-Fit 동작은 시스템 수준에서의 변환 과정에서 공격 표면을 제공하며, 이는 다양한 도구에서 취약점을 유발할 수 있음.
  • 표준 라이브러리나 프로그래밍 언어의 함수로는 이러한 공격을 완전히 막을 수 없음.
Hacker News 의견
  • Microsoft는 최소 1년 전부터 이 문제를 알고 있었음. CA2101이라는 특별한 코드 분석 규칙을 통해 best-fit 매핑 사용을 권장하지 않음. 보안 취약점을 언급했지만 세부 사항은 모호했음

  • 이 문제는 시스템적임. Microsoft는 유니코드를 ASCII로 변환하는 "best fit" 코드 매핑을 제공함. 이 매핑은 많은 곳에서 사용되며, Microsoft가 하위 호환성을 중요시하기 때문에 계속 포함될 필요가 있음. 기본적으로 모든 곳에 연결되어 있음

    • 주로 비정상적인 코드 포인트를 슬래시, 하이픈, 인용 부호 등으로 변환하는 데 악용됨. 현대 프로그래밍 언어에서는 올바르게 평가되지만, 쉘 명령이나 Win32 API로 전달될 때 문제가 발생함

    • curl 유지보수자는 "curl이 피해자"라고 말하지만, 문제의 원인은 다른 곳에 있음. 서버가 사용자 입력을 검증할 때와 시스템 라이브러리에 적용할 때 다르게 처리하면 문제가 발생함

    • Win32 공간에서 "best fit" 변환을 선택적으로 해제하는 것이 해결책일 수 있음. 오픈 소스 제공자는 이를 모범 사례로 추가할 수 있음

  • Windows는 Munchkin 카드 게임처럼 여러 기능이 우연히 결합되어 강력한 취약점을 초래할 수 있음. ANSI 하위 시스템을 UTF-8로 변환하는 것이 이 문제를 완화할 수 있음

  • Microsoft는 NT 3.5부터 ANSI를 단계적으로 폐지하고 Wide Character API 사용을 장려해왔음. 그러나 Microsoft의 C/C++ 런타임 라이브러리 구현 방식이 주요 장애물임

    • 표준 함수는 A-함수를 사용하여 유니코드 변환 실패를 보고하지 않고 best-fit 접근 방식을 사용함
  • Microsoft가 모든 Windows 에디션에서 기본적으로 UTF-8을 활성화할 가능성은 낮음. 오래된 애플리케이션이 특정 코드 페이지나 1바이트 문자에 의존하기 때문임

    • win32 xxxA API에서 Best-Fit 논리를 제거하는 것이 더 적은 문제를 일으킬 것임
  • 애플리케이션에서 "Ansi" 코드 페이지를 UTF-8로 강제 설정하는 두 가지 방법이 있음. 하나는 Manifest 파일을 사용하는 것이고, 다른 하나는 "App Locale" 도구를 사용하는 것임

  • 개인 Windows 컴퓨터에서 UTF-8 모드를 설정하여 이 버그로부터 안전했음. 오래된 외국 게임에서 깨진 텍스트가 표시되어 설정했음

  • 문제 해결은 단순히 main()을 wide-character 버전으로 대체하는 것만으로는 해결되지 않음. 모든 변수를 wchar_t *로 변환해야 하며, 이는 고통스럽고 오류가 발생하기 쉬움

    • 대신 수신한 wide characters를 UTF-8로 변환하고 "char"를 계속 사용할 수 있음. ANSI 또는 OEMCP 문자열과 UTF-8 문자열을 혼합하지 않도록 주의해야 함
  • Windows API가 best-fit 변환을 제공한다는 것을 알고 있었지만, 기본 동작인 줄은 몰랐음. 이 기능은 금지되어야 함

  • 베타 체크박스가 ActiveCodePage를 UTF-8로 설정하는 것과 같은지 궁금했음. GDI는 프로세스별 코드 페이지를 따르지 않고 전역 코드 페이지만 따름. UTF-8을 완전히 선택할 수 없는 것은 아쉬움