• ฟอร์ม กู้คืนชื่อผู้ใช้แบบ No-JS ของ Google ยืนยันชุดหมายเลขโทรศัพท์และชื่อที่แสดงได้ ทำให้เกิดเชนการโจมตีที่สามารถค้นหาหมายเลขโทรศัพท์เต็มของผู้ใช้ Google รายใดรายหนึ่งได้
  • ประเด็นสำคัญคือความแตกต่างของ การ redirect ระหว่าง /signin/usernamerecovery และ /signin/usernamerecovery/lookup ซึ่งทำให้แยกได้ว่าไม่มีบัญชีหรือมีบัญชีอยู่
  • แม้จะมีการจำกัดคำขอตาม IP และ CAPTCHA แต่เมื่อนำ โทเค็น BotGuard จากฟอร์ม JS ไปใส่ใน bgresponse ของฟอร์ม No-JS ก็ทำงานได้โดยไม่ถูกจำกัด และยังนำมารวมกับการหมุน IPv6 ได้ด้วย
  • ผู้โจมตีสามารถใช้ Looker Studio เพื่อหา ชื่อที่แสดงของบัญชี Google และผสานหมายเลขโทรศัพท์ที่ถูกมาสก์จากขั้นตอนกู้คืนรหัสผ่านกับรูปแบบหมายเลขของแต่ละประเทศ เพื่อลดจำนวนตัวเลือกลงได้มาก
  • บนเซิร์ฟเวอร์ระดับ 16 vCPU ราคา $0.30 ต่อชั่วโมง สามารถตรวจสอบได้ประมาณ 40,000 ครั้งต่อวินาที และ Google ได้ยกเลิกฟอร์มกู้คืนชื่อผู้ใช้แบบ No-JS ทั้งหมดเมื่อวันที่ 6 มิถุนายน 2025 พร้อมจ่ายรางวัลรวม $5,000

ช่องโหว่ที่เริ่มจากฟอร์มกู้คืนชื่อผู้ใช้แบบ No-JS

  • ระหว่างตรวจสอบการทำงานของบริการ Google ในเบราว์เซอร์ที่ปิด JavaScript พบว่า ฟอร์มกู้คืนชื่อผู้ใช้ ยังคงทำงานอยู่
  • เดิมทีเชื่อกันว่าฟอร์มกู้คืนบัญชีจำเป็นต้องใช้ JavaScript เพราะพึ่งพากลไกป้องกันตระกูล BotGuard ที่สร้างโดยโค้ด JavaScript แบบ proof-of-work ซึ่งถูกทำให้อ่านยาก
  • แต่ฟอร์ม No-JS มีโฟลว์ที่สามารถตรวจสอบได้ว่าอีเมลกู้คืนหรือหมายเลขโทรศัพท์เชื่อมโยงกับชื่อที่แสดงหนึ่ง ๆ หรือไม่

ตรวจสอบการมีอยู่ของบัญชีด้วยคำขอสองครั้ง

  • คำขอแรกส่งหมายเลขโทรศัพท์ไปที่ /signin/usernamerecovery แล้วรับค่า ess ที่เชื่อมโยงกับหมายเลขโทรศัพท์นั้นจาก Location ในการตอบกลับ
    • คุกกี้และค่า gxf นำมาจาก HTML ของหน้าเริ่มต้น
  • จากนั้นส่ง ess, ชื่อ, นามสกุล และ bgresponse=js_disabled ไปที่ /signin/usernamerecovery/lookup
  • redirect ในการตอบกลับแตกต่างกัน ทำให้ระบุได้ว่ามีบัญชี Google ที่ใช้หมายเลขโทรศัพท์และชื่อที่แสดงนั้นหรือไม่
    • ไม่มีบัญชี: usernamerecovery/noaccountsfound
    • มีบัญชี: usernamerecovery/challenge

