파일 · 권한 · 사용자 관리 16 / 50 · Part 2. Linux 파일 종류와 속성
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정analyst)
기초편 연계: 「리눅스 시스템 기초」 14. inode와 파일 시스템
지금까지 inode(13편), 링크(14편), 타임스탬프(15편)를 각각 확인했다. 이 정보를 한 번에 보여 주는 명령 이 stat이다. 침해 조사에서 의심 파일을 발견하면 가장 먼저 실행하는 명령 중 하나이기도 하다.
이번 글에서는 stat 출력의 모든 필드를 해석하고, 실습용 SUID 파일 하나를 분석해 한 화면에서 이상 징후 세 가지를 읽어 내는 과정 을 보여 준다. 마지막으로 보고서에 바로 붙일 수 있는 -c 형식 템플릿을 정리한다.
| 필드 | 의미 |
|---|---|
File | 입력한 경로 |
Size | 크기(바이트) |
Blocks | 할당된 512바이트 블록 수 |
IO Block | 파일 시스템 I/O 단위 |
| (종류) | regular file, directory, symbolic link 등 |
Device | 파일이 있는 장치 번호 (16진/10진) |
Inode | inode 번호 |
Links | 링크 수 |
Access: (4755/-rwsr-xr-x) | 권한 8진수/문자 |
Uid / Gid | 번호와 이름 |
Access / Modify / Change / Birth | atime / mtime / ctime / 생성 시각 |
| 옵션 | 의미 |
|---|---|
-c FORMAT | 원하는 필드만 출력 (끝에 줄바꿈 자동) |
--printf FORMAT | \n 등 이스케이프 해석, 줄바꿈 자동 없음 |
-L | 심볼릭 링크를 따라가 대상 정보 출력 |
-f | 파일이 아니라 파일 시스템 정보 출력 |
-t | 기계 처리용 간결 출력 |

stat은 statx() 시스템 콜로 inode 정보를 가져온다. statx()는 기존 stat()과 달리 생성 시각(birth) 을 요청할 수 있어서, 커널 4.11 이상 + 최신 coreutils 조합에서 Birth가 표시된다. 파일 시스템이 생성 시각을 저장하지 않으면 -로 표시된다.
stat 자체는 파일 내용을 읽지 않으므로 atime을 바꾸지 않는다. 그래서 증거 수집의 첫 단계로 적합하다.
실습용 파일
/data/svc-helper는 root가/bin/true를 복사해 SUID를 설정하고,touch -d로 mtime을 2024-02-01로 바꿔 둔 파일이다. 공격자가 남긴 파일을 흉내 낸 분석 연습용 샘플 이다.
# 1) 기본 출력
stat /data/svc-helper
# 2) 보고서용 한 줄 (구분자 |)
stat -c '%n|%A|%a|%U(%u)|%G(%g)|%s|%i|%h|%W|%Y|%Z' /data/svc-helper
# 3) 심볼릭 링크 자체 vs 대상
ln -s /data/svc-helper /data/lnk && stat -c '%n %F' /data/lnk && stat -L -c '%n %F' /data/lnk
# 4) 파일 시스템 정보
stat -f /data

