Linux에서 SUID, SGID 및 고정 비트를 사용하는 방법

Linux 환경에서 SUID, SGID 및 고정 비트는 실행 파일과 디렉터리에 특별한 권한을 부여하는 강력한 메커니즘입니다. 이러한 권한 설정의 이점과 잠재적인 위험성을 함께 살펴보겠습니다.

이미 널리 활용되는 기능

다중 사용자 운영 체제에서 보안을 유지하는 것은 복잡한 문제입니다. 예를 들어, 기본적인 암호 개념을 생각해 봅시다. 사용자가 로그인할 때마다 시스템은 입력한 암호를 저장된 사본과 비교해야 합니다. 암호는 시스템 접근의 핵심이므로 철저히 보호해야 합니다.

Linux 시스템에서 저장된 암호는 암호화되어 보호되며, 루트 권한을 가진 사용자만 해당 암호 파일에 접근할 수 있습니다. 하지만 루트 권한이 없는 사용자가 암호를 변경해야 할 때는 어떻게 해야 할까요?

권한 상승의 필요성

일반적으로 Linux 명령어 및 프로그램은 해당 프로그램을 실행한 사용자와 동일한 권한으로 실행됩니다. 만약 루트 사용자가 passwd 명령어를 실행하여 암호를 변경하면, 해당 명령어는 루트 권한으로 실행됩니다. 이로 인해 passwd 명령어는 /etc/shadow 파일에 저장된 암호에 자유롭게 접근할 수 있습니다.

시스템의 모든 사용자가 passwd 프로그램을 실행할 수 있지만, 해당 프로그램이 루트 권한을 유지하도록 설계하는 것이 이상적입니다. 이렇게 하면 모든 사용자가 자신의 암호를 변경할 수 있게 됩니다.

이러한 시나리오가 바로 SUID(사용자 ID 설정) 비트가 하는 역할입니다. SUID는 프로그램과 명령어를 실행할 때, 실행하는 사용자의 권한이 아닌 파일 소유자의 권한으로 실행되도록 합니다.

프로그램 권한 상승의 함정

하지만 또 다른 과제가 있습니다. 다른 사용자의 암호를 탈취하는 행위를 막아야 합니다. Linux는 SUID 시스템을 통해 응용 프로그램을 일시적으로 상승된 권한으로 실행할 수 있도록 지원하지만, 이는 보안 문제의 절반에 불과합니다.

다른 사용자의 암호 사용을 막는 제어 메커니즘은 운영 체제 자체나 SUID 시스템이 아닌, passwd 프로그램 내부에 구현되어 있습니다.

높은 권한으로 실행되는 프로그램은 “보안 설계” 원칙에 따라 개발되지 않았다면 심각한 보안 위험을 초래할 수 있습니다. 이는 보안을 최우선으로 고려하고 그 위에 프로그램을 구축해야 함을 의미합니다. 프로그램을 개발한 후에 보안을 추가하는 방식은 위험합니다.

오픈 소스 소프트웨어의 가장 큰 장점은 소스 코드를 직접 확인하거나 신뢰할 수 있는 동료의 평가를 참고할 수 있다는 것입니다. passwd 프로그램의 소스 코드에는 프로그램을 실행하는 사용자가 루트인지 확인하는 검사 기능이 있습니다. 루트 사용자(또는 sudo 권한을 가진 사용자)의 경우, 다른 기능을 사용할 수 있습니다.

이 코드가 루트 사용자를 감지하는 부분입니다.

다음은 이를 보여주는 예시입니다. 루트 사용자는 암호를 변경할 수 있으므로, 프로그램은 일반적으로 어떤 암호가 변경 권한을 가지고 있는지 확인하는 검사에 신경 쓸 필요가 없습니다. 따라서 루트 사용자의 경우 이러한 검사를 건너뛰고 검사 기능을 종료합니다.

핵심 Linux 명령어와 유틸리티는 보안이 내장되어 있고 코드가 여러 번 검토되었기 때문에 안심하고 사용할 수 있습니다. 물론 아직 알려지지 않은 취약점의 위협은 항상 존재하지만, 새롭게 발견된 취약점에 대한 패치나 업데이트는 신속하게 제공됩니다.

특히 오픈 소스가 아닌 제3자 소프트웨어의 경우 SUID 사용 시 매우 주의해야 합니다. 사용하지 말라는 의미는 아니지만, 시스템이 위험에 노출되지 않도록 주의해야 합니다. 보안에 취약한 프로그램에 실행 권한을 부여하는 것은 매우 위험합니다.

SUID를 사용하는 Linux 명령어

다음은 일반 사용자가 실행할 때 명령어에 높은 권한을 부여하기 위해 SUID 비트가 설정된 몇 가지 Linux 명령어입니다.

ls -l /bin/su
ls -l /bin/ping
ls -l /bin/mount
ls -l /bin/umount
ls -l /usr/bin/passwd

