본문 바로가기
App hacking

[안드로이드]OKHTTP Pinning Bypass

by m_.9m 2022. 5. 30.

 

2-1 OKHTTP란?

Okhttp는 REST API, HTTP 통신을 간편하게 구현할 수 있도록 다양한 기능을 제공해주는 java 라이브러리다.

“Square"라는 회사가 만든 OkHttp 라이브러리는 Retrofit(서버와 클라이언트 간 http 통신을 위한) 라이브러리의 베이스가 된다. OkHttp를 이용하면 간편하게 몇 줄의 코딩으로 REST 호출을 전송, HTTP 기반의 요청, 응답을 처리할 수 있다. OkHttp는 오픈소스로 공개된 소프트웨어이며, 깃허브에 가면 소스코드를 볼 수 있다. (링크 : OkHttp 깃허브 리파지토리)

Retrofit은 가능한 경우 OkHTTP를 자동으로 사용합니다. Volley를 OkHTTP에 연결하는 Jake Wharton 의 Gist가 있습니다.

2-2. OKHTTP 사용

Android OKHTTP SSL Pinning 적용하기 (certificate pinning)

 

2-3. 우회 시도 - (1) 스크립트 사용

 

Java.perform(function () {
console.log('')
console.log('===')
console.log('* Injecting hooks into common certificate pinning methods *')
console.log('===')

var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var SSLContext = Java.use('javax.net.ssl.SSLContext');

// build fake trust manager
var TrustManager = Java.registerClass({
    name: 'com.sensepost.test.TrustManager',
    implements: [X509TrustManager],
    methods: {
        checkClientTrusted: function (chain, authType) {
        },
        checkServerTrusted: function (chain, authType) {
        },
        getAcceptedIssuers: function () {
            return [];
        }
    }
});

// 요청시 custom trust manager 전달
var TrustManagers = [TrustManager.$new()];
var SSLContext_init = SSLContext.init.overload(
    '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'
);
SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {
    console.log('! Intercepted trustmanager request');
    SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
};

console.log('* Setup custom trust manager');

// okhttp3
try {
    var CertificatePinner = Java.use('okhttp3.CertificatePinner');
    CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function (str) {
        console.log('! Intercepted okhttp3: ' + str);
        return;
    };

    console.log('* Setup okhttp3 pinning')
} catch(err) {
    console.log('* Unable to hook into okhttp3 pinner')
}

// trustkit
try {
    var Activity = Java.use("com.datatheorem.android.trustkit.pinning.OkHostnameVerifier");
    Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (str) {
        console.log('! Intercepted trustkit{1}: ' + str);
        return true;
    };

    Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (str) {
        console.log('! Intercepted trustkit{2}: ' + str);
        return true;
    };

    console.log('* Setup trustkit pinning')
} catch(err) {
    console.log('* Unable to hook into trustkit pinner')
}

// TrustManagerImpl
try {
    var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
    TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
        console.log('! Intercepted TrustManagerImp: ' + host);
        return untrustedChain;
    }

    console.log('* Setup TrustManagerImpl pinning')
} catch (err) {
    console.log('* Unable to hook into TrustManagerImpl')
}

// Appcelerator
try {
    var PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
    PinningTrustManager.checkServerTrusted.implementation = function () {
        console.log('! Intercepted Appcelerator');
    }

    console.log('* Setup Appcelerator pinning')
} catch (err) {
    console.log('* Unable to hook into Appcelerator pinning')
}
});

 

(2) objection 사용

pip3 install objection

 

 

objection --gadget "tech.httptoolkit.pinning_demo" explore

android sslpinning disable

 

 

\object 설명

GitHub - sensepost/objection: 📱 objection - runtime mobile exploration

Objection

[Android/ios 공통] 오브젝션(Objection) 프리다(Frida)를 활용한 앱 분석 도구

2-4. Bypass 과정

 

