1 điểm bởi GN⁺ 2025-06-10 | 1 bình luận | Chia sẻ qua WhatsApp
  • Có thể vượt qua biểu mẫu tìm tài khoản Google để xác minh xem có số điện thoại nào được liên kết với một tên người dùng cụ thể hay không
  • Ngay cả trong môi trường đã tắt JavaScript, vẫn có thể cố ý chèn token BotGuard để triển khai phương thức tấn công vượt qua giới hạn IP
  • Ở một số quốc gia như Hà Lan, do đặc điểm định dạng số điện thoại chỉ có dưới 1 triệu tổ hợp, nên trên thực tế có thể brute-force quy mô lớn bằng cách xoay vòng proxy và IPv6
  • Có thể dễ dàng làm lộ tên hiển thị của tài khoản Google bằng Looker Studio mà không cần bất kỳ thao tác nào từ nạn nhân
  • Lỗ hổng này đã được báo cáo cho Google và vá xong, và chuỗi tấn công thực tế có thể tự động hóa để xác minh số điện thoại trong thời gian rất ngắn

Tổng quan

Bài viết này trình bày một trường hợp thực tế về cách dò ra số điện thoại của tài khoản Google bằng tấn công brute-force, toàn bộ quá trình, cũng như phản ứng từ phía phòng thủ. Thông thường, các biểu mẫu tìm/khôi phục tài khoản sẽ dùng môi trường Javascript và cơ chế chống bot để ngăn chặn lạm dụng. Tuy nhiên, bài viết chứng minh rằng trong môi trường tắt JS kết hợp với một mẫu cụ thể, có thể vượt qua cơ chế này.

Bối cảnh điều tra và phương pháp

  • Phát hiện rằng biểu mẫu Google dùng để tìm tên người dùng tài khoản hoạt động mà không cần JavaScript
  • Biểu mẫu cho phép xác minh sự tồn tại của số điện thoại liên kết với một tên (Display Name) cụ thể chỉ bằng 2 yêu cầu HTTP
    • Yêu cầu 1: lấy giá trị ess (token phiên) dựa trên số điện thoại
    • Yêu cầu 2: dùng ess và tham số tên (GivenName/FamilyName) để xác định tài khoản có tồn tại hay không
  • Nếu tài khoản tồn tại thì phản hồi bằng chuyển hướng usernamerecovery/challenge, nếu không tồn tại thì chuyển hướng noaccountsfound

Vượt giới hạn IP (dùng proxy, IPv6)

  • Ban đầu, brute-force là bất khả thi do rate limit theo IP và CAPTCHA
  • Với số di động Hà Lan, có khoảng 1 triệu tổ hợp (do các chữ số đầu đã cố định), nên khi dùng proxy thì đây là kịch bản khả thi
  • Có thể tận dụng khối IPv6 /64 của các cloud như AWS/Vultr để xoay sang địa chỉ khác ở mỗi yêu cầu, và máy chủ cũng hỗ trợ IPv6

Vượt qua token BotGuard

  • Trong biểu mẫu JS, token BotGuard là bắt buộc
  • Nếu trên biểu mẫu không-JS, thay vì tham số bgresponse=js_disabled, chèn token thu được từ biểu mẫu JS thì có thể gửi không giới hạn
  • Đã tạo một công cụ đa luồng, nhập hàng loạt số điện thoại để nhanh chóng phát hiện tài khoản tồn tại

Loại bỏ dương tính giả (filtering)

  • Có thể có nhiều người trùng điều kiện cùng tên/cùng 2 số cuối của số điện thoại
  • Bằng cách nhập lại với một họ (last name) ngẫu nhiên để kiểm tra lần nữa, đã thêm logic tự động lọc dương tính giả

Định dạng số điện thoại theo quốc gia và thu thập thông tin tên

  • Biểu mẫu khôi phục chỉ cung cấp một phần định dạng che số điện thoại
  • Có thể xác định mẫu số điện thoại theo từng quốc gia (national format) bằng cách khảo sát dữ liệu từ libphonenumbers của Google
  • Tên hiển thị của nạn nhân có thể được xác minh trong Looker Studio bằng cách lạm dụng tính năng chuyển quyền sở hữu, không cần hành động nào từ người dùng

