เกี่ยวกับช่องโหว่หนึ่งใน...

เกี่ยวกับช่องโหว่หนึ่งใน...

หนึ่งปีที่ผ่านมา 21 มีนาคม 2019 เวลา โปรแกรมรางวัลบั๊ก Mail.Ru สิ่งที่ดีมากมาถึง HackerOne รายงานข้อผิดพลาด จาก แม็กซ์ซาร์. เมื่อแนะนำศูนย์ไบต์ (ASCII 0) ลงในพารามิเตอร์ POST ของหนึ่งในคำขอ Webmail API ที่ส่งคืนการเปลี่ยนเส้นทาง HTTP ชิ้นส่วนของหน่วยความจำที่ไม่ได้เตรียมใช้งานจะมองเห็นได้ในข้อมูลการเปลี่ยนเส้นทาง ซึ่งชิ้นส่วนจากพารามิเตอร์ GET และส่วนหัวของคำขออื่น ๆ ไปยัง เซิร์ฟเวอร์เดียวกัน

นี่เป็นช่องโหว่ที่สำคัญเนื่องจาก... คำขอยังมีคุกกี้เซสชันด้วย ไม่กี่ชั่วโมงต่อมามีการแก้ไขชั่วคราวที่กรองไบต์เป็นศูนย์ (ตามที่ปรากฏในภายหลังซึ่งไม่เพียงพอเนื่องจากยังมีความเป็นไปได้ที่จะฉีด CRLF / ASCII 13, 10 ซึ่งช่วยให้คุณสามารถจัดการส่วนหัวและ ข้อมูลการตอบสนอง HTTP สิ่งนี้มีความสำคัญน้อยกว่า แต่ก็ยังไม่เป็นที่พอใจ) ในเวลาเดียวกัน ปัญหาก็ถูกถ่ายโอนไปยังนักวิเคราะห์ความปลอดภัยและนักพัฒนา เพื่อค้นหาและกำจัดสาเหตุของจุดบกพร่อง

เมล Mail.ru เป็นแอปพลิเคชันที่ซับซ้อนมาก ส่วนประกอบส่วนหน้า/ส่วนหลังที่แตกต่างกันจำนวนมาก ทั้งโอเพ่นซอร์ส (ขอบคุณมากสำหรับนักพัฒนาซอฟต์แวร์ฟรีทุกคน) และที่พัฒนาขึ้นภายในองค์กรสามารถมีส่วนร่วมในการสร้างการตอบสนองได้ เราจัดการเพื่อแยกส่วนประกอบทั้งหมดยกเว้น nginx และ openresty และแปลปัญหาก่อนการโทร ngx.req.set_uri() ในสคริปต์ OpenResty ที่ไม่ทำงานตามที่คาดไว้ (การแทรกไบต์ว่างหรือการป้อนบรรทัดผ่านพารามิเตอร์ GET พร้อมการเขียนใหม่ใน ngx_http_rewrite_module ซึ่งตามเอกสารประกอบถูกใช้และดูเหมือนว่าจะทำงานในลักษณะเดียวกันทุกประการ ไม่ทำงาน). ผลที่ตามมาที่เป็นไปได้ถูกกำจัดออกไป เพิ่มการกรองอย่างเคร่งครัดที่สุดเท่าที่จะเป็นไปได้ และการกรองได้รับการตรวจสอบเพื่อกำจัดเวกเตอร์ที่เป็นไปได้ทั้งหมด แต่กลไกที่นำไปสู่การรั่วไหลของเนื้อหาหน่วยความจำยังคงเป็นปริศนา หนึ่งเดือนต่อมา รายงานข้อบกพร่องถูกปิดเมื่อได้รับการแก้ไขแล้ว และการวิเคราะห์สาเหตุของข้อบกพร่องถูกเลื่อนออกไปจนกว่าจะถึงเวลาที่ดีขึ้น

