니케 런처 해킹으로 돌아본 홈서버 보안 [with CDN, 공급망 공격]

서론

2026년 11월 4일 새벽, 니케 게임 런처가 악성코드를 뿌리고 있다는 문제가 제기되었다.

승리의 여신: 니케 | 절망에 맞서 승리로 향하는 소녀들의 건슈팅 RPG
세계 탈환을 위한 미소녀 건슈팅 액션! 11월 4일 정식 런칭!
[단독] ‘니케’ 해킹 사태에 넥슨 전사 보안 공지…”런처 즉시 삭제”
시프트업의 인기 게임 ‘승리의 여신: 니케’에서 악성코드가 유포된 정황이 드러나자 국내 게임사들이 보안 점검에 나서고 있다. 넥슨은 전사 차원의 보안 공지를 내리고 관련 프로그램이 설치된 경우 즉시 삭제와 보안팀 신고를 지시한 것으로 확인됐다. 4일 게임업계에 따르면…

안타깝게도 4주년을 맞아 필자도 게임을 설치했었고, 해당 기간에 PC 런처를 실행했다.

그간 필자의 홈서버 운영 기조는 단순했다. '밖에서 못 들어오게만 하면 안전하다.' 공유기에서 연 포트는 WireGuard 진입점(UDP) 하나로 일원화하였고, 외부에 공개해야 하는 포트폴리오와 블로그는 Cloudflare Tunnel로 내보냈다. 나머지 서비스는 전부 방화벽 뒤에 두고 VPN으로만 접근하도록 제한하였다.

다만 이번 사태의 문제는 그 VPN 키를 가진 PC가 해킹당했다는 것이다.
즉, 그간 구축한 홈서버 보안 대책이 무색하게 인가된 기기가 탈취됨으로써 해킹의 직접적인 영향을 받게 된 셈이다.

이번 글에서는 사건의 전개를 살펴보며 그간 필자가 믿어 온 운영 기조가 어디서부터 틀렸는지 정리해 보고자 한다.


본론

ChatGPT와 선의의 경쟁을 하고 계신, 아울러 곧 상장을 앞두신 대황클로드님께 자문을 구하였다.

공급망 공격(Supply Chain Attack)이라고 부릅니다. 목표를 직접 공격하는 대신, 목표가 이미 신뢰하고 있는 소프트웨어나 서비스를 먼저 장악해 그 신뢰를 타고 들어가는 공격입니다.

업데이트 서버, 빌드 파이프라인, CDN, 오픈소스 패키지처럼 "원래 믿고 받아 쓰던 경로"가 침투 지점이 됩니다. 피해자는 평소처럼 정식 프로그램을 실행했을 뿐이라 알아차리기 어렵고, 공급자 하나를 뚫으면 그 고객 전체로 피해가 번집니다.


출처 | Anthropic. (2026). Claude Opus 5.5 [Large language model]. https://claude.ai/

사건의 전말

이번 사건을 처음 상세히 분석한 보안 연구자 MotherSphere의 사고 보고서에 운영사 발표와 연구자들이 직접 확인한 기록이 시간순으로 잘 정리되어 있는데, 이를 기준으로 주요 사건만 추려 보면 아래와 같다.

일시 (KST) 내용
9/27 10:59 insightjs.com 도메인 등록 (만료된 도메인을 제3자가 새로 등록)
9/27 15:41 런처가 실행 시 내려받는 공식 CDN 스크립트 4개 변조
10/24 01:40 에이전트가 실행된 가장 이른 기록 (피해자 보고)
10/29 00:46 원본 서버의 FeedList.feb647c9.js는 정상본으로 교체됐으나, CDN 엣지는 계속 변조본을 배포
10/30 03:52 운영사 발표상 악성 프로그램 유포 시작
11/4 00:00 운영사 이상 감지
11/4 01:11 니케 커뮤니티 디스코드에 첫 공개 경고
11/4 02:04~02:23 변조 파일 3개 교체
11/4 12:09 나머지 1개 CDN 캐시 갱신
11/4 12:13 운영사 첫 공지 (공식 X)
11/5 08:00 런처에 악성 프로그램 탐지·제거 기능 반영, 이어서 사과문과 수동 점검 안내 게시
11/5 11:05 insightjs.com 도메인 등록기관에 의해 정지
NIKKE PC 런처 침해 사고 (2026년 11월) (NIKKE PC launcher, Nov 2026)
NIKKE PC 런처 침해 사고 (2026년 11월) (NIKKE PC launcher, Nov 2026) - nikke-pc-launcher-compromise_ko.md
시프트업의 다른 게임인 '스텔라 블레이드'에 마더스피어(MotherSphere)가 나오는데, 인용인지는 모르겠다.

타임라인을 정리해 보면 이번 사건에는 성격이 다른 문제 두 개가 겹쳐 있다.

구분 무엇 실제로 한 일
① 도메인 탈취 예전에 쓰다 만료된 insightjs.com 도메인을 공격자가 새로 등록 공격자 소유 서버로, 실제 악성코드를 올려 둠
② 운영사 CDN 런처가 불러오는 공식 스크립트 4개 공격자가 파일에 "insightjs.com에서 스크립트를 불러와라"는 코드를 끼워 넣음

