안녕하세요. 파인더갭의 "shiro"입니다.
원래는 Frida 기능에대한 연재를 해볼까했는대 저희가 근래 버그바운티 프로그램이 늘면서 Flutter 환경이 낯선 분들이 있는거 같아서 Flutter Proxy설정에 관해 글을 작성해볼까 합니다.
일단 백그라운드 지식으로는
Flutter는 구글에서 개발한 Dart라는 언어를 사용하며 multi-platform 을 지원하는 native 앱 개발 프레임워크로 평소에 분석하던 Java로 개발된 앱과는 다르단 걸 인지하셔야 합니다.
내부에서 동작하는 SSL에 관련된 모듈 또한 구글에서 개발한 boringssl 라이브러리를 사용하고 있는 것도 참고 부탁드리며 코드가 공개되어 있으니 아래 링크로 들어가 분석해 보시는 것도 도움이 되실 겁니다.
참고 : https://github.com/google/boringssl/blob/master

위 구성을 보면 알 수 있듯 Dart는 UI를 구현하는데 사용되며 추가적인 http 요청 및 SharedPreference와 같은 부분은 Flutter Engine(C/C++)에서 가져다 사용합니다. 이러한 구조 때문에 Flutter는 아무리 버프 인증서를 시스템 저장소에 마운트 했더라고 통신이 안되는 경우가 다수 존재합니다.
TL;DR Flutter는 시스템 CA 저장소를 사용하지 않는 Dart로 앱이 개발되며 앱에 컴파일된 CA list를 사용. Android 프록시 설정을 인식하지 못하므로 트랙픽을 컨트롤할 다른 방법을 강구해야함 인증서의 체인 검증이 동작하는 경우 이를 우회하는 방안 필요(Ex. 후킹, 패치 등)
그럼 해결과제도 정해졌으니 구성해 보겠습니다.
1번의 “Flutter는 시스템 CA 저장소를 사용하지 않는 Dart로 앱이 개발되며 앱에 컴파일된 CA list를 사용. Android 프록시 설정을 인식하지 못하므로 트랙픽을 컨트롤할 다른 방법을 강구해야함”
은 의외로 간단합니다. iptables와 VPN등 어렵게 환경을 구성할 수도 있지만 Android는 무료로 트래픽을 컨트롤해줄 ProxyDroid와 같은 앱들이 상당히 많이 존재합니다. 쓰시는 앱이 있으시면 해당 앱으로 진행하시면 되고 저는 ProxyDroid로 진행하겠습니다.
간단히 사용법에 대해 알아보죠.
앱을 처음 구동 시 화면 on/off 설정은 바로 보이고 Host/Port에 프록시가 구동되어 있는 디바이스의 주소를 넣어주면 됩니다.
다음은 타겟 앱 설정으로 글로벌 설정은 해당하는 디바이스의 모든 트래픽을 컨트롤하는 기능입니다.
Individual 기능은 개별 설정으로 그림과 같이 앱을 체크하여 해당 앱의 트래픽만 컨트롤할 수 있는 기능입니다.
2번의 “인증서의 체인 검증이 동작하는 경우 이를 우회하는 방안 필요(Ex. 후킹, 패치 등)”에서 Frida를 이용한 후킹 통한 방법 사용할 겁니다.
일단 분석에 앞서 코드가 공개된 라이브러리이기 때문에 소스를 직접 볼 수 있다는 강한 이점을 살려보도록 하겠습니다.
flutter 앱을 컴파일하면 안드로이드 기준으로 libflutter.so라는 파일이 생기며 내부에서 ssl 기능을 사용하기 위해 boringssl를 사용하고 있습니다.
boringssl 라이브러리에서 우리가 주목해야할 함수는 “ssl_crypto_x509_session_verify_cert_chain”이라는 함수입니다. 해당 함수에서 인증서 체인을 검증하는 것을 알수 있으며 감사하게도 bool형을 뱉어주며 또한 분석가가 잘 찾을 수 있도록 “ssl_client”, “ssl_server” 등과 같은 문자열도 함수 내부에 포함해 주고 있습니다.
참고 : https://github.com/google/boringssl/blob/master/ssl/ssl\_x509.cc
그럼 libflutter.so를 추출하고 정적 도구로 보면 심볼이 당연 없으니 우리는 “ssl_crypto_x509_session_verify_cert_chain” 함수를 찾아 갈 수 없지만 우리에게는 “ssl_client”, “ssl_server” 문자열이 있으니 문자열을 역추적해보죠.
해당 문자열을 역추적하면 아래와 같이 함수의 offset를 구할 수 있습니다.
함수의 offset과 변조 포인트, 리턴 유형도 우리는 알고 있으니 빠르게 후킹 코드를 작성해죠.
위와 같은 Frida 코드를 만들 수 있으며 함수 offset 위치에 올바른 offset를 넣은 뒤 스크립트를 동작 시키면 됩니다. 이렇게 두 가지 구성을 하면 프록시 도구에 잡히지 않았던 패킷이 보일 겁니다.
긴 글 읽어주셔서 감사합니다! 그럼 다음 글에서 뵙겠습니다.
