رفتن به محتوا
LoopX

دسترسی‌های ویژه

توی این درس یاد می‌گیری علاوه بر rwx سه بیت ویژه‌ی دسترسی هم هست: setuid (برنامه با هویت صاحبش اجرا شود)، setgid (فایل‌های جدید یک پوشه گروه پوشه را به ارث ببرند) و sticky bit (در پوشه‌ی مشترک فقط صاحب فایل بتواند آن را پاک کند). می‌بینی چرا passwd با اینکه کاربر عادی اجرایش می‌کند می‌تواند /etc/shadow را عوض کند، چرا در /tmp نمی‌توانی فایل دیگران را پاک کنی، و آن‌ها را با chmod g+s، chmod +t و حالت چهاررقمی (2775، 1777) تنظیم می‌کنی. تمرین: یک پوشه‌ی مشترک تیمی می‌سازی که فایل‌هایش گروه پوشه را به ارث ببرند.

۱. فایل /etc/shadow (رمزهای کاربران) را فقط root می‌تواند بنویسد. ولی هر کاربر عادی با passwd رمز خودش را عوض می‌کند. چطور؟

۲. در یک پوشه‌ی مشترک تیمی، فایلی که علی می‌سازد گروه اصلی خودش (ali) را می‌گیرد، نه گروه تیم؛ پس همکارش رضا (که عضو گروه تیم است) نمی‌تواند ویرایشش کند.

۳. در /tmp همه فایل می‌سازند و روی پوشه حق w دارند؛ طبق درس قبل یعنی هر کس می‌تواند هر فایلی را پاک کند. ولی در واقع نمی‌تواند. چرا؟

جواب هر سه، سه بیت ویژه‌اند.

تشبیه: سه برچسب ویژه روی درهای یک ساختمان

Section titled “تشبیه: سه برچسب ویژه روی درهای یک ساختمان”
  • setuid مثل «نمایندگی رسمی» است: کارمند فقط برای یک کار مشخص، به‌جای مدیر امضا می‌کند؛ نه برای هر کاری.
  • setgid مثل «سربرگ تیم» است: هر برگه‌ای که در این اتاق نوشته شود، خودکار سربرگ تیم را می‌خورد.
  • sticky bit مثل «رختکن» است: همه می‌توانند کیف بگذارند، ولی فقط صاحب هر کیف می‌تواند آن را بردارد.
سه بیت ویژه در خروجی ls -l: حرف s یا t جای x می‌نشیند (مالک، گروه یا بقیه). در حالت عددی، یک رقم چهارم در ابتدای عدد می‌آید: ۴، ۲ و ۱.
بیت عدد در ls -l روی فایل اجرایی روی پوشه
setuid 4000 s جای x مالک با هویت مالک فایل اجرا می‌شود روی لینوکس معنایی ندارد
setgid 2000 s جای x گروه با گروه فایل اجرا می‌شود فایل‌ها و پوشه‌های جدید گروه پوشه را به ارث می‌برند
sticky 1000 t جای x بقیه (امروز بی‌اثر) فقط مالکِ فایل (یا مالک پوشه، یا root) می‌تواند آن را پاک یا هم‌نام‌گذاری کند

اگر حرف بزرگ (S یا T) ببینی یعنی بیت روشن است ولی x همان‌جا خاموش است؛ معمولاً نشانه‌ی یک اشتباه است (مثال ۶ و «اشتباهات رایج»).

⚡ بررسی سریع

در drwxrwxrwt کدام حرف نشان‌دهنده‌ی sticky bit است؟

برای آزمایش به چند کاربر لازم داریم: dev1 (برای passwd) و bob، carol و dave. گروه team را برای bob و carol می‌سازیم (dave عضو نیست). همه در پایان درس پاک می‌شوند.

مثال ۱: بیت‌های ویژه را روی سیستم واقعی ببین

