파일 · 권한 · 사용자 관리 28 / 50 · Part 3. Linux 파일 권한
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정analyst)
기초편 연계: 「리눅스 시스템 기초」 16. chmod와 권한 관리
일반 사용자가 passwd로 자기 비밀번호를 바꾸면, 그 정보는 /etc/shadow에 저장된다. 그런데 /etc/shadow는 root만 쓸 수 있다(보통 000 또는 640 root:shadow). 일반 사용자가 어떻게 root 전용 파일을 수정할 수 있을까?
답은 SUID(Set User ID) 다. passwd 프로그램에는 SUID가 설정되어 있어, 일반 사용자가 실행해도 파일 소유자(root)의 권한으로 동작한다. 이번 글에서는 SUID의 동작 원리를 실습으로 확인하고, 그것이 왜 권한 상승 공격에서 가장 먼저 점검하는 항목인지 정리한다.
| 용어 | 의미 |
|---|---|
| 실제 UID (real uid) | 프로세스를 실행한 사용자 |
| 유효 UID (euid) | 권한 검사에 실제로 쓰이는 UID |
보통 둘은 같다. SUID 프로그램을 실행하면 euid가 파일 소유자로 바뀐다. root 소유 SUID 파일이면 euid = 0(root)가 되어, 그 프로세스는 root 권한으로 동작한다.
| 표시 | 의미 |
|---|---|
-rwsr-xr-x | SUID + 소유자 실행 권한 (소문자 s) |
-rwSr-xr-x | SUID인데 소유자 실행 권한 없음 (대문자 S, 무의미) |
chmod 4755 | 앞자리 4 = SUID |
chmod u+s | 기호 방식 |
권한이 네 자리가 되는 것을 주목하자. 앞자리는 특수 권한(SUID=4, SGID=2, Sticky=1)이다.
셸 스크립트에 SUID를 설정해도 효과가 없다. Linux 커널은 인터프리터 스크립트의 SUID를 보안상 무시한다. 스크립트 SUID를 허용하면 경쟁 상태·인자 조작으로 쉽게 악용되기 때문이다. 그래서 SUID는 컴파일된 바이너리 에만 유효하다.

커널이 SUID 파일을 실행(execve)할 때, 새 프로세스의 euid를 파일 소유자의 UID 로 설정한다. 그래서 root 소유 SUID 프로그램은 실행자와 무관하게 root 권한으로 시작한다.
passwd가 이 구조를 쓴다. passwd는 root 소유 SUID 바이너리이고, 내부적으로 자신이 root 권한임을 이용해 /etc/shadow를 수정하되, 호출한 사용자 본인의 항목만 바꾸도록 제한한다. 즉 SUID는 "권한을 빌려주되, 프로그램이 그 권한을 안전하게 쓰도록 설계"하는 방식이다.
문제는 이 "안전하게"가 깨질 때다. SUID 바이너리에 취약점이 있거나, 파일을 읽고 셸을 여는 기능이 있으면, 그 기능이 root 권한으로 실행되어 권한 상승이 된다.
실습용으로
myid(SUID된id),scat(SUID된cat),script.sh(SUID 셸 스크립트)를 root가 만들어 뒀다.secret.txt는 root 소유600파일이다. 격리된 테스트 환경에서만 진행한다.
cd /srv/lab28
# 1) 정상 SUID 파일 (참고)
ls -l /usr/bin/passwd # -rwsr-xr-x root root
# 2) 실습 SUID 파일들
ls -l myid script.sh scat
id # 실제 uid = 1000
# 3) SUID 바이너리 실행 → euid 변화
./myid # euid=0(root)
# 4) root 전용 파일 접근
cat secret.txt # 직접: Permission denied
./scat secret.txt # SUID cat: 읽힘 (euid=root)
# 5) SUID 스크립트는 무시된다
bash script.sh # euid 안 바뀜