사실 ①은 쓰던 도메인을 만료되도록 방치한 관리 소홀로 이해는 간다. 공격자 입장에서는 그럴듯한 이름의 서버를 하나 얻은 것뿐이고, 이것만으로는 아무 일도 일어나지 않는다. 런처가 그 도메인을 부를 이유가 없기 때문이다.

진짜 핵심은 ②다. ①만 단독으로 존재했다면 그저 해당 서버에 악성코드가 있는 것에 그쳤을 뿐, 지금처럼 문제가 커지지는 않았을 것이다. 그런데 어떤 이유에서인지 공격자가 운영사의 CDN에 파일을 쓸 수 있었고, 이로 인해 런처를 켠 사용자 모두가 ①의 악성코드를 내려받게 됐다.

그렇다면 "CDN에 파일을 쓸 수 있다"는 게 왜 이렇게까지 큰 문제일까. 기사들도 하나같이 "CDN이 해킹됐다"고만 쓰는데, 이를 제대로 이해하려면 CDN이 정확히 뭔지부터 짚고 넘어가야 한다. 공격자가 그 권한을 어떻게 얻었는지는 그다음에 살펴보자.

CDN에 대한 이해

MDN(MDN Web Docs)에서는 CDN을 아래와 같이 설명하고 있다.

A CDN (Content Delivery Network) is a group of servers spread out over many locations. These servers store duplicate copies of data so that servers can fulfill data requests based on which servers are closest to the respective end-users.

출처 : MDN Web Docs, "CDN", https://developer.mozilla.org/en-US/docs/Glossary/CDN

이를 요약해 보면, 원본 서버(Origin) 앞에 전 세계로 흩어진 엣지 서버(Edge)를 두고 사용자와 가장 가까운 엣지가 대신 응답하게 하는 구조라는 뜻이다. 서울 사용자가 미국 원본까지 왕복하는 대신 서울 엣지에서 파일을 받으니 빠르고, 원본 서버는 요청 대부분을 엣지가 흡수해 주니 편하다. AWS CloudFront나 Cloudflare가 대표적인 CDN의 예시이다.

즉, 엣지가 하는 일의 본질은 캐시(Cache)다. 처음 요청이 들어오면 원본에서 파일을 가져와 엣지에 저장해 두고, 이후 요청에는 저장해 둔 사본으로 응답한다. 웹 서버(Nginx 등)의 정적 파일 전달 역할을 전 세계 단위로 키운 것이라고 봐도 무방하다.

백엔드 개발자 입장에서 정적 파일을 CDN에 올리는 흐름은 대략 아래와 같다.

단계 작업 비고
1. 빌드 app.js → app.7fec4c32.js 파일 내용의 해시를 이름에 붙임
2. 업로드 원본 저장소(S3 등)에 올림 CI가 업로드 키로 올림
3. 캐시 설정 해시 붙은 파일은 1년(immutable), index.html은 매번 확인(no-cache) Cache-Control 헤더로 지정

내용이 바뀌면 이름도 바뀌니 옛 파일을 1년씩 캐시해도 문제가 없다. 이를 캐시 무효화(Cache Busting)라고 한다.

Cache-Control header - HTTP | MDN
The HTTP Cache-Control header holds directives (instructions) in both requests and responses that control caching in browsers and shared caches (e.g., Proxies, CDNs).

문제는 변조된 파일 중 하나가 images.7fec4c32.js였다. 이름의 해시는 그대로인데 내용만 바뀌어 있었다. 애초에 파일 이름의 해시는 빌드 때 붙인 약속일 뿐 검증이 아니다. CDN은 올라온 파일을 따로 확인 없이 그대로 뿌린다.

HTTPS도 마찬가지다. TLS는 "그 도메인과 통신했다"까지만 보증하고, 파일 내용까지는 보증하지 않는다.

이러한 캐시의 특징은 사건을 수습할 때도 문제가 되었다. FeedList.feb647c9.js는 원본에서 10월 29일에 이미 정상본으로 바뀌었지만, 일부 엣지는 11월 4일 캐시를 비울 때까지 변조본을 계속 내보냈다. 운영사 대응에 "CDN 캐시 갱신"이 따로 들어간 이유다.

CDN은 어떻게 털렸나

최초 사건 발생일인 9월 27일 하루 동안 일어난 일을 시간순으로 보면 아래와 같다.

시각 (KST) 내용
10:59 insightjs.com 도메인 등록
12:00 insightjs.com 인증서 첫 발급
13:08 insightjs.com 서버 응답 시작
15:41~15:42 운영사 CDN 스크립트 4개 변조

공격자는 도메인을 등록하고, 인증서를 받고, 서버를 띄워 악성코드를 받을 곳부터 준비한 것 같다. 그리고 도메인 등록 약 4시간 40분 뒤 CDN 파일 4개를 1~2분 사이에 한꺼번에 바꿨다. 받을 곳을 먼저 갖춰 둔 뒤 CDN을 건드린 걸 보면, CDN 쓰기 권한은 그 전부터 이미 확보했고, 파일도 한 번에 밀어 넣었을 가능성이 높다.

