0 / 5
네트워크 파일 시스템(NFS, Network File System)
NFS는 다른 컴퓨터(서버)의 디렉터리를 내 컴퓨터(클라이언트)의 폴더처럼 쓰게 해 주는 프로토콜이다. 파일은 서버 디스크에 있고 클라이언트는 읽기와 쓰기 요청을 네트워크로 보낸다. 프로그램은 로컬 파일을 열 때와 똑같이 파일을 연다.
예: 회사 서버의 /data 폴더를 내 컴퓨터의 /mnt/data 폴더에 연결하고 서버에 있는 a.txt를 연다.
서버의 답: exports에 적힌 호스트의 요청을 처리한다.
1 / 5
서버: 공유할 디렉터리를 내보낸다
서버 관리자가 exports 설정에 공유할 디렉터리 /data와 접근을 허용할 클라이언트 192.168.0.10을 적는다. 클라이언트는 이렇게 내보낸(export) 디렉터리만 가져다 쓴다.
2 / 5
클라이언트: 서버 디렉터리를 마운트한다
클라이언트가 서버의 /data를 자기 폴더 /mnt/data에 마운트(mount)한다. 서버는 요청한 호스트가 exports에 적혀 있는지 확인하고 허용한다. 마운트가 끝나면 /mnt/data는 서버의 /data를 가리킨다.
3 / 5
프로그램: /mnt/data/a.txt를 연다
프로그램은 /mnt/data/a.txt를 열 뿐이다. 운영체제는 이 경로가 NFS로 연결된 곳임을 알아보고 로컬 디스크 대신 NFS 클라이언트에 파일 요청을 넘긴다.
4 / 5
NFS 클라이언트에서 서버로: 읽기 요청을 보낸다
NFS 클라이언트가 읽기 요청을 RPC(원격 프로시저 호출)로 만들어 서버에 보낸다. RPC는 다른 컴퓨터의 기능을 불러 쓰는 호출 방식이다. 서버의 NFS 서비스는 2049번 포트로 이 요청을 받는다.
5 / 5
서버에서 클라이언트로: 파일 내용을 돌려준다
서버가 자기 디스크에서 /data/a.txt를 읽어 내용을 응답으로 돌려준다. 프로그램은 로컬 파일을 읽은 것처럼 내용을 받는다. 쓰기 요청도 같은 길로 간다. 그때는 서버 디스크의 파일이 바뀐다.
1 / 5
서버: 누구에게나 열어 둔 설정
exports의 *는 모든 호스트를 뜻한다. 옵션 rw는 읽기와 쓰기를 모두 허용한다. 옵션 no_root_squash는 클라이언트 root의 요청을 서버에서도 root로 처리하게 한다. 이 옵션을 쓰지 않으면 기본값인 root_squash가 적용된다.
2 / 5
공격자: 서버 디렉터리를 마운트한다
공격자가 자기 컴퓨터에서 서버의 /data를 /mnt/data에 마운트한다. 서버의 exports가 *라서 공격자의 호스트도 허용 대상에 들어간다.
3 / 5
공격자: root로 파일에 쓴다
공격자가 root(UID 0)로 /mnt/data/a.txt에 쓴다. 자기 컴퓨터의 root라서 클라이언트 쪽에는 막는 장치가 없다.
4 / 5
NFS 클라이언트에서 서버로: 쓰기 요청을 보낸다
쓰기 요청이 사용자 번호 0과 함께 RPC로 서버에 간다. AUTH_SYS에서는 서버가 이 번호가 진짜 root의 것인지 확인할 방법이 없다.
5 / 5
서버: UID 0을 믿고 그대로 처리한다
서버는 보내온 사용자 번호 0을 서버의 root로 받아들인다. 설정이 no_root_squash라서 권한도 낮추지 않는다. 그 결과 서버 디스크의 a.txt가 공격자가 쓴 내용으로 바뀐다.
1 / 4
서버: 호스트와 쓰기, root 권한을 제한한다
192.168.0.10만 적어서 다른 호스트는 마운트가 안 된다. 옵션 ro는 읽기만 허용한다. 옵션 root_squash는 클라이언트 root의 요청을 일반 사용자 번호(기본값 65534, nobody)로 바꿔 처리한다.
2 / 4
허용되지 않은 호스트: 마운트를 거부한다
공격자의 호스트(192.168.0.99)는 exports에 없다. 서버가 마운트 요청을 거부해서 공격자는 /data를 볼 수 없다.
3 / 4
허용된 호스트: 쓰기 요청을 거부한다
허용된 호스트도 /data에 쓸 수는 없다. 서버는 쓰기 요청을 받으면 ro 설정을 보고 거부한다.
4 / 4
허용된 호스트의 root: 권한이 낮아져 거부된다
root가 secret.txt를 읽으려 하면 요청은 사용자 번호 0으로 도착한다. 서버의 root_squash가 이 번호를 65534로 바꾼다. 파일 secret.txt는 root만 읽을 수 있어서 서버가 거부한다. 클라이언트의 root가 서버의 root가 되지 못한다. 다만 root가 아닌 다른 사용자 번호로 보낸 요청은 이 설정으로 막지 못한다.
1 / 3
서버: nfsd, statd, lockd를 중지한다
NFS를 처리하는 데몬(백그라운드로 도는 서비스)을 멈춘다. 파일 요청은 nfsd가 처리한다. 상대 컴퓨터의 재시작은 statd가 알아내 잠금을 복구하게 하고, 파일 잠금 요청은 lockd가 처리한다. NFS v3 서버에는 마운트를 맡는 mountd와 포트를 안내하는 rpcbind도 있으니 함께 확인한다.
2 / 3
인가되지 않은 시스템의 접근을 끊는다
서버 관리자가 exports에서 인가되지 않은 호스트를 빼서 접근을 막는다. 그 시스템에 남은 마운트는 그 시스템에서 umount해야 정리된다. 서비스를 멈추는 것과 별개로 이미 붙어 있는 시스템을 정리하는 조치다.
3 / 3
공격자의 요청: 받아 주는 서비스가 없다
공격자가 다시 파일을 읽으려 해도 2049번 포트로 오는 요청을 받아 줄 nfsd가 없다. 서비스를 끄면 설정이 허술해도 공격이 닿을 곳이 없다.