카스퍼스키는 이 패키지들이 단순한 빈 껍데기나 고장 난 미끼가 아니었다고 밝혔다. PyPI 페이지에 적힌 기능은 실제로 구현하면서, 동시에 숨겨진 악성 파일을 전달하는 것이 진짜 목적이었다는 설명이다. The Hacker News도 같은 카스퍼스키 분석을 인용해, 해당 패키지들이 겉으로는 동작하지만 Windows와 Linux에 ZiChatBot을 은밀히 배포하도록 설계됐다고 보도했다.
uuid32-utilscolorinaltermncolor귀속 판단은 문구를 조심해서 읽어야 한다. 카스퍼스키 Securelist 글은 샘플을 Kaspersky Threat Attribution Engine에 제출해 분석했으며, 해당 패키지들이 OceanLotus 관련 위협 인텔리전스 보고서에서 다룬 악성코드와 연계됐을 가능성이 있다고 표현했다. 반면 카스퍼스키의 위협 연구 인덱스는 이 PyPI ZiChatBot 활동을 OceanLotus APT에 귀속한다고 더 직접적으로 적고 있다.
또 다른 공개 요약은 이 귀속을 ‘중간 신뢰도’로 정리했다.
공개된 내용상 감염 구조는 Windows와 Linux를 모두 겨냥한 크로스플랫폼 드로퍼 체인에 가깝다. 카스퍼스키의 위협 연구 인덱스는 악성 PyPI wheel 패키지가 두 운영체제를 대상으로 했고, ZiChatBot이라는 악성코드를 전달하는 드로퍼를 포함했다고 설명한다.
한 공개 요약은 이후 단계로 wheel 패키지에서 DLL 또는 .SO 드로퍼를 추출하고, Windows에서는 Registry, Linux에서는 crontab을 통해 지속성을 확보한 뒤 ZiChatBot을 배포한다고 설명했다. Registry는 Windows 설정과 실행 정보를 저장하는 핵심 구성요소이고, crontab은 Linux에서 예약 작업을 등록하는 기능이다. 공격자가 여기에 흔적을 남기면 재부팅 후에도 악성 동작이 이어질 수 있다.
따라서 점검 범위는 운영 서버에만 머물러서는 안 된다. 개발자 PC, Python 가상환경, CI/CD 빌드 러너, 컨테이너 이미지처럼 패키지 설치가 일어나는 곳은 모두 확인 대상이 될 수 있다.
또 하나의 교훈은 ‘기능이 정상적으로 동작한다’는 사실만으로 패키지를 믿을 수 없다는 점이다. 이번 캠페인의 악성 wheel은 PyPI 페이지에 광고한 기능을 제공하면서도, 뒤로는 악성 파일을 전달한 것으로 보고됐다.
이번 캠페인에서 가장 눈에 띄는 대목은 PyPI 자체보다 ZiChatBot의 명령·제어, 즉 C2 설계다. 카스퍼스키 분석을 인용한 보도에 따르면 ZiChatBot은 전통적인 방식처럼 공격자가 직접 운영하는 전용 C2 서버와 통신하지 않았다. 대신 공개 팀 채팅 앱 Zulip의 REST API들을 C2 인프라처럼 사용했다.
Zulip의 공식 API 문서는 메시지 보내기, 메시지 가져오기, 파일 업로드, 메시지 편집·삭제, 특정 조건으로 메시지를 좁혀 조회하는 narrow 구성, 채널 토픽 관련 기능 등을 제공한다고 설명한다. Zulip의 봇 문서 역시 봇이 사용자가 보낸 메시지를 가로채어 보고 처리한 뒤, 새 메시지로 응답할 수 있다고 안내한다.
높은 수준에서 보면 이런 구조에서는 공격자 지시가 채팅 메시지나 특정 토픽의 메시지 형태로 놓일 수 있고, 감염된 악성코드는 해당 메시지를 조회한 뒤 실행 결과를 같은 서비스로 되돌려 보낼 수 있다. 다만 공개 자료는 ZiChatBot이 사용한 정확한 Zulip 워크스페이스, 봇 자격 증명, 엔드포인트 순서, 명령어 세트를 공개하지 않았다. 따라서 안전한 표현은 ZiChatBot이 공격자 소유의 전용 C2 인프라에만 의존하지 않고, 합법적인 Zulip REST API 기능을 C2 목적으로 악용했다는 것이다.
Zulip API가 언급됐다고 해서 Zulip 자체가 침해됐다는 뜻은 아니다. 인용된 보도와 문서는 정상 REST API와 봇형 메시징 기능의 악용을 설명할 뿐, 채팅 서비스가 해킹됐다고 말하지 않는다.
방어 관점에서 핵심은 목적지 평판만으로는 부족하다는 점이다. Zulip 같은 정상 협업 서비스로 향하는 트래픽도, 해당 호스트나 프로세스, CI 작업, 서비스 계정이 그 서비스를 사용할 이유가 없다면 조사 대상이 될 수 있다. 공격자 소유 도메인 차단 목록만 보는 방식은 이런 패턴을 놓칠 수 있으므로, 목적지뿐 아니라 실행 프로세스와 업무상 기대되는 사용 여부를 함께 봐야 한다.
우선 패키지 인벤토리부터 확인해야 한다. 개발자 장비, 빌드 러너, Python 가상환경, 의존성 잠금 파일, 컨테이너 이미지에서 uuid32-utils, colorinal, termncolor가 설치됐거나 참조됐는지 찾아봐야 한다.
설치 시점도 중요하다. 카스퍼스키가 악성 wheel 업로드 시작 시점으로 언급한 2025년 7월 이후 로그와 아티팩트를 우선 검토해야 한다. 해당 패키지 이름이 발견된다면 단순히 삭제하고 끝내기보다, 조사에 필요한 환경과 로그를 보존하는 편이 안전하다.
운영체제별 지속성 흔적도 봐야 한다. Windows에서는 예상치 못한 Registry 등록값을, Linux에서는 의심스러운 crontab 항목을 확인하는 것이 공개 감염 체인 요약과 맞닿아 있다.
네트워크와 프로세스 텔레메트리에서는 Python 인터프리터, 패키지 설치 프로세스, CI 작업자, 서버 프로세스, 서비스 계정이 Zulip API와 통신했는지 살펴볼 필요가 있다. 질문은 ‘Zulip이 정상 서비스인가’가 아니라 ‘이 특정 호스트와 프로세스가 Zulip API를 호출할 정상 이유가 있는가’여야 한다.
마지막으로, 패키지가 겉으로 제 기능을 한다는 사실을 신뢰의 근거로 삼아서는 안 된다. 이번 사례에서 문제의 패키지들은 광고한 기능을 제공하면서도 악성 파일의 드로퍼 역할을 한 것으로 보고됐다.
Comments
0 comments