필자의 해석이다. 공식적인 침입 경로는 아직 밝혀지지 않았다.

백엔드 개발자 관점에서 CDN에 파일을 쓸 수 있는 길은 대개 둘 중 하나다.

  • 원본 저장소 쓰기 권한: CI에 넣어 둔 업로드 키가 새면, 정식 경로로 파일을 바꿔치기할 수 있다.
  • CDN·클라우드 콘솔 계정: 관리자 세션이 털리면 원본과 캐시 설정까지 전부 손댈 수 있다.

어느 쪽이든 결론은 같다. CDN은 결국 올린 것을 그대로 믿기에 CDN 보안은 "누가 올릴 수 있는가"를 지키는 문제다.

흔히 CDN은 단순히 "정적 파일을 빠르게 내려주는 캐시" 정도로만 여겨진다. 성능 최적화 도구로 보지, 보안을 신경 써야 할 대상으로는 잘 보지 않는 것이다. 실제로 2024년 Web Almanac 조사에 따르면 받은 스크립트를 해시로 검증하는 SRI(SubResource Integrity)를 쓰는 사이트는 데스크톱 기준 23% 남짓이고, 그마저도 페이지당 검증하는 스크립트는 중앙값 3% 수준에 그친다. 이 수치는 2022년 이후 거의 변하지 않았다.

결제 페이지만큼은 카드 결제 보안 표준인 PCI DSS 4.0이 2025년부터 스크립트 무결성 확인과 변조 탐지를 요구하기 시작했지만, 게임 런처는 여전히 해당하지 않는다.

이번 사건에서도 운영사는 CDN 파일이 바뀐 지 한 달이 넘도록 이를 알아차리지 못했다.

하지만 사용자 입장에서 CDN은 곧 공식 배포 경로다. 런처도, 브라우저도 그 경로로 받은 파일은 의심하지 않는다. 이번 사건은 바로 그 배포 경로의 원본을 오염시킨 경우다. 그러자 CDN의 장점이 그대로 공격 수단이 되었고, 전 세계 엣지가 변조본을 빠르게 퍼뜨려 모든 사용자에게 똑같이 나눠 줬다. 원본을 고친 뒤에도 캐시에 오래 살아남았다. CDN을 단순한 캐시로만 생각하면 놓치기 쉬운 위험을 교과서처럼 보여 준 사례라고도 볼 수 있다.

더 심각한 부분은 글을 작성하는 11월 7일 기준으로, 아직까지도 공격자가 어떻게 운영사 CDN에 쓰기 권한을 얻었는지가 밝혀지지 않았다는 점이다. 변조된 파일은 교체됐지만 근본적인 원인이 해결되지 않는 이상, 공격자가 새 도메인을 들고 같은 길로 다시 들어올 수 있다.

런처를 켜면 일어나는 일

그럼 이제 다시 실제 어떻게 해킹이 일어났는지를 살펴보자. 운영사 사과문에는 "악성 프로그램이 실행될 수 있었다" 정도만 적혀 있다. 실제로 무엇이 어떻게 동작했는지는 마찬가지로 MotherSphere의 분석 보고서에 자세히 나와 있는데, 이를 따라가 보면 대충 아래와 같다.

1. 런처 화면이 CDN에서 변조된 JS를 불러옴
2. JS가 insightjs.com/l.js 를 <script> 태그로 끼워 넣고 흔적을 지움
3. l.js가 런처의 다운로드 기능(Srv_DownloadFile)으로 Lua 에이전트(insight.bundle)를 받음
4. 런처에 내장된 Lua 런타임이 에이전트를 실행 → "k2f_chan" 채널 등록
5. l.js가 공격자 서버에서 명령을 받아 채널로 전달 → 에이전트가 PC에서 실행
6. chrome_install 명령 시 Chrome에 DLL을 심어 런처를 꺼도 상주


출처: MotherSphere, "NIKKE PC 런처 침해 사고 (2026년 11월)", https://gist.github.com/MotherSphere/047beaf9e82d1ae52a1daec6e988379f

1~2. 변조된 JS 다운로드

CDN의 변조된 4개 파일에 들어간 코드는 생각보다 작다. 공격자 서버 주소를 숫자 배열로 숨겨 두었다가 실행 시점에 복원하고, 화면에 <script> 태그를 하나 끼워 넣어 insightjs.com/l.js를 불러온 뒤 그 태그를 곧바로 지운다. .com이 응답하지 않으면 .org로 다시 시도하는 예비 경로까지 갖췄다.

즉 CDN에 올라간 건 악성코드 본체가 아니라 본체를 불러오는 로더(Loader)였다.

웹 개발을 해 봤다면 여기서 XSS(Cross-Site Scripting)가 떠오를 수도 있다.

Cross Site Scripting (XSS) | OWASP Foundation
Cross Site Scripting (XSS) on the main website for The OWASP Foundation. OWASP is a nonprofit foundation that works to improve the security of software.

XSS는 게시글이나 URL 파라미터처럼 앱이 받아들인 입력이 코드로 실행되는 앱의 취약점인데, 이번에는 앱에 결함이 있었던 게 아니라 원본 JS 파일 자체가 바꿔치기 됐다.

