파일 · 권한 · 사용자 관리 10 / 50 · Part 1. Linux 파일 관리 기초
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정analyst)
기초편 연계: 「리눅스 시스템 기초」 11. Linux 파일과 디렉터리 관리
Part 1의 마지막 글이다. 지금까지 파일은 이름 → inode → 데이터 블록 구조이고, 이름은 디렉터리에, 속성은 inode에 있다는 것을 확인했다. 이 구조를 이해하면 mv와 rm이 무엇을 하는지 정확히 설명할 수 있다.
mv는 같은 파일 시스템 안에서는 이름표만 옮긴다. 데이터는 한 바이트도 움직이지 않는다.mv가 다른 파일 시스템으로 갈 때는 복사 후 삭제 한다.rm은 데이터를 지우는 것이 아니라 이름 하나를 제거 한다.이 차이는 로그 삭제 흔적 분석, 증거 보존, 안전한 파일 폐기와 직결된다.
| 상황 | 내부 동작 | inode |
|---|---|---|
| 같은 디렉터리에서 이름 변경 | rename() 한 번 | 유지 |
| 같은 파일 시스템의 다른 디렉터리로 이동 | rename() 한 번 (두 디렉터리 엔트리 수정) | 유지 |
| 다른 파일 시스템으로 이동 | rename() 실패(EXDEV) → 복사 + 원본 삭제 | 새 inode |
주요 옵션: -i(덮어쓰기 확인), -n(덮어쓰지 않음), -v(과정 출력), -b(덮어쓸 파일 백업).
| 형태 | 동작 |
|---|---|
rm file | 이름 제거 (unlink()) |
rm -d dir | 빈 디렉터리 제거 (rmdir()) |
rm -r dir | 안의 항목을 모두 제거한 뒤 디렉터리 제거 |
rm -f | 없는 파일 무시, 확인 없이 제거 |
rm -i / -I | 하나씩 확인 / 3개 초과·재귀 시 한 번 확인 |
| 작업 | 필요한 권한 |
|---|---|
mv a b (같은 디렉터리) | 디렉터리의 w + x |
mv dir1/a dir2/ | dir1과 dir2 모두 w + x |
rm file | 파일이 아니라 상위 디렉터리의 w + x (Sticky Bit가 있으면 추가 조건, 30편) |
파일이 r--(읽기 전용)여도 디렉터리에 w가 있으면 삭제할 수 있다. rm이 "write-protected regular file" 경고를 띄우는 것은 사용자 확인일 뿐 권한 검사가 아니다.

같은 파일 시스템 안의 mv는 rename() 시스템 콜 하나로 끝난다. 원래 디렉터리에서 엔트리를 빼고, 새 디렉터리(또는 같은 디렉터리)에 새 이름으로 엔트리를 추가한다. inode의 권한·소유자·mtime은 그대로다. 다만 ext4·xfs는 rename 시 파일의 ctime을 갱신 한다. 그래서 이름을 바꾼 시점이 ctime에 남는다.
rm은 unlink()로 디렉터리 엔트리를 제거하고 inode의 링크 수를 1 줄인다. 02편에서 본 것처럼 링크 수 0 + 열린 fd 0 이 되어야 inode와 블록이 해제된다. 해제된 블록은 "사용 가능"으로 표시될 뿐 즉시 0으로 덮이지 않는다.
이 때문에 다음 두 가지가 동시에 성립한다.
rm 해도 디스크가 비지 않을 수 있다.cd /data && mkdir lab10 && cd lab10
# 1) 같은 파일 시스템 안의 mv — inode 유지, ctime 변화
echo "evidence" > a.txt && ls -li a.txt
stat -c 'inode=%i ctime=%z' a.txt
sleep 1; mv a.txt b.txt && ls -li b.txt
stat -c 'inode=%i ctime=%z' b.txt
# 2) 다른 파일 시스템으로 mv (/data=ext4 → /dev/shm=tmpfs)
mv b.txt /dev/shm/b.txt && ls -li /dev/shm/b.txt
# 3) 링크 수로 rm 추적
ln /dev/shm/b.txt /dev/shm/b-hard.txt && ls -li /dev/shm/b*.txt
rm /dev/shm/b.txt && ls -li /dev/shm/b-hard.txt
rm /dev/shm/b-hard.txt
# 4) 디렉터리 삭제 단계
mkdir dir1 && touch dir1/f && rm dir1
rm -d dir1
rm -rv dir1

