SUID/SGID

lv2dev·2025년 11월 6일

Linux

목록 보기
7/7

TL;DR

  • SUID = 실행하면 파일 소유자 권한으로 동작함 (root 소유면 root 권한 올라감)
  • SGID = 실행하면 파일 그룹 권한으로 동작함 / 디렉터리에 붙이면 하위 파일 그룹 상속
  • ls -l에서 s/S 보이면 붙어있는 거임
  • 필요 없으면 내림(chmod u-s / g-s). 다만 필수 바이너리는 유지해야 함
  • 점검은 find … -perm -4000/-2000, 패키지 기준 검증은 rpm -V로 함

왜 존재함?

  • 일반 사용자가 특정 작업을 하려면 잠깐 권한 상승 필요할 때 쓰는 메커니즘임

    • 예) passwd/etc/shadow 만지려면 root 권한 필요 → SUID root로 해결
    • 협업 디렉터리에서 새 파일이 항상 같은 그룹 갖게 하려면 → SGID 디렉터리

어디서 보임? (퍼미션 읽는 법)

  • ls -l 문자권한에서:

    • 소유자 실행 위치(3번째)s/SSUID
    • 그룹 실행 위치(6번째)s/SSGID
    • 소문자 s = 실행 비트 켜짐, 대문자 S = 실행 비트 꺼짐(대개 설정 미스)
  • 8진수에서 첫 자리가 특수비트:

    • 4=SUID, 2=SGID, 1=sticky
    • 예) 4755(SUID + 755), 2755(SGID + 755), 6750(둘 다 + 750)

디렉터리에서의 의미

  • SGID 디렉터리: 그 안에서 만든 파일/디렉터리의 그룹이 상위 디렉터리 그룹을 상속함 → 팀 공유 디렉터리 운영에 유용
  • SUID 디렉터리: 리눅스에선 의미 없음(무시됨)
  • sticky(1): /tmp 같은 world-writable 디렉터리에서 소유자만 삭제 가능하게 하는 비트 (drwxrwxrwt)

실무에서 자주 보는 예시

  • 유지 권장(기본적으로 필요함)

    • /usr/bin/passwd, chage, gpasswd, newgrp, chfn, chsh
    • crontab(사용자 크론 쓰면 필요)
    • su(보통 4750 root:wheel로 하드닝해 씀)
    • dbus-daemon-launch-helper(4750:dbus)
    • FUSE 쓰면 fusermount
  • 용도 따라 하드닝 고려

    • 일반 사용자 마운트 안 쓰면: mount, umount, mount.nfsu-s 내림
    • 데스크톱 안 쓰면: Xorg, 일부 spice-gtk-*, gnome-pty-helper → 내리거나 패키지 제거
    • pkexec(Polkit) 거의 안 쓰면 → 0755로 낮추거나 패키지 제거
    • at 안 쓰면 → atd 비활성 + u-s
    • abrt/locate 등 환경 따라 내릴 수 있음

무지성으로 다 내리면 서비스 터짐. 쓰는지 확인 → 백업 → 내림 → 검증 순서로 진행함


점검 방법(전수 검사)

# 특수 경로 제외하고 SUID/SGID 파일 찾음
find / -xdev \
  \( -path /proc -o -path /sys -o -path /dev -o -path '/run/user/*/gvfs' -o -path /var/lib/docker -o -path /var/lib/containers \) -prune -o \
  -type f \( -perm -4000 -o -perm -2000 \) -exec ls -al {} \; 2>/dev/null

패키지 기준과 불일치 여부도 점검함:

f=/usr/bin/somebin
rpm -qf "$f"               # 어떤 패키지 소유인지
rpm -V  "$(rpm -qf "$f")"  # 권한/해시 등 검증
# 패키지 기록 권한으로 원복
rpm --setperms  "$(rpm -qf "$f")"
rpm --setugids  "$(rpm -qf "$f")"

설정/해제(하드닝)

# SUID/SGID 부여/해제
chmod u+s /path/to/bin   # SUID 부여
chmod u-s /path/to/bin   # SUID 해제
chmod g+s /path/to/bin   # SGID 부여
chmod g-s /path/to/bin   # SGID 해제

# 필요 바이너리는 그룹 제한 + 실행권 최소화
chgrp wheel /usr/bin/su
chmod 4750 /usr/bin/su   # 소유자 root, 그룹 wheel만 실행

롤백 쉽게 하려면 변경 전 권한 백업해 둠:

stat -c '%a %U:%G %n' /usr/bin/pkexec >> /root/perms.backup
# 문제 생기면 perms.backup 보고 복구

Capabilities 대안(가능하면 이걸로 대체)

  • 최신 배포판은 SUID 대신 리눅스 capabilities 쓰는 추세

    • 예) /bin/pingcap_net_raw=ep
getcap /bin/ping
# 없으면 부여 예시(배포판 기본값과 다르면 비추)
sudo setcap cap_net_raw+ep /bin/ping

패키지 기본값과 다르게 건드리면 업데이트 때 꼬일 수 있음. 배포판 기본 정책 우선


하드닝 체크리스트

  • SUID/SGID 전수 스캔 완료
  • 필수 바이너리 화이트리스트 정의함
  • 불필요 항목 u-s/g-s 내림
  • 가능 시 그룹 제한(4750) 적용
  • 변경 전후 기능 테스트(마운트/크론/정책키트 등)
  • 패키지 업데이트 후 재검증 자동화

장애 회피 팁

  • 서비스 깨지면 패키지 권한 원복으로 빠르게 되돌림:

    rpm --setperms <pkg>; rpm --setugids <pkg>
  • 컨테이너 환경은 네임스페이스/CAPs 영향 큼. 호스트 기준 하드닝이 그대로 안 먹을 수 있음

  • NFS/원격 FS 권한 시맨틱 다를 수 있음. 서비스별로 개별 검증함


치트시트

# SUID만
find / -xdev -type f -perm -4000 -printf '%M %u:%g %m %p\n' 2>/dev/null

# SGID만
find / -xdev -type f -perm -2000 -printf '%M %u:%g %m %p\n' 2>/dev/null

# 패키지 기록 모드 확인(한 파일)
f=/usr/bin/chfn
pkg=$(rpm -qf "$f")
rpm -ql --dump "$pkg" | awk -v F="$f" '$1==F{print "pkg:",$5,"file:",F}'

결론

  • SUID/SGID = 권한 상승의 칼임. 필요한 곳만 예리하게 쓰고 나머지는 무디게 만들면 안전해짐
  • 점검은 find로 하고, 패키지 기준으로 정상/이상 구분함
  • 하드닝은 사용성 테스트 + 롤백 플랜까지 포함해서 진행함
profile
언제나 레벨업을 하고 싶은 영원한 lv1

0개의 댓글