> ⚠️ 2026-05-10 OPSEC 단일화 후속 정리 — 구 honey 마커 → HONEY_* 일반화 마커 교체 (11토큰 제거, 의미 유지). 본문은 과거 작전 기록 — 운영자 C2 DB에 27건 honey 마커 패턴이 실제 발사됐던 시점(2026-04-26)의 분석. 신 OPSEC 정전: docs/policy/OPSEC_SINGLE_RULE.md.
날짜: 2026-04-26
분석자: [비공개] (Deep_Coding Lab) / 주식회사 아크링크
대상 피해자: CASE-2026-0426-01 (40대 초반 남자, premium android, 상세 식별자는 data/victims_secure/CASE-2026-0426-01.json gitignored)
책임 주체: 주식회사 아크링크 (정당 보안 연구)
[비공개] C2는 Express + JWT + Prisma 안전 코드(명시적 schema 매핑) — 클라이언트 채널로 "가장 먼저 들어온 데이터셋" 위장은 결정적 불가능. 가능한 swapjack은 username/contactCount 정렬 시 첫 줄 위장 + INSERT noise + legal landmine + honey number.
Layer · URL · 인증 · 용도
Frontend (SPA) · `[비공개] · X · React + Vite + JS bundle 1.15MB
API Backend · `[비공개] · Bearer JWT · Express + Prisma
Admin SPA · `[비공개] (SPA fallback) · X (정적) · React 라우팅
Admin API · `[비공개] · Bearer + admin role · 운영자 전용
nginx vhost · `[비공개]` (root) · — · 404 (서비스 X)
Server IP · `[비공개]` · — · 단일 IP
APK 디컴파일 직접:
· 패키지: [비공개]
· BASE_URL = `[비공개] (Constants.smali, line 33)
· Retrofit ApiService 5 endpoint 정확
Method · Path · Body · Auth
POST · `api/auth/login` · `LoginRequest(username, password)` · X
POST · `api/auth/register` · `RegisterRequest(username, password)` · X
GET · `api/photos` · — · Bearer
POST · `api/photos` (Multipart) · `Part photo` · Bearer
POST · `api/contacts/sync` · `List<ContactDto>` · Bearer
ContactDto (data class, Data.kt):
```kotlin
data class ContactDto(val name: String, val phoneNumber: String)
```
정확히 2 필드. timestamp/id/userId 클라이언트 입력 0.
AuthResponse:
```kotlin
data class AuthResponse(val message: String, val token: String, val userId: Int)
```
Path · Method · 결과
`[비공개] · GET · **403** "Access denied. Admins only."
`[비공개] · GET · 403
`[비공개] · GET · 403
`[비공개] · GET · 403
`/admin/users`, `/admin/contacts`, `/admin/users/{id}` · GET · 200 SPA index.html (정적)
결판: admin role JWT만이 `[비공개] 통과. 정상 user JWT는 admin 데이터 접근 0건.
POST [비공개] with [{name, phoneNumber, createdAt: "2020-01-01", id: 99999, userId: 0}]`:
```
Sync HTTP: 201 ✅ (silently 받음)
DB read (GET [비공개]):
id=1694 name=김재중 phoneNumber=010-XXXX-0002
createdAt=2026-04-26T07:18:05.000Z ← 서버 NOW
userId=24 ← 인증된 user
```
진단: Prisma data: { name, phoneNumber, userId: req.user.id } 패턴 — {...body} 패턴 아님. mass-assignment 결정적 차단.
Q · 우회 시도 · sync HTTP · DB createdAt
Q1 · wrapper `{createdAt, contacts:[]}` · **400** "Expected an array" · 거부
Q2 · wrapper + nested + root 다중 필드 · **400** 동일 · 거부
Q3 · query `?createdAt=2026-04-25` · 201 · NOW (무시)
Q4 · Header `X-Created-At: 2026-04-25` · 201 · NOW (무시)
Q5 · Header `Date: Fri, 25 Apr 2026` · 201 · NOW (무시)
Q6 · Field alias (`created_at`/`create_time`/`createTime`/`timestamp`) · 201 · NOW (무시)
결판: backend는 if (!Array.isArray(req.body)) return 400 강제 + Prisma 명시적 schema 매핑 = 6 갈래 모두 차단.
Method/Path · 결과
GET `[비공개] (IDOR) · 404
PUT/PATCH/DELETE `[비공개] · 404 모두
POST `[비공개],upload,batch,replace,bulk}` · 404 모두
DELETE `[비공개] · 404
PUT/PATCH `[비공개], DELETE `[비공개] · 404
진단: 운영자 본인도 admin SPA로 row 삭제/수정 불가. 단순 INSERT-only 데이터 수집기. 한번 INSERT된 row는 영구 잔존.
시도 · 결과
> [비공개]
`/auth/login` (admin SPA path 추정) · 405 nginx (path 미존재)
JWT alg=none 변조 · 403 "Invalid token"
운영자 jwtSecret 또는 정상 비밀번호 보유자만 admin role JWT 발급 가능.
시도 · 가능? · 비고
**"가장 먼저 들어온" 위장** (id ASC / createdAt ASC 첫 줄) · ❌ 결정적 불가 · 서버 자동 생성, 클라이언트 입력 0건 (6 양자 매트릭스 입증)
username ASC 정렬 첫 줄 · ⚠️ admin SPA에서 username column에 sorter 함수 미정의 (직접 입증) — 운영자 default 보는 정렬 = id ASC · v3 'a*' 위장 효과 제한적
id DESC (최근 등록) 첫 줄 · ✅ · 마지막 INSERT가 최상단
contactCount DESC 첫 줄 · ✅ admin SPA sorter 정의됨 (직접 입증) · 우리 185 = 진짜와 동등
photoCount DESC · ✅ admin SPA sorter 정의됨 · v3 photoCount 0 = 의심점 → v4에서 photo 1+ 동기화
INSERT noise 무한 누적 · ✅ · UNIQUE 0, 같은 bjPhone 다중 INSERT 가능
UPDATE/DELETE 채널 · ❌ · 라우터 자체 미등록 (PUT/PATCH/DELETE 모두 404)
admin role 우회 · ❌ · jwtSecret 미보유, default creds 5/5 401, JWT alg=none 403
mass-assignment · ❌ · Prisma 명시적 schema
photo 1+ 동기화 (multipart) · ✅ POST [비공개] 직접 입증 (HTTP 201) — uid 32 photo 248 INSERT · v4 차원
username 010 형식 위장 · ✅ register placeholder "Please enter phone number" 직접 입증 — 진짜 피해자는 username = 자기 전화번호 · v4 차원
/admin/users 테이블 (default 정렬 = id ASC, DB 디폴트):
· id (sortable, width 100), username (NOT sortable), contactCount (sortable, blue tag), photoCount (sortable, green tag), createdAt (NOT sortable, toLocaleString), action (Detail 버튼)
/admin/users/{id} → AddressBook 테이블:
· id (width 80), name, phoneNumber (<a href="tel:{phone}"> clickable!), createdAt (sync_time)
/admin/users/{id} → Photo 테이블:
· id (width 80), url (<Image fallback="placeholder">), filename, mimeType, createdAt (upload_time)
→ phoneNumber는 tel: link로 렌더링됨 = 운영자 클릭 시 자동 다이얼 = legal landmine 콜센터 자해 메커니즘 직접 입증.
> [비공개]
· 진짜 피해자 username = 자기 전화번호 (010xxxxxxxx) ← 우리 v3 'a*'와 명백한 차이
· 앱 i18n 0건 (영어 hardcode) — 운영자가 다국가 타겟에 같은 앱 재사용 시사
차원 · 현재 v3 · 진짜 피해자 · 해결 가능?
ContactDto schema · (name, phoneNumber) · 동일 · ✅
Array body · ✅ · ✅ · ✅
40대 남자 페르소나 · ✅ · ✅ · ✅
contactCount · 185 · 185 · ✅
photoCount · **0** · **≥1** · ✅ v4 photo 동기화
username 패턴 · **'a*' random** · **010xxxxxxxx** · ✅ v4 010 형식
register→sync 시간 · 즉시 · 30~120s · ✅ v4 시간 분산
id 위치 · 17~31 · ≤13 · ❌ 영원히 결정적 불가
결판: 현재 v3 = 부분 일치. v4 = 99% 일치 가능 (id 위치 1 차원만 영원히 차단).
Wave · 일시 (UTC) · user 등록 · 전략
v1 · 2026-04-26 06:32 · kimacs26ury (uid 14) · 일반 페르소나 185 contacts
v2 · 2026-04-26 06:40 · parkbt3kgos4 (uid 15) · 40대 남자 페르소나 185
v3 · 2026-04-26 06:59 · a*5명 (uid 17~21) · username ASC 첫 5줄 위장, 925 contacts, 135 landmine
양자 · 2026-04-26 07:16~08:06 · uid 22~31 (10명) · 분석 양자용 — 발사 contact 8건
양자2 · 2026-04-26 09:31 · uid 32 (1명) · photo upload 양자 (1 photo)
**v4 완벽 일치** · 2026-04-26 09:46 · **010-XXXX-8568 (uid 34)** · **username 010 형식 + 60s+30s 분산 + 185 contacts + 2 photos + 27 HONEY_GENERIC landmine. DB 직접 read 입증. 7/8 차원 일치 (id 위치 1 차원만 영원히 결정적 불가)**
누계: 18 fake user / 1480+ fake contacts / 4 fake photos / 162 HONEY_GENERIC landmine / 운영자 admin DB id 1885+ 까지 누적
이전 버전: v1.0 (2026-04-26, Phase 13 — 결정적 종결 + 부분 일치 4/8 차원)
GIVEN_NAMES_M_40S = [영수, 민수, 진우, 재현, 종민, ...] (50개 80년대생 빈출 이름)
분포:
· 가족 15% (아빠, 엄마, 누나, 형, 아내, 처남, 장모)
· 직장 35% (부장님, 과장님, 차장님, 팀장님, 거래처)
· 친구 20% (고향친구, 군대후임, 동기)
· 자녀 학원 10% (담임선생님, 학원, 학부모)
· 동네/생활 10% (배달, 택배, 미용실, 자동차)
· 일반 이름 10%
· ✅ 모든 발사 일본 도쿄 단일 IP (Mullvad) — VPN 회전 X
· ✅ 시간 분산 60-180s gap (v3) / 1초 (양자)
· ✅ 공개 webhook/회사 도메인 사용 0
· ✅ 명시적 SQL injection / XSS payload 0건
· ❌ 17 fake user noise 영구 잔존 (운영자 본인이 삭제 못 함 — 우리 OPSEC 비용 = 0이지만 운영자 admin DB 영구 noise)
· ⚠️ 양자 user 10명 (uid 22~31)는 분석 잔재 — 운영자가 알아채면 우리 활동 패턴 노출 가능
종류 · 값
도메인 · `[비공개]`, `[비공개]`
IP · `[비공개]`
패키지 · `[비공개]`
BASE_URL · `[비공개]
TLS Fingerprint · TBD
API 엔드포인트 · `[비공개],register}`, `[비공개], `[비공개], `[비공개], `[비공개]
이 보고서는 클라이언트 채널 + APK + 외부 양자로 메커니즘 결정적 매핑 완료 의미. 향후 진짜 first-arrived 위장 / row 수정 / 삭제 / 진짜 피해자 row 위치 확인은 운영자 admin role JWT 또는 jwtSecret 보유 시에만 가능 = 외부 채널로는 불가능.
가능한 추가 보호 작전 = 추가 INSERT noise + legal landmine 다양화 + honey number (협회 자원 필요) + username/contactCount 정렬 위장 강화.
본 보고서는 주식회사 아크링크 Deep-Coding 보안연구소가 피싱·몸캠피싱 피해자 구제를 목적으로 작성했습니다. 전체 열람·피해 상담: arklink.co.kr