+14

Bypass SSL Pinning Twilio Chat

Giới thiệu

Gần đây thì mình vọc vạch thử 1 số ứng dụng di động xem thị trường đang dùng các công nghệ, hay kỹ thuật gì mới không. Thì có 1 vị huynh đệ đã gửi cho mình 1 con ứng dụng Android. Theo như lời giới thiệu của vị huynh đệ này thì ứng dụng không có SSL Pinning, dùng Burp Suite test bét nhè chè đỗ đen.

Nhưng trong ứng dụng có chức năng chat giữa các người dùng thì lại không thấy request nào xuất hiện trong Burp. Sẵn đang rảnh, mình lập tức cài ứng dụng và bắt tay vào nghiên cứu.

Vì sao không bắt được request chat?

image.png

Dựa trên kinh nghiệm tích lũy được không hề nhiều sau thời gian dài pentest mobile app, mình đoán được 2 khả năng có thể xảy ra:

  • Giả thiết 1: Phần chat không dùng giao thức HTTP, nên Burp không bắt được request.
  • Giả thiết 2: Ứng dụng sử dụng dịch vụ của bên thứ 3. Dịch vụ này thì có SSL Pinning riêng.

Nếu rơi vào giả thiết 1 thì thôi, bỏ bỏ bỏ. Nên mình tìm hiểu luôn theo hướng giả thiết thứ 2. Thực ra cá nhân mình thấy giả thiết thứ 2 khả năng xảy ra cao hơn, vì nếu lập trình viên triển khai SSL Pinning cho ứng dụng thì sao không phải làm cho cả ứng dụng luôn, mà chỉ làm 1 phần, làm 1 chức năng. Nghe nó không logic, cùng một công thực hiện cả.

Còn chức năng lẻ tẻ có SSL Pinning vì bản thân thư viện đã có, lập trình viên chỉ cần lắp ghép vào, nhiều khi họ còn không biết thư viện đó có SSL Pinning nữa kìa.

Tìm kiếm lib

Để củng cố suy đoán thì mình sẽ decompile tệp tin apk ra bằng công cụ apktool:

java -jar apktool.jar d redacted.apk

image.png

Decompile xong thì tìm kiếm trong thư mục lib, các thư viện của bên thứ 3 được lắp ghép vào thường sẽ nằm ở đây. Dựa vào kỹ năng Guessing luyện tập qua quá trình chơi CTF, thì xác định được cái thư viện thực hiện tính năng chat chính là Twilio (đống còn lại liếc qua toàn pdf với png chắc không liên quan đâu).

image.png

Twillio là gì

image.png

Giới thiệu cho bạn đọc về Twilio như sau:

image.png

Nghe có vẻ liên quan đến chat chit rồi đấy, sờ đúng mạch rồi.

Bypass SSL Pinning

Ok giờ thì bắt đầu tìm cách bypass SSL Pinning thôi. Mình sẽ thử dần từng phương pháp.

Phương pháp 1: hook bằng Frida

Mình quyết định thử phương án phổ biến và đơn giản nhất này trước. Để có thể hook được thì cần tìm ra hàm thực hiện SSL Pinning.

Vì không biết nhiều về dịch ngược, mình chỉ có thể sử dụng các biện pháp thô sơ để tìm kiếm. Đầu tiên sẽ sử dụng lệnh nm để liệt kê ra các hàm có trong thư viện của Twilio.

 nm --demangle --dynamic libtwilio-convo-native.so

Danh sách các hàm native:

