Android@SSL Pinning# Four Ways to Bypass Android SSL Verification and Certificate Pinning
https://blog.netspi.com/four-ways-bypass-android-ssl-verification-certificate-pinning/
Four Ways to Bypass Android SSL Verification and Certificate Pinning
이 블로그에서는 Android에서 SSL 인증서 확인을 우회하는 데 사용할 수 있는 4 가지 기술을 살펴 보겠습니다.
- 신뢰할 수 있는 인증서 저장소에 사용자 지정 CA 추가
- 패키징된 CA인증서에 커스텀 CA 인증서로 덮어 쓰기
- Frida를 사용하여 SSL 인증서 검사를 후킹하고 우회
- 커스텀 인증서 코드 리버싱
Technique 1 – Adding a Custom CA to the User Certificate Store
SSL오류를 피하는 가장 간단한 방법은 신뢰할 수 있는 인증서를 사용하는 것입니다. 새롭고 신뢰할 수 있는 인증서를 디바이스에 설치할 수 있으면 비교적 쉽습니다. Android에는 운영 체제에서 신뢰하는 CA(사전 설치된 CA) 및 사용자 저장소(사용자가 설치한 CA)를 추적하는 두 가지 내장 인증서 저장소가 있습니다.
기본적으로 모든 애플리케이션의 보안 연결(TLS 및 HTTPS와 같은 프로토콜 사용)은 사전 설치된 시스템 CA를 신뢰하고 Android 6.0 (API Level 23)이하를 타겟팅하는 어플리케이션은 기본적으로 사용자가 추가한 CA 저장소를 신뢰합니다. 앱은 base-config(for app wide customization) 혹은 domain-config(for per-domain customization)를 사용하여 자체 연결을 커스터마이징해 사용할 수 있습니다.
이것은 우리에게 무엇을 의미합니까? MITM을 대상으로 하는 애플리케이션이 Android 6.0이하를 대상으로하는 경우 CA를 user-added CA 저장소에 추가하기만 하면 됩니다. 애플리케이션에서 사용자 커스텀 인증서에 대한 트러스트 체인의 유효성을 검사하면 사용자 커스텀 CA가 trust 저장소에서 발견되고 인증서가 신뢰될것입니다. 그러나 6.0이후의 Android 버전을 대상으로 하는 애플리케이션은 사용자가 추가한 CA저장소를 신뢰하지 않습니다. 이 문제를 해결하기 위해 애플리케이션의 Manifest파일을 수정해 Android 6.0을 대상으로 할 수 있습니다. 타겟 API레벨은 AndroidManifest.xml파일의 'manifest' 요소의 'platformBuildVersionCode' 속성에 지정됩니다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test.app" platformBuildVersionCode="25" platformBuildVersionName="7.1.1"> |
위의 manifest 요소는 ‘platformBuildVersionCode=25'을 대상으로 하며, 23으로 변경해댜 합니다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test.app" platformBuildVersionCode="23" platformBuildVersionName="6.0"> |
이 업데이트된 매니페스토로 애플리케이션을 다시 리패키징하면 사용자가 추가 한 CA 저장소가 신뢰됩니다.
특정 플랫 버전을 실행해야하는 경우 APK의 '/res/xml/network_security_config.xml' 구성 파일에 특정 트러스트 앵커를 정의할 수 있습니다. 예를 들어 다음 파일은 /res/raw/my_ca(from https://developer.android.com/training/articles/security-config.html)에 저장해야하는 신뢰할 수 있는 CA를 정의합니다.
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <trust-anchors> <certificates src="@raw/my_ca"/> </trust-anchors> </base-config> </network-security-config> |
애플리케이션에 제시된 인증서가 유효한지만 확인하는 경우이 기술을 사용하면 성공적인 MITM 조건을 설정할 수 있습니다.
Technique 2 – Overwrite Packaged CA Certificate with Custom CA Certificate
사용자가 추가한 CA 저장소에 인증서를 성공적으로 설치하고 애플리케이션 Android 6.0을 대상으로하고 다른 SSL로 보호 된 자원을 시도하고 찾아 볼 때 인증서가 유효한 것으로 나타나지만 SSL 오류로 인해 애플리케이션이 여전히 정지되면 어떻게됩니까? 개발자가 애플리케이션에서 신뢰하는 CA 집합을 제한하기 위한 추가 단계를 수행했을 수 있습니다. technique 1에서 커스텀 사용자 앵커를 정의하고 CA 인증서 경로를 제공했습니다. 이것은 개발자가 응용 프로그램을 SSL interception으로부터 보호하기 위해 사용할 수 있는 기능입니다.
애플리케이션과 함께 커스텀 인증서 체인을 배포하는 경우 APK를 추출하고 제공된 CA를 우리의 커스텀 CA로 덮어 쓰는 것만으로도 상호 수신 인증서를 신뢰할 수 있는 원인이 되기에 충분합니다. 경우에 따라 트러스트 체인의 추가 확인이 진행될 수 있으므로 이 방법은 여러 가지 결과를 초래할 수 있습니다.
APK Studio와 같은 도구로 APK를 열면 배포 된 애플리케이션과 함께 번들로 제공되는 인증서가 있음을 알 수 있습니다. 위 이미지에서 인증서는 'assets'디렉토리 아래에 있습니다. 적절히 이름 붙여진 'UniversalRootCA'인증서를 사용자 지정 CA로 덮어 쓰면 애플리케이션을 속여서 인증서를 수락 할 수 있습니다.
Technique 3 – Frida Hook
자체 CA를 설치하여 SSL 트랙픽을 프록시하는것이 충분하지 않은 경우 애플리케이션이 SSL Pinning이나 추가적으로 SSL 유효성 검사를 수행할 가능성이 있습니다. 일반적으로 이러한 유효성 검사를 우회하려면 애플리케이션의 코드를 후킹하거나 유효성 검사 프로세스를 방해해야합니다. 이러한 유형의 우회는 루팅/탈옥된 단말기에서만 진행할 수 있지만 Frida Gadget을 이용해 루팅하지 않고도 가능합니다.
모바일 애플리케이션 침투 테스트를 수행한 경함이 있다면 Frida 프레임 워크에 익숙할 것입니다. Frida의 전체 기능을 설명하는 것은 이 블로그의 범위를 벗어나지만 Frida는 런타임시 애플리케이션의 코드를 조작할 수 있는 프레임워크입니다. 일반적으로 프리다는 stand-alone 프로그램으로 운영체제에서 실행되지만 디바이스를 루팅해야합니다. 이를 피하기 위해 Frida Gadget을 대상 APK에 삽입할 수 있습니다. Frida Gadget은 Frida의 기능 대부분을 포함하지만 런타임에 타겟 애플리케이션에 의해 로드되는 동적 라이브러리에 캠슐화되어 타겟 애플리케이션의 코드를 수정할 수 있습니다.
Frida Gadget을 로드하려면 APK를 추출, 동적 라이브러리를 삽입, smali코드를 편집하고 동적 라이브러리를 애플리케이션 시작 시 호출 될 첫 번째 항목으로 만든 다음 APK를 리패키징하고 디바이스에 설치해야합니다. 이 전체 과정은 John Kozyrakis에 의해 문서화 되어 있습니다. 그러나 시작을 절약하기 위해 사용할 수 있는 또 다른 툴인 Objection이 있습니다. Objection은 앞서 이야기했던 전체 프로세스를 자동화하며 커맨드라인에 타겟 APK만 제공하면 됩니다.
C:\ >objection patchapk -s test_app.apk No architecture specified. Determining it using `adb`... Detected target device architecture as: armeabi-v7a Github FridaGadget is v10.6.28, local is v10.6.13. Updating... Downloading armeabi-v7a library to C:\.objection\android\armeabi-v7a\libfrida-gadget.so.xz... Unpacking C:\.objection\android\armeabi-v7a\libfrida-gadget.so.xz... Cleaning up downloaded archives... Using Gadget version: 10.6.28 Unpacking test_app.apk App already has android.permission.INTERNET Reading smali from: C:\Temp\tmp8dxqks1u.apktemp\smali\com/test/app/TestMainActivity.smali Injecting loadLibrary call at line: 10 Writing patched smali back to: C:\Temp\tmp8dxqks1u.apktemp\smali\com/test/app/TestMainActivity.smali Creating library path: C:\Temp\tmp8dxqks1u.apktemp\lib\armeabi-v7a Copying Frida gadget to libs path... Rebuilding the APK with the frida-gadget loaded... Built new APK with injected loadLibrary and frida-gadget Signing new APK. jar signed. Signed the new APK Performing zipalign Zipaling completed Copying final apk from C:\Users\cwass\AppData\Local\Temp\tmp8dxqks1u.apktemp.aligned.objection.apk to current directory... Cleaning up temp files... |
이 과정을 거치면 작업 디렉터리에 'test_app.objection.apk'라는 파일이 생성될 것 입니다. 기본적으로 objection은 원래 APK의 이름에 '.objection'을 추가합니다. 이 APK는 다른 APK와 마찬가지로 설치할 수 있습니다. adb install test_app.objection.apk 명령어를 이용해 디바이스에 설치해봅시다. objection을 통해 변경된 APK가 디바이스에 설치된 후에 앱을 실행하면 시작 화면에서 중지되는 것을 확인할 수 있습니다. 이 시점에서 우리는 Frida 서버에 연결할 수 있습니다.
C:\>frida-ps -U PID Name ---- ------ 6383 Gadget C:\>frida -U gadget ____ / _ | Frida 10.3.14 - A world-class dynamic instrumentation framework | (_| | > _ | Commands: /_/ |_| help -> Displays the help system . . . . object? -> Display information about 'object' . . . . exit/quit -> Exit . . . . . . . . More info at http://www.frida.re/docs/home/ [Motorola Moto G (5) Plus::gadget]-> Java.available true Alternatively, Objection supports interaction with the listening Frida server by using the ‘explore’ command: C:\>objection explore ___| |_ |_|___ ___| |_|_|___ ___ | . | . | | | -_| _| _| | . | | |___|___|_| |___|___|_| |_|___|_|_| |___| (object)inject(ion) v1.2.2 Runtime Mobile Exploration by: @leonjza from @sensepost [tab] for command suggestions com.test.app on (motorola: 7.0) [usb] # android hooking search classes TrustManager android.security.net.config.RootTrustManager android.app.trust.ITrustManager$Stub$Proxy android.app.trust.ITrustManager android.security.net.config.NetworkSecurityTrustManager android.security.net.config.RootTrustManagerFactorySpi android.app.trust.TrustManager android.app.trust.ITrustManager$Stub com.android.org.conscrypt.TrustManagerImpl com.android.org.conscrypt.TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker com.android.org.conscrypt.TrustManagerImpl$TrustAnchorComparator com.android.org.conscrypt.TrustManagerFactoryImpl javax.net.ssl.TrustManagerFactory$1 javax.net.ssl.TrustManager javax.net.ssl.TrustManagerFactory javax.net.ssl.X509TrustManager javax.net.ssl.TrustManagerFactorySpi javax.net.ssl.X509ExtendedTrustManager [Ljavax.net.ssl.TrustManager; |
이 시점에서 내장된 SSL 피닝 우회 기능을 활용해야 합니다.
com.test.app on (motorola: 7.0) [usb] # android sslpinning disable Job: 2f633f86-f252-4a57-958e-6b46ac8d69d1 - Starting [6b46ac8d69d1] [android-ssl-pinning-bypass] Custom, Empty TrustManager ready Job: 2f633f86-f252-4a57-958e-6b46ac8d69d1 – Started |
Technique 4 – Reversing Custom Certificate Validation Code
마지막으로, 개발자가 시스템 라이브러리에 의존하지 않고 SSL 인증서 유효성 검사를 처리하는 대신 자신이 개발한 SSL 라이브러리를 사용할 수 도 있습니다. 이 경우 APK를 추출하여 smali를 Java로 변환하여 인증서 유효성 확인을 처리하는 코드를 찾을 수 있습니다.