Section titled “مثال ۱: بیت‌های ویژه را روی سیستم واقعی ببین”
Terminal window
ls -l /usr/bin/passwd /usr/bin/sudo /usr/bin/crontab
echo "--- پوشه‌ها:"
ls -ld /tmp /var/tmp /var/mail
echo "--- عددی (چهار رقم؛ رقم اول بیت‌های ویژه):"
stat -c '%a %A %n' /usr/bin/passwd /usr/bin/crontab /var/mail /tmp
خروجی
-rwxr-sr-x 1 root crontab 68072 Mar 31 2024 /usr/bin/crontab
-rwsr-xr-x 1 root root 72056 May 30 2024 /usr/bin/passwd
-rwsr-xr-x 1 root root 335120 Sep 21 18:37 /usr/bin/sudo
--- پوشه‌ها:
drwxrwxrwt 1 root root 4096 Oct 3 20:51 /tmp
drwxrwsr-x 2 root mail 4096 Sep 11 02:06 /var/mail
drwxrwxrwt 1 root root 4096 Oct 3 20:44 /var/tmp
--- عددی (چهار رقم؛ رقم اول بیت‌های ویژه):
4755 -rwsr-xr-x /usr/bin/passwd
2755 -rwxr-sr-x /usr/bin/crontab
2775 drwxrwsr-x /var/mail
1777 drwxrwxrwt /tmp
  • passwd و sudo: -rwsr-xr-x، یعنی s جای x مالک (setuid) و مالکشان root است؛ عددشان 4755.
  • crontab: -rwxr-sr-x، s جای x گروه (setgid) با گروه crontab؛ عدد 2755.
  • /var/mail: پوشه‌ی drwxrwsr-x با گروه mail؛ setgid روی پوشه، برای اینکه صندوق‌های ایمیل همه گروه mail بگیرند (2775).
  • /tmp و /var/tmp: drwxrwxrwt، t جای x بقیه (sticky) و عدد 1777.

مثال ۲: setuid در عمل، چرا passwd می‌تواند رمز را عوض کند؟

Section titled “مثال ۲: setuid در عمل، چرا passwd می‌تواند رمز را عوض کند؟”

یک کاربر آزمایشی می‌سازم و دو تابع کمکی ترمینال مجازی را (مثل درس قبل) تعریف می‌کنم:

Terminal window
PW=lab-pass
sudo useradd -m -s /bin/bash dev1
echo "dev1:$PW" | sudo chpasswd
run_in_tmux() { tmux -u kill-server 2>/dev/null; tmux -u new-session -d -s t -x 76 -y "${TH:-24}" "$@"; sleep 1; }
screen() { tmux capture-pane -t t -p | sed -e :a -e '/^[[:space:]]*$/{$d;N;ba' -e '}'; }
fp() { sudo awk -F: '$1=="dev1"{print $2}' /etc/shadow | sha256sum | cut -c1-8; }
echo "آماده شد. اثرانگشت (fingerprint) فیلد رمز dev1 در /etc/shadow: $(fp)"
خروجی
آماده شد. اثرانگشت (fingerprint) فیلد رمز dev1 در /etc/shadow: 3e4a92a7

fp یک اثرانگشت کوتاه از فیلد رمز او در /etc/shadow می‌گیرد، تا بدون نمایش چیزی از رمز، تغییرش را ببینیم. حالا به‌عنوان dev1 (کاربر عادی، بدون هیچ اجازه‌ای روی /etc/shadow) رمز خودش را عوض می‌کنم:

Terminal window
echo "اثرانگشت قبل: $(fp)"
run_in_tmux "bash --norc"
tmux send-keys -t t "sudo -u dev1 -i" Enter; sleep 1
tmux send-keys -t t "ls -l /usr/bin/passwd" Enter; sleep 1
tmux send-keys -t t "passwd" Enter; sleep 1
tmux send-keys -t t "$PW" Enter; sleep 1
tmux send-keys -t t "New-Pass-2026x" Enter; sleep 1
tmux send-keys -t t "New-Pass-2026x" Enter; sleep 2
screen
echo "اثرانگشت بعد: $(fp)"
خروجی
اثرانگشت قبل: 3e4a92a7
bash-5.2$ sudo -u dev1 -i
dev1@pc:~$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 72056 May 30 2024 /usr/bin/passwd
dev1@pc:~$ passwd
Changing password for dev1.
Current password:
New password:
Retype new password:
passwd: password updated successfully
dev1@pc:~$
اثرانگشت بعد: 54d57b0a

dev1 رمز را عوض کرد و فیلد او در /etc/shadow واقعاً تغییر کرد، با اینکه خودش اجازه‌ی نوشتن در آن را ندارد. راز: برنامه‌ی /usr/bin/passwd بیت setuid دارد (-rwsr-xr-x) و مالکش root است؛ پس هر کسی اجرایش کند، با هویت root اجرا می‌شود (فقط همین برنامه، فقط تا پایانش). حالا ثابت می‌کنم راز همین بیت است: یک کپی از همان برنامه می‌سازم (کپی بیت‌های ویژه را نگه نمی‌دارد) و با همان کاربر اجرا می‌کنم:

Terminal window
tmux send-keys -t t "clear" Enter
tmux send-keys -t t "cp /usr/bin/passwd ~/mypasswd; ls -l ~/mypasswd" Enter; sleep 1
tmux send-keys -t t "./mypasswd" Enter; sleep 1
tmux send-keys -t t "New-Pass-2026x" Enter; sleep 1
tmux send-keys -t t "New2-Pass-2026y" Enter; sleep 1
tmux send-keys -t t "New2-Pass-2026y" Enter; sleep 5
screen
خروجی
dev1@pc:~$ cp /usr/bin/passwd ~/mypasswd; ls -l ~/mypasswd
-rwxr-xr-x 1 dev1 dev1 72056 Oct 3 20:51 /home/dev1/mypasswd
dev1@pc:~$ ./mypasswd
Changing password for dev1.
Current password:
New password:
Retype new password:
passwd: Authentication token manipulation error
passwd: password unchanged
dev1@pc:~$

کپی، همان برنامه با همان کد است، ولی بیت s ندارد (-rwxr-xr-x، مالکش dev1): با هویت خود dev1 اجرا می‌شود و برای نوشتن در /etc/shadow شکست می‌خورد (Authentication token manipulation error). حالا کپی را به root می‌دهم و setuid را روشن می‌کنم. ترتیب مهم است: chown بیت‌های ویژه را پاک می‌کند، پس اول chown، بعد chmod u+s:

Terminal window
sudo chown root:root /home/dev1/mypasswd
sudo chmod u+s /home/dev1/mypasswd
sudo ls -l /home/dev1/mypasswd
tmux send-keys -t t "clear" Enter
tmux send-keys -t t "./mypasswd" Enter; sleep 1
tmux send-keys -t t "New-Pass-2026x" Enter; sleep 1
tmux send-keys -t t "New2-Pass-2026y" Enter; sleep 1
tmux send-keys -t t "New2-Pass-2026y" Enter; sleep 2
screen
tmux send-keys -t t "exit" Enter; sleep 1
tmux -u kill-server
خروجی
-rwsr-xr-x 1 root root 72056 Oct 3 20:51 /home/dev1/mypasswd
dev1@pc:~$ ./mypasswd
Changing password for dev1.
Current password:
New password:
Retype new password:
passwd: password updated successfully
dev1@pc:~$

با -rwsr-xr-x و مالک root، همان کپی هم کار کرد. (رمز عوض‌شده در همین آزمایش دور ریخته می‌شود.)

مثال ۳: فهرست برنامه‌های setuid و setgid با find

Section titled “مثال ۳: فهرست برنامه‌های setuid و setgid با find”

مدیر سیستم باید بداند کدام برنامه‌ها با قدرت بیشتری اجرا می‌شوند؛ هر کدام یک راه بالقوه برای حمله است. find -perm -4000 یعنی «همه‌ی بیت‌های ۴۰۰۰ روشن باشد»:

Terminal window
echo "--- برنامه‌های setuid:"
find /usr/bin /usr/sbin -perm -4000 -type f 2>/dev/null | sort
echo "--- برنامه‌های setgid:"
find /usr/bin /usr/sbin -perm -2000 -type f 2>/dev/null | sort
echo "--- شمار setuid در کل این فایل‌سیستم: $(find / -xdev -perm -4000 -type f 2>/dev/null | wc -l)"
خروجی
--- برنامه‌های setuid:
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/gpasswd
/usr/bin/mount
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/su
/usr/bin/sudo
/usr/bin/umount
--- برنامه‌های setgid:
/usr/bin/chage
/usr/bin/crontab
/usr/bin/expiry
/usr/bin/plocate
/usr/bin/ssh-agent
/usr/sbin/pam_extrausers_chkpwd
/usr/sbin/unix_chkpwd
--- شمار setuid در کل این فایل‌سیستم: 11

هر کدام کاری می‌کنند که فقط root از پس آن برمی‌آید: passwd، chsh (تغییر shell) و chfn (تغییر اطلاعات) فایل‌های /etc را عوض می‌کنند؛ mount و umount دیسک وصل می‌کنند؛ gpasswd و newgrp گروه‌ها را؛ su و sudo هم که هویت را عوض می‌کنند (درس قبل). فهرست مفصل برای هر سیستم متفاوت است؛ چیز غیرمنتظره‌ای در آن دیدی، مشکوک شو.

مثال ۴: setgid، پوشه‌ی مشترک تیمی (تمرین اصلی)

Section titled “مثال ۴: setgid، پوشه‌ی مشترک تیمی (تمرین اصلی)”

اول کاربرها و گروه را می‌سازم و پوشه‌ی /srv/project را به گروه team می‌دهم، با دسترسی 775 (اعضا بنویسند):

Terminal window
sudo groupadd team
for u in bob carol dave; do sudo useradd -m -s /bin/bash $u; done
sudo usermod -aG team bob
sudo usermod -aG team carol
echo "bob: $(id -Gn bob) | carol: $(id -Gn carol) | dave: $(id -Gn dave)"
sudo mkdir /srv/project
sudo chgrp team /srv/project
sudo chmod 775 /srv/project
ls -ld /srv/project
خروجی
bob: bob team | carol: carol team | dave: dave
drwxrwxr-x 2 root team 4096 Oct 3 20:51 /srv/project

