63. FTP Active·Passive 모드와 보안

changseop lee·6일 전

📚 네트워크 · 패킷 분석 › 02. 포트 · 프로토콜 분석 — 63편
이전 글: 62. HTTPS와 TLS Handshake — 암호화된 통신에서 볼 수 있는 것 · 다음 글: 64. SFTP
참고(리눅스 시스템 기초): Firewalld 이해 — 서비스 단위 포트 허용

1. 왜 알아야 하는가

FTP(File Transfer Protocol)는 다른 서비스와 달리 연결이 두 개입니다. 명령을 주고받는 제어 연결과 실제 파일이 오가는 데이터 연결이 분리되어 있고, 모드에 따라 데이터 연결을 여는 방향이 반대입니다. 이 구조를 모르면 다음과 같은 상황에서 판단이 흔들립니다.

  • 방화벽 로그에 서버가 클라이언트로 접속하는 세션(Active 모드)이 보여 역방향 접속으로 오해하는 경우
  • 21번만 허용했는데 파일 목록 조회가 안 되는 장애(Passive 포트 미허용)
  • 21번 로그인 기록은 있는데 무엇을 가져갔는지는 다른 연결·다른 로그에 있는 경우

또한 FTP는 평문 프로토콜이라 계정 정보가 노출되고, 외부에 열린 FTP는 무차별 대입과 익명 접속 점검 대상이 됩니다. 관제에서 FTP는 "정보 유출 경로"와 "인증 공격 대상" 두 관점으로 봅니다.


2. 핵심 개념

2-1. 두 개의 연결

연결포트내용수명
제어 연결(Control)서버 TCP 21USER, PASS, LIST, RETR 등 명령과 응답 코드세션 동안 유지
데이터 연결(Data)Active: 서버 20 → 클라이언트 임의 포트 / Passive: 클라이언트 → 서버 임의 포트파일 내용, 디렉터리 목록전송 1건마다 새로 열고 닫음

2-2. Active와 Passive

구분Active 모드Passive 모드
데이터 연결을 여는 쪽서버 → 클라이언트클라이언트 → 서버
핵심 명령PORT (IPv6 겸용: EPRT)PASV (IPv6 겸용: EPSV)
서버 출발 포트20서버가 알려준 임의 포트
클라이언트 방화벽·NAT 영향서버의 인바운드 접속이 막히기 쉬움영향 적음 (오늘날 기본)
서버 방화벽20번 아웃바운드 허용Passive 포트 범위 인바운드 허용 필요

2-3. 주요 명령과 응답 코드

명령의미응답 코드의미
USER계정명 전송220서비스 준비됨(접속 배너)
PASS비밀번호 전송(평문)331계정 확인, 비밀번호 필요
PWD / CWD현재 경로 / 경로 이동230로그인 성공
LIST디렉터리 목록530로그인 실패(인증 거부)
RETR파일 다운로드150데이터 연결 열기 시작
STOR파일 업로드226전송 완료, 데이터 연결 닫음
DELE파일 삭제227 / 229Passive / Extended Passive 진입
QUIT종료550파일 없음·권한 없음

2-4. 암호화된 대안

방식포트특징
FTPS (명시적)21접속 후 AUTH TLS로 TLS 전환
FTPS (암묵적)990접속 즉시 TLS
SFTP22FTP가 아니라 SSH 위에서 동작하는 별도 프로토콜

3. 동작 원리

FTP Active와 Passive
그림 1. 제어 연결(21)과 데이터 연결의 방향 비교

3-1. Active 모드

 클라이언트 192.168.10.20                          서버 192.168.10.10
   │ (임의 포트 50000) ── 제어 연결 ──────────────────→ :21
   │ ←── 220 / USER / 331 / PASS / 230 ──────────────→ │
   │                                                   │
   │ ── PORT 192,168,10,20,195,81 ───────────────────→ │  "내 50001 포트로 접속해"
   │                                   (195×256 + 81 = 50001)
   │ ←── 200 PORT command successful ──────────────── │
   │ ── LIST ────────────────────────────────────────→ │
   │                                                   │
   │ :50001 ←═════ 데이터 연결 (서버 :20 → 클라이언트) ═══ │  ← 서버가 먼저 접속
   │ ←═════ 디렉터리 목록 ═══════════════════════════════ │
   │ ←── 226 Transfer complete ─────────────────────── │

