파일 · 권한 · 사용자 관리 20 / 50 · Part 2. Linux 파일 종류와 속성
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정analyst)
기초편 연계: 「리눅스 시스템 기초」 30. Linux 명령어를 활용한 보안 점검
Part 2의 마지막 글이다. 지금까지 파일의 종류·속성·시간·형식·은닉을 다뤘다. 이제 마지막 질문은 이것이다.
이 파일이 원래 그 파일이 맞는가? 누군가 내용을 바꾸지 않았는가?
두 가지 방법이 있다. 첫째, 임의 파일에 대해 해시(sha256sum) 로 이전 값과 비교한다. 둘째, 시스템 파일이라면 패키지 관리자의 검증 기능 으로 배포판이 설치한 원본과 비교한다. 이번 글에서는 실제로 파일을 변조한 뒤 두 방법으로 탐지해 본다. Rocky는 rpm -V, Ubuntu는 dpkg --verify와 debsums를 사용한다.
| 명령 | 용도 |
|---|---|
sha256sum FILE | 파일의 SHA-256 해시 계산 |
sha256sum FILE > SHA256SUMS | 기준값 저장 |
sha256sum -c SHA256SUMS | 저장된 기준값과 현재 파일 비교 |
내용이 1비트라도 바뀌면 해시가 완전히 달라진다. md5는 충돌 공격이 알려져 무결성 검증용으로는 sha256 이상 을 쓴다.
| 배포판 | 파일→패키지 | 검증 |
|---|---|---|
| Rocky/RHEL | rpm -qf FILE | rpm -V 패키지, 전체는 rpm -Va |
| Ubuntu/Debian | dpkg -S FILE | dpkg --verify 패키지, debsums |
패키지 관리자는 설치 시점의 파일 해시·권한·크기를 데이터베이스에 저장해 둔다. 검증은 현재 파일을 이 기준값과 비교하는 것이다.
rpm -V는 변경된 항목만 8자리 코드로 표시한다.
| 문자 | 위치 의미 | 문자 | 위치 의미 |
|---|---|---|---|
S | 크기(Size) | U | 소유자(User) |
M | 권한/종류(Mode) | G | 그룹(Group) |
5 | 내용 해시(MD5) | T | mtime |
D | 장치 번호 | P | 능력(capabilities) |
L | 심볼릭 링크 | . | 변화 없음 |
맨 끝의 c는 설정 파일(config), d는 문서 파일을 뜻한다.