بدون setgid: bob یک فایل و یک پوشه می‌سازد (با umask 002 که فایل‌ها برای گروه قابل‌نوشتن باشند؛ درس دسترسی‌ها) و carol سعی می‌کند فایل او را ویرایش کند:

Terminal window
echo "--- bob فایل و پوشه می‌سازد:"
sudo -u bob sh -c 'umask 002; echo "از bob" > /srv/project/notes.txt; mkdir /srv/project/docs'
ls -l /srv/project
echo "--- carol (هم‌تیمی) می‌خواهد به فایل bob اضافه کند:"
sudo -u carol sh -c 'echo "از carol" >> /srv/project/notes.txt'
خروجی
--- bob فایل و پوشه می‌سازد:
total 8
drwxrwxr-x 2 bob bob 4096 Oct 3 20:51 docs
-rw-rw-r-- 1 bob bob 9 Oct 3 20:51 notes.txt
--- carol (هم‌تیمی) می‌خواهد به فایل bob اضافه کند:
sh: 1: cannot create /srv/project/notes.txt: Permission denied

گروه هر دو آیتم bob است، نه team: گروه فایل‌های جدید همیشه گروه اصلی سازنده است. پس با اینکه carol هم‌تیمی است و فایل برای گروه نوشتنی (rw-rw-r--)، چون گروه فایل bob است و نه team، به او «بقیه» می‌گویند و فقط می‌خواند. حالا chmod g+s روی خود پوشه:

Terminal window
sudo chmod g+s /srv/project
ls -ld /srv/project
echo "--- bob دوباره فایل و پوشه می‌سازد:"
sudo -u bob sh -c 'umask 002; echo "از bob" > /srv/project/plan.txt; mkdir /srv/project/src'
ls -l /srv/project
echo "--- carol حالا می‌تواند:"
sudo -u carol sh -c 'echo "از carol" >> /srv/project/plan.txt' && cat /srv/project/plan.txt
خروجی
drwxrwsr-x 3 root team 4096 Oct 3 20:51 /srv/project
--- bob دوباره فایل و پوشه می‌سازد:
total 16
drwxrwxr-x 2 bob bob 4096 Oct 3 20:51 docs
-rw-rw-r-- 1 bob bob 9 Oct 3 20:51 notes.txt
-rw-rw-r-- 1 bob team 9 Oct 3 20:51 plan.txt
drwxrwsr-x 2 bob team 4096 Oct 3 20:51 src
--- carol حالا می‌تواند:
از bob
از carol

حالا هر چیز جدیدی که در پوشه ساخته می‌شود گروه team می‌گیرد (plan.txt و src)، و پوشه‌ی تازه خودش هم بیت setgid را به ارث می‌برد (drwxrwsr-x) تا قاعده در همه‌ی زیرپوشه‌ها ادامه پیدا کند. ولی setgid عطف به ماسبق نمی‌شود: notes.txt و docs که قبل‌تر ساخته شدند هنوز گروه bob دارند. درستشان می‌کنیم:

Terminal window
sudo chgrp -R team /srv/project
sudo find /srv/project -type d -exec chmod g+s {} +
find /srv/project -printf '%M %u:%g %p\n' | sort -k3
خروجی
drwxrwsr-x root:team /srv/project
drwxrwsr-x bob:team /srv/project/docs
-rw-rw-r-- bob:team /srv/project/notes.txt
-rw-rw-r-- bob:team /srv/project/plan.txt
drwxrwsr-x bob:team /srv/project/src

chgrp -R گروه همه‌ی آیتم‌های موجود را عوض کرد، و find -type d -exec chmod g+s بیت setgid را فقط به پوشه‌ها داد (چرا فقط پوشه‌ها؟ در «اشتباهات رایج»). برای اینکه بقیه‌ی کاربرها دیگر نبینند، دسترسی را به 2770 می‌برم (2 = setgid، 770 = مالک و گروه همه‌چیز، بقیه هیچ) و با dave که عضو تیم نیست امتحان می‌کنم:

Terminal window
sudo chmod 2770 /srv/project
stat -c '%a %A %U:%G %n' /srv/project
echo "--- dave (غیر عضو):"
sudo -u dave ls /srv/project
echo "--- carol (عضو):"
sudo -u carol ls /srv/project
خروجی
2770 drwxrws--- root:team /srv/project
--- dave (غیر عضو):
ls: cannot open directory '/srv/project': Permission denied
--- carol (عضو):
docs
notes.txt
plan.txt
src