0000000000090d20 T Java_com_twilio_conversations_ConversationImpl_chatClient
000000000008f48d T Java_com_twilio_conversations_ConversationImpl_getCreatedBy
000000000008f28d T Java_com_twilio_conversations_ConversationImpl_getDateCreated
000000000008f68d T Java_com_twilio_conversations_ConversationImpl_getDateUpdated
00000000000899da T Java_com_twilio_conversations_ConversationImpl_getFriendlyName
0000000000090a24 T Java_com_twilio_conversations_ConversationImpl_getLastMessageIndex
000000000008b6f7 T Java_com_twilio_conversations_ConversationImpl_getNotificationLevel
0000000000080fec T Java_com_twilio_conversations_ConversationImpl_getSid
00000000000917cb T Java_com_twilio_conversations_ConversationImpl_getState
00000000000919fe T Java_com_twilio_conversations_ConversationImpl_getStateDateUpdatedAsDate
000000000008d93b T Java_com_twilio_conversations_ConversationImpl_getStatus
000000000008efa2 T Java_com_twilio_conversations_ConversationImpl_getSynchronizationStatus
000000000008b4d5 T Java_com_twilio_conversations_ConversationImpl_getUniqueName
000000000008eb33 T Java_com_twilio_conversations_ConversationImpl_nativeDestroy
0000000000090ea0 T Java_com_twilio_conversations_ConversationImpl_nativeDispose
000000000008c5d3 T Java_com_twilio_conversations_ConversationImpl_nativeGetAttributes
0000000000091c8f T Java_com_twilio_conversations_ConversationImpl_nativeGetConversationLimits
00000000000907d2 T Java_com_twilio_conversations_ConversationImpl_nativeGetLastMessageDate
000000000008dc03 T Java_com_twilio_conversations_ConversationImpl_nativeGetMembers
00000000000904f6 T Java_com_twilio_conversations_ConversationImpl_nativeGetMembersCount
000000000008ca1c T Java_com_twilio_conversations_ConversationImpl_nativeGetMessages
000000000008f88d T Java_com_twilio_conversations_ConversationImpl_nativeGetMessagesCount
0000000000090209 T Java_com_twilio_conversations_ConversationImpl_nativeGetUnconsumedMessagesCount
000000000008e615 T Java_com_twilio_conversations_ConversationImpl_nativeJoin
000000000008e8a4 T Java_com_twilio_conversations_ConversationImpl_nativeLeave
000000000008c728 T Java_com_twilio_conversations_ConversationImpl_nativeSetAttributes
0000000000089bda T Java_com_twilio_conversations_ConversationImpl_nativeSetFriendlyName
000000000008b9d4 T Java_com_twilio_conversations_ConversationImpl_nativeSetNotificationLevel
000000000008c286 T Java_com_twilio_conversations_ConversationImpl_nativeSetUniqueName
000000000008edb7 T Java_com_twilio_conversations_ConversationImpl_typing
00000000000955e4 T Java_com_twilio_conversations_ConversationsClientImpl_getConnectionState
000000000009fba1 T Java_com_twilio_conversations_ConversationsClientImpl_getMyIdentity
00000000000a0672 T Java_com_twilio_conversations_ConversationsClientImpl_isReachabilityEnabled
000000000009592b T Java_com_twilio_conversations_ConversationsClientImpl_nativeCreate
00000000000a330c T Java_com_twilio_conversations_ConversationsClientImpl_nativeDispose
000000000009f38f T Java_com_twilio_conversations_ConversationsClientImpl_nativeGetChannels
00000000000a5a2d T Java_com_twilio_conversations_ConversationsClientImpl_nativeGetMediaSettings
00000000000a60b4 T Java_com_twilio_conversations_ConversationsClientImpl_nativeGetTwilsockWrapper
000000000009fe51 T Java_com_twilio_conversations_ConversationsClientImpl_nativeGetUsers
00000000000a5536 T Java_com_twilio_conversations_ConversationsClientImpl_nativeHandleNotification
00000000000a3653 T Java_com_twilio_conversations_ConversationsClientImpl_nativeRegisterToken
00000000000aca84 T Java_com_twilio_conversations_ConversationsClientImpl_nativeSetLogLevel
00000000000a2a08 T Java_com_twilio_conversations_ConversationsClientImpl_nativeShutdown
00000000000a471c T Java_com_twilio_conversations_ConversationsClientImpl_nativeUnregisterToken
00000000000a0c7b T Java_com_twilio_conversations_ConversationsClientImpl_nativeUpdateToken
00000000000a0a6b T Java_com_twilio_conversations_ConversationsClientImpl_reconnect
00000000000a57a7 T Java_com_twilio_conversations_ConversationsClientImpl_simulateCrash
00000000000934a2 T Java_com_twilio_conversations_Conversations_nativeCreateConversation
00000000000933a6 T Java_com_twilio_conversations_Conversations_nativeDispose
00000000000943dc T Java_com_twilio_conversations_Conversations_nativeGetConversation
0000000000092548 T Java_com_twilio_conversations_Conversations_nativeGetMembersByIdentity
0000000000094cdf T Java_com_twilio_conversations_Conversations_nativeGetMyConversations
00000000000b61f4 T Java_com_twilio_conversations_MessageImpl_getAuthor
00000000000b63e3 T Java_com_twilio_conversations_MessageImpl_getDateCreated
00000000000b65e3 T Java_com_twilio_conversations_MessageImpl_getDateUpdated
00000000000b67e3 T Java_com_twilio_conversations_MessageImpl_getLastUpdatedBy
00000000000b7fec T Java_com_twilio_conversations_MessageImpl_getMessageIndex
00000000000b7adf T Java_com_twilio_conversations_MessageImpl_getMessages
00000000000b5e20 T Java_com_twilio_conversations_MessageImpl_getSid
00000000000b85ba T Java_com_twilio_conversations_MessageImpl_nativeDispose
00000000000b8789 T Java_com_twilio_conversations_MessageImpl_nativeGetAggregatedDelivery
00000000000b81ed T Java_com_twilio_conversations_MessageImpl_nativeGetAttributes
00000000000b70d3 T Java_com_twilio_conversations_MessageImpl_nativeGetChannel
00000000000b6e3d T Java_com_twilio_conversations_MessageImpl_nativeGetChannelSid
00000000000ba5f4 T Java_com_twilio_conversations_MessageImpl_nativeGetContentSid
00000000000ba7f5 T Java_com_twilio_conversations_MessageImpl_nativeGetConversationsClient
00000000000b8b06 T Java_com_twilio_conversations_MessageImpl_nativeGetDetailedDeliveryReceiptList
00000000000b98a2 T Java_com_twilio_conversations_MessageImpl_nativeGetMediaByCategories
00000000000b77bc T Java_com_twilio_conversations_MessageImpl_nativeGetMember
00000000000b758d T Java_com_twilio_conversations_MessageImpl_nativeGetMemberSid
00000000000b6a5f T Java_com_twilio_conversations_MessageImpl_nativeGetMessageBody
00000000000ba412 T Java_com_twilio_conversations_MessageImpl_nativeGetSubject
00000000000b8342 T Java_com_twilio_conversations_MessageImpl_nativeUpdateAttributes
00000000000b6bc5 T Java_com_twilio_conversations_MessageImpl_nativeUpdateMessageBody
00000000000bf5a2 T Java_com_twilio_conversations_Messages_nativeAdvanceLastConsumedMessageIndexWithResult
00000000000c03f0 T Java_com_twilio_conversations_Messages_nativeDispose
00000000000c06a9 T Java_com_twilio_conversations_Messages_nativeGetConversation
00000000000c05cc T Java_com_twilio_conversations_Messages_nativeGetConversationsClient
00000000000bf414 T Java_com_twilio_conversations_Messages_nativeGetLastConsumedMessageIndex
00000000000bed14 T Java_com_twilio_conversations_Messages_nativeGetLastMessages
00000000000bcd39 T Java_com_twilio_conversations_Messages_nativeGetMessageByIndex
00000000000be810 T Java_com_twilio_conversations_Messages_nativeGetMessagesAfter
00000000000bd9b4 T Java_com_twilio_conversations_Messages_nativeGetMessagesBefore
00000000000bc844 T Java_com_twilio_conversations_Messages_nativeRemoveMessage
00000000000ba8d2 T Java_com_twilio_conversations_Messages_nativeSendMessage
00000000000bf87e T Java_com_twilio_conversations_Messages_nativeSetAllMessagesConsumedWithResult
00000000000bf1be T Java_com_twilio_conversations_Messages_nativeSetLastConsumedMessageIndexWithResult
00000000000c001c T Java_com_twilio_conversations_Messages_nativeSetNoMessagesConsumedWithResult
00000000000c0bb5 T Java_com_twilio_conversations_Paginator_nativeDispose
00000000000c091b T Java_com_twilio_conversations_Paginator_nativeRequestNextPage
00000000000b1165 T Java_com_twilio_conversations_ParticipantImpl_getChannel
00000000000b0720 T Java_com_twilio_conversations_ParticipantImpl_getDateCreated
00000000000b0920 T Java_com_twilio_conversations_ParticipantImpl_getDateUpdated
00000000000b0f65 T Java_com_twilio_conversations_ParticipantImpl_getIdentity
00000000000b002e T Java_com_twilio_conversations_ParticipantImpl_getSid
00000000000b1dac T Java_com_twilio_conversations_ParticipantImpl_nativeDispose
00000000000b1750 T Java_com_twilio_conversations_ParticipantImpl_nativeGetAndSubscribeUser
00000000000b1376 T Java_com_twilio_conversations_ParticipantImpl_nativeGetAttributes
00000000000b0b20 T Java_com_twilio_conversations_ParticipantImpl_nativeGetChannel
00000000000b0435 T Java_com_twilio_conversations_ParticipantImpl_nativeGetLastConsumedMessageIndex
00000000000b05ba T Java_com_twilio_conversations_ParticipantImpl_nativeGetLastConsumptionTimestamp
00000000000b1f88 T Java_com_twilio_conversations_ParticipantImpl_nativeRemove
00000000000b14db T Java_com_twilio_conversations_ParticipantImpl_nativeUpdateAttributes
00000000000b3310 T Java_com_twilio_conversations_Participants_nativeAdd
00000000000b4926 T Java_com_twilio_conversations_Participants_nativeAddByAddress
00000000000b3f26 T Java_com_twilio_conversations_Participants_nativeAddByIdentity
00000000000b5c3c T Java_com_twilio_conversations_Participants_nativeDispose
00000000000b2c4e T Java_com_twilio_conversations_Participants_nativeGetChannel
00000000000b2197 T Java_com_twilio_conversations_Participants_nativeGetMember
00000000000b28d4 T Java_com_twilio_conversations_Participants_nativeGetMemberBySid
00000000000b2f5d T Java_com_twilio_conversations_Participants_nativeGetMembersList
00000000000b52ec T Java_com_twilio_conversations_Participants_nativeRemove
00000000000b5693 T Java_com_twilio_conversations_Participants_nativeRemoveByIdentity
0000000000289027 T Java_com_twilio_conversations_twilsock_JniFuture_nativeNotifyCompleted
0000000000284fc6 T Java_com_twilio_conversations_twilsock_TwilsockWrapper_notifyConnected
0000000000284a3b T Java_com_twilio_conversations_twilsock_TwilsockWrapper_notifyConnecting
000000000028544c T Java_com_twilio_conversations_twilsock_TwilsockWrapper_notifyDisconnected
0000000000285a78 T Java_com_twilio_conversations_twilsock_TwilsockWrapper_notifyFatalError
0000000000286288 T Java_com_twilio_conversations_twilsock_TwilsockWrapper_notifyNonFatalError
0000000000287b88 T Java_com_twilio_conversations_twilsock_TwilsockWrapper_notifyRawDataReceived
00000000002873a4 T Java_com_twilio_conversations_twilsock_TwilsockWrapper_notifyTargetedMessageReceived
0000000000286a98 T Java_com_twilio_conversations_twilsock_TwilsockWrapper_notifyTokenAboutToExpire
0000000000286f1e T Java_com_twilio_conversations_twilsock_TwilsockWrapper_notifyTokenExpired
00000000000c0ccc T Java_com_twilio_conversations_UserImpl_getFriendlyName
00000000000c1835 T Java_com_twilio_conversations_UserImpl_getIdentity
00000000000c1c49 T Java_com_twilio_conversations_UserImpl_isNotifiable
00000000000c1a45 T Java_com_twilio_conversations_UserImpl_isOnline
00000000000c1fac T Java_com_twilio_conversations_UserImpl_isSubscribed
00000000000c21b0 T Java_com_twilio_conversations_UserImpl_nativeDispose
00000000000c143d T Java_com_twilio_conversations_UserImpl_nativeGetAttributes
00000000000c10f1 T Java_com_twilio_conversations_UserImpl_nativeSetFriendlyName
00000000000c15b3 T Java_com_twilio_conversations_UserImpl_nativeUpdateAttributes
00000000000c1e4d T Java_com_twilio_conversations_UserImpl_unsubscribe
00000000000c33ba T Java_com_twilio_conversations_Users_getMyUser
00000000000c2c0d T Java_com_twilio_conversations_Users_getSubscribedUsers
00000000000c36c9 T Java_com_twilio_conversations_Users_nativeDispose
00000000000c23ae T Java_com_twilio_conversations_Users_nativeGetAndSubscribeUser
00000000000acae8 T JNI_OnLoad
00000000000afd0b T JNI_Unload

