TL;DR
Lý do mình viết bài này là do mình đã viết blog về cách bypass SSL Pinning cho Flutter application trên hệ điều hành Android, nên đã lỡ viết bypass cho Android thì viết nốt iOS cho có đôi có cặp, hehe :v
- Giới thiệu
Mình xin nhắc lại mấy ý trong bài viết trước như sau:
Phần lớn các mobile app hiện nay dùng các framework như Flutter hoặc React Native, có thể vừa buid android và iOS applications với cùng một codebase. Đặc biệt là thằng Flutter này không tuân theo cấu hình proxy của thiết bị được cài đặt bởi pentester mà sẽ sử dụng certificate của lập trình viên cài đặt. Do đó, không thể bắt được request theo cách thông thường được.
Thông tin thêm cho bạn nào tìm hiểu về thư viện BoringSSL mà Flutter apps sử dụng để áp dụng cho TLS connection.
Dưới đây, là hai cách mình dùng để bypass SSL Pinning cho nền tảng iOS.
- Sử dụng reFlutter
Hiện nay có tool reFlutter cho phép bypass SSL Pinning và ý tưởng của tool này khá đơn giản như sau: vì Flutter app thường sử dụng binary (libflutter.so bao gồm các Flutter engine) đã được complied (ahead-of-time – AOT), vậy nên tool này chỉ cần sử dụng bản patch của Flutter library đã được complied sẵn, sau đó re-packing app là ok. Nhưng sẽ có vấn đề xãy ra là nếu version Dart khác nhau sẽ không thể hoạt động được.
Cài đặt
# Linux, Windows, MacOS
pip3 install reflutter==0.7.2
Cách sử dụng
reflutter your_app.ipa
Cài đặt IPA file sau khi thực hiện reFlutter ở trên với 3uTools hoặc appinst với command appinst your_app.ipa (thiết bị đã jailbreak)
Tiếp theo, cần cấu hình trên Burp Suite theo đúng hướng dẫn của reFlutter framework như hình phía trên nhé
Chuyển qua Request Handling Tab
- Sử dụng OpenVPN Server bắt http request
Qua đọc blog của các tiền nhân thì có nhiều cách để bypass SSL Pinning, trong đó có 2 cách thông dụng nhất là:
-
- Sử dụng WIFI adapter và iptable command để chuyển hướng tất cả request đến Burp Suite
- Sử dụng OpenVPN server.
Đối với bản thân thì cảm thấy rằng sử dụng OpenVPN server là cách thuận tiện nhất vì không phải lúc nào cũng có WIFI adapter sẵn ngay cạnh, nên bài viết này sẽ chỉ trình bày cách thứ 2 thôi (Sử dụng OpenVPN server). Bạn nào muốn tìm hiểu thêm thì đọc blog ở đây nhé
Sử dụng script này để thực hiện cài đặt cho OpenVPN server trên Kali (dùng Kali cho tiện).
Để cài đặt được trên Kali thì phải xóa câu lệnh exit trong phần kiểm tra Debian version.
wget https://git.io/vpn -O openvpn-install.sh
sed -i “$(($(grep -ni “debian is too old” openvpn-install.sh | cut -d : -f 1)+1))d” ./openvpn-install.sh
chmod +x openvpn-install.sh
sudo ./openvpn-install.sh
(Nếu các command ở trên không hoạt động thì thực hiện thủ công nhé.)
Sau khi thực hiện command trên, việc cài đặt sẽ được thực hiện và chúng ta chỉ cần cấu hình lại cho phù hợp nha
This server is behind NAT. What is the public IPv4 address or hostname?
Public IPv4 address / hostname [14.177.136.222]: 192.168.1.22
Which protocol should OpenVPN use?
1) UDP (recommended)
2) TCP
Protocol [1]: 1
What port should OpenVPN listen to?
Port [1194]: 1194
Select a DNS server for the clients:
1) Current system resolvers
2) Google
3) 1.1.1.1
4) OpenDNS
5) Quad9
6) AdGuard
DNS server [1]: 3
Enter a name for the first client:
Name [client]: pentest
Script trên sẽ cài đặt, cấu hình mọi thứ cần thiết. Giờ bạn thực hiện command ifconfig bạn sẽ thấy tun0 interface đã được cấu hình
Thực hiện cấu hình iptable để bắt traffic từ OpenVPN interface đến eth0 interface
sudo iptables -t nat -A PREROUTING -i tun0 -p tcp –dport 80 -j REDIRECT –to-port 8080
sudo iptables -t nat -A PREROUTING -i tun0 -p tcp –dport 443 -j REDIRECT –to-port 8080
sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
Thực hiện tải file cấu hình VPN về thiết bị iOS bằng cách sau
Trên máy kali tạo python server port 80
python3 -m http.server 80
Trên thiết bị iOS truy cập với địa chỉ và port tương ứng: http://192.168.1.22:80, thực hiện download file pentest.ovpn
Khởi động OpenVPN service
sudo service openvpn start
hoặc
sudo systemctl status openvpn
Tiếp theo, cài đặt OpenVPN client ở iphone
Cài đặt file cấu hình
Cuối cùng, bật Burp Suite lắng nghe port 8080 (trên máy Kali nha)
Lúc này bạn sẽ bắt được tất cả các http request từ Flutter app, đôi khi các ứng dụng sử dụng https thì sao?? làm tiếp theo các bước phía dưới chứ sao …
- Bắt HTTPS request
Giờ bạn đã thực hiện Man-in-the-middle với http request, phần này sẽ tiếp tục thực hiện với HTTPS request.
Như đã nói Flutter app sử dụng thư viện BoringSSL để áp dụng cho TLS connection mà không sử dụng bất kỳ thư viện mặc định của iOS nên SSLKillSwitch không dùng được trong trường hợp này. Để thực hiện được mục đích là bắt HTTPS request, chúng ta cần thực hiện:
-
- Lấy được Flutter binary
- Import vào Ghidra
- Tìm đúng method để hook bằng Frida
Đầu tiên, bạn phải lấy được file Flutter framework file từ thiết bị, mà điều này phụ thuộc vào cách ứng dụng được cài đặt (SSH vào thiết bị iOS để thực hiện các command)
Nếu ứng dụng được cài từ ipa file: (nhớ cài đặt ipa installer trong cydia nhé)
ipainstaller -b <package_name>
Nếu ứng dụng được cài đặt từ App Store thì dùng Clutch:
Clutch -d <package_name>
Sau bước trên lấy được ipa file từ thiết bị iOS, và nằm ở đường dẫn sau: /private/var/mobile/Documents/flutter_app (be.nviso.flutterApp) v1.0.0.ipa
Tiếp tục thực hiện các command sau:
# Unzip the ipa file
unzip flutter_app.ipa
# Find the Flutter binary
file Payload/Runner.app/Frameworks/Flutter.framework/Flutter
Thực hiện các command sau để tìm kiến trúc của thiết bị (nhớ cài đặt Darwin CC Tools trong cydia nhé)
lipo -thin arm64 Flutter -output FlutterThin
file FlutterThin
Sau khi có được thư viện của ứng dụng, tiếp tục bước tiếp theo là import vào Ghidra và tìm chuỗi bytes đầu bắt đầu của hàm session_verify_cert_chain mà trong blog trước mình đã nhắc đến (chưa đọc thì đọc ủng hộ luôn nhé :v)
Mục đích của việc tìm chuỗi bytes này là dùng Frida hook vào hàm session_verify_cert_chain và chỉnh sửa giá trị theo ý muốn.
Import file FlutterThin vào Ghidra (Import này lâu vãi chưởng, tranh thủ thời gian này đi pha cốc cafe uống cho tỉnh táo :v), đợi quá trình import xong thì click Search -> For Strings… tìm ssl_x509.cc sẽ nhận được kết quả như hình bên dưới
Double click vào XREF[9] sẽ hiển thị như hình dưới
Lúc này phải duyệt qua tất cả các Xrefs để tìm được function có 3 arguments và return 0
Như hình dưới thì FUN_004068C8 chính là hàm mà chúng ta đang tìm kiếm
Chuối bytes đầu tiên của hàm FUN_004068C8 là
ff 03 05 d1 fc 6f 0f a9 f8 5f 10 a9 f6 57 11 a9 f4 4f 12 a9 fd 7b 13 a9
Có thể sử dụng tool binwalk để xác định được chính xác offset
Đến đây thì rồi thì dùng Frida script để bypass SSL Pinning thôi (đoạn code dưới được tham khảo ở (1))
function
hook_ssl_verify_result(address)
{
Interceptor.attach(address, {
onEnter:
function
(args) {
console.log(
"Disabling SSL validation"
)
},
onLeave:
function
(retval)
{
retval.replace(0x1);
}
});
}
function
disablePinning()
{
var
pattern =
"Inject here"
Process.enumerateRangesSync(
'r-x'
).filter(
function
(m)
{
if
(m.file)
return
m.file.path.indexOf(
'Flutter'
) > -1;
return
false
;
}).forEach(
function
(r)
{
Memory.scanSync(r.base, r.size, pattern).forEach(
function
(match) {
console.log(
'[+] ssl_verify_result found at: '
+ match.address.toString());
hook_ssl_verify_result(match.address);
});
});
}
setTimeout(disablePinning, 1000)
- Tham khảo
- https://blog.nviso.eu/2020/06/12/intercepting-flutter-traffic-on-ios/ (1)
- https://sec.vnpt.vn/2022/04/frida-hooking-va-bypass-ssl-pinning-cho-flutter-aplication/ (2)
ndtoan