مثال ۵: sticky bit، /tmp و پوشه‌ی تحویل

Section titled “مثال ۵: sticky bit، /tmp و پوشه‌ی تحویل”

در یک پوشه‌ی باز برای همه (777) بدون sticky، چون حق w روی پوشه یعنی «اجازه‌ی حذف آیتم‌های داخل»، هر کس هر فایلی را پاک می‌کند:

Terminal window
sudo mkdir /srv/drop
sudo chmod 777 /srv/drop
echo "--- بدون sticky:"
sudo -u bob sh -c 'echo "فایل bob" > /srv/drop/bob.txt'
sudo -u carol rm /srv/drop/bob.txt && echo "carol فایل bob را پاک کرد!"
echo "--- با chmod +t:"
sudo chmod +t /srv/drop
ls -ld /srv/drop
sudo -u bob sh -c 'echo "فایل bob" > /srv/drop/bob.txt'
sudo -u carol rm /srv/drop/bob.txt
sudo -u bob rm /srv/drop/bob.txt && echo "bob فایل خودش را پاک کرد"
خروجی
--- بدون sticky:
carol فایل bob را پاک کرد!
--- با chmod +t:
drwxrwxrwt 2 root root 4096 Oct 3 20:51 /srv/drop
rm: cannot remove '/srv/drop/bob.txt': Operation not permitted
bob فایل خودش را پاک کرد

با chmod +t حرف t آمد (drwxrwxrwt، همان که در /tmp دیدی) و carol دیگر نمی‌تواند فایل bob را پاک کند (Operation not permitted)، ولی bob فایل خودش را می‌تواند. فقط مالک فایل، مالک پوشه و root می‌توانند حذف یا تغییر نام بدهند. این دقیقاً چیزی است که /tmp را امن می‌کند: همه در آن می‌نویسند، ولی کسی فایل دیگران را پاک نمی‌کند.

مثال ۶: حالت عددی چهاررقمی و نمادین

Section titled “مثال ۶: حالت عددی چهاررقمی و نمادین”

بیت‌های ویژه همان رقم اول در عدد چهاررقمی‌اند (۴ = setuid، ۲ = setgid، ۱ = sticky، و جمعشان): 4755 یعنی setuid + 755، و 3770 یعنی setgid + sticky + 770:

Terminal window
mkdir -p ex6 && cd ex6
touch f; mkdir d1 d2 d3
chmod 4755 f
chmod 2775 d1
chmod 1777 d2
chmod 3770 d3
stat -c '%a %A %n' f d1 d2 d3
echo "--- برداشتن با حالت نمادین:"
chmod u-s f
chmod g-s d1
chmod -t d2
stat -c '%a %A %n' f d1 d2
خروجی
4755 -rwsr-xr-x f
2775 drwxrwsr-x d1
1777 drwxrwxrwt d2
3770 drwxrws--T d3
--- برداشتن با حالت نمادین:
755 -rwxr-xr-x f
775 drwxrwxr-x d1
777 drwxrwxrwx d2

به d3 نگاه کن: drwxrws--T. مقدار 3770 یعنی sticky روشن ولی «بقیه» اصلاً x ندارند، پس به‌جای t یک T بزرگ دیده می‌شود. (در نمادین: chmod g+s، chmod +t، chmod u+s روشن می‌کنند و - خاموش.)

پشت پرده: هویت واقعی و مؤثر

Section titled “پشت پرده: هویت واقعی و مؤثر”

هر پروسه سه شماره‌ی کاربری دارد: real UID (چه کسی راهش انداخت)، effective UID (هسته دسترسی‌ها را با این می‌سنجد) و saved UID (برای برگشتن). بیت setuid فقط در لحظه‌ی اجرا (exec) یک کار می‌کند: effective UID را برابر مالک فایل می‌گذارد. با یک نسخه‌ی setuid-root از برنامه‌ی بی‌خطر sleep ببین:

Terminal window
sudo cp /usr/bin/sleep /usr/local/bin/lx-sleep
sudo chmod u+s /usr/local/bin/lx-sleep
ls -l /usr/local/bin/lx-sleep
echo "--- dev1 آن را اجرا می‌کند و ما از بیرون نگاه می‌کنیم:"
sudo -u dev1 sh -c '/usr/local/bin/lx-sleep 20 & pid=$!; sleep 1; ps -o ruser,euser,comm -p $pid; grep "^Uid" /proc/$pid/status; kill $pid; wait $pid 2>/dev/null'
sudo rm /usr/local/bin/lx-sleep
خروجی
-rwsr-xr-x 1 root root 67944 Oct 3 20:51 /usr/local/bin/lx-sleep
--- dev1 آن را اجرا می‌کند و ما از بیرون نگاه می‌کنیم:
RUSER EUSER COMMAND
dev1 root lx-sleep
Uid: 1002 0 0 0