즉, 엄밀히 말하면 XSS는 아니다만 신뢰받는 런처 화면 안에서 공격자의 스크립트가 실행됐다는 결과만 보면 XSS와 다를 바 없다.

3~4. Lua 에이전트

감염된 CDN으로 인해 공격자 서버에서 불러온 l.js는 런처가 원래 업데이트 파일을 받을 때 쓰는 기능인 Srv_DownloadFile을 호출해 insight.bundle이라는 파일을 내려받는다. 이 파일이 PC를 원격 조종하는 에이전트로, 난독화된 LuaJIT 바이트코드다. 내려받은 파일은 로그 파일처럼 보이는 이름으로 저장되고, 런처에 원래 들어 있던 Lua 런타임이 이를 실행한 뒤 곧바로 지운다.

실행된 에이전트는 런처 내부 통신 모듈에 k2f_chan이라는 채널을 등록하는데, 각종 점검 가이드가 debug.log에서 k2f_chan registered를 찾아보라고 하는 이유가 이것이다.
debug.log 내 k2f_chan registered | 출처: https://volx.jp/nikke-k2f-chan-check/

흥미롭게도 이 에이전트에는 네트워크와 관련된 코드가 전혀 없다. 공격자 서버와의 통신은 런처 화면에서 돌고 있는 l.js가 맡는다. l.js가 약 30분 간격으로 서버에 접속해 명령을 받아 오면 채널을 통해 에이전트에 넘기고, 에이전트는 그 명령을 PC에서 실행한 뒤 결과를 다시 l.js에 돌려준다.

웹 화면은 통신만, Lua는 실행만 하는 분업으로, 밖에서 보면 런처가 평소처럼 웹 요청을 보내는 것으로만 보이니 탐지가 어려웠다고 한다.

5. 에이전트가 할 수 있었던 것

보고서에 정리된 명령을 보면, 게임 계정은 곁다리에 불과했다.

명령 하는 일
exec 임의의 명령 실행. 사실상 사용자 권한으로 할 수 있는 모든 것
ls, cat, download 파일 탐색과 다운로드
screens 모든 모니터 스크린샷
creds 런처에 저장된 니케 계정 정보 복호화
browserscan Chrome·Edge·Brave 등 Chromium 계열과 Firefox에 저장된 비밀번호, Chromium 계열 쿠키 수집
keyscan SSH 키, 클라우드·개발 도구 설정, 셸 히스토리, 프로젝트 .env 등 264개 경로 + Windows 자격 증명 관리자
wallet_files 암호화폐 지갑 확장 28종

게다가 런처는 실행할 때 관리자 권한을 요구하기 때문에, 에이전트도 관리자 권한으로 돌았을 가능성이 있다.

6. Chrome에 상주

위까지는 런처가 켜져 있을 때만 동작한다. 그래서 공격자는 과감하게도 chrome_install 명령을 통해 Chrome에 눌러앉는 방법을 채택하였다.

Chrome은 켜질 때마다 Windows의 자녀 보호 기능을 불러온다. 이때 Windows는 사용자 설정을 시스템 설정보다 먼저 확인하는데, 공격자는 사용자 설정에 "자녀 보호 기능 = 악성 DLL"이라고 적어 두었다. 리눅스로 치면 PATH 맨 앞에 가짜 ls를 넣어 둔 것과 같다. 이를 COM 하이재킹(COM Hijacking) 이라 부른다.

COM Hijacking - HackTricks
HKCU의 값은 사용자가 수정할 수 있으므로 COM Hijacking 을 지속성 메커니즘 으로 사용할 수 있습니다. procmon 을 사용하면 아직 존재하지 않아 공격자가 생성할 수 있는 COM 레지스트리 항목을 쉽게 찾을 수 있습니다. 기본 필터:

그 결과 Chrome을 켤 때마다 이 DLL도 함께 실행된다. 레지스트리에 등록된 것이라 런처를 꺼도, 지워도 소용없다. 제보에 따르면 이 DLL은 웹 페이지에 입력하는 비밀번호와 지갑 복구 문구를 읽고, l.js를 거치지 않고 공격자 서버에 직접 접속한다고 한다. 다만 아직 DLL 사본을 확보한 분석가가 없어 실제 동작은 확인되지 않았다.

지금은 운영사가 업데이트한 런처가 실행될 때, 이 DLL과 레지스트리 항목을 찾아 지워 준다. 다만 겁이 나서 런처를 이미 지운 사람이라면 이 정리 기능을 받을 수 없기에 레지스트리 항목을 직접 지워야 한다.

그리고 흔적 지우기

마지막으로 에이전트는 작업 중 만든 임시 파일(쿠키 복사본, 스크린샷)을 쓰자마자 지우고, 내려받았던 페이로드도 삭제하는 정리 명령까지 갖추고 있었다. 실행한 명령들은 런처 로그에도 남지 않는다.

그래서 debug.log에 k2f_chan registered가 적혀 있다면 실제 무엇이 이루어졌는지를 알 수 없기 때문에 점검 가이드들이 포맷과 비밀번호 초기화를 권장하였던 것이다.