การจำกัด IP, IPv6 และการเลี่ยง BotGuard

  • ในการลองช่วงแรก หลังส่งคำขอไม่กี่ครั้ง ที่อยู่ IP ก็ถูก จำกัดคำขอ และมี CAPTCHA แสดงขึ้น
  • ในตัวอย่างหมายเลขมือถือเนเธอร์แลนด์ โฟลว์กู้คืนรหัสผ่านให้คำใบ้เช่น •• ••••••03
    • หมายเลขมือถือเนเธอร์แลนด์ขึ้นต้นด้วย 06 จึงต้อง brute force ตัวเลือกที่เหลือ 6 หลัก หรือ 10^6 = 1,000,000 รายการ
  • ผู้ให้บริการอย่าง Vultr ให้ช่วง IPv6 แบบ /64 ซึ่งตามทฤษฎีสามารถใช้ที่อยู่ได้ 18,446,744,073,709,551,616 รายการ
  • มีการสร้าง PoC ที่ใช้ ClientBuilder.local_address ของ reqwest เพื่อตั้งค่าที่อยู่ IPv6 แบบสุ่มจากซับเน็ตในแต่ละคำขอ
  • เมื่อใช้ฟอร์มที่ปิด JS จาก IP ดาต้าเซ็นเตอร์ จะยังเจอ CAPTCHA ต่อเนื่อง แต่เมื่อนำ โทเค็น BotGuard ของฟอร์มกู้คืนบัญชีแบบเปิด JS ไปใส่ใน bgresponse ของฟอร์ม No-JS คำขอก็ผ่านได้
    • ในฟอร์ม No-JS ดูเหมือนว่าโทเค็น BotGuard ดังกล่าวจะไม่ถูกจำกัดจำนวนคำขอ

คัดกรองผลบวกปลอม

  • ผลการรันครั้งแรกมีบัญชีจำนวนมากที่ชื่อเป็น Henry นามสกุลว่าง และหมายเลขโทรศัพท์ลงท้ายด้วย 03
  • ในกรณีนี้ หากชื่อเป็น Henry ไม่ว่านามสกุลจะเป็นค่าใด usernamerecovery/challenge ก็ถูกส่งกลับมา
  • เพื่อยืนยัน hit ที่เป็นไปได้ จึงตรวจสอบซ้ำด้วยชื่อเดิมแต่ใส่นามสกุลสุ่ม เช่น 0fasfk1AFko1wf
    • หากยังได้ hit ก็กรองออกเป็นผลบวกปลอม
  • ประเมินว่ามีโอกาสต่ำที่ผู้ใช้ Google รายอื่นจะมีชื่อที่แสดงแบบเต็มเหมือนกัน รหัสประเทศเดียวกัน และเลขท้ายสองหลักเดียวกัน

การหารหัสประเทศและชื่อที่แสดง

  • มาสก์หมายเลขโทรศัพท์ในโฟลว์กู้คืนรหัสผ่านสามารถใช้เพื่อ อนุมานรหัสประเทศ ได้
  • Google ใช้ libphonenumber สำหรับ national format ของแต่ละหมายเลข
  • มีการรวบรวม national format ที่ถูกมาสก์ของแต่ละประเทศเพื่อสร้าง mask.json
    • รัสเซีย เนเธอร์แลนด์ สหราชอาณาจักร และสหรัฐฯ มีรูปแบบมาสก์ต่างกัน
  • ในปี 2023 Google เปลี่ยนนโยบายให้แสดงชื่อเฉพาะเมื่อมีปฏิสัมพันธ์โดยตรงกับเป้าหมายเท่านั้น และในเดือนเมษายน 2024 Internal People API ก็หยุดส่งคืนชื่อที่แสดงของบัญชีที่ไม่ได้ยืนยันตัวตนโดยสิ้นเชิง
  • อย่างไรก็ตาม หากสร้างเอกสาร Looker Studio แล้วโอนความเป็นเจ้าของให้เหยื่อ ชื่อที่แสดง จะปรากฏบนหน้าจอหลักโดยไม่ต้องให้เหยื่อมีปฏิสัมพันธ์

