meetlove521 상세 분석 보고서

> ⚠️ 2026-05-10 OPSEC 단일화 후속 정리 — 구 honey 마커 → HONEY_* 일반화 마커 교체 (11토큰 제거, 의미 유지). 본문은 과거 작전 기록 — 운영자 C2 DB에 27건 honey 마커 패턴이 실제 발사됐던 시점(2026-04-26)의 분석. 신 OPSEC 정전: docs/policy/OPSEC_SINGLE_RULE.md.

meetlove521 — Express+JWT+Prisma 양자 분석 + Swapjack 결판

날짜: 2026-04-26

분석자: [비공개] (Deep_Coding Lab) / 주식회사 아크링크

대상 피해자: CASE-2026-0426-01 (40대 초반 남자, premium android, 상세 식별자는 data/victims_secure/CASE-2026-0426-01.json gitignored)

책임 주체: 주식회사 아크링크 (정당 보안 연구)

0. 한 줄 결판

[비공개] C2는 Express + JWT + Prisma 안전 코드(명시적 schema 매핑) — 클라이언트 채널로 "가장 먼저 들어온 데이터셋" 위장은 결정적 불가능. 가능한 swapjack은 username/contactCount 정렬 시 첫 줄 위장 + INSERT noise + legal landmine + honey number.

1. 인프라 매핑 (직접 입증)

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 정확

2. ApiService 정확 schema (smali 직접 입증)

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)

```

3. Admin endpoint 매트릭스 (직접 양자)

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건.

4. Mass-Assignment 양자 (Prisma 명시적 schema 입증)

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 결정적 차단.

5. createdAt 양자 매트릭스 6발 (모두 결정적 불가)

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 갈래 모두 차단.

6. CRUD 매트릭스 (UPDATE/DELETE 0건)

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는 영구 잔존.

7. 외부 우회 0건 입증

시도 · 결과

> [비공개]

`/auth/login` (admin SPA path 추정) · 405 nginx (path 미존재)

JWT alg=none 변조 · 403 "Invalid token"

운영자 jwtSecret 또는 정상 비밀번호 보유자만 admin role JWT 발급 가능.

8. Swapjack 갈래 — 가능 vs 불가 매트릭스

시도 · 가능? · 비고

**"가장 먼저 들어온" 위장** (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 SPA 정확 column 매핑 (직접 입증)

/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 콜센터 자해 메커니즘 직접 입증.

register UI 직접 입증 (LoginScreen.smali const-string)

> [비공개]

· 진짜 피해자 username = 자기 전화번호 (010xxxxxxxx) ← 우리 v3 'a*'와 명백한 차이

· 앱 i18n 0건 (영어 hardcode) — 운영자가 다국가 타겟에 같은 앱 재사용 시사

8.1 완벽 일치 차원 분석 (사용자 [비공개] 대표 질문 직답)

차원 · 현재 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 차원만 영원히 차단).

9. 피해자 CASE-2026-0426-01 보호 작전 누계

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+ 까지 누적

v4 보고서 버전: v2.0 (Phase 15 — 완벽 일치 7/8 차원 입증)

이전 버전: v1.0 (2026-04-26, Phase 13 — 결정적 종결 + 부분 일치 4/8 차원)

10. 페르소나 (40대 초반 남자 전형 전화번호부)

GIVEN_NAMES_M_40S = [영수, 민수, 진우, 재현, 종민, ...] (50개 80년대생 빈출 이름)

분포:

· 가족 15% (아빠, 엄마, 누나, 형, 아내, 처남, 장모)

· 직장 35% (부장님, 과장님, 차장님, 팀장님, 거래처)

· 친구 20% (고향친구, 군대후임, 동기)

· 자녀 학원 10% (담임선생님, 학원, 학부모)

· 동네/생활 10% (배달, 택배, 미용실, 자동차)

· 일반 이름 10%

11. OPSEC 평가

· ✅ 모든 발사 일본 도쿄 단일 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)는 분석 잔재 — 운영자가 알아채면 우리 활동 패턴 노출 가능

12. 직접 입증된 IOC

종류 · 값

도메인 · `[비공개]`, `[비공개]`

IP · `[비공개]`

패키지 · `[비공개]`

BASE_URL · `[비공개]

TLS Fingerprint · TBD

API 엔드포인트 · `[비공개],register}`, `[비공개], `[비공개], `[비공개], `[비공개]

13. 결정적 종결

이 보고서는 클라이언트 채널 + APK + 외부 양자로 메커니즘 결정적 매핑 완료 의미. 향후 진짜 first-arrived 위장 / row 수정 / 삭제 / 진짜 피해자 row 위치 확인은 운영자 admin role JWT 또는 jwtSecret 보유 시에만 가능 = 외부 채널로는 불가능.

가능한 추가 보호 작전 = 추가 INSERT noise + legal landmine 다양화 + honey number (협회 자원 필요) + username/contactCount 정렬 위장 강화.

본 보고서는 주식회사 아크링크 Deep-Coding 보안연구소가 피싱·몸캠피싱 피해자 구제를 목적으로 작성했습니다. 전체 열람·피해 상담: arklink.co.kr