왜 이런 일이 가능했나

신뢰의 전이(Transitive Trust)

일반적으로 설치 파일에는 코드 서명(Code Signing)이 붙어 있어서, 운영체제가 "정말 그 회사가 만든 파일"인지 확인해 준다. 그런데 런처가 실행 중에 CDN에서 받아오는 스크립트는 사정이 다르다. 서명이 보증하는 범위는 설치 시점(런처)까지이고, 그 뒤로 받아오는 코드(런처가 받아오는 JS)는 그 순간 CDN에 뭐가 올라가 있느냐에 달려 있다.

필자는 게임사를 믿었고, 게임사는 CDN을 믿었고, CDN 위의 스크립트는 다시 외부 도메인을 믿었다. 이렇게 사슬을 따라 자동으로 넘어가는 신뢰를 신뢰의 전이(Transitive Trust)라고 부른다. 필자가 실제로 믿게 되는 대상은 사슬 끝까지 늘어나는데, 그 끝에 누가 있는지는 아무도 확인하지 않는다.

이 문제는 무려 40여년 전에 켄 톰프슨(Ken Thompson)이 튜링상 수상 강연에서 이미 경고한 바 있다.

The moral is obvious. You can't trust code that you did not totally create yourself. (Especially code from companies that employ people like me.)

출처: Ken Thompson, "Reflections on Trusting Trust", Communications of the ACM, 1984. https://dl.acm.org/doi/10.1145/358198.358210

네이티브 브리지(Native Bridge)

사실 웹페이지 속 스크립트는 원래 할 수 있는 일이 많지 않다. 브라우저가 스크립트를 샌드박스(Sandbox)라는 울타리 안에 가둬 두기 때문이다. 때문에 아무 웹사이트나 들어갔다고 내 PC의 파일이 읽히거나 프로그램이 실행되지 않는다.

With sandboxing enabled, renderer processes can only perform privileged tasks (such as interacting with the filesystem, making changes to the system, or spawning subprocesses) by delegating these tasks to the main process via inter-process communication (IPC).

출처: Electron Docs, "Process Sandboxing", https://www.electronjs.org/docs/latest/tutorial/sandbox

그런데 게임 런처는 웹사이트가 아니라 PC에 설치된 하나의 앱이다. 앱이 내장 브라우저로 웹 화면을 띄워 둔 구조라, 런처에서 "게임 시작"을 누르면 게임이 켜지고 "업데이트"를 누르면 파일이 내려받아진다. 앱이 띄운 웹 화면이 앱의 기능을 쓸 수 있도록 울타리에 작은 문을 하나 내 둔 셈인데, 이 문을 네이티브 브리지(Native Bridge), 또는 JS 브리지라고 부른다. 모바일 앱이 WebView로 웹 화면을 띄우고 그 안의 스크립트에 앱 기능을 열어 주는 것과 같은 구조다.

A native bridge, sometimes known as a JavaScript bridge, is a mechanism that facilitates communication between a WebView and native Android code.

Reflecting untrusted user-provided content in native bridge-enabled WebViews allows for cross-site scripting (XSS) attacks.

출처: Android Developers, "WebView – Native bridges", https://developer.android.com/privacy-and-security/risks/insecure-webview-native-bridges

앞서 본 Srv_DownloadFile이 바로 그런 문 중 하나다. 이 문은 원래 게임사가 만든 정상 스크립트가 쓰라고 낸 것이지만 변조된 스크립트도 같은 화면에서 돌았으니 같은 문을 쓸 수 있었다. 결국 웹페이지 속 스크립트가 울타리 밖으로 나와 내 PC에 프로그램을 내려받고 실행할 수 있게 됐다.

막을 방법은 없었나

사실 이러한 사태를 막을 방법이 있긴 하다. 앞서 CDN 이야기에서 잠깐 언급한 SRI(Subresource Integrity)가 바로 이러한 일을 방지하기 위한 해결책이다.

SRI(SubResource Integrity)

SRI(SubResource Integrity)는 하위 리소스 무결성의 약자로 스크립트를 불러올 때 기대하는 해시를 함께 적어 두고, 받은 파일의 해시가 다르면 실행을 거부하도록 하는 구조이다.

<!-- 받은 파일의 해시가 integrity 값과 다르면 실행하지 않는다 -->
<script src="https://cdn.example.com/app.7fec4c32.js" integrity="sha384-..."></script>
This specification defines a mechanism by which user agents may verify that a fetched resource has been delivered without unexpected manipulation.

출처: W3C, "Subresource Integrity", https://www.w3.org/TR/SRI/

앞에서 파일 이름의 해시는 "약속일 뿐 검증이 아니다"라고 했는데, SRI가 바로 그 빠진 검증을 채워주기 위함이다. 이름의 해시가 "이 이름이면 이 내용일 것"이라는 약속이라면, SRI는 "이 내용이 아니면 실행하지 않는다"는 검증인 것이다. 런처 화면이 CDN 스크립트를 SRI로 고정해 두었다면 images.7fec4c32.js의 내용이 바뀐 순간 실행이 막혔을 것이다. 웹사이트 열에 여덟이 쓰지 않는다는 바로 그 기능이다.