การปรับช่วงตัวเลือกและเครื่องมือให้เหมาะสม

  • ใช้การตรวจสอบหมายเลขของ libphonenumber เพื่อสร้าง format.json ที่มี prefix มือถือของแต่ละประเทศ รหัสพื้นที่ที่รู้จัก และจำนวนหลัก
    • ตัวอย่างเนเธอร์แลนด์มีรหัสประเทศ 31, รหัสพื้นที่ 61, 62, 63, 64, 65, 68 และจำนวนหลัก [7]
  • ใช้ การตรวจสอบ libphonenumber แบบเรียลไทม์ เพื่อลดการ query ไปยัง Google API สำหรับหมายเลขที่ไม่ถูกต้อง
  • เขียน สคริปต์ Go ที่ใช้ chromedp เพื่อสร้างโทเค็น BotGuard
  • โฟลว์การโจมตีทั้งหมดต่อเนื่องกันเป็นสามขั้นตอน
    • รั่วไหลชื่อที่แสดงของบัญชี Google ผ่าน Looker Studio
    • ได้หมายเลขโทรศัพท์ที่ถูกมาสก์จาก โฟลว์กู้คืนรหัสผ่าน
    • ใส่ชื่อที่แสดงและหมายเลขโทรศัพท์ที่ถูกมาสก์ลงใน gpb เพื่อ brute force หมายเลขโทรศัพท์เต็ม

ประสิทธิภาพการ Brute Force และเวลาที่คาดการณ์

  • บนเซิร์ฟเวอร์ราคา $0.30 ต่อชั่วโมงและสเปกระดับผู้ใช้ทั่วไป 16 vCPU สามารถตรวจสอบได้ประมาณ 40,000 ครั้งต่อวินาที
  • เวลาที่คาดว่าจะใช้เมื่อโฟลว์กู้คืนรหัสผ่านให้เฉพาะเลขท้ายสองหลัก:
    • สหรัฐฯ +1: 20 นาที
    • สหราชอาณาจักร +44: 4 นาที
    • เนเธอร์แลนด์ +31: 15 วินาที
    • สิงคโปร์ +65: 5 วินาที
  • หากโฟลว์รีเซ็ตรหัสผ่านของบริการอื่น เช่น PayPal ให้คำใบ้เป็นตัวเลขมากกว่าเดิม เวลาที่ใช้จะลดลงอย่างมาก
    • ตัวอย่าง: +14•••••1779

ไทม์ไลน์การรายงานและการแก้ไขของ Google

  • 2025-04-14: ส่งรายงานให้ vendor
  • 2025-04-15: vendor รับและจัดหมวดหมู่รายงาน
  • 2025-04-25: ตอบกลับว่า “Nice catch!”
  • 2025-05-15: คณะกรรมการกำหนดรางวัล $1,337 + swag
    • เหตุผลคือประเมินว่าความเป็นไปได้ในการถูกนำไปใช้ในทางที่ผิดต่ำ และยอมรับประเด็นนี้เป็น abuse-related methodology ที่มี high impact
  • 2025-05-15: ยื่นคัดค้านเหตุผลของรางวัล
    • ตาม ตาราง Abuse VRP probability/exploitability ถูกกำหนดจากเงื่อนไขตั้งต้นของการโจมตีและการที่เหยื่อสามารถตรวจพบการนำไปใช้ในทางที่ผิดได้หรือไม่
    • ชี้แจงว่าการโจมตีนี้ไม่มีเงื่อนไขตั้งต้น และเหยื่อไม่สามารถตรวจพบการนำไปใช้ในทางที่ผิดได้
  • 2025-05-22: คณะกรรมการจ่ายเพิ่ม $3,663 ปรับรางวัลรวมเป็น $5,000
    • ปรับ likelihood ขึ้นเป็น medium
  • 2025-05-22: vendor ยืนยันว่าได้ปล่อยมาตรการบรรเทาที่กำลังดำเนินอยู่จนกว่าจะยกเลิก endpoint ทั่วโลก
  • 2025-05-22: ประสานกำหนดการเปิดเผยวันที่ 2025-06-09
  • 2025-06-06: vendor ยืนยันการยกเลิกฟอร์มกู้คืนชื่อผู้ใช้แบบ No-JS อย่างสมบูรณ์
  • 2025-06-09: เผยแพร่รายงาน

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น