무결성 검증의 원리는 "현재 값 vs 신뢰할 수 있는 기준값" 비교다. 여기서 가장 중요한 것은 기준값을 어디에 두느냐 다.
rpm -V의 기준값은 로컬 rpm 데이터베이스(/var/lib/rpm)에 있다.dpkg --verify의 기준값은 /var/lib/dpkg/info/*.md5sums에 있다.root 권한을 얻은 공격자는 파일을 바꾸면서 이 기준값도 함께 조작 할 수 있다. 그러면 검증이 통과되어 버린다. 그래서 실무에서는 기준값을 오프라인·원격 에 별도로 보관하고, AIDE 같은 FIM(파일 무결성 모니터링) 도구로 별도 관리 DB를 둔다.
root 권한으로 시스템 파일을 일부러 변조하는 실습이다. 반드시 격리된 테스트 컨테이너에서만 진행한다.
# 1) 해시 기반 무결성 (임의 파일)
cd /root/lab20
echo "backup-v1" > data.tar && sha256sum data.tar > SHA256SUMS && cat SHA256SUMS
sha256sum -c SHA256SUMS
echo "tampered" >> data.tar && sha256sum -c SHA256SUMS # 변조 후 검증 실패
# 2) 파일 → 패키지 확인
# Rocky
rpm -qf /usr/bin/ls /usr/bin/passwd /etc/login.defs /usr/bin/chage
# Ubuntu
dpkg -S /usr/bin/ls /usr/bin/passwd
# 3) 정상 상태 검증
# Rocky
rpm -V coreutils shadow-utils ; echo "rpm -V exit=$?"
# Ubuntu
dpkg --verify coreutils passwd login | grep -v ' /usr/share/'
# 4) 시스템 파일 변조 후 재검증
# Rocky
echo "# test" >> /etc/login.defs && printf '\x00' >> /usr/bin/chage && rpm -V shadow-utils
# Ubuntu
echo "# test" >> /etc/login.defs && printf '\x00' >> /usr/bin/chage
dpkg --verify passwd login | grep -v ' /usr/share/'
debsums -as passwd login
Rocky Linux 9.8 — rpm -V

Ubuntu 24.04.5 — dpkg --verify / debsums

텍스트 원본(실제 출력) — Rocky:
[root@rocky9-lab ~]# mkdir -p /root/lab20 && cd /root/lab20
[root@rocky9-lab lab20]# echo "backup-v1" > data.tar && sha256sum data.tar > SHA256SUMS && cat SHA256SUMS
ca307569980dfb082d0eec06ae14123a7ae45c5df0a10d692d291acf586fbe30 data.tar
[root@rocky9-lab lab20]# sha256sum -c SHA256SUMS
data.tar: OK
[root@rocky9-lab lab20]# echo "tampered" >> data.tar && sha256sum -c SHA256SUMS
data.tar: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
[root@rocky9-lab lab20]# md5sum /usr/bin/ls ; sha256sum /usr/bin/ls
f0d1d5014bbf29cbc00971fa22124331 /usr/bin/ls
86d43a5e35c1571677367b53507e88927bf90e5030df39f701a2e99fac492598 /usr/bin/ls
[root@rocky9-lab lab20]# rpm -qf /usr/bin/ls /usr/bin/passwd /etc/login.defs /usr/bin/chage
coreutils-8.32-41.el9_8.1.x86_64
passwd-0.80-12.el9.x86_64
shadow-utils-4.9-16.el9.x86_64
shadow-utils-4.9-16.el9.x86_64
[root@rocky9-lab lab20]# rpm -V coreutils shadow-utils ; echo "rpm -V exit=$?"
rpm -V exit=0
[root@rocky9-lab lab20]# echo "# test" >> /etc/login.defs && printf '\x00' >> /usr/bin/chage && rpm -V shadow-utils
S.5....T. c /etc/login.defs
S.5....T. /usr/bin/chage
텍스트 원본(실제 출력) — Ubuntu:
root@ubuntu-lab:~# mkdir -p /root/lab20 && cd /root/lab20
root@ubuntu-lab:~/lab20# echo "backup-v1" > data.tar && sha256sum data.tar > SHA256SUMS && cat SHA256SUMS
ca307569980dfb082d0eec06ae14123a7ae45c5df0a10d692d291acf586fbe30 data.tar
root@ubuntu-lab:~/lab20# sha256sum -c SHA256SUMS
data.tar: OK
root@ubuntu-lab:~/lab20# echo "tampered" >> data.tar && sha256sum -c SHA256SUMS
data.tar: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
root@ubuntu-lab:~/lab20# md5sum /usr/bin/ls ; sha256sum /usr/bin/ls
4b49876e854ddf224deeb12358401d9e /usr/bin/ls
2726eb35864608ff34969fbf45ef4afcbba95eefed5ce5653c9c0124c4cd26cf /usr/bin/ls
root@ubuntu-lab:~/lab20# dpkg -S /usr/bin/ls /usr/bin/passwd
coreutils: /usr/bin/ls
passwd: /usr/bin/passwd
root@ubuntu-lab:~/lab20# dpkg --verify coreutils passwd login | grep -v ' /usr/share/' ; echo "dpkg --verify exit=${PIPESTATUS[0]}"
dpkg --verify exit=0
root@ubuntu-lab:~/lab20# dpkg -S /etc/login.defs /usr/bin/chage
login: /etc/login.defs
passwd: /usr/bin/chage
root@ubuntu-lab:~/lab20# echo "# test" >> /etc/login.defs && printf '\x00' >> /usr/bin/chage && dpkg --verify passwd login | grep -v ' /usr/share/'
??5?????? /usr/bin/chage
??5?????? c /etc/login.defs
root@ubuntu-lab:~/lab20# debsums -as passwd login
debsums: changed file /usr/bin/chage (from passwd package)
debsums: changed file /etc/login.defs (from login package)
| 출력 | 해석 |
|---|---|
data.tar: OK → data.tar: FAILED | 내용을 추가하자 해시 불일치. sha256sum -c가 변조를 탐지 |
Rocky rpm -V coreutils shadow-utils 결과 없음 (exit=0) | 변조 전에는 출력이 없다 = 모두 정상 |
rpm -qf /usr/bin/chage → shadow-utils | chage는 shadow-utils 패키지 소속 |
Rocky 변조 후 S.5....T. c /etc/login.defs | S(크기) 5(해시) T(시간) 변경, c는 설정 파일 |
S.5....T. /usr/bin/chage | 바이너리 가 변경됨. 설정 파일이 아닌데 해시가 바뀐 것은 강한 이상 신호 |
Ubuntu dpkg --verify (변조 전) 출력 없음 | /usr/share 문서 누락 항목을 필터링하면 실제 변경은 없음 |
Ubuntu 변조 후 ??5?????? /usr/bin/chage | dpkg도 5번째 자리(md5=내용)가 바뀐 것을 표시. ?는 검증 항목이 아니거나 확인 불가 |
debsums: changed file /usr/bin/chage | debsums는 변경된 파일을 사람이 읽기 쉽게 출력 |
두 배포판 모두 내용 해시(5번째 자리) 에서 변조를 잡아냈다. 크기(S)와 시간(T)은 조작으로 되돌릴 수 있지만, 내용 해시는 내용을 원본으로 되돌리지 않는 한 일치시킬 수 없다.
참고: Ubuntu의
dpkg --verify는 컨테이너 이미지에서 문서·man 페이지가 제거되어missing /usr/share/...가 많이 나온다. 실제 바이너리 변조와 구분하기 위해grep -v ' /usr/share/'로 필터링했다. 일반 서버에서는 이런 누락이 없다.
| 시나리오 | 탐지 | 주의 |
|---|---|---|
| 시스템 바이너리 백도어(트로이목마) | rpm -Va/debsums의 5(해시) 변경 | 설정 파일(c)의 변경은 정상 편집일 수 있음 |
| SUID 바이너리 교체 | 해시 + 권한(M) 변경 | 47편과 연계 |
라이브러리 변조 (.so) | 패키지 검증 | 실행 중 프로세스는 재시작 필요 |
| 검증 우회 | 기준값(rpm DB) 조작 | 기준값을 오프라인 보관 |
핵심 원칙 두 가지.
c 표시가 있는 파일(/etc/*)은 관리자가 정상적으로 편집해도 변경으로 표시된다. 바이너리 파일의 해시 변경 이 훨씬 강한 침해 신호다.[정기 점검] rpm -Va 2>/dev/null | grep -E '^..5' | grep -v ' c ' (Rocky, 내용 변경된 비-설정 파일)
debsums -c 2>/dev/null (Ubuntu, 변경 파일만)
↓
[비교] 결과를 오프라인 기준값·이전 스냅샷과 대조
↓
[Evidence] 변경 파일: stat(ctime) + sha256sum → 위협 인텔 조회
↓
[Timeline] ctime 을 사고 시각과 대조, 같은 시각 sudo/su 로그(49편)
↓
[Response] 패키지 재설치(dnf reinstall / apt install --reinstall), 침입 경로 조사
| 관점 | 내용 |
|---|---|
| FIM | AIDE·Tripwire·Wazuh 등이 기준 DB와 비교해 변경을 탐지한다. DB는 읽기 전용 매체·원격에 보관 |
| Baseline | 배포판·버전별로 주요 바이너리 해시를 관리 (같은 이름도 버전마다 다름, 12편) |
| 복구 | 변조 확인 시 dnf reinstall <pkg> / apt install --reinstall <pkg>로 원본 복원 후 침입 경로부터 차단 |
| 한계 인식 | 로컬 검증만으로는 정교한 공격을 놓칠 수 있다. 원격 로그·네트워크 증거와 결합 |
| 실수 | 결과 | 예방 |
|---|---|---|
| md5로만 검증 | 충돌 위조 가능 | sha256 이상 |
| 로컬 rpm DB만 신뢰 | root 공격자가 기준값 조작 | 기준값 오프라인 보관, FIM |
| 설정 파일 변경을 침해로 오판 | 오탐 다수 | c 표시·바이너리 여부 구분 |
| 검증 통과 = 100% 안전으로 판단 | 새 파일·미등록 파일은 검증 대상 아님 | 신규 파일은 별도 탐지 |
| 배포판 공통 해시 기준 사용 | 버전 차이로 오탐 | 버전별 기준값 |
[ ] sha256sum -c 로 변조를 탐지했다
[ ] rpm -qf / dpkg -S 로 파일의 소속 패키지를 확인했다
[ ] 정상 상태에서 rpm -V / dpkg --verify 가 조용한 것을 확인했다
[ ] 시스템 파일 변조 후 5(해시) 자리가 바뀌는 것을 확인했다
[ ] 설정 파일(c)과 바이너리 변경을 구분했다
[ ] 기준값을 오프라인에 둬야 하는 이유를 설명할 수 있다
sha256sum -c, 시스템 파일은 rpm -V(Rocky) / dpkg --verify·debsums(Ubuntu).rpm -V의 5번째 자리). 크기·시간은 조작 가능하다.c)의 변경은 정상 편집일 수 있다. 바이너리 해시 변경 이 강한 침해 신호다.Part 2 정리 — 11~20편에서 파일 종류(7가지), ls -l 해석, inode, 링크, 타임스탬프, stat, 확장자와 형식, Magic Number, 숨김·위장, 무결성 검증까지 파일의 속성 전체 를 다뤘다. Part 3부터는 이 속성 중 권한 을 깊게 파고든다.
Part 3 「Linux 파일 권한」을 시작한다. 다음 글 「21. Linux 파일 권한의 기본 구조」 에서는 rwx와 소유자·그룹·기타 3주체, 커널의 권한 검사 순서(처음 일치하는 한 칸만 적용), 그리고 root의 예외를 정리한다.
--verify — https://man7.org/linux/man-pages/man1/dpkg.1.html