실제로 운영사가 사과문에서 내놓은 재발 방지책도 외부에서 불러오는 파일의 무결성 검증 체계 구축, CDN 보안 모니터링 강화, 그리고 런처 기능별 최소 권한 구조로의 개편이었다. SRI와 같은 검증 수단의 부재와 네이티브 브리지 문제를 정확히 짚은 것이다.

재발 방지를 위한 보안 강화 | 출처 : 니케 해킹 사태 공식 사과문 중 발췌
짚기만 하고 해결은 아직 안했다.

내 피해는 어떠한가

비로소 이 글의 시작 지점으로 돌아왔다. 결국 요점은 이러한 해킹 사태로 인해 내 홈서버에 실질적인 피해가 발생했는가를 살펴보기 위해 긴 글을 작성하였다.

메인 PC

현재는 포맷하였지만, 포맷 전에 메인 PC의 debug.log를 확인해 보니 k2f_chan registered가 존재했었다. 즉, 메인 PC에서 에이전트는 실행됐다. 다만 앞서 말했듯이 공격자가 실제로 어떤 명령을 내렸는지는 로그에 남지 않아 알 수 없다.

필자는 Chrome 대신 Brave를 쓰는데, Brave 역시 browserscan의 수집 대상 목록에 들어 있었다. 그나마 비밀번호는 브라우저가 아니라 비밀번호 관리자 확장(Vaultwarden)에 저장해 두었는데, 보고서에 따르면 에이전트에는 비밀번호 관리자 확장을 읽는 코드가 없었다고 한다.

그렇다고 안심할 수는 없는게, 브라우저 세션은 해킹 대상이었고 화면 캡처를 통해 비밀번호가 유출될 가능성 또한 존재한다.

홈서버

필자의 홈서버는 전형적인 경계 보안(Perimeter Security) 구조다. 흔히 성과 해자(Castle-and-Moat)에 비유되는데, 성벽(방화벽)을 높이 쌓고 출입은 성문(VPN) 하나로만 허용하며, 성벽 안에 들어온 건 아군으로 취급하는 방식이다.

성과 해자 네트워크 보안 모델 - CyberHoot
캐슬 앤 모트(Castle-And-Moat)는 네트워크 외부의 누구도 네트워크 내부의 데이터에 접근할 수 없지만, 네트워크 내부의 모든 사람은 접근할 수 있는 네트워크 보안 모델을 말합니다.
홈서버 네트워크 구조 | 출처: Generated by ChatGPT

사실 아직도 이 구조가 틀린 건 아니라고 생각한다. 인터넷을 훑고 다니는 포트 스캔이나 관리 화면 무차별 대입 같은 공격을 방지할 수 있고, 개인 홈서버가 당하는 공격의 대부분이 여기에 속하니 나름 할 일은 다 하고 있었다고 생각한다.

결국 문제는 "안쪽은 믿는다"는 전제이다. 사고 직후 문제의 메인 PC가 쥐고 있던 걸 적어 보니 아래와 같았다.

메인 PC에 있던 것 털렸을 때 열리는 문
홈서버 VPN 키 홈서버 내부망
원격 데스크톱 등록 다른 PC의 화면과 키보드
비밀번호 관리자 로그인 금고 안 전부
GitHub 로그인 세션 홈서버 배포 파이프라인

이렇게 안쪽에 발을 들인 공격자가 옆 시스템으로 옮겨 다니는 걸 측면 이동(Lateral Movement)이라고 부른다. 경계 보안 구조에서는 안쪽끼리 서로 믿기 때문에 이 단계가 특히 쉽다.

이러한 문제를 해결하기 위해 제로 트러스트(Zero Trust) 모델이 권장된다곤 하나,
개인 규모에선 적용하기에 어려움이 있어서 이러한 방식을 택한 것도 있다.

그나마 다행인 건, 방화벽과 컨테이너 로그를 Grafana Loki에 30일간 모아 두고 있었다는 점이다. 덕분에 메인 PC가 지난 한 달간 홈서버의 어디에 접속했는지 사후에 확인할 수 있었다.

sum by (dst, dport) (
  count_over_time({job="filter"} |= ",10.80.80.99," | regexp `...` [30d])
)

결과를 보면 DNS 질의와 NAS 파일 동기화가 대부분이었고, 웹 서비스 접속이 백여 건 있었다. Proxmox SSH나 웹 UI 같은 관리 포트에 직접 붙은 기록은 없었다.

막지는 못했어도, 무엇이 일어났는지는 근거를 갖고 판단할 수 있었다.

모니터링 구축할 때는 대시보드 예쁘게 뽑는 맛에 했는데, 이렇게 쓰일 줄은 몰랐다.

홈서버 쪽은 이렇게 한숨 돌렸지만, 정작 메인 PC가 문제였다. 에이전트가 실행된 흔적이 남아 있었고, 문제가 된 런처도 여전히 설치되어 있었다. 런처 캐시에는 변조된 스크립트가 남아 있을 수 있고, 에이전트가 무엇을 더 심어 두었는지도 확인할 길이 없었다. 해서 메인 PC는 포맷하기로 했다.

