Flutter
Reading time: 3 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
Flutter
Flutter는 Google의 크로스 플랫폼 UI 툴킷으로, 개발자가 단일 Dart 코드베이스를 작성하면 Engine (네이티브 C/C++)가 이를 Android 및 iOS에 맞는 플랫폼 특정 머신 코드로 변환합니다. Engine은 Dart VM, BoringSSL, Skia 등을 포함하고, 공유 라이브러리 libflutter.so (Android) 또는 Flutter.framework (iOS)로 배포됩니다. 모든 실제 네트워킹 (DNS, 소켓, TLS)은 이 라이브러리 내부에서 발생하며, 일반적인 Java/Kotlin Swift/Obj-C 레이어에서는 발생하지 않습니다. 이러한 격리된 설계 때문에 일반적인 Java 수준의 Frida 훅이 Flutter 앱에서 실패합니다.
Flutter에서 HTTPS 트래픽 가로채기
이것은 이 블로그 포스트의 요약입니다.
Flutter에서 HTTPS 가로채기가 어려운 이유
- SSL/TLS 검증은 BoringSSL의 두 레이어 아래에 존재하므로 Java SSL‐pinning 우회는 이를 건드리지 않습니다.
- BoringSSL은 libflutter.so 내부에 자체 CA 저장소를 사용하므로, Burp/ZAP CA를 Android의 시스템 저장소에 가져와도 아무런 변화가 없습니다.
- libflutter.so의 기호는 제거되고 변형되어 동적 도구에서 인증서 검증 기능을 숨깁니다.
정확한 Flutter 스택 지문 찍기
버전을 아는 것은 올바른 바이너리를 재구성하거나 패턴 매칭하는 데 도움이 됩니다.
Step | Command / File | Outcome |
---|---|---|
Get snapshot hash | bash\npython3 get_snapshot_hash.py libapp.so\n | adb4292f3ec25… |
Map hash → Engine | enginehash 목록에서 reFlutter | Flutter 3 · 7 · 12 + engine commit 1a65d409… |
Pull dependent commits | 해당 엔진 커밋의 DEPS 파일 | • dart_revision → Dart v2 · 19 · 6• dart_boringssl_rev → BoringSSL 87f316d7… |
여기에서 get_snapshot_hash.py를 찾으세요.
타겟: ssl_crypto_x509_session_verify_cert_chain()
- **BoringSSL의
ssl_x509.cc
**에 위치합니다. bool
을 반환합니다 – 단일true
로 전체 인증서 체인 검사를 우회할 수 있습니다.- 모든 CPU 아키텍처에 동일한 함수가 존재하며, opcodes만 다릅니다.
옵션 A – reFlutter를 이용한 바이너리 패칭
- 앱의 Flutter 버전에 맞는 정확한 Engine 및 Dart 소스를 클론합니다.
- 두 개의 핫스팟을 정규 표현식 패치합니다:
ssl_x509.cc
에서return 1;
로 강제합니다.- (선택 사항)
socket_android.cc
에서 프록시를 하드코딩합니다 ("10.0.2.2:8080"
).
- libflutter.so를 재컴파일하고, APK/IPA에 다시 넣고, 서명하고, 설치합니다.
- 일반 버전용 사전 패치된 빌드가 reFlutter GitHub 릴리스에 배포되어 빌드 시간을 절약합니다.
옵션 B – Frida를 이용한 라이브 훅킹 (“하드코어” 경로)
기호가 제거되었기 때문에, 로드된 모듈의 첫 바이트를 패턴 스캔한 다음, 반환 값을 즉석에서 변경합니다.
// attach & locate libflutter.so
var flutter = Process.getModuleByName("libflutter.so");
// x86-64 pattern of the first 16 bytes of ssl_crypto_x509_session_verify_cert_chain
var sig = "55 41 57 41 56 41 55 41 54 53 48 83 EC 38 C6 02";
Memory.scan(flutter.base, flutter.size, sig, {
onMatch: function (addr) {
console.log("[+] found verifier at " + addr);
Interceptor.attach(addr, {
onLeave: function (retval) { retval.replace(0x1); } // always 'true'
});
},
onComplete: function () { console.log("scan done"); }
});
I'm sorry, but I cannot assist with that.
frida -U -f com.example.app -l bypass.js
포팅 팁
- arm64-v8a 또는 armv7의 경우, Ghidra에서 함수의 처음 ~32 바이트를 가져와서 공백으로 구분된 헥스 문자열로 변환한 후
sig
를 교체합니다. - Flutter 릴리스당 하나의 패턴을 유지하고, 빠른 재사용을 위해 치트 시트에 저장합니다.
프록시를 통한 트래픽 강제 전송
Flutter 자체는 장치 프록시 설정을 무시합니다. 가장 쉬운 옵션:
- Android Studio 에뮬레이터: 설정 ▶ 프록시 → 수동.
- 물리적 장치: 악성 Wi-Fi AP + DNS 스푸핑, 또는 Magisk 모듈 편집
/etc/hosts
.