Linux จะเพิกเฉยต่อบิต setuid on ที่ executables ที่ถูกตีความทั้งหมด (เช่น executables ที่เริ่มต้นด้วย#!
บรรทัด) comp.unix.questions คำถามที่พบบ่อยอธิบายปัญหาด้านความปลอดภัยที่มีเชลล์สคริปต์ setuid ปัญหาเหล่านี้มีสองประเภท: ที่เกี่ยวข้องกับ shebang และที่เกี่ยวข้องกับเชลล์ ฉันไปดูรายละเอียดเพิ่มเติมด้านล่าง
หากคุณไม่สนใจเกี่ยวกับความปลอดภัยและต้องการอนุญาตสคริปต์ setuid ใน Linux คุณจะต้องแก้ไขเคอร์เนล ในฐานะของเมล็ด 3.x ฉันคิดว่าคุณต้องเพิ่มการเรียกไปinstall_exec_creds
ยังload_script
ฟังก์ชันก่อนเรียกใช้open_exec
แต่ฉันยังไม่ได้ทดสอบ
ตั้งค่า shebang
มีสภาพการแข่งขันที่เป็นไปตามวิธีที่ shebang ( #!
) ถูกนำไปใช้โดยทั่วไป:
#!
เคอร์เนลเปิดปฏิบัติการและพบว่ามันเริ่มต้นด้วย
- เคอร์เนลปิดการปฏิบัติการและเปิดล่ามแทน
- เคอร์เนลแทรกเส้นทางไปยังสคริปต์ไปยังรายการอาร์กิวเมนต์ (ตาม
argv[1]
) และดำเนินการล่าม
หากอนุญาตสคริปต์ setuid ด้วยการนำไปใช้งานผู้โจมตีสามารถเรียกใช้สคริปต์ที่กำหนดเองได้โดยการสร้างลิงก์สัญลักษณ์ไปยังสคริปต์ setuid ที่มีอยู่ดำเนินการและจัดเรียงเพื่อเปลี่ยนการเชื่อมโยงหลังจากเคอร์เนลทำตามขั้นตอนที่ 1 และก่อนที่ล่ามจะเข้ามา เปิดอาร์กิวเมนต์แรก ด้วยเหตุผลนี้unices ส่วนใหญ่จึงไม่สนใจบิต setuidเมื่อตรวจพบ shebang
วิธีหนึ่งที่จะทำให้การใช้งานนี้ปลอดภัยสำหรับเคอร์เนลเพื่อล็อคไฟล์สคริปต์จนกว่าล่ามจะเปิดขึ้น (โปรดทราบว่าสิ่งนี้จะต้องป้องกันไม่เพียง แต่การยกเลิกการเชื่อมโยงหรือเขียนทับไฟล์ แต่ยังเปลี่ยนชื่อไดเรกทอรีใด ๆ ในเส้นทางด้วย) แต่ระบบยูนิกซ์มีแนวโน้มที่จะห่างไกลจากคำสั่งบังคับล็อคและลิงก์สัญลักษณ์จะทำให้คุณสมบัติการล็อคถูกต้องโดยเฉพาะอย่างยิ่งยากและรุกราน ฉันไม่คิดว่าจะมีใครทำแบบนี้
ไม่กี่ระบบยูนิกซ์ (ส่วนใหญ่ OpenBSD, NetBSD และ Mac OS X ซึ่งทั้งหมดนี้จำเป็นต้องมีการตั้งค่าเคอร์เนลที่จะเปิดใช้งาน) ใช้shebang setuid ที่เชื่อถือได้โดยใช้คุณสมบัติเพิ่มเติม: เส้นทางหมายถึงไฟล์ที่เปิดอยู่แล้วในไฟล์อธิบายN (เพื่อเปิดเป็น เทียบเท่ากับ) ระบบยูนิกซ์หลายระบบ (รวมถึง Linux) มีแต่ไม่มีสคริปต์ setuid/dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
#!
เคอร์เนลเปิดปฏิบัติการและพบว่ามันเริ่มต้นด้วย สมมุติว่าไฟล์ descriptor ของไฟล์สั่งการเป็น 3
- เคอร์เนลเปิดล่าม
- เคอร์เนลแทรก
/dev/fd/3
รายการอาร์กิวเมนต์ (ตามargv[1]
) และดำเนินการล่าม
หน้า shebang Sven Mascheck ของมีจำนวนมากของข้อมูลเกี่ยวกับ shebang ทั่ว Unices รวมทั้งการสนับสนุน setuid
ล่าม Setuid
สมมติว่าคุณมีการจัดการเพื่อให้โปรแกรมของคุณทำงานเป็นรูทไม่ว่าจะเป็นเพราะระบบปฏิบัติการของคุณรองรับ setuid shebang หรือเพราะคุณใช้โปรแกรมแปลงไฟล์ไบนารีดั้งเดิม (เช่นsudo
) คุณได้เปิดช่องรักษาความปลอดภัยหรือไม่? บางที ปัญหาที่นี่ไม่เกี่ยวกับการแปลโปรแกรมที่คอมไพล์แล้ว ปัญหาคือว่าระบบรันไทม์ของคุณทำงานอย่างปลอดภัยหรือไม่หากดำเนินการด้วยสิทธิ์พิเศษ
ปฏิบัติการไบนารีเนทีฟแบบไดนามิกใด ๆ ที่เชื่อมโยงแบบไดนามิกอยู่ในวิธีที่ตีความโดยตัวโหลดแบบไดนามิก (เช่น/lib/ld.so
) ซึ่งโหลดไลบรารีแบบไดนามิกที่โปรแกรมต้องการ ในหลาย ๆ unices คุณสามารถกำหนดค่าพา ธ การค้นหาสำหรับไลบรารีแบบไดนามิกผ่านสภาพแวดล้อม ( LD_LIBRARY_PATH
เป็นชื่อทั่วไปสำหรับตัวแปรสภาพแวดล้อม) และแม้แต่โหลดไลบรารีเพิ่มเติมลงในไบนารีที่ดำเนินการทั้งหมด ( LD_PRELOAD
) ทรงของโปรแกรมสามารถรันโค้ดในบริบทของโปรแกรมนั้นโดยการวางเป็นพิเศษที่สร้างขึ้นlibc.so
ใน$LD_LIBRARY_PATH
(ในหมู่กลยุทธ์อื่น ๆ ) ระบบมีสติทั้งหมดละเว้นLD_*
ตัวแปรในไฟล์เรียกทำงาน setuid
ในเชลล์เช่น sh, csh และอนุพันธ์ตัวแปรสภาพแวดล้อมจะกลายเป็นพารามิเตอร์ของเชลล์โดยอัตโนมัติ ผ่านพารามิเตอร์เช่นPATH
, IFS
และอื่น ๆ อีกมากมายทรงของสคริปต์มีโอกาสมากมายที่จะรันโค้ดในบริบทเชลล์สคริปต์ของ เชลล์บางตัวตั้งค่าตัวแปรเหล่านี้ให้เป็นค่าเริ่มต้นที่มีเหตุผลหากตรวจพบว่าสคริปต์นั้นได้รับการเรียกใช้ด้วยสิทธิ์ แต่ฉันไม่รู้ว่ามีการใช้งานเฉพาะที่ฉันเชื่อถือ
สภาพแวดล้อมรันไทม์ส่วนใหญ่ (ไม่ว่าจะเป็น native, bytecode หรือตีความ) มีคุณสมบัติคล้ายกัน ไม่กี่ข้อควรระวังพิเศษใน setuid executables แม้ว่าคนที่เรียกใช้รหัสพื้นเมืองมักจะไม่ทำอะไรที่น่าสนใจกว่าการเชื่อมโยงแบบไดนามิก (ซึ่งจะใช้ความระมัดระวัง)
Perlเป็นข้อยกเว้นที่น่าสังเกต มันชัดเจนสนับสนุนสคริปต์ setuidในทางที่ปลอดภัย ในความเป็นจริงสคริปต์ของคุณสามารถเรียกใช้ setuid แม้ว่าระบบปฏิบัติการของคุณจะละเว้นบิต setuid ในสคริปต์ นี่เป็นเพราะ Perl มาพร้อมกับผู้ช่วยรูท setuid ที่ดำเนินการตรวจสอบที่จำเป็นและเรียกใช้ล่ามในสคริปต์ที่ต้องการด้วยสิทธิ์พิเศษที่ต้องการ นี่คือคำอธิบายในคู่มือperlsec มันเคยเป็นสคริปต์ Perl setuid ที่จำเป็น#!/usr/bin/suidperl -wT
แทน#!/usr/bin/perl -wT
แต่ในระบบที่ทันสมัยส่วนใหญ่#!/usr/bin/perl -wT
ก็เพียงพอแล้ว
โปรดทราบว่าการใช้ไบนารีพื้นเมืองเสื้อคลุมไม่ทำอะไรเลยในตัวเองเพื่อป้องกันไม่ให้ปัญหาเหล่านี้ ในความเป็นจริงมันสามารถทำให้สถานการณ์แย่ลงเพราะอาจป้องกันไม่ให้สภาพแวดล้อมรันไทม์ของคุณตรวจพบว่ามีการเรียกใช้ด้วยสิทธิ์และข้ามการกำหนดค่ารันไทม์
native wrapper แบบไบนารีสามารถสร้างเชลล์สคริปต์ให้ปลอดภัยหาก wrapper สร้างสภาวะแวดล้อมที่เหมาะสม สคริปต์จะต้องระมัดระวังไม่ให้สมมติฐานมากเกินไป (เช่นเกี่ยวกับไดเรกทอรีปัจจุบัน) แต่สิ่งนี้จะเกิดขึ้น คุณสามารถใช้ sudo สำหรับสิ่งนี้หากว่ามันถูกตั้งค่าเพื่อฆ่าเชื้อในสภาพแวดล้อม ตัวแปรการขึ้นบัญชีดำนั้นเกิดข้อผิดพลาดได้ง่าย ด้วย sudo ตรวจสอบให้แน่ใจว่าenv_reset
มีเปิดตัวเลือกที่setenv
จะปิดและที่env_file
และenv_keep
มีเพียงตัวแปรที่ไม่มีพิษมีภัย
TL, DR:
- Setuid shebang ไม่ปลอดภัย แต่มักจะเพิกเฉย
- หากคุณรันโปรแกรมที่มีสิทธิ์ใช้งาน (ไม่ว่าจะผ่าน sudo หรือ setuid) ให้เขียนโค้ดเนทีฟหรือ perl หรือเริ่มโปรแกรมด้วย wrapper ที่ฆ่าเชื้อสภาพแวดล้อม (เช่น sudo พร้อม
env_reset
ตัวเลือก)
¹ การสนทนานี้ใช้อย่างเท่าเทียมกันถ้าคุณแทน“setgid” สำหรับ“setuid”; ทั้งคู่ถูกละเว้นโดยเคอร์เนล Linux บนสคริปต์