บิต setuidสามารถตั้งค่าในแฟ้มที่ปฏิบัติการเพื่อที่ว่าเมื่อเรียกใช้โปรแกรมจะมีสิทธิ์ของเจ้าของไฟล์แทนของผู้ใช้จริงที่ว่าพวกเขาจะแตกต่างกัน นี่คือความแตกต่างระหว่างuid ที่มีประสิทธิภาพ (id ผู้ใช้) และuid จริง
ยูทิลิตี้ทั่วไปบางอย่างเช่นเป็นpasswd
เจ้าของรูทและกำหนดค่าด้วยวิธีนี้ไม่จำเป็น (จำเป็นpasswd
ต้องเข้าถึง/etc/shadow
ซึ่งรูทสามารถอ่านได้เท่านั้น)
กลยุทธ์ที่ดีที่สุดเมื่อทำสิ่งนี้คือทำสิ่งที่คุณต้องทำในฐานะผู้ใช้ระดับสูงทันทีจากนั้นลดสิทธิพิเศษเพื่อให้บั๊กหรือการใช้งานในทางที่ผิดมีโอกาสเกิดขึ้นน้อยลงในขณะที่รันรูท เมื่อต้องการทำเช่นนี้คุณตั้งค่าuid ที่มีประสิทธิภาพของกระบวนการเป็นuid ที่แท้จริง ใน POSIX C:
#define _POSIX_C_SOURCE 200112L // Needed with glibc (e.g., linux).
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void report (uid_t real) {
printf (
"Real UID: %d Effective UID: %d\n",
real,
geteuid()
);
}
int main (void) {
uid_t real = getuid();
report(real);
seteuid(real);
report(real);
return 0;
}
ฟังก์ชั่นที่เกี่ยวข้องซึ่งควรจะมีความเทียบเท่าในภาษาระดับสูงกว่ามากที่สุดหากใช้โดยทั่วไปในระบบ POSIX:
getuid()
: รับuid จริง
geteuid()
: รับที่มีประสิทธิภาพ UID
seteuid()
: ตั้งค่าที่มีประสิทธิภาพ UID
คุณไม่สามารถทำอะไรกับอันสุดท้ายที่ไม่เหมาะสมกับ uid จริงยกเว้นในกรณีที่บิต setuid ถูกตั้งค่าไว้ในไฟล์ที่เรียกใช้งานได้ gcc test.c -o testuid
ดังนั้นลองนี้รวบรวม จากนั้นคุณต้องมีสิทธิ์:
chown root testuid
chmod u+s testuid
อันสุดท้ายตั้งค่าบิต setuid หากตอนนี้คุณทำงาน./testuid
ในฐานะผู้ใช้ปกติคุณจะเห็นกระบวนการโดยค่าเริ่มต้นทำงานกับ uid 0 ที่มีประสิทธิภาพ, รูท
แล้วสคริปต์ล่ะ
สิ่งนี้แตกต่างจากแพลตฟอร์มหนึ่งไปอีกแพลตฟอร์มแต่บน Linux สิ่งที่ต้องใช้ล่ามรวมถึง bytecode ไม่สามารถใช้บิต setuid ได้จนกว่าจะมีการตั้งค่าไว้ที่ล่าม นี่เป็นสคริปต์ Perl ง่าย ๆ ที่เลียนแบบรหัส C ด้านบน:
#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);
print "Real UID: $< Effective UID: $>\n";
$> = $<; # Not an ASCII art greedy face, but genuine perl...
print "Real UID: $< Effective UID: $>\n";
True เป็น * ราก nixy, perl มีการสร้างในตัวแปรพิเศษสำหรับ uid ที่มีประสิทธิภาพ ( $>
) และ uid จริง ( $<
) แต่ถ้าคุณลองแบบเดียวกันchown
และchmod
ใช้กับไฟล์ที่คอมไพล์แล้ว (จาก C ตัวอย่างก่อนหน้า) มันจะไม่สร้างความแตกต่างเลย สคริปต์ไม่สามารถรับสิทธิ์ได้
คำตอบนี้คือการใช้ setuid binary เพื่อรันสคริปต์:
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
if (argc < 2) {
puts("Path to perl script required.");
return 1;
}
const char *perl = "perl";
argv[0] = (char*)perl;
return execv("/usr/bin/perl", argv);
}
คอมไพล์นี้แล้วgcc --std=c99 whatever.c -o perlsuid
chown root perlsuid && chmod u+s perlsuid
ตอนนี้คุณสามารถรันสคริปต์ perl ใด ๆด้วย uid ที่มีประสิทธิภาพของ 0 ไม่ว่าใครจะเป็นเจ้าของ
กลยุทธ์ที่คล้ายกันจะทำงานกับ php, python และอื่น ๆ แต่ ...
# Think hard, very important:
>_< # Genuine ASCII art "Oh tish!" face
ได้โปรดได้โปรดอย่าปล่อยชนิดของสิ่งนี้โกหกรอบ เป็นไปได้ว่าคุณต้องการรวบรวมในชื่อของสคริปต์เป็นเส้นทางที่แน่นอนเช่นแทนที่รหัสทั้งหมดmain()
ด้วย:
const char *args[] = { "perl", "/opt/suid_scripts/whatever.pl" }
return execv("/usr/bin/perl", (char * const*)args);
พวกเขาทำให้แน่ใจ/opt/suid_scripts
และทุกอย่างในนั้นเป็นแบบอ่านอย่างเดียวสำหรับผู้ใช้ที่ไม่ใช่รูท whatever.pl
มิฉะนั้นคนที่สามารถแลกเปลี่ยนในสิ่งที่สำหรับ
นอกจากนี้ระวังว่าภาษาสคริปต์ช่วยให้หลายตัวแปรสภาพแวดล้อมที่มีการเปลี่ยนแปลงวิธีที่พวกเขาดำเนินการสคริปต์ ตัวอย่างเช่นตัวแปรสภาพแวดล้อมอาจทำให้ไลบรารีที่จัดหาโดยผู้เรียกถูกโหลดซึ่งอนุญาตให้ผู้เรียกใช้เรียกใช้โค้ดโดยพลการในฐานะรูท ดังนั้นถ้าคุณไม่ทราบว่าทั้งล่ามและสคริปต์ที่ตัวเองมีประสิทธิภาพกับทุกตัวแปรสภาพแวดล้อมที่เป็นไปได้ไม่ทำเช่นนี้
ดังนั้นฉันควรทำอย่างไรดี
เป็นวิธีที่ปลอดภัยเพื่อให้ผู้ใช้ที่ไม่ใช่รากเพื่อเรียกใช้สคริปต์เป็นรากคือการเพิ่มsudosudo /path/to/script
กฎและมีการทำงานของผู้ใช้ Sudo รวบรวมตัวแปรสภาพแวดล้อมส่วนใหญ่และยังช่วยให้ผู้ดูแลระบบสามารถเลือกผู้ที่สามารถเรียกใช้คำสั่งและสิ่งที่ขัดแย้ง ดูวิธีรันโปรแกรมเฉพาะในฐานะรูทโดยไม่ต้องใส่รหัสผ่าน? สำหรับตัวอย่าง
-privileged
เชลล์และหากเรียกจากสคริปต์ที่รับผิดชอบสามารถเรียกใช้suid root
วิธีนั้นได้อย่างปลอดภัย ฉันกลัวว่าความคิดของสคริปที่รับผิดชอบนั้นเป็นเรื่องเล็ก ๆ น้อย ๆ ในโลกแห่งความเป็นจริง อย่างไรก็ตามมันอาจจะคุ้มค่าที่จะกล่าวถึงความสำคัญของการหลีกเลี่ยงการเขียนทุกชนิดถ้าเป็นไปได้ทั้งหมดในขณะที่สิทธิ์จะเพิ่มขึ้น ...