diff --git a/src/mobile-pentesting/android-app-pentesting/android-anti-instrumentation-and-ssl-pinning-bypass.md b/src/mobile-pentesting/android-app-pentesting/android-anti-instrumentation-and-ssl-pinning-bypass.md index 63522cb25..594d74141 100644 --- a/src/mobile-pentesting/android-app-pentesting/android-anti-instrumentation-and-ssl-pinning-bypass.md +++ b/src/mobile-pentesting/android-app-pentesting/android-anti-instrumentation-and-ssl-pinning-bypass.md @@ -2,30 +2,30 @@ {{#include ../../banners/hacktricks-training.md}} -이 페이지는 instrumentation을 차단하거나 루트 감지(root‑block)를 하는 Android 앱에 대해 동적 분석을 복구하기 위한 실용적인 워크플로우를 제공합니다. 빠른 분류, 일반적인 탐지 기법, 그리고 가능하면 repacking 없이 적용 가능한 복사‑붙여넣기형 훅/전술에 중점을 둡니다. +이 페이지는 instrumentation을 탐지하거나 루트 차단(root‑block)을 수행하거나 TLS pinning을 강제하는 Android apps에 대해 dynamic analysis를 다시 수행할 수 있도록 하는 실용적인 워크플로를 제공합니다. 가능한 경우 repacking 없이 우회하기 위한 빠른 분류(triage), 일반적인 탐지 항목, 그리고 복사·붙여넣기 가능한 hooks/전술에 초점을 맞춥니다. -## Detection Surface (what apps check) +## Detection Surface (앱이 검사하는 항목) -- 루트 검사: su binary, Magisk paths, getprop values, common root packages -- Frida/debugger 검사 (Java): Debug.isDebuggerConnected(), ActivityManager.getRunningAppProcesses(), getRunningServices(), scanning /proc, classpath, loaded libs -- 네이티브 anti‑debug: ptrace(), syscalls, anti‑attach, breakpoints, inline hooks -- 초기 초기화 검사: Application.onCreate() 또는 프로세스 시작 훅에서 instrumentation이 존재하면 크래시를 유발 +- Root checks: su binary, Magisk paths, getprop values, common root packages +- Frida/debugger checks (Java): Debug.isDebuggerConnected(), ActivityManager.getRunningAppProcesses(), getRunningServices(), scanning /proc, classpath, loaded libs +- Native anti‑debug: ptrace(), syscalls, anti‑attach, breakpoints, inline hooks +- Early init checks: Application.onCreate() or process start hooks that crash if instrumentation is present - TLS pinning: custom TrustManager/HostnameVerifier, OkHttp CertificatePinner, Conscrypt pinning, native pins ## Step 1 — Quick win: hide root with Magisk DenyList - Magisk에서 Zygisk 활성화 -- DenyList 활성화하고 대상 패키지 추가 +- DenyList 활성화 후 대상 패키지 추가 - 재부팅 후 재테스트 -많은 앱은 명확한 지표(su/Magisk paths/getprop)만 확인합니다. DenyList는 종종 이런 단순한 검사를 무력화합니다. +많은 앱은 (su/Magisk paths/getprop) 같은 명백한 지표만 확인합니다. DenyList는 흔히 단순한 검사들을 무력화합니다. References: - Magisk (Zygisk & DenyList): https://github.com/topjohnwu/Magisk ## Step 2 — 30‑second Frida Codeshare tests -깊게 분석하기 전에 일반적으로 사용하는 드롭인 스크립트를 먼저 시도하세요: +깊이 들어가기 전에 일반적으로 사용하는 drop‑in 스크립트를 먼저 시도하세요: - anti-root-bypass.js - anti-frida-detection.js @@ -35,13 +35,13 @@ Example: ```bash frida -U -f com.example.app -l anti-frida-detection.js ``` -이들은 일반적으로 Java의 root/debug checks, process/service scans, 그리고 native ptrace()를 스텁 처리합니다. 보호 수준이 낮은 앱에서는 유용하지만, 보안이 강화된 대상(hardened targets)은 맞춤형 훅이 필요할 수 있습니다. +이들은 일반적으로 Java root/debug checks, process/service scans, 그리고 native ptrace()를 스텁 처리합니다. 보안이 약한 앱에서 유용하며, 강화된 대상은 맞춤형 훅이 필요할 수 있습니다. - Codeshare: https://codeshare.frida.re/ -## Automate with Medusa (Frida framework) +## Medusa (Frida framework)로 자동화 -Medusa는 SSL unpinning, root/emulator detection bypass, HTTP comms logging, crypto key interception 등을 위한 90+개의 기성 모듈을 제공합니다. +Medusa는 SSL unpinning, root/emulator detection bypass, HTTP comms logging, crypto key interception 등을 포함한 90+ 즉시 사용 가능한 모듈을 제공합니다. ```bash git clone https://github.com/Ch0pin/medusa cd medusa @@ -54,40 +54,40 @@ use http_communications/multiple_unpinner use root_detection/universal_root_detection_bypass run com.target.app ``` -팁: Medusa는 커스텀 hooks를 작성하기 전에 빠른 승리를 가져오기 좋습니다. modules를 cherry-pick하고 자체 scripts와 결합할 수도 있습니다. +팁: Medusa는 custom hooks를 작성하기 전에 빠른 성과를 내기에 좋습니다. 또한 modules를 cherry-pick해서 자신의 scripts와 결합할 수 있습니다. -## 3단계 — Bypass init-time detectors by attaching late +## Step 3 — init-time 탐지기를 우회하려면 늦게 attach하세요 -많은 탐지들은 process spawn/onCreate() 동안에만 실행됩니다. Spawn‑time injection (-f)이나 gadgets는 탐지되기 쉽고, UI가 로드된 이후에 attaching하면 우회할 수 있습니다. +많은 탐지는 process spawn/onCreate() 동안에만 실행됩니다. Spawn‑time injection (-f)이나 gadgets는 잡히기 쉬우며; UI가 로드된 후에 attaching하면 우회할 수 있습니다. ```bash # Launch the app normally (launcher/adb), wait for UI, then attach frida -U -n com.example.app # Or with Objection to attach to running process aobjection --gadget com.example.app explore # if using gadget ``` -이 방법이 통하면 세션을 안정적으로 유지하고 map 및 stub checks로 진행하세요. +이 방법이 작동하면 세션을 안정적으로 유지하고 매핑(map) 및 스텁(stub) 검사를 진행하세요. -## Step 4 — Jadx 및 문자열 탐색을 통한 탐지 로직 매핑 +## Step 4 — Jadx와 string hunting을 통한 탐지 로직 매핑 -Jadx에서의 정적 triage 키워드: +Static triage keywords in Jadx: - "frida", "gum", "root", "magisk", "ptrace", "su", "getprop", "debugger" -일반적인 Java 패턴: +Typical Java patterns: ```java public boolean isFridaDetected() { return getRunningServices().contains("frida"); } ``` -검토/후킹할 공통 API: +검토/후킹할 일반적인 API: - android.os.Debug.isDebuggerConnected - android.app.ActivityManager.getRunningAppProcesses / getRunningServices - java.lang.System.loadLibrary / System.load (native bridge) - java.lang.Runtime.exec / ProcessBuilder (probing commands) - android.os.SystemProperties.get (root/emulator heuristics) -## Step 5 — Frida로 런타임 스텁 처리 (Java) +## Step 5 — Frida (Java)를 이용한 런타임 스터빙 -재패키징 없이 안전한 값을 반환하도록 커스텀 가드를 재정의: +재패키징 없이 안전한 값을 반환하도록 커스텀 가드를 오버라이드: ```js Java.perform(() => { const Checks = Java.use('com.example.security.Checks'); @@ -102,7 +102,7 @@ const AM = Java.use('android.app.ActivityManager'); AM.getRunningAppProcesses.implementation = function () { return java.util.Collections.emptyList(); }; }); ``` -초기 크래시를 분석 중인가요? 종료되기 직전에 Dump classes해서 감지 가능성이 높은 네임스페이스를 찾아보세요: +초기 크래시를 트리아징 중인가요? 종료 직전에 Dump classes를 실행해 탐지 가능성이 있는 namespaces를 찾아보세요: ```js Java.perform(() => { Java.enumerateLoadedClasses({ @@ -111,7 +111,6 @@ onComplete: () => console.log('Done') }); }); ``` -``` // Quick root detection stub example (adapt to target package/class names) Java.perform(() => { try { @@ -119,9 +118,8 @@ const RootChecker = Java.use('com.target.security.RootCheck'); RootChecker.isDeviceRooted.implementation = function () { return false; }; } catch (e) {} }); -``` -실행 흐름을 확인하기 위해 의심스러운 메서드를 로깅하고 무력화하세요: +의심스러운 메서드를 기록하고 무력화하여 실행 흐름을 확인하세요: ```js Java.perform(() => { const Det = Java.use('com.example.security.DetectionManager'); @@ -131,9 +129,9 @@ return false; }; }); ``` -## 에뮬레이터/VM 감지 우회 (Java stubs) +## 에뮬레이터/VM 탐지 우회 (Java stubs) -일반적인 휴리스틱: Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE에 generic/goldfish/ranchu/sdk가 포함되어 있는지; /dev/qemu_pipe, /dev/socket/qemud 같은 QEMU 아티팩트; 기본 MAC 02:00:00:00:00:00; 10.0.2.x NAT; 전화 기능/센서 누락. +일반적인 휴리스틱: Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE에 generic/goldfish/ranchu/sdk가 포함되는 경우; QEMU 아티팩트(예: /dev/qemu_pipe, /dev/socket/qemud); 기본 MAC 02:00:00:00:00:00; 10.0.2.x NAT; telephony/sensors 누락. Build 필드의 빠른 스푸핑: ```js @@ -145,11 +143,11 @@ Build.BRAND.value = 'google'; Build.FINGERPRINT.value = 'google/panther/panther:14/UP1A.231105.003/1234567:user/release-keys'; }); ``` -파일 존재 검사와 식별자에 대한 스텁을 추가하여 TelephonyManager.getDeviceId/SubscriberId, WifiInfo.getMacAddress, SensorManager.getSensorList 호출이 현실적인 값을 반환하도록 보완하세요. +파일 존재 검사와 식별자(예: TelephonyManager.getDeviceId/SubscriberId, WifiInfo.getMacAddress, SensorManager.getSensorList)에 대한 스텁을 추가하여 현실적인 값을 반환하도록 보완하세요. ## SSL pinning bypass quick hook (Java) -사용자 정의 TrustManagers를 무력화하고 허용적인 SSL contexts를 강제합니다: +커스텀 TrustManagers를 무력화하고 허용적인 SSL 컨텍스트를 강제합니다: ```js Java.perform(function(){ var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager'); @@ -167,28 +165,28 @@ return SSLContextInit.call(this, km, TrustManagers, sr); }; }); ``` -노트 -- OkHttp 확장: 필요한 경우 okhttp3.CertificatePinner와 HostnameVerifier를 hook하거나, CodeShare의 universal unpinning script를 사용하세요. +참고 +- OkHttp에 대해 확장: 필요에 따라 okhttp3.CertificatePinner와 HostnameVerifier를 hook하거나, CodeShare의 범용 unpinning 스크립트를 사용하세요. - 실행 예: `frida -U -f com.target.app -l ssl-bypass.js --no-pause` -## 6단계 — Java hooks가 실패할 때 JNI/native 경로 추적 +## 6단계 — Java hooks가 실패할 때 JNI/native 경로를 따라가세요 -JNI entry points를 추적하여 native loaders와 detection init을 찾으세요: +JNI 진입점을 추적하여 네이티브 로더와 탐지 초기화를 찾아보세요: ```bash frida-trace -n com.example.app -i "JNI_OnLoad" ``` -번들된 .so 파일에 대한 빠른 네이티브 선별: +번들된 .so 파일의 빠른 네이티브 분류: ```bash # List exported symbols & JNI nm -D libfoo.so | head objdump -T libfoo.so | grep Java_ strings -n 6 libfoo.so | egrep -i 'frida|ptrace|gum|magisk|su|root' ``` -인터랙티브/네이티브 리버싱: +인터랙티브/네이티브 reversing: - Ghidra: https://ghidra-sre.org/ - r2frida: https://github.com/nowsecure/r2frida -예: ptrace를 무력화하여 libc의 단순 anti‑debug를 우회: +예제: libc의 단순한 anti‑debug를 무력화하기 위해 ptrace를 중화하는 방법: ```js const ptrace = Module.findExportByName(null, 'ptrace'); if (ptrace) { @@ -202,22 +200,22 @@ return -1; // pretend failure reversing-native-libraries.md {{#endref}} -## 7단계 — Objection patching (embed gadget / strip basics) +## 단계 7 — Objection patching (embed gadget / strip basics) repacking을 runtime hooks보다 선호한다면, 다음을 시도해보세요: ```bash objection patchapk --source app.apk ``` 참고: -- apktool이 필요합니다; 빌드 문제를 피하려면 공식 가이드에서 최신 버전을 사용하세요: https://apktool.org/docs/install -- Gadget injection은 root 없이 instrumentation을 가능하게 하지만 더 강력한 init‑time checks에 의해 차단될 수 있습니다. +- apktool이 필요합니다; 빌드 문제를 피하려면 공식 가이드의 최신 버전을 사용하세요: https://apktool.org/docs/install +- Gadget injection은 root 없이 instrumentation을 가능하게 하지만 더 강력한 init‑time 검사에서는 여전히 탐지될 수 있습니다. -선택적으로, Zygisk 환경에서 루트 은닉을 강화하기 위해 LSPosed 모듈과 Shamiko를 추가하고, 하위 프로세스를 포함하도록 DenyList를 정리하세요. +선택적으로, Zygisk 환경에서 더 강력한 root 은닉을 위해 LSPosed 모듈과 Shamiko를 추가하고, 하위 프로세스를 포함하도록 DenyList를 관리하세요. -참조: +참고자료: - Objection: https://github.com/sensepost/objection -## Step 8 — 폴백: TLS pinning 패치로 네트워크 가시성 확보 +## 8단계 — 폴백: TLS pinning 패치로 네트워크 가시성 확보 instrumentation이 차단된 경우, pinning을 정적으로 제거하여 트래픽을 검사할 수 있습니다: ```bash @@ -225,7 +223,7 @@ apk-mitm app.apk # Then install the patched APK and proxy via Burp/mitmproxy ``` - 도구: https://github.com/shroudedcode/apk-mitm -- 네트워크 구성 CA‑trust 트릭(및 Android 7+ user CA trust)은 다음을 참조하세요: +- 네트워크 구성 CA‑trust 트릭(및 Android 7+ user CA trust)에 대해서는 다음을 참조하세요: {{#ref}} make-apk-accept-ca-certificate.md @@ -235,7 +233,7 @@ make-apk-accept-ca-certificate.md install-burp-certificate.md {{#endref}} -## 유용한 명령 치트시트 +## 유용한 명령어 치트‑시트 ```bash # List processes and attach frida-ps -Uai @@ -253,14 +251,32 @@ objection --gadget com.example.app explore # Static TLS pinning removal apk-mitm app.apk ``` -## 팁 및 주의사항 +## 범용 proxy 강제 + TLS unpinning (HTTP Toolkit Frida hooks) -- 앱이 런치 시 크래시할 때에는 spawn하기보다 나중에 attach하는 것을 권장합니다 -- 일부 감지 로직은 중요한 흐름(예: payment, auth)에서 재실행됩니다 — 네비게이션 중에는 hooks를 활성 상태로 유지하세요 -- 정적(static)과 동적(dynamic)을 혼합하세요: Jadx에서 string hunt로 클래스 후보를 추려낸 다음, 런타임에서 검증하기 위해 hook methods를 사용하세요 -- 하드닝된 앱은 packers와 native TLS pinning을 사용할 수 있으므로 reverse native code를 예상하세요 +현대 앱들은 종종 시스템 proxies를 무시하고 여러 겹의 pinning (Java + native)을 적용하여, 사용자/시스템 CAs가 설치되어 있어도 트래픽 캡처가 매우 어렵습니다. 실용적인 접근법은 범용 TLS unpinning과 준비된 Frida hooks를 통한 proxy 강제화를 결합하고, 모든 트래픽을 mitmproxy/Burp로 라우팅하는 것입니다. -## References +Workflow +- 호스트에서 mitmproxy(또는 Burp)를 실행하세요. 디바이스가 호스트의 IP/포트에 접근할 수 있는지 확인하세요. +- HTTP Toolkit의 통합 Frida hooks를 로드하여 TLS를 unpin하고 OkHttp/OkHttp3, HttpsURLConnection, Conscrypt, WebView 등 일반적인 스택 전반에서 proxy 사용을 강제하세요. 이는 CertificatePinner/TrustManager 검사를 우회하고 proxy selectors를 오버라이드하여, 앱이 명시적으로 proxies를 비활성화하더라도 트래픽이 항상 당신의 proxy를 통해 전송되게 합니다. +- Frida와 훅 스크립트로 대상 앱을 시작하고 mitmproxy에서 요청을 캡처하세요. + +Example +```bash +# Device connected via ADB or over network (-U) +# See the repo for the exact script names & options +frida -U -f com.vendor.app \ +-l ./android-unpinning-with-proxy.js \ +--no-pause + +# mitmproxy listening locally +mitmproxy -p 8080 +``` +노트 +- 가능한 경우 `adb shell settings put global http_proxy :`를 통해 시스템 전체 proxy와 결합하세요. Frida hooks는 앱이 전역 설정을 우회하더라도 proxy 사용을 강제합니다. +- pinning이나 proxy 회피가 흔한 mobile-to-IoT 온보딩 플로우를 MITM해야 할 때 이 기법이 이상적입니다. +- Hooks: https://github.com/httptoolkit/frida-interception-and-unpinning + +## 참고자료 - [Reversing Android Apps: Bypassing Detection Like a Pro](https://www.kayssel.com/newsletter/issue-12/) - [Frida Codeshare](https://codeshare.frida.re/)