파일 · 권한 · 사용자 관리 06 / 50 · Part 1. Linux 파일 관리 기초
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정analyst)
기초편 연계: 「리눅스 시스템 기초」 11. Linux 파일과 디렉터리 관리 · 12. 절대경로와 상대경로
cd는 너무 단순해 보여서 따로 공부할 대상이 아닌 것 같다. 하지만 cd에는 Linux 프로세스와 권한 모델의 핵심이 두 가지 들어 있다.
cd는 외부 프로그램일 수 없고 쉘 내장 명령(builtin)이어야 한다.r이 아니라 x다. 소유자 본인이라도 x가 없으면 들어갈 수 없다.이번 글에서는 cd의 주요 사용법과 함께 이 두 원리를 실습으로 확인한다.
| 형태 | 이동 위치 | 해석 주체 |
|---|---|---|
cd | 홈 디렉터리 ($HOME) | 쉘 |
cd ~ / cd ~analyst | 내 홈 / 지정 사용자 홈 | 쉘 |
cd - | 직전 디렉터리 ($OLDPWD), 이동 후 경로 출력 | 쉘 |
cd .. | 상위 디렉터리 | 커널 (.. 엔트리) |
cd /var/log | 절대경로 | 커널 |
cd -P link | 심볼릭 링크를 풀어 물리 경로로 이동 | 쉘 + 커널 |
| 변수 | 의미 |
|---|---|
PWD | 현재 디렉터리 (논리 경로) |
OLDPWD | 직전 디렉터리 |
HOME | cd만 입력했을 때의 목적지 |
CDPATH | 상대경로 cd 시 먼저 찾아보는 디렉터리 목록 |

외부 명령은 쉘이 fork()로 자식 프로세스를 만들고 그 안에서 실행한다. 자식이 chdir()로 cwd를 바꿔도 자식이 끝나면 그 상태는 사라진다. 부모 쉘의 cwd는 그대로다. 그래서 쉘 자신이 chdir()을 호출해야 하므로 cd는 builtin 이다. 같은 이유로 export, umask, exit도 builtin이다.
참고로 Rocky 등 일부 배포판에는 /usr/bin/cd라는 파일이 있다. 이것은 POSIX 호환을 위한 스크립트로, 실행해도 호출한 쉘의 위치는 바뀌지 않는다.
chdir() 시스템 콜은 경로상의 모든 디렉터리와 목적지 디렉터리에 대해 x(search) 권한 을 검사한다. r은 "이름 목록을 읽는 권한"이고, x는 "안으로 들어가거나 통과하는 권한"이다. 둘은 독립적이다.
r 없이 x만 있으면 → 들어갈 수는 있지만 ls는 실패한다.x 없이 r만 있으면 → 들어갈 수 없다. 소유자라도 마찬가지다.# 1) 기본 이동과 직전 디렉터리
cd /var/log && pwd
cd - # 직전 위치로 이동 후 경로 출력
cd ~ && pwd
echo "PWD=$PWD OLDPWD=$OLDPWD"
# 2) x 권한이 없는 디렉터리 (소유자 본인)
mkdir -p ~/lab06/secret && chmod 600 ~/lab06/secret
cd ~/lab06/secret # rw- 이지만 x 없음
ls -ld ~/lab06/secret
chmod 700 ~/lab06/secret && cd ~/lab06/secret && pwd
# 3) 다른 사용자(root)의 홈
cd /root
ls -ld /root

