naroSEC
article thumbnail

들어가기 앞서

 

안드로이드 피닝(Pinning) 개요 및 Root CA 검증 우회 방법

들어가기 앞서 라이브러리 모듈 검사를 통한 Frida 탐지 방안과 우회 기법 들어가기 앞서 통신 포트 검사를 통한 Frida 탐지 방안과 우회 기법 들어가기 앞서 Frida 실행 시 생성되는 파일 검사를 통

naro-security.tistory.com

이전 "안드로이드 피닝(Pinning) 개요 및Root CA 검증 우회 방법"에 이어서 이번 포스팅에서는 피닝(Pinning 이하 피닝) 기법 중에서도 모바일 앱에 인증서를 사전 등록하는 방식인 고정 피닝 기법에 대해서 다뤄보도록 하겠다.

 

 ※ 실습 진행에 사용되는 ANDITER 앱은 아래의 GitHub에서 다운로드 가능하다.

 

GitHub - naroSEC/Anditer

Contribute to naroSEC/Anditer development by creating an account on GitHub.

github.com


개요

[그림 1] 고정 인증서 검증 프로세스

이번 포스팅에서 살펴볼 피닝 기법은 고정 인증서 검증 방식으로 애플리케이션에서 허용하는 인증서 외의 인증서를 서버가 반환하는 경우 통신을 하지 못하도록 하는 방법이다. 앞서 살펴본 Root CA에 의한 인증서 신뢰 기반의 피닝 기법이 중간자 공격을 막기 위한 가장 기초적인 방어 방법이었다면 고정 인증서 방식은 조금 더 높은 보안을 요구하는 플랫폼에서 사용되는 방법이다.

고정 인증서란 디바이스에 임의의 인증서를 설치해 서버와 통신 하는 방식이 아닌 애플리케이션의 자바 코드 내에서 특정 호스트와 통신할 때 지정한 인증서의 해시 값과 서버 인증서의 해시 값을 비교해 동일한 해시 값일 경우 통신을 허용하는 방식이다. 인증서 지정 방법으로는 가장 기본적인 하드 코딩 방식부터 공격자에 의한 변조 방지를 위한 리소스 다운로드, 동적 로딩 기법 등을 통해 지정하는 방법이 있다.

[그림 2] Bypass Pinning(Allow CA) 탐지

Bypass Pinning(Allow CA) 탐지 항목은 통신을 시도하는 서버의 인증서 해시 값이 애플리케이션의 자바 코드에서 지정한 인증서 해시 값과 다를 경우 중간자 공격을 시도 중인 것으로 판단해 탐지하게 된다.


분석

[그림 3]  isCheckAllowCA() 함수의 소스코드

[그림 3]isCheckAllowCA() 함수는 Bypass Pinning(Allow CA) 탐지 결과를 반환해주는 역할을 한다. 코드를 보면  ①에서 OkHttp.certificatePinner 클래스 객체를 생성할 때 호스트 이름과 서버의 인증서 해시 값을 인자로 넘겨주고 있으며 해당 해시 값이 서버와 통신 시 인증서 비교에 사용되는 값이다. 따라서, 서버가 반환하는 인증서의 해시 값을 "sha256/+hIxKEB6NLsH9zGi9fx81iY3nbFfuipoNjz1liPufEI=“와 비교해 다를 경우 통신을 하지 못하게 한다. ② ①에서 생성한 객체를 코루틴 인자로 넘겨줘서 서버와 실질적인 통신 작업을 수행한다.

[그림 4] invokeSuspend() 함수

[그림 4]는 "안드로이드 피닝(Pinning) 개요 및Root CA 검증 우회 방법" [그림 15]에서 살펴본 함수와 동일한 기능을 수행하는 코루틴의 suspend() 함수이다. ① [그림 4]isCheckAllowCA() 함수에서 생성한 OkHttp.certificatePinner 클래스 객체를 통해 통신을 수행하게 되며 ② 통신 성공 시 onResponse() 함수가 동작되며 ③ 통신 실패 시 onFailure() 함수가 실행된다.

[그림 5]  okhttp3.CertificatePinner 클래스의 check$okhttp() 함수 소스코드

[그림 5]check$okhttp() 함수는 클라이언트와 서버가 SSL/TLS HandShake를 진행할 때 인증서의 유효성 검사 시 사용되는 함수이다. ① 함수 내에서 사용되는 findMatchingPins() 함수의 경우 호스트 이름과 매핑되는 인증서의 핀 리스트를 반환하는 역할을 수행하는데 호스트 이름과 일치하는 고정된 인증서가 존재하지 않을 경우 빈 리스트를 반환하게 된다. ② ①에서 반환 받은 리스트가 빈 리스트라면 check$okhttp() 함수는 인증서에 대한 유효성 검사를 수행하지 않고 null 값을 반환하게 되며 이는 고정 인증서 핀을 우회하고 어떤 인증서든 사용할 수 있게 허용하게 된다.

Bypass Pinning(Allow CA) 탐지를 우회하기 위한 후킹 포인트는 두 가지가 있다. 첫 번째는 인증서의 유효성 검사를 수행하지 않게 항상 null 값을 반환하도록 check$okhttp() 함수를 재 작성하는 방법이고 두 번째는 호스트 이름에 매핑되는 인증서를 찾을 때 사용하는 findMatchingPins() 함수의 결과 값을 매핑되는 인증서가 없을 때와 동일하게 항상 빈 리스트를 반환하도록 변조하는 방법이다. 여기서는 첫 번째 방법을 사용해 우회해 보도록 하겠다.


우회 실습

[그림 6]  check$okhttp() 함수를 후킹하기 위한 Frida 스크립트

[그림 6]check$okhttp() 함수를 후킹하기 위해 필자가 작성한 Frida 스크립트이다. 코드를 보면 에서 check$okhttp() 함수 사용을 위해 okhttp3.CertificatePinner 클래스 객체를 생성하고 인증서 유효성 검사를 위해 check$okhttp() 함수 호출 시 전달되는 인자의 데이터 타입에 맞춰 check$okhttp() 함수를 오버로딩으로 구현했다. ② 해당 함수가 호출되면 인증서 유효성 검사를 수행하지 않도록 null 값을 반환한다. 자바 스크립트에서 null 값을 반환할 때는 return 키워드만 명시하면 된다.

[그림 7]  Bypass Pinning(Allow CA) 탐지 우회 성공

Frida를 통해 작성한 스크립트를 ADITER 애플리케이션에 어태치 한다. 그 후 프록시가 연결된 상태에서 Bypass Module 탐지 항목을 체크하면 Success! 가 출력되며 탐지가 우회된 것을 볼 수 있다.


마무리

지금까지 클라이언트 단(모바일 앱)에 인증서를 사전 등록함으로써, 서버에서 반환하는 인증서가 클라이언트에 등록된 인증서의 해시 값과 다를 경우 통신을 하지 못하도록 막는 고징 인증서 방식의 피닝 기법을 살펴봤다. 다음 포스팅에서는 Frida와 같은 후킹 도구가 아닌 모바일 디바이스에 인증서를 직접 설치하여 피닝(Root CA 검증)을 우회하는 방안에 대해서 다뤄보도록 하겠다.

profile

naroSEC

@naroSEC

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...