Tối ưu hóa và tự động hóa

  • Dùng libphonenumbers để tạo dictionary quy tắc xác thực theo từng quốc gia về prefix/độ dài/tính hợp lệ
  • Tạo API tự động cấp token BotGuard bằng chromedp nền tảng Go, cho phép tự động hóa trong tấn công thực tế

Quy trình tấn công thực tế

  1. Lấy tên của nạn nhân (tên hiển thị) qua việc chuyển quyền sở hữu trong Looker Studio
  2. Trong luồng “quên mật khẩu”, thu thập phần số điện thoại bị che một phần của email đó
  3. Dùng công cụ gpb để thực hiện brute-force dựa trên tên, phần che, và mã quốc gia

Thời gian và hiệu quả

  • Với máy chủ 16 vCPU, 3000 luồng, có thể kiểm tra khoảng 40.000 trường hợp mỗi giây
  • Tùy theo số lượng tổ hợp số và độ dài gợi ý theo từng quốc gia, chỉ cần khoảng Mỹ (20 phút), Anh (4 phút), Hà Lan (15 giây), Singapore (5 giây)
  • Nếu dịch vụ khác cung cấp gợi ý đầy đủ hơn (ví dụ: PayPal) thì thời gian còn rút ngắn hơn nữa

Google và timeline vá lỗi

  • 2025.4.14: báo cáo cho Google, ngày 4.25 được cảm ơn trên panel
  • Giữa 2025.5: nhận bug bounty $5.000
  • 2025.5: biểu mẫu không-JS bị ngừng dần và các biện pháp ứng phó được áp dụng
  • 2025.6.9: công khai lỗ hổng chính thức

Kết luận

Trường hợp này cho thấy chỉ với sự kết hợp của nhiều thông tin như luồng khôi phục tài khoản, che số điện thoại, tên hiển thị cũng có thể tạo ra tấn công tự động hóa quy mô lớn. Google đã hoàn tất việc ứng phó bằng cách vá lỗ hổng trong quy trình và đóng các biểu mẫu liên quan.

Có thể liên hệ qua Signal/email (xem nguyên văn)