텍스트 원본(실제 출력):
[analyst@rocky9-lab ~]$ cd /srv/lab28
[analyst@rocky9-lab lab28]$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 32656 May 15 2022 /usr/bin/passwd
[analyst@rocky9-lab lab28]$ ls -l myid script.sh scat
-rwsr-xr-x 1 root root 40472 Sep 24 10:57 myid
-rwsr-xr-x 1 root root 36312 Sep 24 10:57 scat
-rwsr-xr-x 1 root root 15 Sep 24 10:57 script.sh
[analyst@rocky9-lab lab28]$ id
uid=1000(analyst) gid=1000(analyst) groups=1000(analyst)
[analyst@rocky9-lab lab28]$ ./myid
uid=1000(analyst) gid=1000(analyst) euid=0(root) groups=1000(analyst)
[analyst@rocky9-lab lab28]$ cat secret.txt 2>&1 || echo "→ 직접 cat: 권한 없음"
cat: secret.txt: Permission denied
→ 직접 cat: 권한 없음
[analyst@rocky9-lab lab28]$ ./scat secret.txt 2>&1 || echo "→ SUID cat 이지만..."
root secret
[analyst@rocky9-lab lab28]$ bash script.sh
uid=1000(analyst) gid=1000(analyst) groups=1000(analyst)
| 출력 | 해석 |
|---|---|
/usr/bin/passwd → -rwsr-xr-x root root | 정상 SUID 바이너리 |
id → uid=1000(analyst) | 실제 사용자는 analyst |
./myid → uid=1000 ... euid=0(root) | SUID로 euid가 root 로 바뀜 |
cat secret.txt → Permission denied | analyst 권한으로는 root 600 파일 못 읽음 |
./scat secret.txt → root secret | SUID된 cat이 root 권한으로 읽어 냄 |
bash script.sh → uid=1000 ... groups=1000 | euid 안 바뀜. 스크립트 SUID 무시 |
./scat이 root 전용 파일을 읽어 낸 것이 SUID의 위력이자 위험이다. 만약 시스템에 이런 SUID된 cat이 방치되면, 누구나 /etc/shadow를 읽을 수 있는 백도어가 된다.
| 주제 | 내용 |
|---|---|
| 정상 SUID | passwd, sudo, su, mount, ping(일부) 등 root 권한이 꼭 필요한 소수의 프로그램 |
| 위험 신호 | 표준 목록에 없는 SUID, 특히 cat/cp/bash/find/vim 같은 범용 도구의 SUID |
| GTFOBins | 많은 표준 도구는 SUID가 붙으면 셸 탈출·파일 읽기로 권한 상승이 가능하다. find, vim, less, awk 등 |
| 지속성 | root를 얻은 공격자가 cp /bin/bash /tmp/.b; chmod u+s /tmp/.b로 SUID 셸을 숨겨 둔다(09편) |
핵심 방어: SUID 파일 목록을 기준값으로 관리 하고, 새로 생긴 SUID를 탐지한다(47편). SUID를 최소화하고, mount -o nosuid로 사용자 쓰기 가능 파일 시스템에서 SUID를 무력화한다.
# 사용자 데이터 파티션에서 SUID 무력화
mount -o remount,nosuid /home
[Baseline] 초기 SUID 목록 저장
find / -xdev -perm -4000 -type f 2>/dev/null | sort > /var/lib/baseline/suid.txt
↓
[정기 점검] 현재 목록과 비교
diff <(find / -xdev -perm -4000 -type f 2>/dev/null | sort) /var/lib/baseline/suid.txt
↓
[Detection] auditd: chmod 로 SUID 설정 시도 (권한 상승 준비)
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -k suid_change
↓
[Evidence] 신규 SUID: stat(ctime·소유자), sha256sum, 패키지 소속(rpm -qf/dpkg -S)
↓
[Response] 비인가 SUID 제거(chmod u-s), root 획득 경로 역추적
| 관점 | 내용 |
|---|---|
| IOC | 패키지에 속하지 않는 SUID 바이너리, 범용 도구의 SUID |
| 탐지 | SUID 설정(chmod u+s)은 auditd로 실시간 탐지 가능 |
| Baseline | 배포판·버전마다 표준 SUID 목록이 다르므로 시스템별로 관리 |
| 실수 | 결과 | 예방 |
|---|---|---|
| SUID를 남발 | 권한 상승 표면 확대 | 꼭 필요한 프로그램만 |
| 범용 도구에 SUID | 즉시 권한 상승 경로 | 절대 금지 |
| 스크립트에 SUID로 권한 위임 시도 | 무시됨 (또는 우회 위험) | 래퍼 바이너리·sudo 규칙 사용 |
| SUID 목록 미관리 | 백도어 탐지 실패 | 기준값 + 정기 비교 |
| 사용자 파티션에 SUID 허용 | 악용 가능 | nosuid 마운트 |
[ ] SUID 파일 실행 시 euid 가 소유자로 바뀌는 것을 확인했다
[ ] SUID cat 이 root 전용 파일을 읽는 것을 재현했다
[ ] 실제/유효 UID 의 차이를 설명할 수 있다
[ ] 셸 스크립트의 SUID 가 무시됨을 확인했다
[ ] find -perm -4000 으로 SUID 파일을 찾을 수 있다
[ ] SUID 기준값 관리의 필요성을 이해했다
passwd가 root 전용 /etc/shadow를 수정할 수 있는 것이 SUID 덕분이다.-rws...(소문자 s), 설정은 chmod 4755 또는 u+s.nosuid 마운트로 위험을 줄인다.다음 글 「29. SGID 권한」 에서는 SGID의 두 가지 동작 — 파일에서는 그룹 권한 실행, 디렉터리에서는 새 파일의 그룹 상속 — 을 구분하고, 그룹 협업 디렉터리의 표준 설정을 실습한다.