Tunf 상세 분석 보고서

Tunf (com.pdutcbi.bctdimp) 심층 분석 보고서 (Quantum Nano)

> 분석일: 2026-06-14

> 분석 레벨: static_deep → ml_level (C2 라이브 확인 + 엔드포인트 매핑 + 방어기제 전면 파훼)

> 패밀리: wavegrid (RuoYi `[비공개] 계열, 연락처+갤러리 탈취형)

> 원본 파일명: Fun.zip(위장) → Fun.apk (Telegram 배포 추정)

1. 개요 (Executive Summary)

Tunf은 초대코드 기반 연락처·갤러리 탈취 악성앱이다. 정상 앱처럼 보이는 단일 로그인 화면 뒤에서, 권한이 부여되는 즉시 피해자의 전체 주소록 + 전화번호 + 통신사 정보 + 갤러리 사진 전량을 RuoYi 기반 C2 서버([비공개], [비공개])로 전송한다.

핵심 특징:

· 정적 분석 방해: 629개 액티비티 중 627개가 난수 이름의 더미(클래스 부풀리기)

· 실제 로직은 단 3개 액티비티(Login/Home/Base) + 6개 유틸 클래스

· 암호화·패킹 없음: C2 URL은 평문 상수, 통신 페이로드도 평문 JSON

· SSL 검증 자체 무력화(unsafe OkHttpClient) → 운영자 편의이자 분석가에게 MITM 자유 제공

· C2 라이브, 한국어 응답("초대코드가 잘못되었습니다") → 한국 피해자 표적

2. 대상 식별 (Target Application)

항목 · 값

패키지명 · `com.pdutcbi.bctdimp`

표시 라벨 · `Tunf`

versionName / Code · 3.0.29 / 3029

minSdk / targetSdk · 29 / 34

런처 액티비티 · `com.pdutcbi.bctdimp.view.LoginActivity`

APK SHA-256 · `4a636e12f6e195534affe8a021224e575e60c88270a02f4811fed4cd39db6646`

APK MD5 · `048188123da7d78ee71fa9d46a0d21f8`

파일 크기 · 23,355,535 bytes (≈22.3 MB)

서명 주체(DN) · `OU=pdutcbi` (자체 서명)

서명 SHA-256 · `63e12b8b782afa2df4f6f624cd185534a40853cdf27f239edea1383fc4bf10c5`

DEX 구성 · classes.dex(10.3MB) + classes2.dex(10.1MB), multidex

네이티브 코드 · 없음 (.so 0개)

서명 DN OU=pdutcbi가 패키지명 앞부분(pdutcbi)과 일치 → 운영자가 동일 빌드 파이프라인으로 자체 생성.

3. 권한 분석 (Permissions)

권한 · 목적

`READ_CONTACTS` · **주소록 전량 탈취**

`READ_MEDIA_IMAGES` / `READ_MEDIA_VIDEO` · **갤러리 사진/영상 탈취** (SDK 33+)

`READ_EXTERNAL_STORAGE` (maxSdk 32) · 구버전 갤러리 접근

`READ_PHONE_STATE` / `READ_PHONE_NUMBERS` · **[피해자 정보 비공개] 전화번호 획득**(`getLine1Number`)

`INTERNET` / `ACCESS_NETWORK_STATE` · C2 통신

SMS·위치·카메라 권한은 요청하지 않음. 단 코드(StatusUtils)에는 SMS 수집 메서드가 잔존(다른 변종에서 재사용된 흔적) — 본 빌드에서는 권한 미선언으로 비활성.

4. 방어기제 분석 및 파훼 (Defense Mechanisms — ALL BROKEN)

# · 방어기제 · 실태 · 파훼 결과

1 · **클래스 부풀리기** · 629 activity / 30 서브패키지(그중 26개·1,251 클래스가 더미) · `deobfuscate_core.py` **reachability BFS**로 자동 분리. 코어가 더미를 **0회 참조** → unreachable 디코이 확정

2 · **디코이 암호화 문자열** · `strings.xml`의 `cvknjykupldphsu`, `xleezfmzqobllzqapindz` (Base62 외형) · 추적 결과 **더미 액티비티의 Toast 메시지**일 뿐. 암호 키 아님 → 무시

3 · **SSL 인증서 검증 무력화** · `HttpUtil.buildUnsafeOkHttpClient`: X509TrustManager `getAcceptedIssuers`=빈 배열, `hostnameVerifier`=항상 `true` · 운영자 자해성 방어. **분석가는 MITM/프록시로 평문 가로채기 자유**

4 · **평문 트래픽 허용** · `network_security_config.xml`: `cleartextTrafficPermitted=true` · HTTP 다운그레이드 가능. 트래픽 가시성 100%

5 · 안티-분석(루팅/에뮬/Frida/디버거) · **전무** (코어 패키지 grep 0건) · 에뮬레이터·동적 분석 제약 없음

6 · 패킹/안티-탬퍼 · **없음** (dex 평문, assets 암호화 페이로드 없음) · jadx 완전 디컴파일 성공

결론: 유일하게 유효한 방어는 #1 클래스 부풀리기뿐이며, 이는 패키지 명명 통계 + 코어 참조 BFS로 완전 우회됨. 나머지는 디코이거나 오히려 분석가에게 유리.

4.1 파훼 자동화 (deobfuscate_core.py 출력)

방법: 참조 도달성(reachability) BFS. 런처 액티비티 패키지(Manifest에서 자동 추출 = view)를

시드로, 코어가 참조하는 서브패키지만 transitive하게 확장 → 나머지는 unreachable 디코이.

명명(모음비 등)에 의존하지 않으므로 다른 변종에 그대로 재사용 가능.

```

method: reachability BFS (seed=launcher activity package)

seed_subpackage: view

total_subpackages: 30 (core 4: view·util·bean·respon / dummy 26)

dummy_classes_total: 1251

dummy_classes_referenced_by_core: [] ← 0개 = PASS

real_logic: LoginActivity / HomeActivity / BaseActivity

+ ContainValue / HttpUtil / StatusUtils / GlobuleValue / PermissDialog

+ bean.InfoBeanDTO / bean.CollectBeanDTO / respon.ResposeResult

```

> 부수 발견: api 서브패키지(HttpsUtils)도 unreachable → 선언만 되고 미사용.

> 실제 통신은 전적으로 util.HttpUtil이 수행. (명명 휴리스틱으로는 잡히지 않을 사실)

5. C2 서버 인텔리전스 (C2 Intelligence)

항목 · 값

C2 Base · `[비공개]

해석 IP · **[비공개]**

프레임워크 · RuoYi (Spring Boot, `/prod-api` 게이트웨이 prefix, `{code,msg,data}` 응답)

상태 · **LIVE** (2026-06-14 검증, HTTP 200, 초대코드 검증 작동)

URL 저장 위치 · `util.ContainValue.Api` (평문 상수)

응답 언어 · 한국어 → 한국 [피해자 정보 비공개]

C2 base URL이 난수 도메인 + .rest TLD인 점은 wavegrid 패밀리의 도메인 회전(rotation) 전술과 일치. 기존 등록 변종 [비공개]과 동일 엔드포인트 구조([비공개], /saveAddressBook`).

6. API 엔드포인트 매핑 (Discovered Endpoints)

Method · Endpoint · 목적 · 파라미터

POST · `[비공개] · 초대코드 인증 · `name`(초대코드), `cId`(UUID)

POST · `[비공개] · **연락처/번호/통신사 탈취** · `userName`(초대코드), `model`, `bjPhone`(피해자번호), `operatorName`, `phoneContent`(연락처 JSON)

POST(multipart) · `[비공개] · **갤러리 사진 업로드** · `file`(JPEG), `other_field=yuvaluejing`

상세 페이로드 구조는 Tunf_data_transmission_report.md 참조.

7. 데이터 탈취 흐름 (Kill Chain)

```

LoginActivity

└ 초대코드 입력 → POST /webapp/login {name, cId=UUID}

└ code==200 → INVITE_CODE/UUID 저장 → HomeActivity

HomeActivity (btn_submit 클릭)

└ getPerInfo(): PermissionX로 연락처+미디어+전화번호 권한 요청

├ 전체 허용 → shareCOntain()

│ ├ getLine1Number() → [피해자 정보 비공개] 번호(codeValue)

│ ├ startNextInfo() → POST /webapp/saveAddressBook (연락처 전량)

│ └ startImgShowInfo()→ 갤러리 전체 → Luban 압축 → /webapp/image/{code} 반복 업로드

└ 부분/거부 → showActiveDialog(): APPLICATION_DETAILS_SETTINGS로 유도 후 재시도

└ 성공 시 IS_UPLOAD=true 저장 → "동기화 성공" 다이얼로그 → 버튼 비활성

```

stamswj()는 빈 본문의 디코이 메서드.

8. 취약점 분석 (Vulnerabilities)

취약점 · 내용 · 영향

SSL 검증 무력화 · 모든 인증서 신뢰 + 호스트명 검증 무시 · 제3자 MITM 가능 / 분석가 트래픽 가로채기

평문 페이로드 · 연락처·번호가 암호화 없이 JSON 전송 · 네트워크 캡처만으로 피해 데이터 전량 노출

인증 부재 · C2 게이트가 초대코드 단일 의존, 토큰/서명 없음 · 초대코드 확보 시 임의 데이터 주입/조회 가능성

도메인 평문 상수 · C2가 단일 상수에 하드코딩 · 차단·싱크홀링 용이

9. IOC (Indicators of Compromise)

```

패키지/앱

package com.pdutcbi.bctdimp

label Tunf

versionName 3.0.29 (3029)

해시

apk_sha256 4a636e12f6e195534affe8a021224e575e60c88270a02f4811fed4cd39db6646

apk_md5 048188123da7d78ee71fa9d46a0d21f8

cert_sha256 63e12b8b782afa2df4f6f624cd185534a40853cdf27f239edea1383fc4bf10c5

cert_sha1 77e9638fb7d4d015582b1d0972528c883d303f90

C2

domain [비공개]

ip [비공개]

endpoints [비공개] upload_marker other_field=yuvaluejing

SharedPreferences 키

INVITECODE / UUIDVALUE / ISUPLOAD / IFFIRST

```

10. 사용 라이브러리 (Supply Chain)

라이브러리 · 용도

`com.blankj:utilcode` (AndroidUtilCode) · SPUtils 등 (중국계 유틸)

`com.permissionx.guolindev:PermissionX` · 런타임 권한 요청 UX

`top.zibin.luban:Luban` · 업로드 전 이미지 압축

`okhttp3` + `gson` · 네트워크/직렬화

11. 🔬 기법 점검 (규칙서 14.13)

```

🔬 기법 점검:

· 시도한 기법:

· STR-001 (문자열/상수 C2 추출)

· SA-253 OBF-REACHABILITY (참조 도달성 BFS로 디코이 클래스 분리) ← 자동화 스크립트

· NET-PROBE (C2 라이브 검증, OPSEC-safe 더미 페이로드)

· SIG-FINGERPRINT (서명 DN/해시로 빌더 귀속)

· 확장된 기법:

· NET-PROBE — HTTP status와 application code(RuoYi {code})를 분리 보고하여

"서버 가동"과 "데이터 수신 성공"의 혼동 차단(code-review 반영)

· 신규 기법:

· SA-253 OBF-REACHABILITY — 런처 액티비티 패키지를 시드로 한 transitive 참조 BFS로

Manifest 등록 but unreachable한 디코이 패키지를 명명 무관하게 정확 분리.

(초기 모음비 휴리스틱은 fragile하여 reachability로 근본 재설계 — false positive 0)

· 한계 발견:

· 동적 트래픽(실기기 saveAddressBook 평문 캡처)은 미수행 — 정적+C2프로브로 흐름 확정.

추가 확증이 필요하면 에뮬레이터 + MITM 프록시로 평문 바디 1회 캡처 권장.

· saveAddressBook가 login 없이도 초대코드만으로 호출 가능한지(차등 인증)는 동적 확인 필요.

```

혁신 점검

```

· 새 아이디어/시도: 패키지 명명 통계 → (code-review 후) 참조 도달성 BFS로 근본 재설계

· 결과: 성공. reachability가 명명 휴리스틱이 못 잡는 사실까지 포착

(api/HttpsUtils가 선언만 되고 미사용 = unreachable 임을 자동 발견).

26 더미 패키지 / 1,251 클래스 격리, 코어 4패키지, false positive 0.

· 기법 카탈로그 반영: SA-253 OBF-REACHABILITY 신규 등재

· 다음 앱에서 시도할 아이디어: reachability를 smali 메서드 호출 그래프로 확장해

"등록 but 미도달(dead) 액티비티" 비율을 패밀리별 난독화 지문으로 정량화

```

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