1 bình luận

 
GN⁺ 2025-06-10
Ý kiến Hacker News
  • Điểm thú vị trong bài này là, mặc dù hầu hết các nhà cung cấp hosting hay ISP đều cấp ít nhất một khối IPv6 /64, phần lớn cơ chế rate limit hoặc chặn IP vẫn chỉ áp dụng cho từng IP đơn lẻ. Trong môi trường IPv6, tôi nghĩ việc rate limit hoặc chặn nên được thực hiện theo toàn bộ khối /64

    • Tôi thường xuyên thấy ngay cả những công ty có trách nhiệm quản lý vấn đề này hoặc kiếm tiền từ nó cũng phản ứng rất lệch lạc trong việc quản lý IPv6. Công ty tôi làm việc dùng một dịch vụ CDN nổi tiếng, nhưng đôi khi vẫn nhận được những cảnh báo bảo mật vô lý kiểu “đăng nhập từ IP lạ” dù truy cập từ cùng một khối /64

    • Tôi nghĩ từ sau khi IPv6 xuất hiện, cách chặn IP truyền thống đã bị vô hiệu hóa đáng kể. Ngay cả người dùng Internet gia đình bình thường cũng có thể tự động nhận khối /56 hoặc /48 qua DHCPv6 Prefix Delegation. Ví dụ, tôi nhận /56 từ Comcast, và nó có thể được chia thành tối đa 65536 khối /64. Muốn lọc IP hiệu quả trong IPv6 thì không thể chỉ đơn giản thay cơ chế dựa trên từng IP đơn lẻ bằng /64

    • Ngay cả rate limit theo khối /64 cũng có thể chưa đủ. Việc nhận được khối /48 cũng quá dễ. Để kiểm soát tối ưu, cần phân loại theo ASN và còn phải xem từng nhà mạng phân phối IP như thế nào để điều chỉnh độ chi tiết cho phù hợp

    • Rate limit theo đơn vị /64 trong IPv6 vốn đã là điều ngành này biết rõ, và Google cũng áp dụng cho các dịch vụ khác. Tôi cho rằng đây là kết quả của việc không cập nhật đúng các chính sách cũ khi triển khai IPv6

    • Ngay cả các nhà cung cấp hosting giá rẻ như BuyVM cũng cấp địa chỉ theo đơn vị /48 ở gói rẻ nhất ($2/tháng, hiện chỉ còn hàng gói $7/tháng). Vì vậy những người vận hành đáng ngờ có xu hướng rất thích dùng

  • Trước đây tôi từng thử cách tương tự trên Facebook để tìm số điện thoại của một người cụ thể. Trong quá trình đặt lại mật khẩu, Facebook hiển thị phần lớn số điện thoại, nên tôi sắp xếp các con số đó vào một file vcard, nhập vào điện thoại rồi đối chiếu bằng ảnh. Cách này hiệu quả ngoài mong đợi

    • Ảnh hồ sơ Google hoặc các ứng dụng Google cũng có lỗ hổng tương tự. Ví dụ nếu trên đánh giá Google Maps hiện tên John Smith, bạn có thể thêm nhiều biến thể email khác nhau (johnsmith@gmail.com, smithjohn@gmail.com v.v.) vào Hangouts và kiểm tra ảnh hồ sơ để lần ra đúng người

    • Vì lý do đó tôi tuyệt đối không nhập số điện thoại thật của mình. Việc vận hành dịch vụ cũng đâu thực sự cần đến nó

  • Điều gây ấn tượng là một người có thể bắn 40.000 request mỗi giây vào server trong thời gian dài mà tài nguyên không tăng vọt hoặc không có cảnh báo nào vang lên

    • Có thể cảnh báo thực sự đã vang lên, nhưng hành vi bị dừng lại nhanh hoặc tình hình được khôi phục quá sớm nên đến lúc kỹ sư mở dashboard thì mọi thứ đã trở lại bình thường. 40.000 QPS không hẳn nổi bật ở quy mô traffic của Focus hay Google API, và nếu được phân tán qua nhiều IP cùng các khối IPv6 /64 khác nhau thì cũng có thể trôi qua mà không bị chú ý. Điểm cốt lõi trong vụ này theo tôi không phải monitoring, mà là luồng khi tắt JS (dùng token mượn từ luồng bật JS trước đó) hoàn toàn không có rate limit

    • Tôi cũng tự hỏi không biết có dùng botnet không, nhưng có vẻ như IP đã được thay đổi theo từng request

  • Những vụ bug bounty kiểu này thường có mức thưởng thấp đến phi lý. Thật đáng tiếc

    • Cứ tiếp tục giảm tiền thưởng thì cuối cùng chỉ là tự hại mình

    • Trả dưới 100.000 USD cho loại vấn đề bảo mật này thì thật sự quá bèo bọt

  • Tôi thường cảm nhận rất rõ rằng việc duy trì và bảo trì các trang web legacy là một gánh nặng khổng lồ. Nhiều website phải tiếp tục duy trì cả code và trang đã vài chục năm tuổi, và gần như không thể kiểm thử mọi tổ hợp. Nếu đào sâu vào phần cài đặt Gmail, bạn vẫn có thể tận mắt thấy những popup cũ kiểu năm 2004

    • Các chương trình bug bounty có vẻ là một cách sử dụng chi phí cực kỳ hiệu quả. Chỉ với vài nghìn đô là có thể huy động lực lượng tự nguyện đi tìm những edge case cực đoan. Nếu dùng nhân sự nội bộ thì chi phí chắc chắn còn lớn hơn nhiều

    • Đây chính là lý do lớn nhất khiến các công ty cố gắng loại bỏ mạnh tay những dịch vụ và sản phẩm cũ. Câu trả lời cho câu hỏi “chẳng phải cứ để nguyên là được sao” là cuối cùng mọi dịch vụ legacy đều trở thành lỗ hổng bảo mật. Đoạn mã thực sự an toàn duy nhất là đoạn mã không tồn tại

    • Tôi luôn thắc mắc không biết ai đang phụ trách mấy thứ như tính năng “poke” của Facebook

    • Bên trong các công ty lớn cũng có những hạ tầng legacy tương tự vẫn chạy mãi. Ví dụ một người bạn tôi bảo trì một ứng dụng rút gọn liên kết nội bộ trong một tập đoàn đa quốc gia lớn, nhưng dù lưu lượng sử dụng gần như bùng nổ thì mỗi lần cũng chỉ có một hai ticket được tạo ra vì những lý do rất đơn giản như cập nhật phiên bản Node. Thậm chí monitoring không hoạt động bình thường mà bug report vẫn hiếm đến mức đáng ngạc nhiên

    • Gần đây tôi cũng từng gặp một trang Google vẫn hiện logo Catull cũ (~2013)

  • Bài có nhắc đến “2025-05-15 – Hội đồng trả $1,337 + đồ swag. Lý do: khả năng khai thác thấp (lol)”, nhưng tôi thực sự nghĩ khả năng bị khai thác là rất cao. Có thể số người bị lộ số điện thoại không quá nhiều, nhưng nếu cần thì tôi tin rằng thám tử tư, tội phạm, điều tra viên và nhiều đối tượng khác hoàn toàn sẽ khai thác lỗ hổng này ngoài đời thực

  • Qua vụ này tôi mới nhận ra rằng việc đưa ra gợi ý một phần số điện thoại trong luồng tìm lại mật khẩu thực sự là một rủi ro bảo mật. Nếu nhiều dịch vụ cùng cung cấp gợi ý số điện thoại/email bị che theo những thứ tự khác nhau thì mức độ rủi ro còn lớn hơn

    • Không biết có an ủi được không, nhưng vì 2FA và đủ loại lý do khác, hàng trăm hoặc hàng nghìn dịch vụ đã thu thập số điện thoại của tôi, và rất nhiều trong số đó đã bị rò rỉ bất kể tôi có đồng ý hay không. Tổ hợp tên thật-email-số điện thoại gần như chắc chắn đã bị dump vào dữ liệu công khai

    • Cũng có những bot Telegram chuyên tìm các thông tin kiểu này. Mỗi khi một lỗ hổng brute force như vậy bị phơi bày, có vẻ ngay cả những người dùng công cụ tự động hóa cũng cảm thấy khó chịu (bot EoG là ví dụ tiêu biểu)

    • Các dịch vụ trả phí tự động tổng hợp thông tin cá nhân kiểu này cũng đã tồn tại từ lâu. Email, số điện thoại và nhiều dữ liệu khác được gom từ nhiều nguồn, và do động cơ trên quy mô toàn cầu đủ lớn nên người ta rất tích cực tấn công vào các điểm yếu bảo mật của dịch vụ. Cuối cùng cấu trúc này dẫn đến các vụ rò rỉ hàng loạt

    • Trước đây cũng từng có các trường hợp social engineering, khi ai đó gọi cho bộ phận hỗ trợ khách hàng của một công ty để hỏi 4 số cuối của thẻ, rồi dùng chính thông tin đó để vượt qua xác minh danh tính ở công ty khác

    • Tôi cũng nhớ hồi đại học từng nghe một nhà nghiên cứu bảo mật trình bày rằng thẻ tín dụng cũng có thể bị thu thập thông tin theo kiểu này

  • Năm 2025, 2023 và 2021, các bài viết kiểu “không có cách nào để ngăn chuyện này” cùng những vụ rò rỉ dữ liệu quy mô lớn cứ lặp đi lặp lại. Phiên bản 2025, phiên bản 2023, phiên bản 2021 cứ thế lặp lại. Tôi còn đang nghĩ không biết phiên bản nào buồn cười hơn

  • Tôi thấy vụ này rất sáng tạo và rất ngầu. Brutecat lại làm thêm một cú nữa

  • Giờ Google thật sự cho cảm giác như một con tàu ma. Mức bug bounty $5.000 là một sự xúc phạm, và ngay việc bắt đầu với con số nhỏ như vậy tự nó đã giống bằng chứng quyết định rằng Google không nghiêm túc trong việc bảo vệ dữ liệu người dùng

    • Tham gia bug bounty không phải nghĩa vụ bắt buộc. Nếu không thích mức thưởng thì đơn giản là đừng tham gia. Rốt cuộc các chương trình này cũng có giới hạn của mô hình bền vững