3-2. Passive 모드

 클라이언트 192.168.10.20                          서버 192.168.10.10
   │ ── 제어 연결 ───────────────────────────────────→ :21
   │ ── PASV ────────────────────────────────────────→ │
   │ ←── 227 Entering Passive Mode (192,168,10,10,156,65) │
   │                                   (156×256 + 65 = 40001)
   │ ── LIST ────────────────────────────────────────→ │
   │ ═══════ 데이터 연결 (클라이언트 → 서버 :40001) ══════→ │  ← 클라이언트가 접속
   │ ←═════ 디렉터리 목록 ═══════════════════════════════ │
   │ ←── 226 Transfer complete ─────────────────────── │

PORT/227 응답의 마지막 두 숫자는 상위 바이트, 하위 바이트이므로 p1 × 256 + p2로 포트를 계산합니다.

3-3. 방화벽이 FTP를 따라가는 방법

데이터 포트가 매번 바뀌기 때문에, 상태 기반 방화벽은 제어 연결의 PORT/PASV 응답을 읽어 데이터 연결을 "관련(RELATED) 연결"로 허용합니다. 리눅스에서는 nf_conntrack_ftp 헬퍼가 이 역할을 하며, firewalld의 ftp 서비스 정의는 이 헬퍼를 함께 사용합니다. 단, 제어 연결이 FTPS로 암호화되면 방화벽이 내용을 읽을 수 없으므로 Passive 포트 범위를 고정해서 직접 허용해야 합니다.


4. 실제 명령어 / 실습

실습 환경: 본인 소유 Linux VM (Rocky Linux 또는 Ubuntu), 인터페이스는 ens33을 예시로 사용합니다. 접속은 루프백(127.0.0.1)에서만 하고, 실습 전용 계정을 사용합니다.

4-1. 설치

# Rocky Linux
sudo dnf install -y vsftpd ftp tcpdump

# Ubuntu
sudo apt install -y vsftpd ftp tcpdump

설정 파일 위치가 배포판마다 다릅니다.

항목Rocky LinuxUbuntu
설정 파일/etc/vsftpd/vsftpd.conf/etc/vsftpd.conf
서비스 이름vsftpdvsftpd
인증 로그/var/log/secure/var/log/auth.log

4-2. 보안·로그 설정

설정 파일을 백업한 뒤 아래 항목을 확인·수정합니다(이미 있는 항목은 값만 변경).

sudo cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak   # Ubuntu는 /etc/vsftpd.conf
anonymous_enable=NO          # 익명 접속 금지
local_enable=YES             # 로컬 계정 로그인 허용
write_enable=YES
chroot_local_user=YES        # 홈 디렉터리 밖 이동 제한
allow_writeable_chroot=YES   # 쓰기 가능한 홈에서 chroot 허용 (실습용)
pasv_enable=YES
pasv_min_port=40000          # Passive 포트 범위 고정
pasv_max_port=40010
xferlog_enable=YES           # 전송 로그 활성화
xferlog_std_format=YES       # /var/log/xferlog (표준 형식)
dual_log_enable=YES          # vsftpd 자체 로그도 함께 기록
vsftpd_log_file=/var/log/vsftpd.log

참고로 log_ftp_protocol=YES를 쓰면 명령·응답까지 기록되지만, vsftpd 매뉴얼상 xferlog_std_format이 꺼져 있을 때만 적용되므로 이 실습에서는 사용하지 않습니다.

sudo useradd -m ftptest && sudo passwd ftptest
echo "sample data" | sudo tee /home/ftptest/sample.txt
sudo systemctl restart vsftpd
sudo ss -tlnp | grep ':21 '

Rocky Linux에서 SELinux가 로컬 계정 홈 접근을 막으면 sudo setsebool -P ftpd_full_access on이 필요할 수 있습니다(실습 후 off로 되돌림).

