파일 · 권한 · 사용자 관리 08 / 50 · Part 1. Linux 파일 관리 기초
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정analyst)
기초편 연계: 「리눅스 시스템 기초」 11. Linux 파일과 디렉터리 관리 · 14. inode와 파일 시스템
touch는 보통 "빈 파일을 만드는 명령"으로 소개된다. 하지만 이름 그대로 touch의 본래 목적은 파일의 시간을 건드리는 것 이다. 파일이 없으면 만들고, 있으면 시간을 현재로 갱신하며, 옵션을 주면 임의의 과거 시간 으로도 바꿀 수 있다.
마지막 기능은 공격자가 자주 사용한다. 웹셸이나 백도어를 심은 뒤 주변 파일과 같은 날짜로 시간을 바꿔 ls -lt에서 눈에 띄지 않게 하는 타임스탬프 조작(timestomping) 이다.
이번 글에서는 touch의 파일 생성과 시간 변경 동작을 실제로 재현하고, 조작할 수 있는 시간과 조작할 수 없는 시간 을 구분한다. 네 가지 타임스탬프의 상세 의미는 15편에서 다룬다.
| 상황 | 동작 |
|---|---|
| 파일이 없음 | 크기 0인 파일 생성 (-c를 주면 생성하지 않음) |
| 파일이 있음 | atime·mtime을 현재 시각으로 갱신 (내용은 그대로) |
| 옵션 | 의미 | 예 |
|---|---|---|
-a | atime만 변경 | touch -a f |
-m | mtime만 변경 | touch -m f |
-d "문자열" | 지정한 날짜로 설정 | touch -d "2021-03-15 09:00" f |
-t [[CC]YY]MMDDhhmm[.ss] | 숫자 형식 날짜 | touch -t 202103150900 f |
-r 참조파일 | 다른 파일과 같은 시간으로 | touch -r /etc/hosts f |
-c | 파일이 없으면 만들지 않음 | touch -c f |
-h | 심볼릭 링크 자체의 시간 변경 | touch -h link |
| 시간 | 바뀌는 때 | ls -l 표시 |
|---|---|---|
| atime | 내용을 읽을 때 (relatime 정책 적용) | ls -lu |
| mtime | 내용을 수정할 때 | 기본 표시 |
| ctime | inode(권한·소유자·링크·시간 등)가 바뀔 때 | ls -lc |
| birth | 파일이 생성될 때 (지원 FS에서만) | stat의 Birth |

touch는 파일이 없으면 open(O_CREAT)로 만들고, 그다음 utimensat() 시스템 콜로 atime·mtime을 설정한다. 이때 중요한 규칙이 있다.
utimensat() 호출 자체가 inode 변경이므로 ctime은 오히려 "조작한 시각"으로 갱신된다.단, ctime도 절대적인 증거는 아니다. root 권한이 있으면 시스템 시계를 바꾼 뒤 조작하거나, debugfs로 inode를 직접 수정하는 방법이 존재한다. 이런 경우에는 시스템 시계 변경 로그, 다른 파일·로그와의 상호 모순 을 찾아야 한다.
실습은 실습용 ext4 볼륨(
/data)에서 진행했다. ext4는 birth time을 지원한다.
cd /data && mkdir lab08 && cd lab08
# 1) 파일 생성 직후 — 네 시간이 모두 같다
touch new.txt
stat new.txt
# 2) 내용 수정 → mtime, ctime 갱신
sleep 2; echo "data" >> new.txt
stat --printf 'mtime=%y\nctime=%z\n' new.txt
# 3) 타임스탬프 조작 재현
touch -d "2021-03-15 09:00:00" new.txt
stat --printf 'atime=%x\nmtime=%y\nctime=%z\nbirth=%w\n' new.txt
ls -l --time-style=full-iso new.txt
# 4) 조작된 파일 찾기 — mtime 기준 vs ctime 기준
find . -newermt "2026-01-01" -ls
find . -newerct "2026-01-01" -ls
| 형식 지정자 | 의미 |
|---|---|
%x / %y / %z / %w | atime / mtime / ctime / birth (사람이 읽는 형식) |
find -newermt 날짜 | mtime이 날짜보다 최근인 파일 |
find -newerct 날짜 | ctime이 날짜보다 최근인 파일 |