RUSER (واقعی) برابر dev1 است ولی EUSER (مؤثر) برابر root. در /proc/.../status هم چهار شماره‌ی Uid: به‌ترتیب real، effective، saved و filesystem هستند: 1002 0 0 0. برای همین passwd به /etc/shadow می‌نویسد، با اینکه dev1 هستی.

نکته‌ی امنیتی بزرگ: هر باگ در یک برنامه‌ی setuid-root یعنی مهاجمی که آن را اجرا کند root می‌شود. به همین دلیل:

  • برنامه‌های setuid کوچک و وسواسی نوشته می‌شوند، و مدیرها فهرستشان را (مثال ۳) می‌شناسند.
  • هرگز chmod u+s روی ویرایشگر، shell، cp، find، یا هر برنامه‌ای که بشود با آن دستور دلخواه اجرا کرد نزن.
  • لینوکس setuid را روی اسکریپت‌ها نادیده می‌گیرد (مشاهده در «اشتباهات رایج»).
  • می‌شود یک پارتیشن را با گزینه‌ی nosuid وصل کرد تا بیت setuid در آن اثری نداشته باشد (برای /tmp و پوشه‌ی آپلودها معمول است).
دستور کار
ls -l /usr/bin/passwd دیدن بیت setuid (s جای x مالک)
stat -c '%a %A %n' فایل عدد چهاررقمی و حروف
chmod u+s فایل روشن‌کردن setuid (با احتیاط!)
chmod g+s پوشه setgid: فایل‌های جدید گروه پوشه را بگیرند
chmod +t پوشه sticky bit
chmod 2775 پوشه setgid + rwxrwxr-x
chmod 1777 پوشه sticky + rwxrwxrwx (مثل /tmp)
chmod 2770 پوشه تیمی و خصوصی
find / -xdev -perm -4000 -type f همه‌ی برنامه‌های setuid
find DIR -type d -exec chmod g+s {} + setgid فقط روی پوشه‌ها
نماد در ls معنی
s (جای x مالک) setuid روشن، x هم روشن
S setuid روشن ولی x خاموش (معمولاً اشتباه)
s (جای x گروه) setgid
t (جای x بقیه) sticky
T sticky روشن ولی x بقیه خاموش
Terminal window
mkdir -p m1 && cd m1
touch t.sh && chmod 644 t.sh
chmod u+s t.sh
ls -l t.sh
echo "--- بعد از اضافه‌کردن x:"
chmod u+x t.sh
ls -l t.sh
خروجی
-rwSr--r-- 1 ali ali 0 Oct 3 20:51 t.sh
--- بعد از اضافه‌کردن x:
-rwsr--r-- 1 ali ali 0 Oct 3 20:51 t.sh

-rwSr--r-- یعنی setuid روشن است ولی x خاموش، پس بیت بی‌اثر است. راه‌حل: یا x را هم بده یا بیت را خاموش کن. (برای T مثال ۶.)

Terminal window
printf '#!/bin/sh\nid -un\n' | sudo tee /usr/local/bin/lx-who.sh > /dev/null
sudo chown root:root /usr/local/bin/lx-who.sh
sudo chmod 4755 /usr/local/bin/lx-who.sh
ls -l /usr/local/bin/lx-who.sh
echo "--- dev1 اجرا می‌کند، اسکریپت می‌گوید چه کسی است:"
sudo -u dev1 /usr/local/bin/lx-who.sh
sudo rm /usr/local/bin/lx-who.sh
خروجی
-rwsr-xr-x 1 root root 17 Oct 3 20:51 /usr/local/bin/lx-who.sh
--- dev1 اجرا می‌کند، اسکریپت می‌گوید چه کسی است:
dev1

اسکریپت s دارد و مالکش root است، ولی خروجی dev1 شد، نه root: هسته setuid را روی اسکریپت‌های تفسیری عمداً نادیده می‌گیرد (اجرای اسکریپت دو مرحله دارد و مهاجم می‌تواند بین آن‌ها فایل را عوض کند). راه‌حل: برای دادن اجازه‌ی محدود به یک اسکریپت از sudo با قاعده‌ی دقیق استفاده کن (درس قبل).