4-3. Passive / Active 캡처 비교

# 터미널 1
sudo tcpdump -i lo -nn -A 'tcp port 21 or portrange 40000-40010 or tcp port 20'
# 터미널 2: ftp 클라이언트 접속
ftp 127.0.0.1
# 로그인 후 ftp> 프롬프트에서:
#   passive     ← Passive 모드 켜기/끄기 토글 (현재 상태가 출력됨)
#   ls
#   get sample.txt
#   bye

passive를 한 번 더 입력해 모드를 바꾼 뒤 ls를 다시 하면, 캡처에서 PASV/227 대신 PORT/200이 보입니다(클라이언트 구현에 따라 EPSV/EPRT가 먼저 시도될 수 있음).

📷 [실습 화면 삽입] tcpdump -A에서 USER ftptest, PASS ...(가림 처리), 227 Entering Passive Mode (...)가 보이는 부분

4-4. 로그 확인

sudo tail -n 20 /var/log/vsftpd.log
sudo tail -n 5 /var/log/xferlog

📷 [실습 화면 삽입] vsftpd.log의 OK LOGIN, OK DOWNLOAD 줄과 xferlog의 전송 기록

4-5. 정리

sudo systemctl disable --now vsftpd
sudo userdel -r ftptest

5. 결과 확인

vsftpd.log (형식 예시(값은 환경마다 다름))

Sat Sep 26 11:02:10 2026 [pid 3101] CONNECT: Client "::ffff:127.0.0.1"
Sat Sep 26 11:02:14 2026 [pid 3100] [ftptest] OK LOGIN: Client "::ffff:127.0.0.1"
Sat Sep 26 11:02:30 2026 [pid 3102] [ftptest] OK DOWNLOAD: Client "::ffff:127.0.0.1", "/sample.txt", 12 bytes, 3.10Kbyte/sec
Sat Sep 26 11:05:41 2026 [pid 3110] [baduser] FAIL LOGIN: Client "::ffff:127.0.0.1"

xferlog 표준 형식 (형식 예시(값은 환경마다 다름))

Sat Sep 26 11:02:30 2026 1 ::ffff:127.0.0.1 12 /sample.txt b _ o r ftptest ftp 0 * c
xferlog 필드예시 값의미
전송 시간(초)1전송에 걸린 시간
원격 호스트::ffff:127.0.0.1클라이언트 주소
파일 크기12바이트
파일 이름/sample.txtchroot 기준 경로
방향oo = 다운로드(outgoing), i = 업로드(incoming)
접근 모드rr = 로컬 계정, a = 익명
완료 상태cc = 완료, i = 미완료

점검 체크리스트

  • 제어 연결(21)과 데이터 연결(40000~40010 또는 20)이 별도로 생기는 것을 확인했다
  • Passive에서 227 응답의 포트를 p1×256+p2로 계산해 실제 데이터 포트와 비교했다
  • USER/PASS가 평문으로 캡처되는 것을 확인했다
  • vsftpd.log에서 OK LOGIN/FAIL LOGIN/OK DOWNLOAD를 확인했다
  • xferlog에서 전송 방향(o/i)과 파일명을 확인했다
  • 실습 후 vsftpd 중지와 테스트 계정 삭제를 확인했다

6. 패킷 / 로그 분석

6-1. 판단 기준

관찰정상일 수 있는 경우의심해야 하는 경우
서버 :20 → 클라이언트 접속Active 모드 정상 동작FTP 제어 세션 없이 20번 출발 연결만 존재
FAIL LOGIN 반복사용자 비밀번호 오입력 몇 회짧은 시간 다수 계정·다수 시도 (무차별 대입)
익명(anonymous) 로그인 성공공개 배포용 익명 FTP로 문서화됨익명 비허용 정책인데 성공
대량 o(다운로드) 전송정기 백업·배포 작업 시간대업무 외 시간, 평소 없던 계정, 대용량
i(업로드) 후 웹 경로 파일 생성콘텐츠 배포FTP 루트가 웹 루트와 같고 스크립트 파일 업로드
PORT에 다른 IP 지정NAT 환경 설정 문제클라이언트와 다른 제3의 IP 지정 (FTP Bounce 원리)
내부 → 외부 FTP 업로드협력사 파일 교환 승인 건미승인 목적지로 대용량 업로드 (유출 의심)

