
หนึ่งปีที่ผ่านมา 21 มีนาคม 2019 เวลา สิ่งที่ดีมากมาถึง HackerOne จาก . เมื่อแนะนำศูนย์ไบต์ (ASCII 0) ลงในพารามิเตอร์ POST ของหนึ่งในคำขอ Webmail API ที่ส่งคืนการเปลี่ยนเส้นทาง HTTP ชิ้นส่วนของหน่วยความจำที่ไม่ได้เตรียมใช้งานจะมองเห็นได้ในข้อมูลการเปลี่ยนเส้นทาง ซึ่งชิ้นส่วนจากพารามิเตอร์ GET และส่วนหัวของคำขออื่น ๆ ไปยัง เซิร์ฟเวอร์เดียวกัน
นี่เป็นช่องโหว่ที่สำคัญเนื่องจาก... คำขอยังมีคุกกี้เซสชันด้วย ไม่กี่ชั่วโมงต่อมามีการแก้ไขชั่วคราวที่กรองไบต์เป็นศูนย์ (ตามที่ปรากฏในภายหลังซึ่งไม่เพียงพอเนื่องจากยังมีความเป็นไปได้ที่จะฉีด CRLF / ASCII 13, 10 ซึ่งช่วยให้คุณสามารถจัดการส่วนหัวและ ข้อมูลการตอบสนอง HTTP สิ่งนี้มีความสำคัญน้อยกว่า แต่ก็ยังไม่เป็นที่พอใจ) ในเวลาเดียวกัน ปัญหาก็ถูกถ่ายโอนไปยังนักวิเคราะห์ความปลอดภัยและนักพัฒนา เพื่อค้นหาและกำจัดสาเหตุของจุดบกพร่อง
เมล Mail.ru เป็นแอปพลิเคชันที่ซับซ้อนมาก ส่วนประกอบส่วนหน้า/ส่วนหลังที่แตกต่างกันจำนวนมาก ทั้งโอเพ่นซอร์ส (ขอบคุณมากสำหรับนักพัฒนาซอฟต์แวร์ฟรีทุกคน) และที่พัฒนาขึ้นภายในองค์กรสามารถมีส่วนร่วมในการสร้างการตอบสนองได้ เราจัดการเพื่อแยกส่วนประกอบทั้งหมดยกเว้น nginx และ openresty และแปลปัญหาก่อนการโทร ในสคริปต์ OpenResty ที่ไม่ทำงานตามที่คาดไว้ (การแทรกไบต์ว่างหรือการป้อนบรรทัดผ่านพารามิเตอร์ GET พร้อมการเขียนใหม่ใน ngx_http_rewrite_module ซึ่งตามเอกสารประกอบถูกใช้และดูเหมือนว่าจะทำงานในลักษณะเดียวกันทุกประการ ไม่ทำงาน). ผลที่ตามมาที่เป็นไปได้ถูกกำจัดออกไป เพิ่มการกรองอย่างเคร่งครัดที่สุดเท่าที่จะเป็นไปได้ และการกรองได้รับการตรวจสอบเพื่อกำจัดเวกเตอร์ที่เป็นไปได้ทั้งหมด แต่กลไกที่นำไปสู่การรั่วไหลของเนื้อหาหน่วยความจำยังคงเป็นปริศนา หนึ่งเดือนต่อมา รายงานข้อบกพร่องถูกปิดเมื่อได้รับการแก้ไขแล้ว และการวิเคราะห์สาเหตุของข้อบกพร่องถูกเลื่อนออกไปจนกว่าจะถึงเวลาที่ดีขึ้น
OpenResty เป็นปลั๊กอินยอดนิยมที่ให้คุณเขียนสคริปต์ Lua ภายใน nginx และใช้ในโครงการ Mail.ru หลายโครงการ ดังนั้นปัญหาจึงไม่ถือว่าได้รับการแก้ไข และหลังจากนั้นสักพัก ในที่สุดพวกเขาก็กลับมาหามันอีกครั้งเพื่อทำความเข้าใจเหตุผลที่แท้จริง ผลที่ตามมาที่อาจเกิดขึ้น และให้คำแนะนำแก่นักพัฒนา มีส่วนร่วมในการขุดค้นซอร์สโค้ด и . ปรากฎว่า:
- ใน nginx เมื่อใช้การเขียนซ้ำด้วยข้อมูลผู้ใช้ มีความเป็นไปได้ที่ไดเรกทอรีจะข้ามผ่าน (และอาจเป็น SSRF) ในการกำหนดค่าบางอย่าง แต่นี่เป็นข้อเท็จจริงที่ทราบแล้วและควรตรวจพบโดยเครื่องวิเคราะห์การกำหนดค่าแบบคงที่ใน и จาก Yandex (ใช่ เราก็ใช้เช่นกัน ขอบคุณ) เมื่อใช้ OpenResty คุณลักษณะนี้จะพลาดได้ง่าย แต่ไม่ได้ส่งผลต่อการกำหนดค่าของเรา
ตัวอย่างการกำหนดค่า:
location ~ /rewrite { rewrite ^.*$ $arg_x; } location / { root html; index index.html index.htm; }ผล
curl localhost:8337/rewrite?x=/../../../../../../../etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
... - Nginx มีข้อบกพร่องที่ทำให้หน่วยความจำรั่วไหลหากบรรทัดที่เขียนใหม่มีไบต์ว่าง เมื่อมีการออกการเปลี่ยนเส้นทาง nginx จะจัดสรรบัฟเฟอร์หน่วยความจำใหม่ที่สอดคล้องกับความยาวเต็มของบรรทัด แต่คัดลอกบรรทัดที่นั่นผ่านฟังก์ชันบรรทัดที่ศูนย์ไบต์เป็นตัวสิ้นสุดของบรรทัด ดังนั้นบรรทัดจะถูกคัดลอกจนถึงศูนย์เท่านั้น ไบต์ ส่วนที่เหลือของบัฟเฟอร์มีข้อมูลที่ยังไม่ได้เตรียมใช้งาน สามารถดูการวิเคราะห์โดยละเอียดได้ .
ตัวอย่างการกำหนดค่า (^@ ศูนย์ไบต์)
location ~ /memleak { rewrite ^.*$ "^@asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdasdf"; } location / { root html; index index.html index.htm; }ผล
curl localhost:8337/secret -vv
...
curl localhost:8337/memleak -vv
...
Location: http://localhost:8337/secret
...
- Nginx ปกป้องพารามิเตอร์ GET จากการแทรกอักขระบริการ และทำให้สามารถใช้เฉพาะพารามิเตอร์ GET ในการเขียนใหม่ได้ ดังนั้นจึงเป็นไปไม่ได้ที่จะใช้ประโยชน์จากการฉีดผ่านพารามิเตอร์ที่ผู้ใช้ควบคุมใน nginx พารามิเตอร์ POST ไม่ได้รับการป้องกัน OpenResty ช่วยให้คุณทำงานกับทั้งพารามิเตอร์ GET และ POST ดังนั้นเมื่อใช้พารามิเตอร์ POST ผ่าน OpenResty จะสามารถแทรกอักขระพิเศษได้
ตัวอย่างการกำหนดค่า:
location ~ /memleak { rewrite_by_lua_block { ngx.req.read_body(); local args, err = ngx.req.get_post_args(); ngx.req.set_uri( args["url"], true ); } } location / { root html; index index.html index.htm; }ผลลัพธ์:
curl localhost:8337 -d "url=secret" -vv
...
curl localhost:8337 -d "url=%00asdfasdfasdfasdfasdfasdfasdfasdf" -vv
...
Location: http://localhost:8337/{...может содержать secret...}
...
ปฏิกิริยาต่อไป
ปัญหาได้รับการรายงานไปยังนักพัฒนาของ nginx และ OpenResty แล้ว นักพัฒนาไม่ได้ถือว่าปัญหาดังกล่าวเป็นข้อบกพร่องด้านความปลอดภัยใน nginx เนื่องจาก ใน nginx เองไม่มีทางที่จะใช้ประโยชน์จากข้อผิดพลาดผ่านการแทรกอักขระพิเศษ แก้ไขได้ เผยแพร่เมื่อวันที่ 16 ธันวาคม ในช่วง 4 เดือนนับตั้งแต่รายงาน ไม่มีการเปลี่ยนแปลงใด ๆ กับ OpenResty แม้ว่าจะมีความเข้าใจว่าจำเป็นต้องใช้ฟังก์ชัน ngx.req.set_uri() เวอร์ชันที่ปลอดภัยก็ตาม ในวันที่ 18 มีนาคม 2020 เราได้เผยแพร่ข้อมูล และในวันที่ 21 มีนาคม OpenResty ก็เผยแพร่ ซึ่งเพิ่มการตรวจสอบ URI
พอร์ตสวิกเกอร์ บทความที่ดีและรับความคิดเห็นจาก OpenResty และ Nginx (แม้ว่าความคิดเห็นที่ว่ามีเพียงส่วนเล็ก ๆ ของหน่วยความจำเท่านั้นที่ถูกเปิดเผยนั้นไม่ถูกต้องและทำให้เข้าใจผิด แต่จะถูกกำหนดโดยความยาวของบรรทัดที่ตามหลังไบต์ว่างและในกรณีที่ไม่มีข้อ จำกัด ที่ชัดเจนใน ความยาวสามารถควบคุมได้โดยผู้โจมตี)
แล้วอะไรคือข้อผิดพลาดและสิ่งที่สามารถทำได้เพื่อป้องกันมัน?
มีข้อผิดพลาดใน nginx หรือไม่? ใช่ มันเป็นเพราะว่าเนื้อหาหน่วยความจำรั่วถือเป็นข้อผิดพลาดในทุกกรณี
มีข้อผิดพลาดใน OpenResty หรือไม่? ใช่ อย่างน้อยปัญหาด้านความปลอดภัยของฟังก์ชันที่นำเสนอโดย OpenResty ยังไม่ได้รับการตรวจสอบและจัดทำเป็นเอกสาร
มีข้อผิดพลาดในการกำหนดค่า / การใช้งานกับ OpenResty หรือไม่ ใช่ เนื่องจากหากไม่มีข้อความที่ชัดเจน จึงมีการตั้งสมมติฐานที่ไม่ได้รับการยืนยันเกี่ยวกับความปลอดภัยของฟังก์ชันการใช้งาน
ข้อบกพร่องใดต่อไปนี้เป็นช่องโหว่ด้านความปลอดภัยพร้อมเงินรางวัล 10000 ดอลลาร์ สำหรับเรา โดยทั่วไปสิ่งนี้ไม่สำคัญ ในซอฟต์แวร์ใดๆ โดยเฉพาะอย่างยิ่งที่จุดบรรจบกันของส่วนประกอบต่างๆ โดยเฉพาะอย่างยิ่งซอฟต์แวร์ที่จัดทำโดยโครงการและนักพัฒนาที่แตกต่างกัน ไม่มีใครสามารถรับประกันได้ว่าคุณลักษณะทั้งหมดของงานของตนเป็นที่รู้จักและบันทึกไว้ และไม่มีข้อผิดพลาด ดังนั้นช่องโหว่ด้านความปลอดภัยใดๆ จะเกิดขึ้นตรงจุดที่ส่งผลต่อความปลอดภัย
ไม่ว่าในกรณีใด ถือเป็นแนวปฏิบัติที่ดีที่จะทำให้ข้อมูลอินพุตที่อยู่ในโมดูล/API ภายนอกเป็นมาตรฐานหรือจำกัด/กรองให้ได้มากที่สุดเท่าที่จะเป็นไปได้ เว้นแต่จะมีคำแนะนำที่ชัดเจนและความเข้าใจที่ชัดเจนว่าไม่จำเป็น
พิมพ์ผิด
จากประสบการณ์ เพื่อรักษาความบริสุทธิ์ของภาษา
รางวัลบั๊ก - การแข่งขันล่าแมลง
รายงานข้อผิดพลาด - การแจ้งเตือนข้อผิดพลาด
เปลี่ยนเส้นทาง - การเปลี่ยนเส้นทาง
โอเพ่นซอร์ส - โอเพ่นซอร์ส
erratum - ทำงานกับข้อผิดพลาด
ที่มา: will.com
