- ในโฟลว์การเชื่อมต่อ OAuth ของ Outlook Calendar ใน Harvest, callback URL จะย้ายต่อไปยังปลายทางในค่า
stateทำให้เกิด open redirect และเมื่อรวมกับ implicit grant flow อาจทำให้โทเค็นรั่วไหลไปยัง URL ภายนอกได้ - ปัญหาไม่ได้อยู่ที่ Microsoft แต่อยู่ฝั่งการผสานรวมของ Harvest โดย OAuth
redirect_uriที่ลงทะเบียนไว้กลายเป็น จุดผ่านสำหรับรีไดเรกต์ ที่ส่งผู้ใช้ไปยังโดเมนที่ผู้โจมตีกำหนด stateเป็น JSON ที่เข้ารหัส URI และหากใส่โดเมนภายนอกที่มีสแลชต่อท้าย เช่นexample.com/ในsubdomainก็จะถูกย้ายไปยังรูปแบบexample.com/.harvestapp.com/...- PoC แสดงโฟลว์ที่ใช้
client_id=0dcef4db-36d8-4aed-9cc5-ab43e1814884,response_type=id_token,response_mode=fragment,scope=openidใน Microsoft OAuth authorize URL แล้วทำให้ fragment#id_token=...ติดไปกับปลายทางรีไดเรกต์ - ช่องโหว่ถูกรายงานเมื่อวันที่ 23 สิงหาคม 2020 และยืนยันว่าแพตช์แล้วเมื่อวันที่ 1 สิงหาคม 2023; วันที่ 22 ตุลาคม 2023 Harvest ขอโทษโดยระบุว่าความล่าช้าเกิดจาก human error
โฟลว์ที่โทเค็นรั่วจาก OAuth callback
- Harvest เป็นซอฟต์แวร์ติดตามเวลาที่ให้ผู้ใช้เชื่อมต่อ Outlook Calendar ผ่าน OAuth ได้
- เมื่อการอนุญาตสำเร็จ ผู้ใช้จะถูกรีไดเรกต์ไปที่
https://outlook-integration.harvestapp.com/auth/outlook-calendar/… - callback นี้จะย้ายผู้ใช้ต่อไปยัง URL ที่ให้ไว้ใน
stateและในกระบวนการนั้นเกิด open redirect - ค่า
stateของ callback URL ที่ตรวจพบเดิมเป็น JSON ที่เข้ารหัส URI- เมื่อถอดรหัสจะอยู่ในรูป
{"return_to":"/","subdomain":"hackerone295"} - ค่า
subdomainใช้เพื่อคาดเดาพื้นที่แอป Harvest เช่นhackerone295.harvestapp.com
- เมื่อถอดรหัสจะอยู่ในรูป
- หากใส่สแลชต่อท้ายใน
subdomainเช่นexample.com/callback URL จะกลายเป็นรูปแบบที่ย้ายไปยังโดเมนภายนอก - callback URL นี้เป็น redirect_uri ที่ลงทะเบียนไว้กับแอปพลิเคชัน OAuth ดังนั้นเมื่อรวม open redirect กับ implicit grant flow โทเค็นอาจถูกเปิดเผยต่อปลายทางที่รีไดเรกต์ไป
- PoC authorize URL ใช้ค่าต่อไปนี้
client_id=0dcef4db-36d8-4aed-9cc5-ab43e1814884response_type=id_tokenredirect_uri=https://outlook-integration.harvestapp.com/auth/outlook-calendar/…?...scope=openidresponse_mode=fragmentstate=1nonce=123456
- สุดท้ายผู้ใช้จะถูกรีไดเรกต์ไปยังรูปแบบดังต่อไปนี้
https://example.com/.harvestapp.com/auth/… access token]&state=1
- นี่ไม่ใช่ช่องโหว่ฝั่ง Microsoft
ระยะเวลาตั้งแต่รายงานจนถึงแพตช์
- ทีม Harvest ตอบสนองน้อยมากระหว่างกระบวนการเปิดเผยช่องโหว่และแพตช์ และแม้จะยอมรับช่องโหว่ในขั้น triage แล้ว ก็ใช้เวลานานกว่าจะมีการแก้ไข
- ช่องโหว่ถูกรายงานเมื่อวันที่ 23 สิงหาคม 2020 และ Harvest ติดต่อกลับครั้งแรกเมื่อวันที่ 16 ตุลาคม 2020
- วันที่ 27 พฤศจิกายน 2020 รายงานถูกปรับเป็นสถานะ triaged
- วันที่ 28 เมษายน 2022 บริษัทระบุว่ากำลังแก้ไขและให้กรอบเวลาคาดการณ์ 2 สัปดาห์ แต่ในความเป็นจริงต้องใช้เวลาเพิ่มอีกราว 1 ปีจึงแก้ไขเสร็จ
- วันที่ 1 สิงหาคม 2023 ยืนยันว่าแพตช์ช่องโหว่แล้ว
- วันที่ 21 ตุลาคม 2023 รายงานถูกเผยแพร่ผ่านโพสต์สาธารณะ
- ณ วันเดียวกัน รายงานยังคงอยู่ในสถานะ triage และแม้นโยบาย bug bounty จะระบุถึงรางวัล แต่ไม่มีการจ่าย bounty หรือคะแนน HackerOne
- หลังโพสต์ได้รับความสนใจในวันที่ 22 ตุลาคม 2023 Harvest ได้อธิบายว่าเป็น human error และขอโทษต่อความล่าช้า
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ในฐานะผู้ดูแลโปรแกรม bug bounty ขออธิบายว่าเกิดอะไรขึ้นภายในบ้าง ได้ขอโทษ @0xcrypto และอธิบายภายในไปแล้ว แต่คิดว่าควรสรุปไว้ที่นี่ด้วย
ตั้งแต่แรกเราไม่สามารถทำซ้ำปัญหานี้ได้ครบถ้วน และก็ยังปิดไม่ได้เพราะกลัวว่าจะพลาดอะไรไป หลังจากตอบครั้งสุดท้ายว่า “จะหาทางแก้” เราก็เริ่มเอนเอียงไปทางข้อสรุปว่าทำซ้ำไม่ได้ และเมื่อมี รายงานเกี่ยวกับ OAuth ที่คล้ายกันเข้ามา ก็เกิดความสับสนภายใน จนเข้าใจผิดว่าได้จัดการและส่งต่อเรื่องนี้ไปแล้ว
เนื่องจากการตั้งค่าการแจ้งเตือน ทำให้พลาดข้อความติดตามผล และ issue ค้างอยู่ในสถานะ Triage อย่างไม่มีกำหนดโดยไม่มีอัปเดต นี่ไม่ใช่ข้อแก้ตัว และในฐานะที่เคยเป็น bug bounty hunter มานาน ผมเข้าใจดีว่าการรออัปเดตจากบริษัทนั้นน่าหงุดหงิดแค่ไหน ความปลอดภัยของลูกค้าคือสิ่งสำคัญสูงสุด และสิ่งที่เขียนไว้บนหน้าความปลอดภัยก็เป็นความจริง
ยิ่งกว่านั้น ตอนนี้ก็ยังไม่ชัดเจนว่าจะจัดการรายงานที่ทำซ้ำไม่ได้อย่างไร อยากคุยต่อใน HackerOne แต่หลังจากข้อความขอโทษก็ดูเหมือนจะกลับไป เงียบไม่ตอบ อีกครั้ง
สถานะของแอปมักไม่ตรงกับสถานะบนเซิร์ฟเวอร์ การเปลี่ยนแปลงบนเซิร์ฟเวอร์จะเห็นได้ก็ต่อเมื่อบังคับรีเฟรช หรือการเปลี่ยนแปลงฝั่งไคลเอนต์ถูกย้อนกลับหลังบันทึก ประสบการณ์ใช้งาน time tracking ก็ไม่สะดวก ปุ่มต้องเลื่อนหน้าจอถึงจะเห็น หรือปุ่มเริ่ม/หยุด/เริ่มใหม่/ลบก็เปลี่ยนตำแหน่งไปเรื่อย ๆ ตามสถานะของรายการ แอปเดิมอาจไม่สวย แต่ทำงานได้ไม่มีปัญหา
ค่อนข้างน่ากังวล ตอนที่เคยใช้ Harvest ฝ่ายซัพพอร์ตยอดเยี่ยมมาก ตอบเร็ว เข้าใจอย่างละเอียดว่าลูกค้าใช้ผลิตภัณฑ์อย่างไร และยังอธิบายละเอียดถึงวิธีใช้ฟีเจอร์ที่มีอยู่เดิมอย่างสร้างสรรค์ด้วย
สำหรับฟีเจอร์ที่ยังไม่ได้ทำ คำตอบคือ “จะใส่ไว้ใน backlog แต่รับประกันไม่ได้” เห็นว่ามีวิศวกร 30 คน [1] แต่ก็ไม่ค่อยแน่ใจว่ากำลังคนเหล่านั้นถูกใช้ไปกับอะไร เพราะไม่เห็นว่ามีฟีเจอร์อื่นออกมาเร็วเช่นกัน
ในฐานะ “ผู้ใช้ Harvest” ผมเริ่มได้รับสแปม เลยสงสัยว่าพวกเขาขายรายชื่อลูกค้าหรือไม่ แต่ผู้บริหารบริษัทติดต่อกลับมาทันที ปฏิเสธอย่างหนักแน่น และจริงจังถึงขั้นเริ่มตรวจสอบทันที ตรงนั้นถือว่าดี
แต่สุดท้ายนี่ก็ดูเป็นปัญหาด้านวิศวกรรมอยู่ดี ผมพบวิธีที่ค่อนข้างง่ายในการประเมินลูกค้าที่ใช้งานอยู่ และเรื่องนี้ก็ถูกใส่เข้า “backlog” แล้วไม่ได้รับการแก้ไขมาหลายเดือน การแก้ไขดูเล็กน้อยมาก อีกทั้ง MFA มีให้เฉพาะเมื่อเข้าสู่ระบบด้วย Google เท่านั้น [2] ถึงอย่างนั้นตัวแอปเองก็ทำหน้าที่ของมันได้ดีมากจริง ๆ
1: https://www.getharvest.com/about/meet-the-team
2: https://support.getharvest.com/hc/en-us/articles/36005266713...
การสื่อสารกับผู้รายงานในเธรดนี้ผิดพลาดเป็นความผิดของผมทั้งหมด และตามที่อธิบายในคำตอบด้านบน ผมจะทำให้แน่ใจว่าจะไม่เกิดเรื่องแบบนี้อีก
คำขอฟีเจอร์บางอย่างก็ถูกใส่เข้าไปในผลิตภัณฑ์จริงด้วย อาจไม่ใช่เพราะอิทธิพลของผมก็ได้ แต่อย่างน้อยก็ดูเหมือนว่าเรามีแนวคิดคล้ายกันเกี่ยวกับเครื่องมือติดตามเวลาที่ดี
ชื่อเรื่องดูไม่ค่อยยุติธรรมกับ Microsoft เท่าไร เหมือนพยายามอาศัยกระแสที่ Microsoft ถูกจับตามองจากเหตุการณ์ด้านการยืนยันตัวตนเมื่อไม่นานมานี้ และทันทีที่เห็นชื่อเรื่องก็คิดว่า “MS โดนเจาะอีกแล้วหรือ”
จริง ๆ แล้วมันคือ โทเคนของ Harvest และเป็นเพราะช่องโหว่ injection ในโค้ดของ Harvest ที่ทำให้สิทธิ์เข้าถึงแอป Harvest ถูกเปิดเผยผิดพลาดเท่านั้น ต่อให้อยู่หลัง identity provider รายอื่น ก็จะเปราะบางเหมือนกัน
เพราะช่องโหว่นี้ส่งผลเฉพาะกับ การใช้งาน OAuth สำหรับการเชื่อมต่อบัญชี Microsoft เท่านั้น ชื่อเดิมคือ “Microsoft OAuth token leak via open redirect in Harvest App” และต่อมาเปลี่ยนเป็น “Microsoft Account's OAuth tokens leaking via open redirect in Harvest App” ยังคิดจะเปลี่ยนอยู่ และยินดีรับข้อเสนอแนะ
RFC 6749 อธิบายรายละเอียดถึงวิธีที่เซิร์ฟเวอร์ยืนยันตัวตนควรใช้เพื่อป้องกันการโจมตีแบบนี้
เซิร์ฟเวอร์ยืนยันตัวตนต้องบังคับให้ไคลเอนต์สาธารณะลงทะเบียน URI สำหรับการเปลี่ยนเส้นทาง และควรกำหนดให้ไคลเอนต์แบบลับทำเช่นกัน หากมีการส่ง URI สำหรับการเปลี่ยนเส้นทางมาในคำขอ เซิร์ฟเวอร์ยืนยันตัวตนต้องตรวจสอบโดยเทียบกับค่าที่ลงทะเบียนไว้
ถ้าอย่างนั้น แอป Harvest ก็คงไม่ได้ลงทะเบียน
redirect_uriที่เป็นอันตรายไว้ เลยสงสัยว่าเรื่องนี้เกิดขึ้นได้อย่างไร เป็นเพราะเซิร์ฟเวอร์ OAuth ของ Microsoft เพิกเฉยต่อพารามิเตอร์ URL ภายในredirect_uriตอนเปรียบเทียบกับ URI สำหรับการเปลี่ยนเส้นทางที่ลงทะเบียนไว้ของไคลเอนต์ OAuth หรือเปล่า?stateน่าจะมีจุดประสงค์เพื่อเปลี่ยนเส้นทางไปที่ไหนก็ได้โฟลว์ที่ตั้งใจไว้คือ ไปยัง URL ยืนยันตัวตนของ Harvest → รีไดเรกต์ไปยัง URL ยืนยันตัวตนของ Microsoft พร้อมแนบ
redirect_uri=registered_uriและstate=some_encoded_final_uri→ ผู้ใช้กรอกข้อมูลรับรอง → รีไดเรกต์กลับไปยัง URI ที่ลงทะเบียนไว้ → อ่านstateแล้วรีไดเรกต์ต่อไปยัง URI ที่อยู่ในนั้นการโจมตีนี้ยังคงรีไดเรกต์ไปยัง URI ที่ได้รับอนุญาต แต่ endpoint นั้นอ่าน
stateแล้วส่งต่อ response/token ไปตามเดิม ความผิดพลาดมีสามอย่าง: ใช้stateผิดวัตถุประสงค์, ถ้าจะใช้แบบนั้นก็ไม่ได้เข้ารหัสและตรวจสอบstate, และเปิดใช้ implicit grant ถ้าจำเป็นจริง ๆ ควรสร้างการลงทะเบียนแยกสำหรับการใช้งานที่จำกัดไว้redirect_uriของ Harvest ลงทะเบียนไว้กับ Microsoft แล้ว หลังจากเซิร์ฟเวอร์ OAuth ของ Microsoft รีไดเรกต์ไปยัง Harvest แล้ว Harvest ก็ใช้ข้อมูลในstateเพื่อทำกลไกรีไดเรกต์ของตัวเองimplicit grant แย่มากด้วยเหตุผลแบบนี้ตามที่เห็นในบทความนี้
อนึ่ง ในข้อกำหนด OAuth 2.1 ที่กำลังจะออกมาเร็ว ๆ นี้ มีแผนจะถอดออก: https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.htm...
หมายความว่าใช้เวลา 3 ปี ในการแก้ช่องโหว่หรือ? ตั้งแต่สิงหาคม 2020 ถึงสิงหาคม 2023 ไม่รู้ว่าทีม Harvest ใหญ่แค่ไหน แต่ก็ดูไร้เหตุผลมาก
อยากให้ผู้เชี่ยวชาญ OAuth อธิบายปัญหานี้ให้ละเอียดขึ้นอีกหน่อย อ่านบล็อกไปหลายรอบแล้วแต่ยังไม่เข้าใจว่าช่องโหว่จริง ๆ คืออะไร
จากความรู้ OAuth แบบจำกัดมากของผม แอป Harvest ขอให้ Microsoft ตรวจสอบผู้ใช้ และหลังจาก Microsoft ตรวจสอบผู้ใช้แล้ว หากสำเร็จก็รีไดเรกต์ไปยัง callback URL พร้อมส่ง access token ใน response body ไม่ใช่หรือ?
ในกรณีนี้ ผู้เขียนบล็อกก็แค่สร้าง URL ทำเอง ที่ทำให้ URL ส่งกลับไปที่ example.com แทนที่จะเป็น URL ส่งกลับจริง ๆ เท่านั้นไม่ใช่หรือ?
harvestappและส่วนที่ผู้โจมตีควบคุมอยู่ในstateซึ่งแทบจะเป็นกล่องดำสำหรับเซิร์ฟเวอร์ OAuthการใช้ URL นั้นทำให้สามารถส่งลิงก์
login.microsoftonline.comให้ใครสักคน แสดงพรอมป์ล็อกอินว่า “เข้าสู่ระบบ Harvest” แล้วผู้โจมตีจะได้สิทธิ์ที่เกี่ยวข้องกับบัญชี Harvest จริงโดยปกติทำไม่ได้ ผู้โจมตีอาจลงทะเบียนแอปใหม่ที่รีไดเรกต์ไป
example.comได้ แต่ก็จะไม่ได้ access token ที่มีสิทธิ์เกี่ยวกับ Harvest จึงไม่มีประโยชน์แอป OAuth ฝั่ง Microsoft มี allowlist ของ URL รีไดเรกต์ที่ถูกต้อง ดังนั้นความพยายามอย่าง
login.microsoftonline.com/authorize?client_id=$harvestAppID&redirect_uri=attacker.comจะเกิด error ฝั่ง Microsoft เหตุที่โจมตีได้คือ URLoutlook-integration.harvestapp.comที่ถูกต้องได้รับ access token แล้วรีไดเรกต์ต่อไปยังไซต์ของผู้โจมตีพร้อมส่ง access token ไปด้วยoutlook-integration.harvestapp.comหลังจาก callback ของ OAuth2 สำเร็จ ระบบใช้อ็อบเจ็กต์ JSON ที่มีคำสั่งว่าต้องทำอะไรต่อเป็นstateพร็อพเพอร์ตี
subdomainถูกใช้เพื่อรีไดเรกต์เบราว์เซอร์ไปยังซับโดเมนของharvestapp.comพร้อมส่ง#id-tokenไปด้วย ปัญหาคือค่าsubdomainถูกแทรกเข้าไปใน URL ด้านล่างโดยตรงhttps://${subdomain}.harvestapp.com/...#id-token=...
หากตั้งค่า
subdomainใน JSON payload เป็นค่าอย่างattacker-controlled.com/ที่มีสแลชต่อท้าย URL จะกลายเป็นhttps://attacker-controlled.com/.harvestapp.com/...#id-token=..และเบราว์เซอร์จะไปยังโดเมนอื่น ทำให้ token รั่วไหลดังนั้นนี่ไม่ใช่ปัญหาโดยนัยของ OAuth เอง แต่เป็น การใช้งานที่บกพร่อง
ตอนตั้งค่า workflow แทนที่จะสร้างรายการจริงของ callback URL ที่เชื่อถือได้ อาจใช้ wildcard ใน allowlist ของ callback URL ก็ได้ ผมอาจจะเข้าใจผิดทั้งหมดก็ได้
ไม่เข้าใจว่าทำไมถึงรอกันนานถึง 3 ปี ระยะเวลาผ่อนผันก่อนเปิดเผย 90 วัน ก็เพียงพอแล้ว
อย่างไรก็ตาม ระยะผ่อนผันเพิ่มเติมแบบนั้นควรเป็นสิ่งที่นักวิจัยหรือทนายความ/ตัวแทนของเขาอนุญาตให้ได้ เป็นเรื่องที่บริษัทสามารถร้องขอโดยสุจริตได้สำหรับกรณีที่ใหญ่กว่าปกติ
ถ้า HackerOne ปล่อยให้บริษัทต่าง ๆ ดองเรื่องแบบนี้ไว้นานถึง 3 ปี ก็ดูเหมือนจะทำหน้าที่ของตัวเองได้ไม่ดี
ในระดับพื้นฐานที่สุด ก็แค่ให้แพลตฟอร์มเปิดเผยช่องโหว่ และถ้อยคำทางกฎหมายมาตรฐานเพื่อไม่ให้นักวิจัยถูกฝ่ายกฎหมายฟ้อง
ในกรณีส่วนใหญ่ บริษัทจะปฏิเสธคำขอเปิดเผยข้อมูล หากนักวิจัยเปิดเผยโดยไม่ได้รับอนุญาต ก็จะละเมิดข้อตกลงกับ HackerOne และบริษัท และเปิดให้ตัวเองรับความรับผิดทางกฎหมาย กรณีนี้ดูเหมือนบริษัทจะยินยอมให้เปิดเผย ซึ่งแม้การตอบสนองจะช้ามาก แต่ผมมองว่าจุดนั้นก็น่าชื่นชมได้
โดยส่วนตัว ผมก็เคยมีบั๊กที่มีเงินรางวัลระดับสี่หลักหลายครั้งที่ไม่ได้รับการแก้ไขนานเกิน 1 ปี แต่ก็ไม่ได้คิดว่าเป็นความผิดของ HackerOne
HackerOne ไม่สนใจเลย แม้จะแจ้งหลายครั้งว่าบุคคลนั้นละเมิดกฎของพวกเขาเอง ก็ยังบอกว่าทำอะไรไม่ได้
ความรู้สึกเหมือนบริษัทที่เคยสร้างมาจนดำเนินงานได้ตามปกติ ถูกลดขนาดเหลือแค่พนักงานขั้นต่ำสุด โดยมีเจ้าหน้าที่ซัพพอร์ตที่ไม่มีอำนาจคอยตอบคำถาม เรื่องนี้เกิดขึ้นค่อนข้างนานแล้ว ตอนนี้อาจเปลี่ยนไปแล้วก็ได้ แต่ตอนนั้นความประทับใจเป็นแบบนั้น
ถ้า HackerOne ล้ำเส้นและทำให้บริษัทรู้สึกว่าตนเป็นคนตัดสินใจว่าจะ “อนุญาต” ให้บริษัททำอะไร บริษัทต่าง ๆ ก็แค่ออกจาก HackerOne แล้วสร้างโซลูชันภายในเอง
ไม่เข้าใจว่าทำไมอิชชูนี้ถึงไม่ถูกส่งต่อไปยัง Microsoft ทั้งที่ Microsoft น่าจะเพิกถอนสิทธิ์การเข้าถึงของ OAuth application นี้ได้จนกว่าปัญหาจะได้รับการแก้ไข
แต่ก็คงมี implementation แย่ ๆ คล้ายกันที่เชื่อมต่อกับ Microsoft ผ่าน OAuth อยู่เป็นพัน ๆ ตัว