ls -l 결과에 rwxr-s--- 처럼 실행 비트 자리에 s 가 보인다. x 여야 할 자리에 다른 글자가 있어 무슨 뜻인지, 어디에 걸려 있는지 확인이 필요하다.
일반 권한 아홉 자리 위에 특수 비트 세 개가 더 있다. chmod 의 네 자리 표기에서 맨 앞자리가 이 셋이다.
| 비트 | 8진수 | 표시 자리 | 뜻 |
|---|---|---|---|
| setuid | 4000 | 소유자 실행 자리 | 실행 시 파일 소유자 권한으로 동작 |
| setgid | 2000 | 그룹 실행 자리 | 파일: 그룹 권한으로 실행. 디렉터리: 하위에 그룹 상속 |
| sticky | 1000 | 기타 실행 자리 | 디렉터리 안에서 자기 파일만 지울 수 있음 |
표시 규칙은 이렇다. 해당 자리에 실행 권한이 있으면 소문자, 없으면 대문자가 나온다.
rwsr-xr-x setuid, 소유자 실행 권한 있음
rwSr-xr-x setuid, 소유자 실행 권한 없음
rwxr-s--- setgid, 그룹 실행 권한 있음
rwxr-S--- setgid, 그룹 실행 권한 없음
drwxrwxrwt sticky, 기타 실행 권한 있음 (/tmp 가 이 모양)
따라서 rwxr-s--- 는 8진수로 2750 이다. 소유자는 읽기·쓰기·실행, 그룹은 읽기·실행, 기타는 없음이고 setgid 가 켜져 있다.
한 파일의 모드를 숫자로 본다. %a 는 특수 비트가 있을 때만 네 자리로 나오므로, 항상 네 자리로 보려면 %04a 를 쓴다.
stat -c '%04a %U %G %n' /usr/bin/passwd
ls -ld /shared/project
특수 비트가 걸린 것을 찾아내려면 find 의 -perm 에 - 를 붙여 "그 비트를 포함하는" 조건으로 건다.
find /opt -perm -4000 -type f # setuid 파일
find /opt -perm -2000 # setgid 파일·디렉터리
find /data -perm -1000 -type d # 스티키 디렉터리
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f -printf '%M %u %g %p\n' 2>/dev/null
디렉터리에 setgid 를 걸면 그 안에 새로 만들어지는 파일과 하위 디렉터리가 생성자의 기본 그룹이 아니라 디렉터리의 그룹을 물려받는다. 여러 사람이 같이 쓰는 작업 디렉터리에서 그룹이 제각각으로 찍히는 문제를 막는다.
sudo chgrp analysts /data/shared
sudo chmod 2770 /data/shared
이것만으로는 부족한 경우가 있다. 파일의 그룹은 맞지만 그룹 쓰기 비트가 umask 때문에 깎이면 결국 못 쓴다. 기본 ACL 을 함께 걸면 확실하다.
sudo setfacl -d -m g:analysts:rwx /data/shared
getfacl /data/shared
chmod g+s /data/shared # setgid 켜기
chmod g-s /data/shared # 끄기
chmod 2770 /data/shared # 숫자로 한 번에
chmod u+s /usr/local/bin/tool
chmod +t /data/dropbox # 스티키
setuid 를 스크립트에 걸어도 리눅스는 무시한다. 셸 스크립트의 setuid 는 동작하지 않으므로, 권한 상승이 필요하면 sudo 규칙으로 푼다.
setuid 실행 파일은 권한 상승 취약점의 통로다. 직접 만든 바이너리에 함부로 걸지 않고, 주기적으로 목록을 뽑아 예상 밖의 항목이 늘지 않았는지 본다.
nosuid 로 마운트된 파일시스템에서는 setuid·setgid 가 무시된다. 권한이 안 먹는다면 마운트 옵션부터 본다.
findmnt -o TARGET,OPTIONS | grep nosuid
파일을 수정하거나 소유자를 바꾸면 커널이 setuid·setgid 비트를 떨어뜨린다. 배포 스크립트에서 파일을 덮어쓴 뒤 다시 걸어 주지 않으면 조용히 풀린다.
ls · stat · find 기본 사용법.