Với kết quả trên, chỉ cần Ctrl + F với từ khóa liên quan như cert, ssl,... hoặc nhìn bằng mắt cũng có thể thấy rằng: chẳng có cái hàm nào thực hiện kiểm tra chứng chỉ SSL, chẳng có cái nào liên quan đến SSL Pinning để hook cả.

image.png

Do đó, mình cần phải tim sâu hơn để xem Twilio làm gì với chứng chỉ SSL.

Đào sâu 3 thước: Reverse tìm vận may

Đúng dịp có một bài đăng trên facebook chia sẻ về công cụ GDA để dịch ngược tệp tin apk. Đây là một công cụ miễn phí, sử dụng tiện hơn so với Bytecode Viewer, JADX. Nhược điểm là chỉ dành cho Windows. Mình đem ra thử luôn xem có ngon thật không.

GDA reverse tool

Khi không có kỹ năng thì chỉ có 2 phương hướng để lựa chọn: Mò và Tìm theo từ khóa. Mình đã mò qua tất cả các hàm của Twilio, cũng đã thử tìm kiếm với các từ khóa liên quan đến SSL Pinning. Cuối cùng thì tìm được hàm readCertificateStore có nội dung như sau:

image.png

Đoạn code trên có vẻ đọc 1 danh sách các Root Cert có sẵn trong máy. Nếu quá trình đọc này xảy ra vấn đề thì sẽ đọc trong một tệp tin chứa các Root Cert. Khi chứng chỉ của Burp Suite nằm trong Root Cert thì mới bắt được request.