사용자 코드에 SSL pinning 적용 부분이 CertificatePinner$check$1 함수에서 쉽게 노출되기 때문에 앱 코드를 분석할 필요 없이 후킹으로 아주 쉽게 우회할 수 있다. xposed나 frida등의 후킹 프레임워크로 okhttp3.certificatePinner 클래스의 check()함수를 후킹하면 된다.

 

모바일 app에서 인증서 고정을 Bypsss하려면 Frida 또는 Xposed와 같은 계측 프레임워크를 사용하거나 원본 APK를 다운로드하고 네트워크 보안 구성 파일을 수정하여 사용자가 제공한 인증서를 신뢰하고 인증서를 비 활성화할 수 있습니다. 고정. 이 수정 후에는 MitM 공격으로 트래픽을 다시 가로챌 수 있습니다. 이런 Bypsss에 대한 예시는 원본이며 원본 API 서버를 사용하지만 생성된 수익이 app 작성자가 아닌 공격자에게 가는 광고를 표시하는 리패키지된 app입니다. 보다 정교한 예는 인앱 구매에 대한 지불을 공격자의 은행 계좌로 리디렉션하는 재 포장된 app입니다.

 

 

/* 
 *  Description: OkHttp3 various SSL Pinning bypasses, including versions 4.2+.
 *  Authors: 	 @apps3c and @pcipolloni
 */

setTimeout(function() {

    Java.perform(function () {

		var okhttp3_CertificatePinner_class = null;
		try {
            okhttp3_CertificatePinner_class = Java.use('okhttp3.CertificatePinner');    
        } catch (err) {
            console.log('[-] OkHTTPv3 CertificatePinner class not found. Skipping.');
            okhttp3_CertificatePinner_class = null;
        }

        if(okhttp3_CertificatePinner_class != null) {

	        try{
	            okhttp3_CertificatePinner_class.check.overload('java.lang.String', 'java.util.List').implementation = function (str,list) {
	                console.log('[+] Bypassing OkHTTPv3 1: ' + str);
	                return true;
	            };
	            console.log('[+] Loaded OkHTTPv3 hook 1');
	        } catch(err) {
	        	console.log('[-] Skipping OkHTTPv3 hook 1');
	        }

	        try{
	            okhttp3_CertificatePinner_class.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (str,cert) {
	                console.log('[+] Bypassing OkHTTPv3 2: ' + str);
	                return true;
	            };
	            console.log('[+] Loaded OkHTTPv3 hook 2');
	        } catch(err) {
	        	console.log('[-] Skipping OkHTTPv3 hook 2');
	        }

	        try {
	            okhttp3_CertificatePinner_class.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function (str,cert_array) {
	                console.log('[+] Bypassing OkHTTPv3 3: ' + str);
	                return true;
	            };
	            console.log('[+] Loaded OkHTTPv3 hook 3');
	        } catch(err) {
	        	console.log('[-] Skipping OkHTTPv3 hook 3');
	        }

	        try {
	            okhttp3_CertificatePinner_class['check$okhttp'].implementation = function (str,obj) {
		            console.log('[+] Bypassing OkHTTPv3 4 (4.2+): ' + str);
		        };
		        console.log('[+] Loaded OkHTTPv3 hook 4 (4.2+)');
		    } catch(err) {
	        	console.log('[-] Skipping OkHTTPv3 hook 4 (4.2+)');
	        }

		}

	});
    
}, 0);

 

 

2-5. 안되던 원인

OkHttp3 버전이나 함수에 따라 적용되는 스크립트가 다르다. Demo app에 Bypassing OkHTTPv3 4 (4.2+)가 사용되고 있었기 때문에

해당 pinning 적용 부분을 보고 해당 형식과 같은 스크립트를 사용해줘야 한다.

okhttp3_CertificatePinner_class['check$okhttp'].implementation = function (str,obj) {

console.log('[+] Bypassing OkHTTPv3 4 (4.2+): ' + str);

};

 

-