파일 이름이 빨간색으로 강조 표시되어 SUID 비트가 설정되었음을 나타냅니다.

파일 또는 디렉터리의 권한은 일반적으로 rwx 세 글자로 구성된 세 그룹으로 표시됩니다. 각각 읽기, 쓰기 및 실행 권한을 나타냅니다. 문자가 있으면 해당 권한이 부여된 것이고, 하이픈(-)으로 표시되면 해당 권한이 없는 것입니다.

이러한 권한에는 세 가지 그룹이 있으며(왼쪽에서 오른쪽으로), 각각 파일 소유자, 파일 그룹 구성원 및 기타 사용자의 권한을 나타냅니다. SUID 비트가 파일에 설정되면, 소유자의 실행 권한을 나타내는 자리에 “s”가 표시됩니다.

실행 권한이 없는 파일에 SUID 비트가 설정되어 있으면 대문자 “S”로 표시됩니다.

예를 들어, 일반 사용자 dave가 다음과 같이 passwd 명령어를 입력한다고 가정해 보겠습니다.

passwd

passwd 명령어는 dave에게 새 암호를 입력하라는 메시지를 표시합니다. 실행 중인 프로세스의 세부 정보를 확인하기 위해 ps 명령어를 사용할 수 있습니다.

다른 터미널 창에서 grep과 함께 ps를 사용하여 passwd 프로세스를 찾을 것입니다. 또한 ps 명령어에 -e(모든 프로세스) 및 -f(전체 형식) 옵션을 사용할 것입니다.

다음 명령어를 입력합니다.

ps -e -f | grep passwd

두 줄의 결과가 출력되는데, 두 번째 줄은 “passwd” 문자열을 포함하는 명령어를 찾는 grep 프로세스입니다. 우리가 관심을 갖는 것은 첫 번째 줄인데, 이는 dave가 시작한 passwd 프로세스이기 때문입니다.

passwd 프로세스가 루트 사용자가 실행한 것과 동일한 권한으로 실행되는 것을 볼 수 있습니다.

SUID 비트 설정

chmod 명령어를 사용하여 SUID 비트를 쉽게 변경할 수 있습니다. u+s 기호 모드는 SUID 비트를 설정하고, u-s 기호 모드는 SUID 비트를 제거합니다.

SUID 비트의 개념을 설명하기 위해 htg라는 간단한 프로그램을 만들었습니다. 이 프로그램은 dave 사용자의 루트 디렉터리에 있으며 SUID 비트는 설정되어 있지 않습니다. 실행 시 실제 및 유효 사용자 ID(UID)를 표시합니다.

실제 UID는 프로그램을 시작한 사용자의 ID이고, 유효 ID는 프로그램이 실행되는 계정의 ID입니다.

다음 명령어를 입력합니다.

ls -lh htg
./htg

프로그램의 로컬 복사본을 실행하면 실제 ID와 유효 ID가 모두 dave로 설정된 것을 볼 수 있습니다. 따라서 프로그램은 일반적인 방식으로 작동합니다.

다른 사용자들이 사용할 수 있도록 /usr/local/bin 디렉터리에 복사해 보겠습니다.

다음 명령어를 입력하고, chmod를 사용하여 SUID 비트를 설정한 다음, 제대로 설정되었는지 확인합니다.

sudo cp htg /usr/local/bin
sudo chmod u+s /usr/local/bin/htg
ls -hl /usr/local/bin/htg

프로그램이 복사되었고 SUID 비트가 설정되었습니다. 이제 다시 실행하지만 이번에는 /usr/local/bin 폴더에서 복사본을 실행합니다.

htg

dave가 프로그램을 실행했지만 유효 ID는 루트 사용자로 설정됩니다. mary 사용자가 프로그램을 실행하면 아래와 같이 동일한 현상이 발생합니다.

htg

실제 ID는 mary이고 유효 ID는 root입니다. 프로그램은 루트 사용자의 권한으로 실행됩니다.

SGID 비트

SGID(Set Group ID) 비트는 SUID 비트와 매우 유사합니다. SGID 비트가 실행 파일에 설정되면 유효 그룹은 파일 그룹으로 설정됩니다. 프로세스는 파일을 시작한 사용자의 권한이 아닌 파일 그룹 구성원의 권한으로 실행됩니다.

효과적인 그룹도 표시하도록 ht 프로그램을 조정했습니다. htg 프로그램의 그룹을 사용자 mary의 기본 그룹인 mary로 변경합니다. 또한 chown과 함께 u-s 및 g+s 기호 모드를 사용하여 SUID 비트를 제거하고 SGID를 설정합니다.

다음 명령어를 입력합니다.

sudo chown root:mary /usr/local/bin/htg
sudo chmod u-s,g+s /usr/local/bin/htg
ls -lh /usr/local/bin/htg