Rõ ràng là có vấn đề gì đó đã xảy ra, nên việc kiểm tra Root Cert có sẵn trong máy không thành công. Nếu thành công thì Burp đã bắt được request chat rồi, vì trong máy mình đã cài đặt chứng chỉ của Burp vào kho Root Cert từ lâu.

Vậy thì Twilio sẽ còn giấu danh sách Root Cert dự phòng ở đâu?

Apktool

Câu trả lời là chắc chắn được đính kèm trong tệp tin apk rồi. Mình đã quay lại tìm trong thư mục decompile của Apktool và tìm thấy tệp tin rootcert.pem tại /res/raw.

Tệp tin này có một danh sách các root cert image.png

Không nghi ngờ gì nữa, chắc chắn Twillio đọc root cert từ đây.

Phương pháp 2: patch apk

Với các thông tin đã thu thập được, mình xác định các bước bypass SSL Pinning như sau:

  • Bước 1: Chèn thêm chứng chỉ của burp vào file
  • Bước 2: Dùng apktool patch lại apk

Bước 1

Mình chèn thêm chứng chỉ của Burp vào ngay đầu tệp tin rootcert.pem

image.png

Bước 2

Chạy lần lượt các lệnh sau để tạo ra tệp tin apk mới.

java -jar apktool_2.9.3.jar b redacted.apk

cd redacted\dist

"C:\Users\user\AppData\Local\Android\Sdk\build-tools\35.0.0\zipa
lign.exe" -f -p 4 redacted.apk redacted-1.apk

sign-apk-2.bat redacted-1.apk

Nội dung sign-apk-2.bat

keytool -genkeypair -v -keystore key.keystore -alias publishingdoc -keyalg RSA -keysize 2048 -validity 10000

"C:\Users\user\AppData\Local\Android\Sdk\build-tools\35.0.0\apksigner.bat" sign --ks key.keystore %1

=> Kết quả: vẫn không bắt được request

image.png

Sau 1 hồi tự hỏi thì chợt nhận ra việc thêm cert của mình có vấn đề, bị sai format. Format phải đảm bảo:

// tên cert
----BEGIN CERTIFICATE-----
DFJNDKSJNDSCJNDCSDC
...
----END CERTIFICATE-----

Chỉ cần sửa lại cho đúng image.png

Giờ thì lặp lại các bước patch apk bên trên.

=> Thành công. Lúc này đã bắt được request chat qua socket.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.