텍스트 원본(실제 출력):
[analyst@rocky9-lab ~]$ cd /data && mkdir lab08 && cd lab08
[analyst@rocky9-lab lab08]$ touch new.txt
[analyst@rocky9-lab lab08]$ stat new.txt
File: new.txt
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 700h/1792d Inode: 12 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ analyst) Gid: ( 1000/ analyst)
Access: 2026-09-24 10:16:04.851687911 +0900
Modify: 2026-09-24 10:16:04.851687911 +0900
Change: 2026-09-24 10:16:04.851687911 +0900
Birth: 2026-09-24 10:16:04.851687911 +0900
[analyst@rocky9-lab lab08]$ sleep 2; echo "data" >> new.txt
[analyst@rocky9-lab lab08]$ stat --printf 'mtime=%y\nctime=%z\n' new.txt
mtime=2026-09-24 10:16:06.879687923 +0900
ctime=2026-09-24 10:16:06.879687923 +0900
[analyst@rocky9-lab lab08]$ touch -d "2021-03-15 09:00:00" new.txt
[analyst@rocky9-lab lab08]$ stat --printf 'atime=%x\nmtime=%y\nctime=%z\nbirth=%w\n' new.txt
atime=2021-03-15 09:00:00.000000000 +0900
mtime=2021-03-15 09:00:00.000000000 +0900
ctime=2026-09-24 10:16:06.899687923 +0900
birth=2026-09-24 10:16:04.851687911 +0900
[analyst@rocky9-lab lab08]$ ls -l --time-style=full-iso new.txt
-rw-r--r-- 1 analyst analyst 5 2021-03-15 09:00:00.000000000 +0900 new.txt
[analyst@rocky9-lab lab08]$ find . -newermt "2026-01-01" -ls
11 4 drwxr-xr-x 2 analyst analyst 4096 Sep 24 10:16 .
[analyst@rocky9-lab lab08]$ find . -newerct "2026-01-01" -ls
11 4 drwxr-xr-x 2 analyst analyst 4096 Sep 24 10:16 .
12 4 -rw-r--r-- 1 analyst analyst 5 Mar 15 2021 ./new.txt
| 단계 | 관찰 | 해석 |
|---|---|---|
생성 직후 stat | Access·Modify·Change·Birth 모두 10:16:04.851 | 생성 순간 네 시간이 같다. regular empty file, 크기 0 |
| 내용 추가 후 | mtime·ctime 10:16:06.879 | 내용이 바뀌면 mtime, 크기(inode)가 바뀌어 ctime도 갱신 |
touch -d 후 atime·mtime | 2021-03-15 09:00:00.000000000 | 과거로 조작 성공. 나노초가 정확히 .000000000인 점도 특징 |
touch -d 후 ctime | 10:16:06.899 | 조작한 순간의 실제 시각 으로 갱신됨 |
| birth | 10:16:04.851 (변화 없음) | 최초 생성 시각이 그대로 남아 있다 |
ls -l --time-style=full-iso | 2021-03-15 09:00:00 | ls -l은 mtime을 보여 주므로 조작된 시간만 보인다 |
find -newermt 2026-01-01 | new.txt 없음 | mtime 기준 검색은 조작된 파일을 놓친다 |
find -newerct 2026-01-01 | ./new.txt 발견 | ctime 기준 검색은 조작된 파일을 찾아낸다 |
마지막 두 줄이 실무 결론이다. 침해 조사에서 "최근 변경 파일"을 찾을 때 mtime만 보면 공격자가 의도한 결과를 보게 된다. ctime(-newerct, -cmin, -ctime)을 함께 사용한다.
| 구분 | 내용 |
|---|---|
| 공격 기법 | MITRE ATT&CK T1070.006 (Indicator Removal: Timestomp) — 파일 시간을 주변 정상 파일과 같게 맞춰 은닉 |
| 흔한 패턴 | touch -r /var/www/html/index.php shell.php — 기존 파일과 동일한 시간으로 위장 |
| 판별 단서 | mtime < ctime 차이가 비정상적으로 큼, 나노초가 .000000000, birth가 mtime보다 늦음 |
| 과장 금지 | cp -p, tar x, rsync -a, 패키지 설치도 원본 mtime을 보존해 같은 패턴을 만든다. 단독 증거가 아니라 다른 로그와 결합 해 판단 |
정상 사례와 구분하는 기준:
| 단서 | 정상 가능성이 높은 경우 | 의심 경우 |
|---|---|---|
| mtime ≪ ctime | 패키지·백업 복원으로 설치된 파일 | 웹 업로드 폴더의 단일 스크립트 파일 |
나노초 .000000000 | tar로 푼 파일(초 단위 보존) | 단일 파일만 해당 |
| birth > mtime | 복사·복원 파일 | 최근 생성인데 수년 전 mtime을 가진 실행 파일 |
[Detection] FIM 알림: /var/www/html/assets/img/logo.php 신규 파일
↓
[Evidence] stat → Modify 2023-05-02 (주변 파일과 동일)
Change 2026-09-24 02:13:55 ← 실제 작업 시각
Birth 2026-09-24 02:13:54
↓
[판단] 이미지 폴더의 .php + mtime/ctime 불일치 → timestomping 된 웹셸
↓
[Timeline] 웹 로그 02:13:5x 전후 POST 요청 → 업로드 경로·공격 IP 확인
↓
[Response] 파일 보존(해시) → 차단 → 동일 시각(ctime) 파일 전체 검색
find /var/www -newerct "2026-09-24 02:00" ! -newerct "2026-09-24 02:30"
| 관점 | 내용 |
|---|---|
| SIEM | 파일 시간 조작 자체는 기본 로그에 남지 않는다. auditd로 utimensat/utimes 시스템 콜을 감시하면 기록할 수 있지만 정상 이벤트가 많아 민감 경로 한정 으로 적용한다 |
| Timeline | 타임라인 분석은 ctime·birth 우선, mtime은 참고값으로 사용한다 |
| Evidence | 증거 수집 시 stat 결과 전체를 저장한다. ls -l의 날짜 하나만 기록하면 조작 여부를 판단할 수 없다 |
| 실수 | 결과 | 예방 |
|---|---|---|
ls -lt로만 최근 파일 조사 | timestomping된 파일 누락 | find -newerct, ls -lct 병행 |
| mtime ≠ ctime이면 무조건 공격으로 판단 | 오탐 (패키지·백업 복원) | 위치·형식·소유자·로그와 결합 |
| 증거 파일을 열어 본 뒤 stat 수집 | atime 변경 가능 | stat 먼저, 내용 확인은 나중에 |
touch로 로그 파일을 "초기화"하려 함 | 내용은 그대로, 시간만 바뀜 | 로그 비우기는 logrotate 또는 : > file |
| birth가 항상 있다고 가정 | FS·도구에 따라 - 표시 | stat 출력에서 Birth 지원 여부 확인 |
[ ] touch 로 빈 파일을 만들고 네 시간이 같음을 확인했다
[ ] 내용 수정 시 mtime 과 ctime 이 함께 바뀌는 것을 확인했다
[ ] touch -d 로 atime·mtime 을 과거로 바꿨다
[ ] ctime 과 birth 가 조작되지 않음을 확인했다
[ ] find -newermt 와 -newerct 결과 차이를 확인했다
[ ] timestomping 과 정상 복원을 구분하는 기준을 정리했다
touch는 파일이 없으면 만들고, 있으면 atime·mtime을 갱신 한다.-d, -t, -r 옵션으로 atime·mtime은 임의의 시간 으로 바꿀 수 있다.ls -l과 find -newermt는 mtime 기준이라 timestomping에 속는다. -newerct로 교차 확인 한다.다음 글 「09. cp로 파일 복사하기」 에서는 복사할 때 무엇이 보존되고 무엇이 바뀌는지 를 확인한다. 증거 파일을 복사할 때 cp만 쓰면 소유자·시간·SUID가 사라지는 이유와, cp -a로 속성을 보존하는 방법을 실습한다.