OpenResty เป็นปลั๊กอินยอดนิยมที่ให้คุณเขียนสคริปต์ Lua ภายใน nginx และใช้ในโครงการ Mail.ru หลายโครงการ ดังนั้นปัญหาจึงไม่ถือว่าได้รับการแก้ไข และหลังจากนั้นสักพัก ในที่สุดพวกเขาก็กลับมาหามันอีกครั้งเพื่อทำความเข้าใจเหตุผลที่แท้จริง ผลที่ตามมาที่อาจเกิดขึ้น และให้คำแนะนำแก่นักพัฒนา มีส่วนร่วมในการขุดค้นซอร์สโค้ด เดนิส เดนิซอฟ и นิโคไล เออร์มิชกิน. ปรากฎว่า:

  • ใน nginx เมื่อใช้การเขียนซ้ำด้วยข้อมูลผู้ใช้ มีความเป็นไปได้ที่ไดเรกทอรีจะข้ามผ่าน (และอาจเป็น SSRF) ในการกำหนดค่าบางอย่าง แต่นี่เป็นข้อเท็จจริงที่ทราบแล้วและควรตรวจพบโดยเครื่องวิเคราะห์การกำหนดค่าแบบคงที่ใน Nginx ขยาย и กิ๊กซี่ จาก 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 ก็เผยแพร่ รุ่น 1.15.8.3ซึ่งเพิ่มการตรวจสอบ URI

พอร์ตสวิกเกอร์ ที่ผมเขียน บทความที่ดีและรับความคิดเห็นจาก OpenResty และ Nginx (แม้ว่าความคิดเห็นที่ว่ามีเพียงส่วนเล็ก ๆ ของหน่วยความจำเท่านั้นที่ถูกเปิดเผยนั้นไม่ถูกต้องและทำให้เข้าใจผิด แต่จะถูกกำหนดโดยความยาวของบรรทัดที่ตามหลังไบต์ว่างและในกรณีที่ไม่มีข้อ จำกัด ที่ชัดเจนใน ความยาวสามารถควบคุมได้โดยผู้โจมตี)

แล้วอะไรคือข้อผิดพลาดและสิ่งที่สามารถทำได้เพื่อป้องกันมัน?

มีข้อผิดพลาดใน nginx หรือไม่? ใช่ มันเป็นเพราะว่าเนื้อหาหน่วยความจำรั่วถือเป็นข้อผิดพลาดในทุกกรณี

มีข้อผิดพลาดใน OpenResty หรือไม่? ใช่ อย่างน้อยปัญหาด้านความปลอดภัยของฟังก์ชันที่นำเสนอโดย OpenResty ยังไม่ได้รับการตรวจสอบและจัดทำเป็นเอกสาร

มีข้อผิดพลาดในการกำหนดค่า / การใช้งานกับ OpenResty หรือไม่ ใช่ เนื่องจากหากไม่มีข้อความที่ชัดเจน จึงมีการตั้งสมมติฐานที่ไม่ได้รับการยืนยันเกี่ยวกับความปลอดภัยของฟังก์ชันการใช้งาน

ข้อบกพร่องใดต่อไปนี้เป็นช่องโหว่ด้านความปลอดภัยพร้อมเงินรางวัล 10000 ดอลลาร์ สำหรับเรา โดยทั่วไปสิ่งนี้ไม่สำคัญ ในซอฟต์แวร์ใดๆ โดยเฉพาะอย่างยิ่งที่จุดบรรจบกันของส่วนประกอบต่างๆ โดยเฉพาะอย่างยิ่งซอฟต์แวร์ที่จัดทำโดยโครงการและนักพัฒนาที่แตกต่างกัน ไม่มีใครสามารถรับประกันได้ว่าคุณลักษณะทั้งหมดของงานของตนเป็นที่รู้จักและบันทึกไว้ และไม่มีข้อผิดพลาด ดังนั้นช่องโหว่ด้านความปลอดภัยใดๆ จะเกิดขึ้นตรงจุดที่ส่งผลต่อความปลอดภัย

ไม่ว่าในกรณีใด ถือเป็นแนวปฏิบัติที่ดีที่จะทำให้ข้อมูลอินพุตที่อยู่ในโมดูล/API ภายนอกเป็นมาตรฐานหรือจำกัด/กรองให้ได้มากที่สุดเท่าที่จะเป็นไปได้ เว้นแต่จะมีคำแนะนำที่ชัดเจนและความเข้าใจที่ชัดเจนว่าไม่จำเป็น

พิมพ์ผิด

จากประสบการณ์ บทความก่อนหน้านี้เพื่อรักษาความบริสุทธิ์ของภาษา

รางวัลบั๊ก - การแข่งขันล่าแมลง
รายงานข้อผิดพลาด - การแจ้งเตือนข้อผิดพลาด
เปลี่ยนเส้นทาง - การเปลี่ยนเส้นทาง
โอเพ่นซอร์ส - โอเพ่นซอร์ส
erratum - ทำงานกับข้อผิดพลาด

ที่มา: will.com

เพิ่มความคิดเห็น