Terminal window
mkdir -p m3/proj/sub && cd m3
echo hi > proj/a.txt; echo hi > proj/sub/b.txt
chmod -R g+s proj
ls -lR proj | grep -v total
echo "--- راه‌حل: فقط پوشه‌ها بیت بگیرند:"
find proj -type f -exec chmod g-s {} +
ls -lR proj | grep -v total
خروجی
proj:
-rw-r-Sr-- 1 ali ali 3 Oct 3 20:51 a.txt
drwxr-sr-x 2 ali ali 4096 Oct 3 20:51 sub
proj/sub:
-rw-r-Sr-- 1 ali ali 3 Oct 3 20:51 b.txt
--- راه‌حل: فقط پوشه‌ها بیت بگیرند:
proj:
-rw-r--r-- 1 ali ali 3 Oct 3 20:51 a.txt
drwxr-sr-x 2 ali ali 4096 Oct 3 20:51 sub
proj/sub:
-rw-r--r-- 1 ali ali 3 Oct 3 20:51 b.txt

-R بیت را روی فایل‌ها هم گذاشت (-rw-r-Sr--)؛ بیت setgid روی فایل معنی «اجرا با گروه فایل» دارد و در فایل‌های متنی بی‌معنی و گمراه‌کننده است. راه‌حل: با find -type d -exec chmod g+s {} + فقط پوشه‌ها را علامت بزن (مثل مثال ۴).

۴) chown بیت setuid را پاک می‌کند

Section titled “۴) chown بیت setuid را پاک می‌کند”
Terminal window
mkdir -p m4 && cd m4
touch prog && chmod 4755 prog
ls -l prog
sudo chown root prog
ls -l prog
خروجی
-rwsr-xr-x 1 ali ali 0 Oct 3 20:51 prog
-rwxr-xr-x 1 root ali 0 Oct 3 20:51 prog

با عوض‌شدن مالک، s رفت (-rwxr-xr-x)، چون بیت‌های ویژه با مالک جدید معنی دیگری پیدا می‌کنند و لینوکس برای امنیت پاکشان می‌کند. راه‌حل: اول chown/chgrp، بعد chmod u+s (همان ترتیبی که در مثال ۲ رفتیم).

۵) فایل با mv گروه پوشه را نمی‌گیرد

Section titled “۵) فایل با mv گروه پوشه را نمی‌گیرد”
Terminal window
sudo mkdir /srv/project2
sudo chgrp team /srv/project2
sudo chmod 2775 /srv/project2
sudo -u bob sh -c 'cd /home/bob; umask 002; echo moved > moved.txt; echo copied > copied.txt; mv moved.txt /srv/project2/; cp copied.txt /srv/project2/'
ls -l /srv/project2
sudo rm -rf /srv/project2
خروجی
total 8
-rw-rw-r-- 1 bob team 7 Oct 3 20:51 copied.txt
-rw-rw-r-- 1 bob bob 6 Oct 3 20:51 moved.txt

گروه فقط وقتی از پوشه به ارث می‌رسد که فایل ساخته شود: cp فایل تازه می‌سازد (team)، ولی mv فقط همان فایل قبلی را جابه‌جا می‌کند و گروه قدیمی‌اش (bob) می‌ماند. راه‌حل: بعد از mv با chgrp team گروه را درست کن، یا به‌جای mv از cp استفاده کن.

✎ تمرینآسان

فقط برنامه‌ی setuid ای که اسمش با pass شروع می‌شود را در /usr/bin پیدا کن و عدد و حروف دسترسی‌اش را با stat بگیر.

دیدن جواب
Terminal window
find /usr/bin -perm -4000 -name 'pass*'
stat -c 'عددی=%a نمادین=%A مالک=%U' /usr/bin/passwd
خروجی
/usr/bin/passwd
عددی=4755 نمادین=-rwsr-xr-x مالک=root
✎ تمرینمتوسط

تمرین اصلی: یک پوشه‌ی مشترک تیمی بساز که فایل‌ها گروهش را به ارث ببرند. پوشه‌ی /srv/shared-team را برای گروه جدید crew (اعضا: bob و carol) با دسترسی 2770 بساز. ثابت کن فایلی که bob می‌سازد گروه crew می‌گیرد، carol می‌تواند به آن اضافه کند و dave (غیر عضو) هیچ دسترسی ندارد. (از کاربرهای مثال‌ها استفاده کن.)

دیدن جواب
Terminal window
sudo groupadd crew
sudo usermod -aG crew bob; sudo usermod -aG crew carol
sudo mkdir /srv/shared-team
sudo chgrp crew /srv/shared-team
sudo chmod 2770 /srv/shared-team
stat -c '%a %A %U:%G %n' /srv/shared-team
sudo -u bob sh -c 'umask 002; echo "از bob" > /srv/shared-team/todo.txt'
sudo ls -l /srv/shared-team
sudo -u carol sh -c 'echo "از carol" >> /srv/shared-team/todo.txt' && sudo -u carol cat /srv/shared-team/todo.txt
echo "--- dave:"
sudo -u dave cat /srv/shared-team/todo.txt
sudo rm -rf /srv/shared-team; sudo groupdel crew
خروجی
2770 drwxrws--- root:crew /srv/shared-team
total 4
-rw-rw-r-- 1 bob crew 9 Oct 3 20:51 todo.txt
از bob
از carol
--- dave:
cat: /srv/shared-team/todo.txt: Permission denied
✎ تمرینسخت

