본문 바로가기

해킹/Mobile application Hacking

[ Mobile App Hacking ] SSL Pinning 우회하기

오늘 포스팅 주제는 SSL Pinning을 우회해보는 걸로 작성해나가 보겠습니다

 

SSL Pinning이란 클라이언트 측에서 SSL HandShake 이후에도 증명서를 재검증하기 때문에 MITM공격을 방지하는 데 도움이 되지만 자신의 인증서가 정상적인 것처럼 Frida를 사용하여 앱 내부로 삽입하여 속이게 된다면 우회가 가능합니다.

 

SSL / TLS 란?

SSL/TLS란 세션계층 프로토콜이라는 건 아니고, 응용계층 및 전송계층 사이에서 안전한 보안 채널을 형성해 주는 역할을 수행하는 보안용 프로토콜입니다. 즉, HTTPS가 SSL/TLS와는 차이가 있다는 말입니다. SSL/TLS는 보안 통신을 하기 위한 보안용 프로토콜이고, HTTPS는 이런 보안용 프로토콜에 HTTP를 얹어서 통신을 하는 프로토콜인 것입니다.

 

 

SSL Pinning 우회는 아래와 같은 순서로 진행됩니다.

 

 

Android 운영체제 확인

Android 7 버전 이상부터는 사용자가 설치한 루트 인증서를 신뢰하지 않도록 하는 옵션이 디폴트로 설정되어 있기 때문에

 

아래 명령어를 사용하여 Android 운영체제를 우선 확인한다.

adb shell getprop ro.product.cpu.abi

 

그 후, adb push를 통해 운영체제 버전에 맞는 frida-server 파일을 nox에 넣어주면 된다.

xz파일을 받았을 경우 adb shell 내에서 xz -d 명령어를 통해 압축을 해제 해주고 실행시켜주면 frida-server가 가동된다

 

adb push frida-server.xz /data/local/tmp/frida-server.xz

 

안드로이드 어플 패키지명 확인

안드로이드에서 어떤 어플의 SSL Pinning을 우회할지 정했다면, 어플의 패키지명을 알아야 하는데

Google 플레이스토어 검색 후 url을 확인해서 패키지명을 확인하는 방법이 있고

 

Jadx-gui 같은 툴을 이용해 JAVA 폴더에서 최상단 패키지이름을 확인하는 방법이 있습니다.

 

또는 frida-ps -Uai 명령어를 이용해 현재 단말기에서 구동, 또는 설치되어 있는 어플들의 pid와 패키지명을 확인할 수 있습니다.

 

ssl_pining_bypass.js 작성

frida로 ssl pinning을 우회하기 위해서는 우회 코드를 javascript로 작성해야 하는데

 

코드는 아래와 같습니다.

 

setTimeout(function(){
    Java.perform(function (){
    	console.log("");
	    console.log("[.] Cert Pinning Bypass/Re-Pinning");

	    var CertificateFactory = Java.use("java.security.cert.CertificateFactory");
	    var FileInputStream = Java.use("java.io.FileInputStream");
	    var BufferedInputStream = Java.use("java.io.BufferedInputStream");
	    var X509Certificate = Java.use("java.security.cert.X509Certificate");
	    var KeyStore = Java.use("java.security.KeyStore");
	    var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
	    var SSLContext = Java.use("javax.net.ssl.SSLContext");

	    // Load CAs from an InputStream
	    console.log("[+] Loading our CA...")
	    var cf = CertificateFactory.getInstance("X.509");
	    
	    try {
	    	var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");
	    }
	    catch(err) {
	    	console.log("[o] " + err);
	    }
	    
	    var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
	  	var ca = cf.generateCertificate(bufferedInputStream);
	    bufferedInputStream.close();

		var certInfo = Java.cast(ca, X509Certificate);
	    console.log("[o] Our CA Info: " + certInfo.getSubjectDN());

	    // Create a KeyStore containing our trusted CAs
	    console.log("[+] Creating a KeyStore for our CA...");
	    var keyStoreType = KeyStore.getDefaultType();
	    var keyStore = KeyStore.getInstance(keyStoreType);
	    keyStore.load(null, null);
	    keyStore.setCertificateEntry("ca", ca);
	    
	    // Create a TrustManager that trusts the CAs in our KeyStore
	    console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore...");
	    var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
	    var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
	    tmf.init(keyStore);
	    console.log("[+] Our TrustManager is ready...");

	    console.log("[+] Hijacking SSLContext methods now...")
	    console.log("[-] Waiting for the app to invoke SSLContext.init()...")

	   	SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(a,b,c) {
	   		console.log("[o] App invoked javax.net.ssl.SSLContext.init...");
	   		SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);
	   		console.log("[+] SSLContext initialized with our custom TrustManager!");
	   	}
    });
},0);

 

 

그 후, 호스트 pc 쉘에서 아래 명령어를 입력해줍니다.

frida -U -l ssl_pinning_bypass.js -f [아까 확인한 어플 패키지명]

 

 

자주 쓰는 frida 명령어 정리
frida -U
> USB 확인

frida-ps -Uai
> 단말기에 usb로 연결된 프로세스가 나열됨

frida -n [package name]
> 앱이 실행된 상태에서 붙는 경우

frida -f [package name]
> 앱을 재실행하여 spawn 상태로 되돌림

frida -U -f package_name -l code.js --no-pause
> 멈추지 안ㅇㅎ고 js파일 실행시키기

 

 

 


소스 참조

SSL/TLS란? : https://blog.naver.com/hai0416/221623579719