모바일 앱 분석을 시작할 때 기본은 앱이 주고받는 네트워크 트래픽을 확인하는 것입니다. 이번 글에서 Android 앱의 HTTP/HTTPS 트래픽을 프록시 도구로 가로채고, 인증서 피닝을 우회하는 과정을 살펴보겠습니다.

시작하기

APK 파일을 다운로드 후 직접적으로 기기에 설치합니다. 설치된 앱을 클릭하여 접속한 뒤 NETWORK INTERCEPTING 메뉴로 이동하면 총 4개의 버튼이 존재합니다. 각 단계는 HTTP, HTTPS, OkHttp3 그리고 Native로 나눠져 있습니다.

01. HTTP 트래픽

먼저 가장 기본적인 HTTP 트래픽을 가로채는 것으로부터 시작하겠습니다. HTTP는 암호화되지 않은 프로토콜이기 때문에 프록시 설정만으로도 쉽게 트래픽을 가로챌 수 있습니다.

Burpsuite에서 Proxy Settings → Proxy Listeners → Edit 클릭 후 Bind to address를 All interfaces로 선택하여 외부 기기의 연결을 허용합니다. 이렇게 하면 같은 네트워크에 Android 기기가 PC의 Burp Suite에 연결할 수 있게 됩니다.

다음으로 Android 기기의 Wi-Fi 설정으로 이동하여 연결된 네트워크이 고급 설정을 엽니다. 프록시를 수동으로 변경하고, 프록시 호스트 이름에는 PC의 IP 주소를, 프록시 포트에는 Burp Suite에서 설정한 포트 번호를 입력합니다.

설정을 저장한 뒤 앱의 HTTP 버튼을 클릭하면 Burp Suite의 Proxy 탭에서 HTTP 요청이 정상적으로 가로채지는 것을 확인할 수 있습니다.

02. HTTPS 트래픽 가로채기와 인증서 설치

두 번째 HTTPS 버튼을 클릭하면 화면에는 Toast 메시지로 URL 전송이 표시되지만, Burp Suite의 History에는 아무것도 기록되지 않습니다. HTTPS는 SSL/TLS 암호화를 사용하기 때문에, 프록시가 중간에서 트래픽을 복호화하려면 자체 인증서로 통신을 가로채야 합니다.

하지만 Android 기기는 Burp Suite의 인증서를 신뢰하지 않기 때문에 연결이 차단되는 것입니다. 이 문제를 해결하기 위해 Burp Suite의 CA 인증서를 Android 기기에 시스템 인증서로 설치해야 합니다.

Burp Suite 인증서 내보내기

Burp Suite의 Proxy Settings → Import/Export CA Certificate 메뉴를 찾아 클릭합니다. Export 내 Certificate in DER format을 클릭한 뒤 Next 버튼을 클릭하고 cacert.der 파일명으로 저장합니다.

Android 7.0 이상 버전에서는 사용자가 설치한 인증서는 기본적으로 신뢰하지 않기 때문에 이 인증서를 시스템 인증서로 변환하는 과정이 필요합니다.

시스템 인증서 변환

먼저 OpenSSL을 사용하여 DER 형식의 인증서를 PEM 형식으로 변환합니다.

openssl x509 -inform DER -in cacert.der -out burp_ca.pem

다음으로 인증서의 해시 값을 추출합니다. Android는 인증서를 해시 값으로 식별하기 때문에 파일명을 해시 값으로 변경해야 합니다.

openssl x509 -inform PEM -subject_hash_old -in burp_ca.pem | Select-Object -First 1

이 명령어의 출력 값인 해시 값을 사용하여 파일명을 변경합니다.

cp burp_ca.pem 9a5ba575.0

Android 기기에 설치하기

이제 ADB(Android Debug Bridge)를 사용하여 변환된 인증서를 Android 기기에 설치합니다. 먼저 파일을 기기로 전송합니다.

adb -s [기기명] push 9a5ba575.0 /data/local/tmp

다음으로 루트 권한으로 쉘에 접속 후 파일 시스템을 쓰기 가능 모드로 마운트합니다.

adb -s [기기명] shell
$ su
# mount -o rw,remount /

인증서를 시스템 인증서 디렉토리로 이동하고 적절한 권한을 설정합니다.