2FA의 한계

사실 가장 허탈했던 부분이다. 중요한 계정에는 전부 2단계 인증(2FA)을 걸어 두었는데, 이번 악성코드는 그걸 우회할 필요조차 없었다.

여기서 짚고 넘어갈 개념이 인증(Authentication)과 인가(Authorization)다. 인증은 "내가 누구인지" 확인하는 절차로, 비밀번호와 2FA 코드를 입력하는 로그인 과정이 여기에 해당한다. 인가는 "내가 이걸 해도 되는지" 허락하는 절차로, 메일을 읽거나 설정을 바꾸는 요청 하나하나마다 이뤄진다.

Authorization - OWASP Cheat Sheet Series
Website with the collection of all the cheat sheets of the project.

문제는 서버가 요청마다 비밀번호를 다시 묻지 않는다는 점이다. 인증이 끝나면 서버는 세션 쿠키(Session Cookie)를 내주고, 이후의 요청은 이 쿠키만 보고 "로그인한 그 사람"이라 판단해 권한을 내준다. 즉, 세션 쿠키는 2FA를 이미 통과했다는 증표다. 2FA가 지키는 건 인증이라는 입구뿐이라, 공격자가 쿠키를 가져가면 입구를 건너뛰고 곧장 인가 단계로 들어온다.

비밀번호 관리자에 저장해 둔 패스키(Passkey)도 마찬가지다. 동기화되는 패스키는 금고 데이터의 일부이기 때문에 금고가 열린 PC에서는 같이 빠져나갈 수 있다. 복사할 수 없는 패스키는 하드웨어 키나 기기 보안칩에 묶인 것뿐이다.

때문에 이번 대응은 "비밀번호 변경"이 아니라 "이미 발급된 것 전부 무효화" 가 되어야 했다. 모든 계정의 로그인 세션을 강제로 끊고, 비밀번호와 패스키, 액세스 토큰을 다시 발급하고, 메인 PC의 VPN 키를 폐기하고, 원격 데스크톱과 화면 공유를 꺼 주었다.

운영사 사과문의 이용자 권고도 결국 같은 이야기였다. 감염 우려가 없는 기기에서 주요 서비스의 「모든 기기 로그아웃」을 먼저 실행한 뒤 비밀번호를 바꾸고, PC에 저장해 둔 개발자 키와 토큰은 폐기 후 재발급하라는 것이다.

그나마 다행이었던 건 지난 글에서 홈서버의 시크릿을 Infisical로 일원화해 두었다는 점이다. 수십 개의 키를 Infisical에서 바꾸고 나니 GitHub Actions Secrets까지 자동으로 동기화됐고, Github Actions를 통해 홈서버에 일괄적으로 갱신도 가능했다.

시크릿 관리를 IaC로 옮길 때는 "언젠가 키를 한 번에 바꿀 일이 있겠지" 정도로 생각했는데, 생각보다 너무 빨리 왔다.


결론

이번 사건을 정리해 보면, 니케 런처는 CDN 위의 파일 몇 개가 바뀐 것만으로 수많은 PC에 원격 제어 에이전트를 심었다. CDN은 받은 파일을 검증 없이 배포했고, 런처는 그 파일을 의심 없이 실행했으며, 런처 화면에 열어 둔 문 덕분에 그 스크립트는 PC 전체의 권한을 얻었다. 사용자 입장에서는 정식 프로그램을 정식 경로로 실행했을 뿐이니 막을 방법이 없었다.

그간 필자의 홈서버 운영 기조는 외부로부터의 진입 자체를 막는 데 있었다. 포트는 최소한으로만 열고, 공개 서비스는 터널로 분리하고, 나머지는 VPN 뒤에 숨겼다. 이 방향 자체는 지금도 틀리지 않았다고 생각한다.

다만 이번 일로 이미 진입이 허가된 기기가 탈취될 경우에 대한 대책은 사실상 없었다는 걸 깨달았다.

당장은 세션을 끊고 키를 갈아엎어 급한 불만 끈 상태다. 이걸 근본적으로 어떻게 해결할지는 아직까지 뚜렷한 해결책이 보이지 않아 좀 더 고민해본 뒤 개선안을 가져오도록 하겠다.


참고자료