텍스트 원본(실제 출력):
[analyst@rocky9-lab ~]$ cd /data && mkdir lab10 && cd lab10
[analyst@rocky9-lab lab10]$ echo "evidence" > a.txt && ls -li a.txt
12 -rw-r--r-- 1 analyst analyst 9 Sep 24 10:15 a.txt
[analyst@rocky9-lab lab10]$ stat -c 'inode=%i ctime=%z' a.txt
inode=12 ctime=2026-09-24 10:15:45.199687790 +0900
[analyst@rocky9-lab lab10]$ sleep 1; mv a.txt b.txt && ls -li b.txt
12 -rw-r--r-- 1 analyst analyst 9 Sep 24 10:15 b.txt
[analyst@rocky9-lab lab10]$ stat -c 'inode=%i ctime=%z' b.txt
inode=12 ctime=2026-09-24 10:15:46.227687797 +0900
[analyst@rocky9-lab lab10]$ mv b.txt /dev/shm/b.txt && ls -li /dev/shm/b.txt
2 -rw-r--r-- 1 analyst analyst 9 Sep 24 10:15 /dev/shm/b.txt
[analyst@rocky9-lab lab10]$ ln /dev/shm/b.txt /dev/shm/b-hard.txt && ls -li /dev/shm/b*.txt
2 -rw-r--r-- 2 analyst analyst 9 Sep 24 10:15 /dev/shm/b-hard.txt
2 -rw-r--r-- 2 analyst analyst 9 Sep 24 10:15 /dev/shm/b.txt
[analyst@rocky9-lab lab10]$ rm /dev/shm/b.txt && ls -li /dev/shm/b-hard.txt
2 -rw-r--r-- 1 analyst analyst 9 Sep 24 10:15 /dev/shm/b-hard.txt
[analyst@rocky9-lab lab10]$ rm /dev/shm/b-hard.txt
[analyst@rocky9-lab lab10]$ mkdir dir1 && touch dir1/f && rm dir1
rm: cannot remove 'dir1': Is a directory
[analyst@rocky9-lab lab10]$ rm -d dir1
rm: cannot remove 'dir1': Directory not empty
[analyst@rocky9-lab lab10]$ rm -rv dir1
removed 'dir1/f'
removed directory 'dir1'
| 단계 | 출력 | 해석 |
|---|---|---|
a.txt 생성 | inode 12, ctime 10:15:45.199 | 기준값 |
mv a.txt b.txt | inode 12 유지, ctime 10:15:46.227 | 이름만 바뀌고 실체는 같다. 단, ctime에 이름 변경 시각이 남는다 |
mv → /dev/shm | inode 2 | 다른 FS(tmpfs)로 이동 → 새 inode. 내부적으로 복사 후 원본 삭제 |
ln 후 | 두 이름 모두 inode 2, 링크 수 2 | 이름 두 개가 같은 파일을 가리킴 |
rm b.txt 후 | b-hard.txt 링크 수 1 | 이름 하나만 사라지고 데이터는 유지 |
rm b-hard.txt | 출력 없음 | 링크 수 0 → 공간 해제 |
rm dir1 | Is a directory | 옵션 없는 rm은 디렉터리를 지우지 않는다 |
rm -d dir1 | Directory not empty | -d는 빈 디렉터리만 |
rm -rv dir1 | 파일 → 디렉터리 순서로 제거 | 안쪽부터 unlink 후 rmdir |
mv 전후 ctime 비교가 이번 실습에서 가장 실용적인 관찰이다. 공격자가 웹셸을 image.jpg에서 image.php로 이름을 바꿨다면, mtime은 업로드 시각, ctime은 이름 변경 시각 으로 두 사건이 분리되어 남는다.
| 주제 | 내용 |
|---|---|
| 로그 삭제 | rm /var/log/secure는 이름만 제거한다. rsyslog가 열고 있으면 계속 삭제된 inode에 기록된다 (02편). 공격자는 보통 rm보다 내용을 비우거나(> file) 특정 줄만 삭제 한다 |
| 확장자 변경 | 업로드 필터 우회 후 mv로 .php로 변경 → ctime에 흔적 |
| 파일 교체 | 디렉터리 w 권한만 있으면 mv evil.sh backup.sh로 남의 파일을 교체 할 수 있다 (파일 자체 권한과 무관) |
| 안전 삭제 | rm은 복구 가능성이 남는다. shred는 저널링 FS·SSD·스냅샷 환경에서 완전 삭제를 보장하지 못한다. 민감 데이터는 암호화 후 키 폐기가 현실적인 방법 |
rm -rf 사고 | 변수 미설정(rm -rf $DIR/)으로 루트 삭제 시도. GNU rm은 / 자체는 --preserve-root로 기본 보호 |
| 관점 | 내용 |
|---|---|
| Detection | 파일 삭제·이름 변경은 기본 syslog에 남지 않는다. auditd -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat,renameat2 -F dir=/var/log -k log_tamper 같은 규칙으로 민감 경로만 감시한다 |
| IOC | 이름이 바뀌어도 inode와 해시는 같다. 이름 기반 IOC보다 해시 IOC 가 강한 이유 |
| Evidence | 삭제된 파일은 상위 디렉터리의 mtime·ctime 변경으로 "무언가 삭제됐다"는 사실을 간접 확인할 수 있다 |
| Response | 로그 삭제가 의심되면 /proc/*/fd에서 (deleted) 로그를 먼저 확인하고 cp /proc/<PID>/fd/N으로 복구한다. 원격 SIEM에 이미 전송된 로그가 있으면 로컬 로그와 비교한다 |
[Detection] SIEM: 서버 A 로그 수신이 02:14 이후 급감
↓
[확인] ls -l /var/log/secure → 크기 0, ctime 02:14
ls -l /proc/$(pidof rsyslogd)/fd | grep deleted (삭제된 경우)
↓
[판단] 로그 비우기 또는 삭제 = 방어 회피 (ATT&CK T1070.002)
↓
[Evidence] SIEM에 02:14 이전까지 전송된 로그로 공격 행위 재구성
↓
[Response] 로그 원격 전송(Forwarding) 필수화, 로그 파일 append-only 속성 검토 (chattr +a)
로그를 원격으로 실시간 전송 해야 하는 이유가 여기에 있다. 서버 안의 로그는 root 권한을 얻은 공격자가 언제든 지울 수 있다.
| 실수 | 결과 | 예방 |
|---|---|---|
대용량 로그 rm 후 용량 미확보 | 서비스가 파일을 계속 열고 있음 | : > file 또는 서비스 reload |
mv로 증거 파일 이동 | 원본 위치 정보·ctime 변경 | 증거는 cp -a로 복사, 원본 유지 |
다른 FS로 mv 중 중단 | 복사 일부 + 원본 잔존 | 대용량은 rsync 후 검증·삭제 |
rm -rf 경로 변수 미검증 | 대량 삭제 | ${DIR:?} 사용, echo로 먼저 확인 |
| 파일 권한만 막으면 삭제도 막힌다고 생각 | 디렉터리 w로 삭제 가능 | 디렉터리 권한·Sticky Bit 점검 |
[ ] 같은 FS 안의 mv 는 inode 가 유지됨을 확인했다
[ ] mv 후 ctime 이 갱신되는 것을 확인했다
[ ] 다른 FS 로의 mv 는 새 inode 가 됨을 확인했다
[ ] 하드 링크를 만들고 rm 할 때 링크 수 변화를 추적했다
[ ] rm / rm -d / rm -r 의 차이를 확인했다
[ ] 파일 삭제 권한이 상위 디렉터리의 w 에서 나온다는 것을 설명할 수 있다
mv는 rename() — inode 유지, 이름만 변경, ctime 갱신.mv는 복사 + 삭제 — 새 inode가 만들어진다.rm은 unlink() — 이름 하나를 지우고 링크 수를 줄인다. 데이터 해제는 링크 0 + 열린 fd 0일 때다.w·x 에서 나온다.rm은 안전 삭제가 아니며, shred도 저널링·SSD 환경에서 한계가 있다.Part 1 정리 — 01~10편에서 파일의 구조(이름·inode·데이터), 파일 시스템과 fd, 디렉터리 구조, 경로 해석, 그리고 기본 명령(ls, cd, mkdir, touch, cp, mv, rm)이 inode 수준에서 무엇을 바꾸는지 확인했다.
Part 2 「Linux 파일 종류와 속성」을 시작한다. 다음 글 「11. Linux 파일 종류 7가지」 에서는 일반 파일·디렉터리 외에 심볼릭 링크, 블록·문자 장치, 소켓, FIFO를 실제로 하나씩 만들어 보고, 각 종류가 침해사고에서 어떻게 악용되는지 정리한다.