# mv /sdcard/9a5ba575.0 /system/etc/security/cacerts/
# chmod 644 /system/etc/security/cacerts/9a5ba575.0
# chown root:root /system/etc/security/cacerts/9a5ba575.0

그런 다음 기기에서 생체 인식 및 보안 → 기타 보안 설정 → 인증서 확인으로 이동하여 PortSwigger CA 가 시스템 인증서로 등록된 것을 확인할 수 있습니다.

그런 다음 기기에서 생체 인식 및 보안 → 기타 보안 설정 → 인증서 확인으로 이동하여 PortSwigger CA 가 시스템 인증서로 등록된 것을 확인할 수 있습니다.

이제 앱의 HTTPS 버튼을 다시 클릭하면 Burp Suite의 History에서 HTTPS 트래픽이 정상적으로 가로채지는 것을 볼 수 있습니다.

03. OKHttp3 (Code-Based)

많은 앱들이 인증서 피닝(Certificate Pinning)이라는 기술을 사용하여 중간자 공격을 방어합니다. 인증서 피닝은 앱이 특정 인증서나 공개 키만을 신뢰하도록 하드코딩하는 기법으로, 시스템 인증서 저장소를 무시하고 독자적인 검증을 수행합니다.

AndroidManifest.xml 파일을 확인하면 Network를 담당하는 TrafficActivity를 확인할 수 있습니다.

해당 코드를 확인했을 때 OkHttp 라이브러리의 CertificatePinner 클래스를 직접 호출하여 피닝을 설정하고 있었습니다. 접속하고자 하는 owasp.org의 공개키 해시값을 코드에 하드코딩하여 검증하고 있습니다.

이를 우회하기 위해 CertificatePinner 코드를 보면 check() 함수를 Frida 등을 통해 후킹하여 예외를 발생시키지 않고 통과하도록 해야합니다.

Frida 우회

OkHttp3의 CertificatePinner는 check() 메서드를 통해 인증서를 검증합니다. Frida를 사용하여 런타임에 이 메서드를 후킹하고 검증 로직을 우회할 수 있습니다.

아래의 코드는 OkHttp3의 인증서 피닝을 우회하는 Frida 스크립트입니다.

Java.perform(function() {
    console.log("*** OkHttp Only Bypass Started ***");
    try {
        // 1. OkHttp의 CertificatePinner 클래스 로드
        var CertificatePinner = Java.use('okhttp3.CertificatePinner');
        console.log("[+] OkHttp CertificatePinner 클래스를 찾았습니다.");

        // 2. Kotlin용 check 메소드 후킹 
        // check$okhttp(String hostname, Function0<List<Certificate>> cleanedPeerCertificatesFn)
        CertificatePinner.check$okhttp.overload('java.lang.String', 'kotlin.jvm.functions.Function0').implementation = function(hostname, fn) {
            console.log("[*] check$okhttp(Kotlin) 호출됨 -> 검증 무시: " + hostname);
            return;
        };
        console.log("[+] OkHttp 검증 함수 후킹 완료. 대기 중...");

    } catch(e) {
        console.log("[-] 에러 발생 (OkHttp 버전을 확인하세요): " + e);
    }
});

이 스크립트는 check$okhttp 메서드의 실행을 가로채서 실제 검증 로직을 실행하지 않고 바로 반환합니다. 원래 이 메서드는 서버의 인증서가 앱에 하드코딩된 핀과 일치하는지 확인하고, 일치하지 않으면 예외를 발생시켜 연결을 차단합니다. 하지만 Frida 코드에서는 이러한 검증을 건너뛰고 항상 성공한 것처럼 동작합니다.

스크립트를 저장한 후 다음 명령어로 Frida를 실행합니다.

frida -f owasp.sat.agoat -D R3CM609AZRA -l bypass.js

여기서 -f 옵션은 앱을 새로 시작하면서 스크립트를 주입하고, -D 옵션은 연결할 기기를 지정하며, -l 옵션은 실행할 스크립트 파일을 지정합니다.

이제 CERTIFICATE PINNING - OKHTTP3 버튼을 클릭해봅니다.

터미널에서 검증 무시 메시지가 출력되었습니다.