승리의 여신: 니케 | 절망에 맞서 승리로 향하는 소녀들의 건슈팅 RPG
세계 탈환을 위한 미소녀 건슈팅 액션! 11월 4일 정식 런칭!
‘니케’ 런처 해킹 공식 사과... “게임 외 2차 피해 접수할 것” - 보안뉴스
공식 프로그램을 통한 공급망 침해 사태가 불거진 게임 ‘승리의 여신: 니케’ 배급사가 해킹 사고를 인정하고 사과문을 발표했다. 악성코드 자동 치료 기능을 긴급 업
[단독] ‘니케’ 해킹 사태에 넥슨 전사 보안 공지…”런처 즉시 삭제”
시프트업의 인기 게임 ‘승리의 여신: 니케’에서 악성코드가 유포된 정황이 드러나자 국내 게임사들이 보안 점검에 나서고 있다. 넥슨은 전사 차원의 보안 공지를 내리고 관련 프로그램이 설치된 경우 즉시 삭제와 보안팀 신고를 지시한 것으로 확인됐다. 4일 게임업계에 따르면…
NIKKE PC 런처 침해 사고 (2026년 11월) (NIKKE PC launcher, Nov 2026)
NIKKE PC 런처 침해 사고 (2026년 11월) (NIKKE PC launcher, Nov 2026) - nikke-pc-launcher-compromise_ko.md
NIKKE PC launcher compromise (Nov 2026): Level Infinite CDN files modified, remote-control agent, indicators
NIKKE PC launcher compromise (Nov 2026): Level Infinite CDN files modified, remote-control agent, indicators - nikke-pc-launcher-compromise.md
NIKKE PC 런처 침해 사고 | GeekNews
1. 공격 요약 2026년 9월 27일부터 Level Infinite가 운영하는 CDN의 공식 JavaScript 파일 4개에 공격자 코드가 삽입된 정황이 확인됐다. NIKKE PC 런처는 해당 파일을 정상 구성 요소로 로드하기 때문에, 변조된 파일을 받은 런처를 실행하면 외부 스크립…
2026년 승리의 여신: 니케 PC 클라이언트 해킹 사건
NIKKE PC launcher compromise 해킹 사건이 정리된 니케 마이너 갤러리의 글 해킹 사건 총정리
CDN - Glossary | MDN
A CDN (Content Delivery Network) is a group of servers spread out over many locations. These servers store duplicate copies of data so that servers can fulfill data requests based on which servers are closest to the respective end-users. CDNs make for fast service less affected by high traffic.
Cache-Control header - HTTP | MDN
The HTTP Cache-Control header holds directives (instructions) in both requests and responses that control caching in browsers and shared caches (e.g., Proxies, CDNs).
Security | 2024 | The Web Almanac by HTTP Archive
Security chapter of the 2024 Web Almanac covering Transport Layer Security, content inclusion (CSP, Feature Policy, SRI), web defense mechanisms (tackling XSS, XS-Leaks), and drivers of security mechanism adoptions.
PCI DSS 4.0.1 and Requirements 6.4.3 and 11.6.1: What Changed for Payment Page Scripts
For over a decade, PCI DSS treated the browser as someone else’s problem. Card data was protected in transit and at rest on the server, but the code actually running in the customer’s browser — where card details are typed in — sat largely outside the standard’s reach. PCI
Cross Site Scripting (XSS) | OWASP Foundation
Cross Site Scripting (XSS) on the main website for The OWASP Foundation. OWASP is a nonprofit foundation that works to improve the security of software.
COM Hijacking - HackTricks
HKCU의 값은 사용자가 수정할 수 있으므로 COM Hijacking 을 지속성 메커니즘 으로 사용할 수 있습니다. procmon 을 사용하면 아직 존재하지 않아 공격자가 생성할 수 있는 COM 레지스트리 항목을 쉽게 찾을 수 있습니다. 기본 필터:
Subresource Integrity
Process Sandboxing | Electron
One key security feature in Chromium is that processes can be executed within a sandbox. The sandbox limits the harm that malicious code can cause by limiting access to most system resources — sandboxed processes can only freely use CPU cycles and memory. In order to perform operations requiring additional privilege, sandboxed processes use dedicated communication channels to delegate tasks to more privileged processes.
WebView – 네이티브 브리지 | Security | Android Developers
Subresource Integrity (SRI)
SRI(Subresource Integrity)에 대해 알아봅니다.
Subresource Integrity
성과 해자 네트워크 보안 모델 - CyberHoot
캐슬 앤 모트(Castle-And-Moat)는 네트워크 외부의 누구도 네트워크 내부의 데이터에 접근할 수 없지만, 네트워크 내부의 모든 사람은 접근할 수 있는 네트워크 보안 모델을 말합니다.
Authorization - OWASP Cheat Sheet Series
Website with the collection of all the cheat sheets of the project.
Session hijacking attack | OWASP Foundation
Session hijacking attack on the main website for The OWASP Foundation. OWASP is a nonprofit foundation that works to improve the security of software.
인증(Authentication)과 인가(Authorization)
인증과 인가 인증이란? 유저가 누구인지 확인하는 절차, 회원가입하고 로그인 하는 것. 인가란? 유저에 대한 권한을 허락하는 것. 누가, 언제, 어떻게 쓰고 있는가를 파악하기 위해 어떤 사이트에서든 인증, 인가가 있음. 인증과 인가는 API에서 가장 자주 구현되는 기
Proxmox 홈서버 구축기 [네트워크와 방화벽, DNS]
Proxmox + pfSense 위에 WireGuard VPN을 구축하고, Split Tunneling과 DNS Resolver를 통해 내부 도메인으로 안전하고 편리하게 서비스를 이용하는 방법을
홈서버 IaC 전환기 (2) [with Infisical]
홈서버 인프라의 보안과 유지보수성을 높이기 위해 Infisical을 도입한 경험을 공유합니다. GitHub Secrets 단방향 동기화 및 SSH 키 페어를 활용한 안전한 Proxmox LXC 프로비저닝 워크플로우 구축 과정을 확인해 보세요.