텍스트 원본(실제 출력):
[analyst@rocky9-lab ~]$ stat /data/svc-helper
File: /data/svc-helper
Size: 27936 Blocks: 56 IO Block: 4096 regular file
Device: 700h/1792d Inode: 11 Links: 1
Access: (4755/-rwsr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2024-02-01 03:00:00.000000000 +0900
Modify: 2024-02-01 03:00:00.000000000 +0900
Change: 2026-09-24 10:35:22.351694994 +0900
Birth: 2026-09-24 10:35:22.343694994 +0900
[analyst@rocky9-lab ~]$ stat -c '%n|%A|%a|%U(%u)|%G(%g)|%s|%i|%h|%W|%Y|%Z' /data/svc-helper
/data/svc-helper|-rwsr-xr-x|4755|root(0)|root(0)|27936|11|1|1790213722|1706724000|1790213722
[analyst@rocky9-lab ~]$ ln -s /data/svc-helper /data/lnk && stat -c '%n %F' /data/lnk && stat -L -c '%n %F' /data/lnk
/data/lnk symbolic link
/data/lnk regular file
[analyst@rocky9-lab ~]$ stat -f /data
File: "/data"
ID: bb60228942ace593 Namelen: 255 Type: ext2/ext3
Block size: 4096 Fundamental block size: 4096
Blocks: Total: 57274 Free: 57265 Available: 52679
Inodes: Total: 65536 Free: 65524
| 필드 | 값 | 해석 |
|---|---|---|
Access: (4755/-rwsr-xr-x) | SUID + 755 | 실행하면 소유자 root 권한으로 동작 |
Uid: (0/root) | root 소유 | SUID와 결합되면 권한 상승 경로가 될 수 있음 |
Modify: 2024-02-01 03:00:00.000000000 | 약 2년 7개월 전 | 나노초가 정확히 0 → 사람이 지정한 값일 가능성 |
Change: 2026-09-24 10:35:22.351 | 실습 당일 | 마지막 inode 변경 (chmod·touch 시점) |
Birth: 2026-09-24 10:35:22.343 | 실습 당일 | 파일이 실제로 만들어진 시각 |
-c 한 줄 출력의 %W, %Y, %Z | 1790213722, 1706724000, 1790213722 | Unix epoch 초. SIEM·스프레드시트에서 정렬·계산하기 좋음 |
stat -c '%F' /data/lnk | symbolic link | 링크 자체 |
stat -L | regular file | 링크를 따라간 대상 |
stat -f /data | Type: ext2/ext3, inode 총 65536 | 파일 시스템 정보. ext4도 ext2/ext3로 표시된다 (같은 매직 번호 사용) |
종합 판단: Birth(2026-09-24)보다 Modify(2024-02-01)가 2년 이상 이르다. 파일 내용이 생성보다 먼저 수정될 수는 없으므로, mtime은 생성 후에 과거로 설정된 값 이다. 이것만으로 악성이라고 확정할 수는 없지만(cp -p, tar 복원도 같은 모양), SUID + root 소유 + 패키지 미소속 경로 가 겹치면 우선 조사 대상이다.
| stat에서 보는 것 | 의심 신호 | 정상일 수 있는 경우 |
|---|---|---|
| 권한 | 비표준 위치의 SUID/SGID, world-writable | 패키지가 설치한 SUID (rpm -qf, dpkg -S로 확인) |
| 소유자 | 웹 루트 파일이 웹 서버 계정 소유, UID 숫자만 표시 | 업로드 디렉터리 |
| mtime vs birth | birth보다 과거인 mtime | 복사·압축 해제·백업 복원 |
나노초 .000000000 | 수동 지정 시간 | tar 등 초 단위 보존 도구 |
| Links > 1 | 일반 파일에 숨은 다른 이름 | 패키지가 만든 하드 링크 |
보고서용 수집 템플릿:
# 파일 하나 — 사람이 읽는 형식 (시간대 포함)
stat -c 'path=%n type=%F mode=%a owner=%U(%u) group=%G(%g) size=%s inode=%i links=%h
atime=%x
mtime=%y
ctime=%z
birth=%w' <FILE>
# 여러 파일 — CSV (SIEM/엑셀 업로드용, epoch 초)
find /var/www/html -xdev -type f -newerct '2026-09-24 00:00' \
-exec stat -c '%n,%a,%u,%g,%s,%i,%W,%Y,%Z' {} + > /tmp/ir_files.csv
| 관점 | 내용 |
|---|---|
| Evidence | 파일을 열거나 복사하기 전에 stat 결과부터 저장 |
| IOC | stat은 해시를 계산하지 않는다. sha256sum을 함께 수집한다 (20편) |
| Timeline | epoch 값(%W %Y %Z)으로 정렬하면 여러 서버의 사건 순서를 쉽게 맞출 수 있다 |
| Detection → Response | FIM 경보 → stat 수집 → mtime/ctime/birth 비교 → 로그 교차 확인 → 대응 |
| 실수 | 결과 | 예방 |
|---|---|---|
링크에 stat만 실행 | 대상이 아닌 링크 정보를 기록 | 필요 시 stat -L 추가 |
-c에서 \n 사용 | 문자 그대로 출력 | --printf 사용 |
Birth -를 "생성 시각 없음"으로 단정 | FS·도구 미지원일 수 있음 | FS 종류·coreutils 버전 확인 |
| 시간대 없는 epoch 변환 | 9시간 오차 | date -d @EPOCH 시 TZ 확인 |
ext2/ext3 표시를 보고 ext4가 아니라고 판단 | 오해 | df -T, findmnt로 확인 |
[ ] stat 기본 출력의 모든 필드를 설명할 수 있다
[ ] -c 형식으로 보고서용 한 줄을 만들었다
[ ] %W %Y %Z epoch 값을 확인했다
[ ] stat 과 stat -L 의 차이를 확인했다
[ ] stat -f 로 파일 시스템 정보를 확인했다
[ ] mtime 이 birth 보다 과거인 모순을 찾아냈다
stat은 inode 정보(종류·권한·소유자·크기·inode·링크·네 가지 시간)를 한 번에 보여 준다.stat은 내용을 읽지 않으므로 atime을 바꾸지 않는다. 증거 수집 첫 단계로 적합하다.-c/--printf로 보고서·CSV 형식을 만들고, epoch 형식으로 정렬한다.-L은 링크 대상, -f는 파일 시스템 정보를 보여 준다.stat과 sha256sum은 항상 함께 수집한다.다음 글 「17. 파일 확장자와 실제 파일 형식」 에서는 이미지 확장자를 가진 PHP 파일, PDF 이름을 가진 실행 파일처럼 확장자와 내용이 다른 파일 을 만들고, Linux가 확장자를 전혀 신뢰하지 않는다는 점을 확인한다.