cat readme.txt도 안전하지 않다, iTerm2를 사용한다면
3 hours ago
1
- SSH integration은 원격 셸과 통신하기 위해 터미널 escape sequence를 사용하며, 이 구조 때문에 일반 터미널 출력도 conductor 프로토콜처럼 해석될 수 있는 상태
- 핵심 문제는 신뢰 실패로, 실제 원격 conductor가 아닌 악성 파일·배너·MOTD·서버 응답도 위조된 DCS 2000p와 OSC 135를 통해 conductor처럼 동작 가능한 점
- cat readme.txt 실행만으로도 가짜 conductor transcript가 렌더링되면 iTerm2가 getshell·pythonversion·run(...) 흐름을 스스로 진행하고, 공격 출력은 응답만 가장하면 되는 구조
- 익스플로잇은 PTY에 기록된 base64 명령이 실제 SSH conductor가 없을 때 로컬 셸 평문 입력으로 떨어지는 혼선을 이용하며, 마지막 청크가 ace/c+aliFIo 경로로 해석될 때 실행 가능 상태
- 수정은 3월 31일 커밋 a9e745993c2e2cbb30b884a16617cd5495899f86 에 반영됐지만 공개 시점 기준 stable release 미포함 상태였고, 패치 보급 전 공개로 보호 공백 구간이 발생한 상태
iTerm2의 SSH 통합 배경
- iTerm2 SSH integration은 원격 세션을 더 풍부하게 이해하기 위한 기능이며, 원격 셸에 작은 헬퍼 스크립트인 conductor를 올려 동작하는 구조
- it2ssh를 통해 SSH 통합 시작
- 기존 SSH 세션을 통해 원격 부트스트랩 스크립트인 conductor 전송
- 이 원격 스크립트가 iTerm2 프로토콜의 상대 역할 수행
- iTerm2와 원격 conductor는 일반적인 네트워크 서비스가 아니라 터미널 I/O 위에서 escape sequence를 주고받는 방식
- 로그인 셸 탐지
- Python 존재 여부 확인
- 디렉터리 변경
- 파일 업로드
- 명령 실행
PTY 동작 방식
- 현대의 터미널 에뮬레이터는 과거 하드웨어 터미널의 소프트웨어 버전이며, 화면 출력·키보드 입력·터미널 제어 시퀀스 해석 담당
- 셸과 커맨드라인 프로그램은 여전히 실제 터미널처럼 보이는 장치를 기대하므로 OS가 PTY를 제공하는 구조
- PTY는 터미널 에뮬레이터와 포그라운드 프로세스 사이에 위치하는 pseudoterminal
- 일반적인 SSH 세션에서는 iTerm2가 바이트를 PTY에 기록하고, 포그라운드 프로세스인 ssh 가 이를 원격 머신으로 전달하며, 원격 conductor가 stdin으로 읽는 흐름
- iTerm2가 원격 conductor에 명령을 보낼 때 로컬에서는 결국 PTY에 바이트를 기록하는 방식
conductor 프로토콜
- SSH 통합 프로토콜의 전송 수단은 터미널 escape sequence 사용
- 핵심 요소는 두 가지
- DCS 2000p 는 SSH conductor를 hook하는 용도
- OSC 135 는 pre-framer conductor 메시지 용도
- 소스 수준에서 DCS 2000p는 iTerm2가 conductor parser를 생성하게 만들고, 이후 parser가 OSC 135 메시지를 처리하는 구조
- begin <id>
- command output lines
- end <id> <status> r
- unhook
- 정상적인 원격 conductor는 터미널 출력만으로 iTerm2와 통신 가능한 상태
핵심 취약점
- 취약점의 본질은 신뢰 실패이며, 실제 신뢰된 conductor 세션이 아닌 터미널 출력도 iTerm2가 SSH conductor 프로토콜로 받아들이는 점
- 그 결과 신뢰되지 않은 터미널 출력이 원격 conductor를 가장할 수 있는 상태
- 공격 입력은 위조된 DCS 2000p hook과 위조된 OSC 135 응답을 출력할 수 있으며, 이 경우 iTerm2는 실제 SSH integration 교환이 진행 중인 것처럼 동작
익스플로잇 동작 방식
- 익스플로잇 파일은 가짜 conductor transcript를 포함하는 형태
- 사용자가 cat readme.txt를 실행하면 iTerm2는 파일을 렌더링하지만, 파일에는 단순 텍스트가 아니라 다음 요소가 포함된 상태
- 가짜 conductor 세션을 알리는 가짜 DCS 2000p 라인
- iTerm2 요청에 응답하는 가짜 OSC 135 메시지
- hook이 수락되면 iTerm2는 정상 conductor 워크플로를 시작하며, 상류 소스에서 Conductor.start()는 즉시 getshell() 전송 후 성공하면 pythonversion() 전송
- 공격은 이 요청들을 주입할 필요가 없고, iTerm2가 스스로 요청을 발행하며 악성 출력은 응답만 가장하면 되는 구조
상태 머신 진행 과정
- 가짜 OSC 135 메시지는 최소한이지만 정확한 순서로 구성된 상태
- getshell에 대한 command body 시작
- 셸 탐지 출력처럼 보이는 라인 반환
- 해당 명령 성공 종료
- pythonversion에 대한 command body 시작
- 해당 명령 실패 종료
- unhook
- 이 흐름만으로도 iTerm2는 정상적인 fallback 경로로 진입하며, 이후 SSH integration 워크플로가 충분히 완료되었다고 판단하고 다음 단계로 진행
- 다음 단계는 run(...) 명령을 구성해 전송하는 과정
sshargs의 역할
- 위조된 DCS 2000p hook에는 여러 필드가 포함되며, 그중 공격자가 제어하는 sshargs 존재
- 이 값은 이후 iTerm2가 conductor의 run ... 요청을 구성할 때 명령 재료로 사용되는 값
- 익스플로잇은 iTerm2가 다음 데이터를 base64 인코딩할 때
- run <padding><magic-bytes>
- 마지막 128바이트 청크가 ace/c+aliFIo 가 되도록 sshargs 선택
- 이 문자열은 임의값이 아니라 다음 두 조건을 동시에 만족하도록 선택된 값
- conductor 인코딩 경로의 유효한 출력
- 유효한 상대 경로명
익스플로잇을 가능하게 하는 PTY 혼선
- 정상적인 SSH integration 세션에서는 iTerm2가 base64로 인코딩된 conductor 명령을 PTY에 기록하고, ssh 가 이를 원격 conductor로 전달하는 구조
- 익스플로잇 상황에서도 iTerm2는 동일하게 PTY에 명령을 기록하지만, 실제 SSH conductor가 없으므로 로컬 셸이 이를 평문 입력으로 수신하는 차이
- 기록된 세션에서는 다음과 같은 형태 관찰
- getshell이 base64 형태로 나타남
- pythonversion이 base64 형태로 나타남
- 이어서 긴 base64 인코딩된 run ... payload 등장
- 마지막 청크는 ace/c+aliFIo
- 앞선 청크들은 의미 없는 명령으로 실패하고, 마지막 청크는 해당 경로가 로컬에 존재하며 실행 가능할 경우 동작하는 구조
재현 절차
- 원래 파일 기반 PoC는 genpoc.py 로 재현 가능
- python3 genpoc.py
- unzip poc.zip
- cat readme.txt
- 이 절차로 다음 두 파일 생성
- ace/c+aliFIo 라는 실행 가능한 헬퍼 스크립트
- 악성 DCS 2000p 및 OSC 135 시퀀스를 포함한 readme.txt
- 첫 번째 파일은 iTerm2가 가짜 conductor와 통신하도록 유도하고, 두 번째 파일은 마지막 청크 도착 시 셸이 실제로 실행할 대상을 제공
- 익스플로잇이 성공하려면 cat readme.txt를 ace/c+aliFIo가 있는 디렉터리에서 실행해야 하며, 그래야 마지막 공격자 형상 청크가 실제 실행 가능한 경로로 해석되는 조건
공개 및 패치 일정
- 3월 30일 iTerm2에 버그 보고
- 3월 31일 커밋 a9e745993c2e2cbb30b884a16617cd5495899f86 에서 수정 완료
- 작성 시점 기준 수정 사항은 아직 stable release에 포함되지 않은 상태
- 패치 커밋이 반영된 뒤 패치만을 기반으로 익스플로잇을 처음부터 다시 구성하는 시도 진행
- 해당 과정의 프롬프트는 prompts.md
- 결과물은 genpoc2.py
- genpoc.py와 매우 유사하게 동작
공개 시점에 대한 문제 제기
- 수정 사항이 stable release에 도달하기 전에 공개가 이뤄지며 대다수 사용자가 실질적으로 보호받기 어려운 상태에서 취약점이 알려지는 창구 형성
- 이런 공개 시점의 상충 관계에는 명확한 정당화 필요
- 2주는 의미 있는 보급을 기대하기에도 짧고, 조기 공개로 대응을 강제해야 한다고 정당화하기에도 짧은 기간
- 결과적으로 취약점은 널리 알려졌지만 수정판은 현실적으로 필요한 사용자에게 아직 제공되지 않은 공개 공백 구간 형성
- 더 나은 선택지로는 수정판이 실제 사용자 손에 들어갈 때까지 기다리거나, 조기 노출이 왜 필요했는지 분명한 근거 제시 가능했지만 둘 다 충족되지 않은 상태
-
Homepage
-
개발자
- cat readme.txt도 안전하지 않다, iTerm2를 사용한다면