FTP Bounce는 PORT 명령에 클라이언트가 아닌 다른 주소를 넣어 서버가 제3자에게 접속하도록 만드는 오래된 기법입니다. 현대 FTP 서버는 대부분 기본적으로 이를 거부하므로, 로그에 PORT 관련 거부가 보이면 시도 흔적으로 봅니다.

6-2. 확인 명령

# 로그인 실패 출발지별 집계
sudo grep "FAIL LOGIN" /var/log/vsftpd.log | grep -o 'Client "[^"]*"' | sort | uniq -c | sort -rn

# 다운로드/업로드 파일 목록
sudo grep -E "OK (DOWNLOAD|UPLOAD)" /var/log/vsftpd.log

# 현재 FTP 제어·데이터 연결
sudo ss -tnp '( sport = :21 or sport = :20 or ( sport >= :40000 and sport <= :40010 ) )'

7. 보안관제 관점

흔적이 남는 곳

위치남는 정보비고
방화벽21번 세션 + 데이터 세션(RELATED)두 세션을 연결해서 봐야 전체 행위가 보임
FTP 서버 로그로그인 성공/실패, 명령, 전송 파일·크기가장 구체적인 증거
IDS/IPS평문 명령 기반 탐지(익명 로그인, 특정 파일명)FTPS면 내용 탐지 불가 (06 방화벽·IDS 시리즈에서 다룸)
DLP·프록시외부 FTP 업로드 차단/기록조직 정책에 따라 다름

관제 시 핵심 포인트

  • 21번 로그인 기록과 파일 전송 기록은 다른 줄, 때로는 다른 파일에 있습니다. 같은 pid·시각·클라이언트로 묶어서 "누가 로그인해서 무엇을 가져갔는가"를 완성합니다.
  • 외부에 열린 FTP의 로그인 실패 급증은 SSH 무차별 대입과 같은 관점으로 분석합니다(SSH Brute Force 로그 분석). 출발지 수, 시도 계정 수, 성공 여부가 핵심입니다.
  • 가장 위험한 조합은 익명 쓰기 허용 + 웹 루트 공유입니다. 업로드된 파일이 웹에서 실행될 수 있기 때문입니다.

한계와 오탐 주의

  • Active 모드의 "서버 → 클라이언트" 접속은 정상 동작이므로, 역방향 접속으로 오탐하지 않도록 제어 세션 존재를 먼저 확인합니다.
  • FTPS·SFTP는 내용이 암호화되어 네트워크 장비에서는 파일명을 볼 수 없습니다. 이 경우 서버 로그가 유일한 근거가 됩니다.
  • 포트 21이 아닌 곳에서 동작하는 FTP도 있으므로 포트만으로 판단하지 않습니다(20편에서 다룸).

8. 핵심 정리

  • FTP는 제어 연결(TCP 21) 과 데이터 연결(전송마다 새로 생성) 을 분리합니다.
  • Active는 서버(20)가 클라이언트로, Passive는 클라이언트가 서버의 임의 포트로 데이터 연결을 엽니다. 포트는 p1×256+p2로 계산합니다.
  • 응답 코드 230(성공)·530(실패)·226(전송 완료) 과 vsftpd.log·xferlog로 로그인과 파일 전송을 추적합니다.
  • 기본 FTP는 계정·파일이 평문이므로 SFTP 또는 FTPS로 대체하고, 익명 접속과 웹 루트 공유를 피합니다.
  • 관제에서는 로그인 실패 급증, 업무 외 대량 다운로드, 미승인 외부 업로드, 제3자 IP를 지정한 PORT를 주의 깊게 봅니다.

다음 글: 13. 메일 프로토콜 SMTP·POP3·IMAP

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글