파일 · 권한 · 사용자 관리 11 / 50 · Part 2. Linux 파일 종류와 속성
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정analyst)
기초편 연계: 「리눅스 시스템 기초」 13. Linux 파일 종류
Part 2 「Linux 파일 종류와 속성」을 시작한다. Part 1에서 파일이 이름·inode·데이터 블록으로 이루어진다는 것을 봤다면, Part 2는 inode에 저장된 속성 을 하나씩 해석한다. 그 첫 번째가 파일 종류(file type) 다.
Linux에는 일곱 가지 파일 종류가 있다. 일반 파일과 디렉터리 외에 심볼릭 링크, 블록 장치, 문자 장치, 소켓, FIFO가 있다. 이번 글에서는 일곱 종류를 실습 환경에서 직접 하나씩 만들어 확인하고, 각 종류가 공격에 어떻게 쓰이는지 정리한다.
ls -l 첫 글자 | 종류 | 데이터 블록의 의미 | 대표 예 |
|---|---|---|---|
- | 일반 파일 (regular) | 실제 내용 | 문서, 실행 파일, 스크립트 |
d | 디렉터리 | 이름 → inode 목록 | /etc, /home |
l | 심볼릭 링크 | 대상 경로 문자열 | /bin -> usr/bin |
b | 블록 장치 | 없음 (장치 번호만) | /dev/sda, /dev/loop0 |
c | 문자 장치 | 없음 (장치 번호만) | /dev/null, /dev/tty |
s | 소켓 | 없음 (통신 끝점) | /dev/log, /run/*.sock |
p | FIFO (named pipe) | 없음 (커널 버퍼) | mkfifo로 생성 |
장치 파일은 내용 대신 major, minor 번호 를 가진다. ls -l에서 크기 자리에 7, 0처럼 표시된다.
| 구분 | 블록 장치 (b) | 문자 장치 (c) |
|---|---|---|
| 입출력 단위 | 고정 크기 블록, 임의 위치 접근 | 바이트 스트림 |
| 버퍼링 | 커널 페이지 캐시 사용 | 대체로 직접 전달 |
| 예 | 디스크, 파티션, loop | 터미널, /dev/null, /dev/random |

파일 종류는 inode의 mode 필드 상위 비트(S_IFMT)에 저장된다. stat의 %f(16진 mode)나 debugfs의 Mode에서 보이는 100644(일반 파일), 40755(디렉터리)의 앞자리가 바로 종류다.
| mode 상위 값 (8진) | 종류 |
|---|---|
0100000 | 일반 파일 |
0040000 | 디렉터리 |
0120000 | 심볼릭 링크 |
0060000 | 블록 장치 |
0020000 | 문자 장치 |
0140000 | 소켓 |
0010000 | FIFO |
커널은 open()이 들어오면 이 종류를 보고 처리 방식을 결정한다. 일반 파일은 파일 시스템의 데이터 블록으로, 장치 파일은 major 번호에 해당하는 드라이버 로, FIFO는 커널 파이프 버퍼 로 연결한다. 그래서 장치 파일에 대한 접근 권한은 곧 하드웨어(디스크·메모리)에 대한 직접 접근 권한 이 된다.
cd /data && mkdir lab11 && cd lab11
# 1) 사용자가 만들 수 있는 5종류
echo "text" > regular.txt # - 일반 파일
mkdir dir1 # d 디렉터리
ln -s regular.txt link.txt # l 심볼릭 링크
mkfifo pipe1 # p FIFO
python3 -c "import socket,time; s=socket.socket(socket.AF_UNIX); s.bind('app.sock')" # s 소켓
ls -l
# 2) 커널이 만드는 장치 파일과 시스템 소켓
ls -l /dev/loop0 /dev/null /dev/log
# 3) 소켓·FIFO 찾기
find /dev /run -maxdepth 2 \( -type s -o -type p \) -ls 2>/dev/null | head -5
# 4) 종류를 이름으로 출력
stat -c '%-12n %F' regular.txt dir1 link.txt pipe1 /dev/loop0 /dev/null /dev/log
이 실습 컨테이너에서는
/dev/log소켓을 만들기 위해 rsyslog를 imuxsock 방식으로 실행했다. 일반 서버에서는 systemd-journald가/dev/log를 제공한다.

텍스트 원본(실제 출력):
[analyst@rocky9-lab ~]$ cd /data && mkdir lab11 && cd lab11
[analyst@rocky9-lab lab11]$ echo "text" > regular.txt
[analyst@rocky9-lab lab11]$ mkdir dir1
[analyst@rocky9-lab lab11]$ ln -s regular.txt link.txt
[analyst@rocky9-lab lab11]$ mkfifo pipe1
[analyst@rocky9-lab lab11]$ python3 -c "import socket,time; s=socket.socket(socket.AF_UNIX); s.bind('app.sock')"
[analyst@rocky9-lab lab11]$ ls -l
total 8
srwxr-xr-x 1 analyst analyst 0 Sep 24 10:35 app.sock
drwxr-xr-x 2 analyst analyst 4096 Sep 24 10:35 dir1
lrwxrwxrwx 1 analyst analyst 11 Sep 24 10:35 link.txt -> regular.txt
prw-r--r-- 1 analyst analyst 0 Sep 24 10:35 pipe1
-rw-r--r-- 1 analyst analyst 5 Sep 24 10:35 regular.txt
[analyst@rocky9-lab lab11]$ ls -l /dev/loop0 /dev/null /dev/log
srw-rw-rw- 1 root root 0 Sep 24 10:35 /dev/log
brw------- 1 root root 7, 0 Sep 24 10:35 /dev/loop0
crw-rw-rw- 1 root root 1, 3 Sep 24 10:35 /dev/null
[analyst@rocky9-lab lab11]$ find /dev /run -maxdepth 2 \( -type s -o -type p \) -ls 2>/dev/null | head -5
118 0 srw-rw-rw- 1 root root 0 Sep 24 10:35 /dev/log
[analyst@rocky9-lab lab11]$ stat -c '%-12n %F' regular.txt dir1 link.txt pipe1 /dev/loop0 /dev/null /dev/log
regular.txt regular file
dir1 directory
link.txt symbolic link
pipe1 fifo
/dev/loop0 block special file
/dev/null character special file
/dev/log socket
| 출력 | 해석 |
|---|---|
srwxr-xr-x ... app.sock 크기 0 | 소켓. 데이터가 파일에 저장되지 않으므로 크기 0 |
prw-r--r-- ... pipe1 크기 0 | FIFO. 쓰는 쪽과 읽는 쪽이 동시에 열어야 데이터가 흐른다 |
lrwxrwxrwx ... link.txt -> regular.txt 크기 11 | 링크 크기는 대상 문자열 regular.txt의 길이(11자) |
srw-rw-rw- ... /dev/log | syslog 소켓. 모든 사용자가 로그를 보낼 수 있어야 하므로 666 |
brw------- ... 7, 0 /dev/loop0 | 블록 장치, major 7(loop) minor 0. root만 접근 (600) |
crw-rw-rw- ... 1, 3 /dev/null | 문자 장치, major 1(mem) minor 3. 누구나 쓸 수 있는 "버리는 곳" |
find ... -type s -o -type p | /dev, /run 아래 소켓·FIFO 검색 결과로 /dev/log만 나왔다 (컨테이너라 서비스 소켓이 적다) |
stat %F 결과 | regular file, directory, symbolic link, fifo, block special file, character special file, socket — 7종류 이름 확인 |
/dev/loop0의 권한 600이 중요하다. 일반 서버의 디스크 장치는 보통 brw-rw---- root disk로, root와 disk 그룹 만 접근할 수 있다. 그래서 disk 그룹 가입은 사실상 root 권한 부여와 같다 (39편). 만약 디스크 장치가 666이라면 일반 사용자가 파일 권한을 무시하고 디스크 블록을 직접 읽어 /etc/shadow 내용을 꺼낼 수 있다. 파일 권한 체계는 장치 파일 권한이 지켜진다는 전제 위에서만 의미가 있다.
| 종류 | 악용 사례 | 확인 방법 |
|---|---|---|
- 일반 파일 | 웹셸, 악성 ELF | file, sha256sum (17·18·20편) |
l 링크 | 쉘 히스토리 파일을 /dev/null로 연결해 기록을 무력화, /tmp 링크 공격 | find / -type l -lname '/dev/null' |
b/c 장치 | /dev 밖에 만든 디스크 장치로 권한 우회 (root가 mknod로 생성해 둔 백도어) | find / -xdev \( -type b -o -type c \) ! -path '/dev/*' |
s 소켓 | /tmp/.x.sock 같은 로컬 백도어, Docker 소켓(/var/run/docker.sock) 접근 = 사실상 root | find /tmp /var/tmp /dev/shm -type s, ss -xlp |
p FIFO | 쉘의 입출력을 FIFO와 네트워크 연결로 이어 붙이는 원격 쉘 기법에 사용됨 | find /tmp -type p + 연결된 프로세스 확인 |
/var/run/docker.sock에 쓰기 권한이 있는 사용자는 컨테이너를 root로 띄워 호스트 파일 시스템을 마운트할 수 있다. docker 그룹 = root와 동등 하다는 말이 나오는 이유다 (39편).
과장하지 말아야 할 점: /tmp에 소켓이 있다고 해서 모두 백도어는 아니다. X11(/tmp/.X11-unix/X0), tmux(/tmp/tmux-1000/default), 각종 데몬이 정상적으로 소켓을 만든다. 소유 프로세스 를 ss -xlp로 확인해야 한다.
[Detection] EDR: /bin/sh 의 stdin/stdout 이 FIFO(/tmp/f) 와 TCP 소켓에 연결
↓
[Evidence] ls -l /tmp/f → prw-r--r-- www-data
ls -l /proc/<PID>/fd → 0 -> /tmp/f, 1 -> socket:[48121]
↓
[판단] FIFO 를 이용한 원격 쉘 의심 (웹 서버 계정)
↓
[IOC] 원격 IP·포트 (ss -tnp), 생성 시각(stat /tmp/f)
↓
[Response] 네트워크 차단 → 프로세스 보존·종료 → 웹 취약점 조사
| 관점 | 내용 |
|---|---|
| SIEM | auditd execve에서 mkfifo, mknod 실행은 드문 이벤트라 탐지 규칙으로 쓰기 좋다 |
| Baseline | /dev 밖의 장치 파일, /tmp의 소켓·FIFO 목록을 주기적으로 수집해 비교 |
| Evidence | 소켓·FIFO는 내용이 없다. 증거는 소유자·생성 시각·연결된 프로세스 다 |
| 실수 | 결과 | 예방 |
|---|---|---|
| 확장자로 파일 종류 판단 | 종류와 형식을 놓침 | ls -l 첫 글자 + file |
find -type f만으로 의심 파일 검색 | 링크·소켓·FIFO 누락 | 필요 시 -type l,s,p 추가 (GNU find는 쉼표 목록 지원) |
| 장치 파일 크기를 파일 크기로 해석 | 7, 0을 오해 | major, minor 번호로 읽기 |
링크를 따라가며 chmod -R, chown -R | 링크 대상(시스템 파일) 권한 변경 | -h 옵션, find -type f 대상 한정 |
/tmp 소켓을 모두 삭제 | 정상 서비스 장애 | 소유 프로세스 확인 후 판단 |
[ ] 일반 파일·디렉터리·링크·FIFO·소켓을 직접 만들었다
[ ] ls -l 첫 글자로 7가지 종류를 구분했다
[ ] 장치 파일의 major, minor 번호를 읽었다
[ ] stat %F 로 종류 이름을 확인했다
[ ] /dev 밖의 장치 파일이 왜 위험한지 설명할 수 있다
[ ] FIFO 가 원격 쉘에 악용될 수 있는 이유를 이해했다
-, d, l, b, c, s, p 일곱 가지이며 inode mode의 상위 비트에 저장된다./dev 밖 장치 파일, /tmp의 FIFO·소켓, /dev/null을 가리키는 로그 링크는 우선 점검 대상이다.다음 글 「12. ls -l 출력 해석하기」 에서는 ls -l 한 줄에 들어 있는 10개 정보(종류, 권한 9비트, 특수 권한 표시, ACL +, 링크 수, 소유자, 그룹, 크기, 시간, 이름)를 Rocky와 Ubuntu 실제 출력으로 한 칸씩 해석한다.