실제로 Burp Suite의 History에서도 트래픽이 정상적으로 전송되며 가로채지는 것도 확인할 수 있었습니다.

Frida CodeShare 사용

직접 코드 타이핑 없이 범용적으로 사용 가능한 피닝 우회 코드도 있습니다. akabe1/frida-multiple-unpinning에는 여러 종류의 인증서 피닝 기법을 한 번에 우회하는 스크립트입니다. 사용법은 아래와 같습니다.

PS C:\Users\WIN11> frida -f owasp.sat.agoat -D R3CM609AZRA --codeshare akabe1/frida-multiple-unpinning
     ____
    / _  |   Frida 16.1.4 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
   . . . .
   . . . .   Connected to SM G977N (id=R3CM609AZRA)
Spawned `owasp.sat.agoat`. Resuming main thread!
[SM G977N::owasp.sat.agoat ]->
======
[#] Android Bypass for various Certificate Pinning methods [#]
======
...
[SM G977N::owasp.sat.agoat ]-> [+] Bypassing Trustmanager (Android < 7) pinner
[+] Bypassing OkHTTPv3 {4}: owasp.org

피닝을 우회하여 위와 동일한 동작이 가능합니다.

Objection 사용

PS C:\Users\WIN11> objection -S R3CM609AZRA -n owasp.sat.agoat start

     _   _         _   _
 ___| |_|_|___ ___| |_|_|___ ___
| . | . | | -_|  _|  _| | . |   |
|___|___| |___|___|_| |_|___|_|_|
      |___|(object)inject(ion) v1.12.2

     Runtime Mobile Exploration
        by: @leonjza from @sensepost

[tab] for command suggestions
owasp.sat.agoat (run) on (Android: 12) [usb] # android sslpinning disable

또 다른 유용한 도구는 Objection입니다. Objection은 Frida 기반의 런타임 모바일 탐색 도구로, 명령어 한 줄로 SSL 피닝을 비활성화할 수 있습니다.

android sslpinning disable

이 명령어는 앱 내의 여러 SSL 피닝 구현을 자동으로 탐지하고 우회합니다.

04. NSC 우회

res/xml/network_security_config.xml 파일을 통해 네트워크 보안 정책을 선언할 수 있습니다. 이 파일은 앱이 HTTPS 통신 시 어떤 인증서를 신뢰할지, 평문 통신을 허용할지 등을 정의합니다. 해당 파일에서 cve.org 도메인에 대한 피닝이 작성되어 있습니다. 이는 특정 인증서의 공개 키 해시만을 신뢰하도록 설정된 것입니다.

이를 우회할 수 있는 방법은 두 가지가 있습니다.

  • Frida 사용
    • 안드로이드 시스템의 TrustManager를 후킹하는 전반적인 Android SSL Pinning Bypass 스크립트를 사용할 수 있습니다.
  • APK 변조
    • APK를 디컴파일 후 XML 파일에서 <domain-config> 부분을 삭제하고 다시 빌드하면 피닝이 사라집니다.

간단하게 첫 번째 방법으로 진행해보겠습니다.

```
PS C:\Users\WIN11> frida -f owasp.sat.agoat -D R3CM609AZRA --codeshare akabe1/frida-multiple-unpinning
     ____
    / _  |   Frida 16.1.4 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
   . . . .
   . . . .   Connected to SM G977N (id=R3CM609AZRA)
Spawned `owasp.sat.agoat`. Resuming main thread!
[SM G977N::owasp.sat.agoat ]->
======
[#] Android Bypass for various Certificate Pinning methods [#]
======
...
[SM G977N::owasp.sat.agoat ]-> [+] Bypassing Trustmanager (Android < 7) pinner
[+] Bypassing OkHTTPv3 {4}: cve.org
[+] Bypassing OkHTTPv3 {4}: www.cve.org
```

Frida CodeShare에 있는 akabe1/frida-multiple-unpinning 코드를 스크립트로 사용합니다.

사용한 뒤 앱의 CERTIFICATE PINNING - NATIVE 버튼을 클릭한 뒤에 터미널을 확인하면 도메인을 우회한 것을 볼 수 있습니다.

Burp Suite의 History 탭에서도 피닝을 우회하여 정상적으로 통신하고 있는 것을 볼 수 있습니다.