یک «پوشه‌ی تحویل» بساز: اعضای گروه students (bob و carol) بتوانند فایل بگذارند و فایل‌ها گروه students را بگیرند، ولی هیچ‌کس نتواند فایل دیگری را پاک کند، و dave هیچ دسترسی نداشته باشد. دسترسی پوشه چند می‌شود؟

دیدن جواب

setgid (۲) و sticky (۱) با هم می‌شوند ۳، پس 3770:

Terminal window
sudo groupadd students
sudo usermod -aG students bob; sudo usermod -aG students carol
sudo mkdir /srv/drop2
sudo chgrp students /srv/drop2
sudo chmod 3770 /srv/drop2
stat -c '%a %A %U:%G %n' /srv/drop2
sudo -u bob sh -c 'echo "تکلیف bob" > /srv/drop2/hw-bob.txt'
sudo ls -l /srv/drop2
echo "--- carol می‌خواهد فایل bob را پاک کند:"
sudo -u carol rm /srv/drop2/hw-bob.txt
echo "--- dave:"
sudo -u dave ls /srv/drop2
sudo -u bob rm /srv/drop2/hw-bob.txt && echo "bob فایل خودش را پاک کرد"
sudo rm -rf /srv/drop2; sudo groupdel students
خروجی
3770 drwxrws--T root:students /srv/drop2
total 4
-rw-rw-r-- 1 bob students 15 Oct 3 20:51 hw-bob.txt
--- carol می‌خواهد فایل bob را پاک کند:
rm: cannot remove '/srv/drop2/hw-bob.txt': Operation not permitted
--- dave:
ls: cannot open directory '/srv/drop2': Permission denied
bob فایل خودش را پاک کرد
؟ آزمونک
  1. در -rwsr-xr-x حرف s چه معنی دارد؟

  2. چرا کاربر عادی با passwd می‌تواند /etc/shadow را عوض کند؟

  3. setgid روی یک پوشه چه می‌کند؟

  4. چرا در /tmp (با 1777) نمی‌توانی فایل دیگران را پاک کنی؟

  5. chmod 2770 dir چه می‌کند؟

  6. chmod u+s روی یک اسکریپت bash چه اثری در لینوکس دارد؟

  • سه بیت ویژه: setuid (4000، s جای x مالک)، setgid (2000، s جای x گروه)، sticky (1000، t جای x بقیه). S/T بزرگ یعنی x خاموش است.
  • setuid روی برنامه: با هویت مالک اجرا می‌شود (passwd → root). خطرناک است؛ فقط برای برنامه‌های کوچک و دقیق، روی اسکریپت اثر ندارد، و با chown پاک می‌شود (اول chown، بعد chmod u+s).
  • setgid روی پوشه (chmod g+s): فایل‌ها و پوشه‌های جدید گروه پوشه را می‌گیرند؛ برای پوشه‌ی مشترک تیمی (2775 یا 2770). عطف به ماسبق نمی‌شود و mv گروه را عوض نمی‌کند.
  • sticky روی پوشه (chmod +t): فقط مالک فایل، مالک پوشه یا root می‌تواند پاک کند (/tmp با 1777).
  • حالت عددی چهاررقمی: رقم اول بیت‌های ویژه (۴+۲+۱)؛ 3770 = setgid + sticky + 770.
  • با find / -xdev -perm -4000 -type f همه‌ی برنامه‌های setuid را فهرست و بازبینی کن.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
ls -l /usr/bin/passwdدیدن setuid (s جای x مالک)
stat -c "%a %A %n" فایلعدد چهاررقمی و حروف
chmod u+s فایل / chmod 4755 فایلsetuid (با احتیاط)
chmod g+s پوشه / chmod 2775 پوشهsetgid برای پوشه‌ی مشترک
chmod +t پوشه / chmod 1777 پوشهsticky bit
chmod 2770 پوشهتیمی و خصوصی
chmod 3770 پوشهsetgid + sticky (پوشه‌ی تحویل)
find / -xdev -perm -4000 -type fفهرست برنامه‌های setuid
find DIR -type d -exec chmod g+s {} +setgid فقط روی پوشه‌ها
ps -o ruser,euser,comm -p PIDهویت واقعی و مؤثر یک پروسه