그룹 권한에서 “s”로 표시된 SGID 비트를 확인할 수 있습니다. 또한 그룹이 mary로 설정되고 파일 이름이 이제 노란색으로 강조 표시됩니다.

프로그램을 실행하기 전에 dave와 mary가 속한 그룹을 설정해 보겠습니다. -G(그룹) 옵션과 함께 id 명령어를 사용하여 모든 그룹 ID를 출력합니다. 그런 다음 ht 프로그램을 dave 사용자로 실행합니다.

다음 명령어를 입력합니다.

id -G dave
id -G mary
htg

mary의 기본 그룹 ID는 1001이고 htg 프로그램의 유효 그룹은 1001입니다. 따라서 dave에 의해 시작되었지만 mary 그룹 구성원의 권한으로 실행되고 있습니다. 데이브가 메리 그룹에 합류한 것과 같습니다.

SGID 비트를 디렉터리에 적용해 보겠습니다. 먼저 “work”라는 디렉터리를 만든 다음 그룹을 “geek”으로 변경합니다. 그런 다음 디렉터리에 SGID 비트를 설정합니다.

ls 명령어를 사용하여 디렉터리 설정을 확인할 때 -d(디렉터리) 옵션도 사용하여 내용이 아닌 디렉터리의 세부 정보를 확인합니다.

다음 명령어를 입력합니다.

sudo mkdir work
sudo chown dave:geek work
sudo chmod g+s work
ls -lh -d work

SGID 비트와 “geek” 그룹이 설정되었습니다. 이는 work 디렉터리 내에서 생성된 모든 항목에 영향을 미칩니다.

다음 명령어를 입력하여 work 디렉터리로 이동하고 “demo”라는 디렉터리를 만든 다음 속성을 확인합니다.

cd work
mkdir demo
ls -lh -d demo

SGID 비트와 “geek” 그룹이 “demo” 디렉터리에 자동으로 적용됩니다.

다음 명령어를 입력하여 파일을 생성하고 touch 명령어를 실행하고 속성을 확인합니다.

touch useful.sh
ls -lh useful.sh

새 파일의 그룹은 자동으로 “geek”으로 설정됩니다.

고정 비트

고정 비트(sticky bit)는 역사적인 용도에서 그 이름을 얻었습니다. 실행 파일에 설정되면 운영 체제에 실행 파일의 텍스트 부분을 스왑에 유지해야 한다는 신호를 보내어 재사용 속도를 높입니다. Linux에서 고정 비트는 디렉터리에만 영향을 미치므로 파일에 설정하는 것은 의미가 없습니다.

디렉터리에 고정 비트를 설정하면 해당 디렉터리 내에서 자신에게 속한 파일만 삭제할 수 있습니다. 파일에 설정된 파일 권한 조합에 관계없이 다른 사용자의 파일을 삭제할 수 없습니다.

이를 통해 모든 사용자와 그들이 실행하는 프로세스가 공유 파일 저장소로 사용할 수 있는 디렉터리를 만들 수 있습니다. 다시 말하지만, 다른 사용자의 파일을 삭제할 수 없기 때문에 파일이 보호됩니다.

“shared”라는 디렉터리를 만들어 보겠습니다. chmod 명령어와 함께 o+t 기호 모드를 사용하여 해당 디렉터리에 고정 비트를 설정합니다. 그런 다음 해당 디렉터리와 /tmp 및 /var/tmp 디렉터리에 대한 권한을 살펴보겠습니다.

다음 명령어를 입력합니다.

mkdir shared
sudo chmod o+t shared
ls -lh -d shared
ls -lh -d /tmp
ls -lh -d /var/tmp

고정 비트가 설정되면 “기타” 파일 권한 집합의 실행 비트가 “t”로 설정됩니다. 파일 이름도 파란색으로 강조 표시됩니다.

/tmp 및 /var/tmp 폴더는 소유자, 그룹 및 기타 사용자에 대해 설정된 모든 파일 권한을 가진 디렉터리의 대표적인 예입니다(그래서 녹색으로 강조 표시됨). 이러한 폴더들은 임시 파일의 공유 위치로 사용됩니다.

이러한 권한을 가지고 있으면 이론적으로 누구든지 무엇이든 할 수 있어야 하지만, 고정 비트가 이러한 행위를 막고 누구도 자신에게 속하지 않은 파일을 삭제할 수 없도록 합니다.

핵심 요약

다음은 위에서 다룬 내용을 다시 한번 정리한 요약입니다.

SUID는 파일에만 적용됩니다.
SGID는 디렉터리와 파일 모두에 적용할 수 있습니다.
고정 비트는 디렉터리에만 적용할 수 있습니다.
“s”, “g” 또는 “t” 표시기가 대문자로 나타나면 실행 가능한 비트(x)가 설정되지 않은 것입니다.