텍스트 원본(실제 출력):
[analyst@rocky9-lab ~]$ cd /var/log && pwd
/var/log
[analyst@rocky9-lab log]$ cd -
/home/analyst
[analyst@rocky9-lab ~]$ cd ~ && pwd
/home/analyst
[analyst@rocky9-lab ~]$ echo "PWD=$PWD OLDPWD=$OLDPWD"
PWD=/home/analyst OLDPWD=/home/analyst
[analyst@rocky9-lab ~]$ mkdir -p ~/lab06/secret && chmod 600 ~/lab06/secret
[analyst@rocky9-lab ~]$ cd ~/lab06/secret
-bash: cd: /home/analyst/lab06/secret: Permission denied
[analyst@rocky9-lab ~]$ ls -ld ~/lab06/secret
drw------- 2 analyst analyst 4096 Sep 24 10:16 /home/analyst/lab06/secret
[analyst@rocky9-lab ~]$ chmod 700 ~/lab06/secret && cd ~/lab06/secret && pwd
/home/analyst/lab06/secret
[analyst@rocky9-lab secret]$ cd /root
-bash: cd: /root: Permission denied
[analyst@rocky9-lab secret]$ ls -ld /root
dr-xr-x--- 1 root root 4096 Sep 24 10:12 /root
| 출력 | 해석 |
|---|---|
cd - → /home/analyst | cd -는 이동과 함께 도착 경로를 출력한다 |
PWD=/home/analyst OLDPWD=/home/analyst | cd ~를 홈에서 실행했으므로 직전 위치도 홈이다 |
cd: .../secret: Permission denied | 소유자 analyst 본인이 만든 디렉터리지만 권한이 rw-(600)라 x가 없다 |
drw------- analyst analyst | 소유자 칸에 r, w는 있지만 x가 없다 |
chmod 700 후 이동 성공 | x가 추가되자 들어갈 수 있다 |
cd: /root: Permission denied | /root는 dr-xr-x--- root root. analyst는 other 칸(---)에 해당해 x가 없다 |
600 디렉터리 실습은 "디렉터리를 파일처럼 600으로 잠그면 안전하다"는 오해를 깨 준다. 디렉터리를 소유자 전용으로 만들 때는 700을 쓴다.
| 주제 | 내용 |
|---|---|
| 경로 통과 권한 | 민감한 파일을 보호하려면 상위 디렉터리의 other x를 제거 하는 것이 가장 확실하다. Rocky의 홈 700, Ubuntu의 홈 750이 그 예다 |
--x 디렉터리 | 목록은 숨기고 이름을 아는 사람만 접근하게 한다. 하지만 이름을 추측할 수 있으면 보호 효과는 약하다 (보안이 아니라 은닉) |
CDPATH 악용 | CDPATH가 설정된 환경에서 cd logs가 엉뚱한 디렉터리로 이동할 수 있다. 스크립트에서 cd 후 rm 같은 명령을 쓰면 위험하다 |
스크립트의 cd 실패 | cd /target; rm -rf *에서 cd가 실패하면 현재 위치 의 파일이 지워진다 |
| 관점 | 내용 |
|---|---|
| 로그 | cd는 builtin이므로 auditd execve 이벤트가 발생하지 않는다. 쉘 내부에서 chdir()만 호출된다 |
| Evidence | 공격자의 이동 경로는 ~/.bash_history, 이후 실행된 명령의 cwd 필드(auditd CWD 레코드)로 추정한다 |
| Detection | 권한 없는 디렉터리 접근 실패는 기본 로그에 남지 않는다. 민감 경로는 auditd 감시 규칙(-w /root -p rwxa)으로 실패 시도까지 기록할 수 있다 |
| Investigation | 실행 중인 프로세스의 작업 위치는 ls -l /proc/<PID>/cwd로 확인한다. 웹셸이 띄운 프로세스의 cwd는 업로드 디렉터리인 경우가 많다 |
[Evidence] auditd: type=CWD cwd="/var/www/html/upload"
type=EXECVE argc=2 a0="cat" a1="../../config/db.php"
↓
[해석] cd 자체는 기록되지 않았지만 CWD 레코드로 "어디서" 실행했는지 복원
↓
[판단] 웹 업로드 디렉터리에서 설정 파일(DB 비밀번호) 열람 → 자격 증명 탈취 시도
.bash_history는 공격자가 쉽게 지우거나 비활성화(unset HISTFILE)할 수 있으므로 보조 증거 로만 사용한다.
| 실수 | 결과 | 예방 |
|---|---|---|
cd /dir; rm -rf * | cd 실패 시 현재 위치 삭제 | cd /dir && rm -rf ./* 또는 set -e |
디렉터리를 600/644로 설정 | 소유자도 진입 불가, 파일 접근 불가 | 디렉터리는 700/755 계열 |
/usr/bin/cd로 이동하려 함 | 부모 쉘 위치 불변 | builtin cd 사용 |
cd 기록이 audit 로그에 있을 거라 기대 | 기록 없음 | CWD 레코드와 이후 명령으로 추정 |
sudo cd /root 시도 | sudo: cd: command not found | sudo -i 또는 sudo ls /root |
[ ] cd, cd ~, cd -, cd .. 의 차이를 확인했다
[ ] $PWD 와 $OLDPWD 값을 확인했다
[ ] x 권한이 없는 디렉터리에 소유자도 들어갈 수 없음을 재현했다
[ ] /root 접근이 거부되는 이유를 권한 칸으로 설명할 수 있다
[ ] cd 가 builtin 이어야 하는 이유를 설명할 수 있다
[ ] cd 가 execve 로그를 남기지 않는다는 점을 이해했다
cd는 쉘 내장 명령 이어야 한다.x 다. 소유자라도 x가 없으면 들어갈 수 없다.r은 목록, x는 진입이며 서로 독립적이다.cd 실패를 처리하지 않으면 엉뚱한 위치에서 명령이 실행된다.cd는 execve 로그를 남기지 않는다. auditd CWD 레코드와 /proc/<PID>/cwd로 위치를 추적한다.다음 글 「07. mkdir과 디렉터리 생성」 에서는 새 디렉터리의 권한이 어떻게 정해지는지, Rocky와 Ubuntu에서 같은 mkdir 명령이 왜 다른 권한을 만드는지 를 umask로 설명한다.