- 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> runhook
- 정상적인 원격 conductor는 터미널 출력만으로 iTerm2와 통신 가능한 상태
핵심 취약점
- 취약점의 본질은 신뢰 실패이며, 실제 신뢰된 conductor 세션이 아닌 터미널 출력도 iTerm2가 SSH conductor 프로토콜로 받아들이는 점
- 그 결과 신뢰되지 않은 터미널 출력이 원격 conductor를 가장할 수 있는 상태
- 악성 파일
- 서버 응답
- 배너
- MOTD
- 공격 입력은 위조된
DCS 2000phook과 위조된OSC 135응답을 출력할 수 있으며, 이 경우 iTerm2는 실제 SSH integration 교환이 진행 중인 것처럼 동작
익스플로잇 동작 방식
- 익스플로잇 파일은 가짜 conductor transcript를 포함하는 형태
- 사용자가
cat readme.txt를 실행하면 iTerm2는 파일을 렌더링하지만, 파일에는 단순 텍스트가 아니라 다음 요소가 포함된 상태- 가짜 conductor 세션을 알리는 가짜
DCS 2000p라인 - iTerm2 요청에 응답하는 가짜
OSC 135메시지
- 가짜 conductor 세션을 알리는 가짜
- hook이 수락되면 iTerm2는 정상 conductor 워크플로를 시작하며, 상류 소스에서
Conductor.start()는 즉시getshell()전송 후 성공하면pythonversion()전송 - 공격은 이 요청들을 주입할 필요가 없고, iTerm2가 스스로 요청을 발행하며 악성 출력은 응답만 가장하면 되는 구조
상태 머신 진행 과정
- 가짜
OSC 135메시지는 최소한이지만 정확한 순서로 구성된 상태getshell에 대한 command body 시작- 셸 탐지 출력처럼 보이는 라인 반환
- 해당 명령 성공 종료
pythonversion에 대한 command body 시작- 해당 명령 실패 종료
unhook
- 이 흐름만으로도 iTerm2는 정상적인 fallback 경로로 진입하며, 이후 SSH integration 워크플로가 충분히 완료되었다고 판단하고 다음 단계로 진행
- 다음 단계는
run(...)명령을 구성해 전송하는 과정
sshargs의 역할
- 위조된
DCS 2000phook에는 여러 필드가 포함되며, 그중 공격자가 제어하는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.pyunzip poc.zipcat 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주는 의미 있는 보급을 기대하기에도 짧고, 조기 공개로 대응을 강제해야 한다고 정당화하기에도 짧은 기간
- 결과적으로 취약점은 널리 알려졌지만 수정판은 현실적으로 필요한 사용자에게 아직 제공되지 않은 공개 공백 구간 형성
- 더 나은 선택지로는 수정판이 실제 사용자 손에 들어갈 때까지 기다리거나, 조기 노출이 왜 필요했는지 분명한 근거 제시 가능했지만 둘 다 충족되지 않은 상태