FTP 实战与排错 — 抓包、lftp/curl 与被动模式故障

Wireshark 提取传输文件、ftp/lftp/curl/nmap 命令、vsftpd 配置与被动模式端口不通排查 / 应用层 / TCP 21/20 / RFC 959

这篇你能学到

  • 用 Wireshark / tcpdump 抓 FTP:怎么把传输的文件直接从抓包里还原出来,以及怎么一眼看出 227 返回的 IP 是不是私网(被动模式最经典故障)。
  • ncftplftpcurlnmap 做手工连接、断点续传、探测匿名登录与 Bounce 漏洞。
  • 一份可直接用的 vsftpd 配置(被动端口范围、pasv_address、FTPS),以及"425 / 530 / 550 / 文件损坏"等经典故障的"结论先行"排错法。
  • FTP / FTPS / SFTP / SCP / HTTP / TFTP 的对比表和 10 道高频面试题。

抓包观察

Wireshark 显示过滤式

目的过滤表达式
控制连接上的命令与应答ftp
数据连接上的文件内容ftp-data
控制 + 数据一起看ftp || ftp-data
只看客户端发出的命令ftp.request
只看服务器应答ftp.response
指定命令ftp.request.command == "RETR"
上传/下载/列表ftp.request.command in {"RETR","STOR","LIST","NLST"}
抓取明文密码(演示协议不安全)ftp.request.command == "PASS"
指定应答码ftp.response.code == 530
所有失败应答ftp.response.code >= 400
找被动模式端口ftp.response.code == 227
扩展被动模式ftp.response.code == 229
主动模式的 PORT 命令ftp.request.command == "PORT"
数据连接建立失败ftp.response.code == 425
按端口过滤(含数据连接)tcp.port == 21 || tcp.port == 20
FTPS(TLS 起来后)tls && tcp.port == 21;隐式 tcp.port == 990

典型字段说明

Wireshark 会自动关联控制连接与数据连接:解析到 227 应答后,它会把对应端口的流量自动标记为 ftp-data,无需手工 Decode As。

排查动作:

  1. 找到 220 欢迎语确认服务器版本(ftp.response.arg),很多漏洞与版本强相关。
  2. 530 判断是认证问题;找 550 判断是权限/路径问题;找 425 判断是数据连接问题。
  3. 227 应答,记下它返回的 IP——若服务器在 NAT 后且未配置 pasv_address,这里会返回一个私网 IP,客户端连不上,这是被动模式最经典的故障。
  4. 对任一 ftp-data 包右键 追踪流 → TCP 流 → 另存为原始数据,可直接把抓包中传输的文件还原出来(文件 → 导出对象 → FTP-DATA 更方便)。这也直观说明了明文 FTP 的危险。

tcpdump

下面这组 tcpdump/tshark 命令用于抓控制连接文本、按主机抓被动模式流量、以及把命令应答抽成表格。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 抓控制连接并直接显示文本命令
tcpdump -i any -A -s 0 'tcp port 21'

# 同时抓控制与主动模式数据连接
tcpdump -i any -s 0 -w ftp.pcap 'tcp port 21 or tcp port 20'

# 被动模式端口不固定,按主机抓
tcpdump -i any -s 0 -w ftp.pcap 'host 198.51.100.5'

# 用 tshark 提取所有命令与应答
tshark -r ftp.pcap -Y ftp -T fields -e ftp.request.command -e ftp.request.arg -e ftp.response.code -e ftp.response.arg

常用命令 / 配置

手工敲 FTP(最能建立直觉)

最直白的方式:用 nc 连上 21 端口,一行行手敲命令,亲眼看到三位数字应答。这是理解 FTP 双连接最快的办法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 用 nc 手打完整流程,逐行输入观察应答
nc 198.51.100.5 21
USER anonymous
PASS user@example.com
SYST
FEAT
TYPE I
PWD
PASV # 记下 227 应答里的 IP 和端口
# 另开一个终端连数据端口:nc 198.51.100.5 49936 > out.bin
RETR README.txt
QUIT

系统自带 ftp 客户端

系统自带的 ftp 客户端排错最常用 -d(打开调试打印所有命令应答)和 -p(强制被动)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
ftp -d 198.51.100.5 # -d 开启调试,打印所有命令与应答(排错必用)
ftp -p 198.51.100.5 # 强制被动模式(部分实现的默认已是被动)

# 进入交互后常用子命令
# open / user / passwd
binary # 等价于 TYPE I —— 传二进制文件前必做
ascii # 等价于 TYPE A
passive # 切换主动/被动模式
ls / dir / pwd / cd
get remote.iso local.iso
put local.txt remote.txt
mget *.log # 批量下载
prompt # 关闭批量操作的逐个确认
hash # 显示传输进度
bye

lftp —— 生产环境推荐的强大客户端

lftp 支持断点续传、镜像目录、显式 FTPS,是日常运维最顺手的客户端。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 一次性执行命令
lftp -u alice,password -e 'set ftp:passive-mode true; ls; bye' 198.51.100.5

# 断点续传下载
lftp -u alice,password 198.51.100.5 -e 'pget -c -n 4 /pub/big.iso; bye'

# 镜像整个目录(下载)
lftp -u alice,password 198.51.100.5 -e 'mirror /remote/dir /local/dir; bye'

# 镜像上传(-R 反向)
lftp -u alice,password 198.51.100.5 -e 'mirror -R /local/dir /remote/dir; bye'

# 使用显式 FTPS
lftp -u alice,password -e 'set ftps:initial-prot ""; set ftp:ssl-force true; set ftp:ssl-protect-data true; ls; bye' ftp://198.51.100.5

# 自签证书环境跳过校验(仅内网调试)
lftp -e 'set ssl:verify-certificate no; ...'

curl 操作 FTP

curl 一条命令就能列目录、下载、上传、续传、强制主动/被动、走 FTPS。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 列目录
curl ftp://198.51.100.5/pub/ --user alice:password

# 下载(-O 保留远端文件名)
curl -O ftp://198.51.100.5/pub/file.iso --user alice:password

# 断点续传
curl -C - -O ftp://198.51.100.5/pub/file.iso --user alice:password

# 上传
curl -T ./report.pdf ftp://198.51.100.5/upload/ --user alice:password

# 强制主动模式(默认是被动)
curl -P - ftp://198.51.100.5/pub/ --user alice:password

# 显式 FTPS(AUTH TLS)
curl --ssl-reqd ftp://198.51.100.5/pub/ --user alice:password

# 隐式 FTPS(990 端口)
curl ftps://198.51.100.5:990/pub/ --user alice:password

# 详细调试
curl -v ftp://198.51.100.5/pub/ --user alice:password

探测与验证

下面这组用于验证端口通不通、探测匿名登录、检测 Bounce 漏洞、确认被动端口范围是否放行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 端口连通性
nc -zv 198.51.100.5 21
telnet 198.51.100.5 21

# nmap 探测 FTP 服务与常见问题
nmap -p 21 -sV 198.51.100.5 # 识别服务与版本
nmap -p 21 --script ftp-anon 198.51.100.5 # 检测是否允许匿名登录
nmap -p 21 --script ftp-syst,ftp-bounce 198.51.100.5 # 系统信息与 Bounce 漏洞
nmap -p 49152-65535 198.51.100.5 # 验证被动端口范围是否放行

# 查看本机 FTP 服务监听与连接
ss -ltnp | grep -E ':21|:990'
ss -tanp | grep ':21'

# 查看已建立的数据连接(被动端口)
ss -tanp | grep vsftpd

vsftpd 服务端配置要点

这份 vsftpd 配置覆盖了关键点:关匿名、开 chroot、配被动端口范围与公网 pasv_address、开 FTPS。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# /etc/vsftpd.conf

listen=YES
listen_port=21

# ── 认证 ──
anonymous_enable=NO # 生产环境关闭匿名
local_enable=YES
write_enable=YES
local_umask=022

# ── 隔离(关键安全项)──
chroot_local_user=YES # 用户锁定在自己家目录
allow_writeable_chroot=YES # chroot 目录可写时必须加,否则登录报 500
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd.userlist # 白名单

# ── 被动模式(NAT 后必配)──
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=40100 # 端口范围要在防火墙放行
pasv_address=203.0.113.20 # 服务器的公网 IP,否则 227 会返回私网地址
pasv_addr_resolve=NO

# ── FTPS(强烈建议开启)──
ssl_enable=YES
force_local_logins_ssl=YES # 强制登录加密
force_local_data_ssl=YES # 强制数据加密
ssl_tlsv1_2=YES
ssl_tlsv1_3=YES
ssl_sslv2=NO
ssl_sslv3=NO
rsa_cert_file=/etc/ssl/certs/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.key
require_ssl_reuse=NO # 部分客户端复用会话失败时关闭

# ── 日志与限制 ──
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
idle_session_timeout=300
data_connection_timeout=120
max_clients=50
max_per_ip=5

对应的防火墙规则:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# firewalld
firewall-cmd --permanent --add-service=ftp
firewall-cmd --permanent --add-port=40000-40100/tcp
firewall-cmd --reload

# iptables(含连接跟踪模块,可自动处理明文 FTP 的数据连接)
modprobe nf_conntrack_ftp
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
iptables -A INPUT -p tcp --dport 40000:40100 -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# SELinux 环境还需
setsebool -P ftpd_full_access on

常见故障与排错

下面每条先给"结论",再看排查——结论先行:先判断是数据连接问题、登录问题、还是传输类型问题。

  • 425 Failed to establish connection / 425 Can't open data connection

    • 先记住结论:数据连接建不起来——主动模式下客户端在 NAT 后,或被动模式下服务器被动端口没在防火墙放行。
    • 排查:先 passive 切被动;服务端确认 pasv_min_port/max_port 已在防火墙与安全组放行;nmap -p 40000-40100 验证。
  • 能登录、能 pwd,但 ls 就卡住

    • 先记住结论:典型的数据连接问题——LIST 也需要单独的数据连接,不是控制连接的问题。
    • 排查:同上。这是"控制通、数据不通"的最经典症状。
  • 227 应答里是私网 IP,客户端连不上

    • 先记住结论:服务器在 NAT/云主机后,没配 pasv_address,把内网地址报给了客户端。
    • 排查:抓包看 227 内容;vsftpd 配 pasv_address=公网IP;或改用 EPSV(229 应答不含 IP)。
  • 530 Login incorrect

    • 先记住结论:登录失败——密码错、用户在黑名单、白名单没包含、或匿名被禁用。
    • 排查:看 /var/log/vsftpd.log/var/log/secure;确认 shell 在 /etc/shells 中。
  • 500 OOPS: vsftpd: refusing to run with writable root inside chroot()

    • 先记住结论:开了 chroot_local_user 但家目录可写,vsftpd 出于安全拒绝启动。
    • 排查:加 allow_writeable_chroot=YES,或把家目录本身设为不可写、在其下建可写子目录。
  • 550 Permission denied / Failed to open file

    • 先记住结论:文件系统权限不足、SELinux 拦截、write_enable=NO 或磁盘配额满。
    • 排查:ls -l 检查属主与权限;getenforceausearch -m avcdf -h
  • 文件传完但打不开 / 大小不对

    • 先记住结论:用了 ASCII 模式传二进制文件,CRLF 被转换导致损坏。
    • 排查:传输前必须 binary / TYPE I;对比本地与远端 SIZE、md5。
  • 421 Service not available / Timeout

    • 先记住结论:空闲超时被踢、max_clients/max_per_ip 达上限,或服务没启动。
    • 排查:调 idle_session_timeout;客户端定期 NOOP 保活;ss -ltnp 确认服务在听。
  • 大文件传到一半断,且传完收不到 226

    • 先记住结论:控制连接长时间空闲被 NAT 会话表或防火墙清除,传输结束后控制线已断。
    • 排查:开启 TCP keepalive;缩短 NAT 会话超时;客户端启用 keepalive 选项。
  • FTPS 能登录但传文件失败

    • 先记住结论:加密后防火墙 ALG 无法解析 227 应答,不能自动放行数据端口。
    • 排查:必须手工放行完整的被动端口范围;或关闭 ALG 后静态放行。
  • FTPS 报 SSL connection reuse 错误

    • 先记住结论:部分客户端不复用控制连接的 TLS 会话到数据连接。
    • 排查:服务端设 require_ssl_reuse=NO
  • 匿名登录成功但看不到任何文件

    • 先记住结论:匿名根目录为空,或权限不允许列目录。
    • 排查:检查 anon_root 指向与目录权限(需 r-x)。
  • Windows 资源管理器/浏览器打不开 FTP

    • 先记住结论:浏览器已彻底移除 FTP 支持(Chrome 95+、Firefox 90+),不是服务器问题。
    • 排查:改用 FileZilla、WinSCP、lftp 等专用客户端。
  • 中文文件名乱码

    • 先记住结论:服务端与客户端字符集不一致,或未启用 UTF-8。
    • 排查:FEAT 查看是否支持 UTF8;客户端 OPTS UTF8 ON;lftp 设 set ftp:charset gbk

通用排查顺序21 端口能否连通(nc -zv)能否登录(看 530)pwd 能否成功(控制连接正常)ls 是否卡住(定位到数据连接)切被动模式重试抓包看 227 返回的 IP 与端口验证该端口是否放行传二进制前确认 TYPE I

与其他协议对比

维度FTPFTPSSFTPSCPHTTP(S)TFTP
底层协议自有(RFC 959)FTP + TLSSSH 子系统SSHHTTP自有(RFC 1350)
端口TCP 21 / 2021(显式)/ 990(隐式)TCP 22TCP 2280 / 443UDP 69
连接数2 条(控制+数据)2 条1 条1 条1 条无连接
加密❌ 全明文✅ TLS✅ SSH✅ SSHHTTPS 才有
身份认证明文口令口令 + 服务器证书公钥 / 口令 / 键盘交互同 SFTP多种
穿 NAT / 防火墙❌ 很差(需 ALG)❌ 更差(ALG 失效)✅ 好✅ 好✅ 好
断点续传✅ REST✅ Range
目录操作✅ 完整❌ 仅传文件有限(WebDAV 补足)
传输效率高(裸流)略低(加密开销)中(SSH 加密+分包)
部署难度中(被动端口麻烦)(有 SSH 即有 SFTP)极低
典型场景遗留系统、内网需保留 FTP 语义的合规场景现代首选快速单文件拷贝公开分发、APIPXE 引导、设备固件

选型建议:新项目一律选 SFTP(有 SSH 就有它,单端口、全加密、无被动模式烦恼);公开下载分发用 HTTPS;只有对接遗留系统或有明确合规要求时才用 FTPS;任何情况下不要在公网跑裸 FTP

速查表 / 常见面试题

核心数字速查

项目
控制连接端口TCP 21
主动模式数据端口(服务器源端口)TCP 20
被动模式数据端口服务器动态指定(常配 40000–50000)
隐式 FTPS 端口TCP 990
SFTP 端口TCP 22(SSH)
TFTP 端口UDP 69
核心 RFCRFC 959
被动模式应答码227(PASV)/ 229(EPSV)
端口计算公式p1 × 256 + p2
匿名用户名anonymousftp,密码填邮箱

关键应答码:150 准备传输 · 200 成功 · 220 就绪 · 226 传输完成 · 227 被动模式 · 230 登录成功 · 250 操作完成 · 257 路径已创建 · 331 需要密码 · 425 数据连接失败 · 530 未登录 · 550 文件不存在或无权限

常见面试题

  1. FTP 为什么要用两个端口? 采用带外控制(out-of-band)设计:控制连接(21)全程保持只传命令与应答,数据连接按需建立只传字节流。好处是传输过程中控制通道仍畅通(可随时 ABOR 中止),且数据流上无需任何协议头——连接关闭即代表传输结束。

  2. 主动模式和被动模式的区别?为什么现在都用被动? 主动模式由服务器从 20 端口向客户端发起数据连接,被动模式由客户端向服务器的临时端口发起。由于 NAT 普及和客户端防火墙默认拒绝入站连接,服务器几乎不可能主动连上客户端,所以现代一律用被动模式。

  3. 被动模式下服务器返回私网 IP 怎么办? 服务器在 NAT 后时,227 应答里会带内网地址,客户端连不上。解决方式有二:① 配置 pasv_address 为公网 IP(vsftpd);② 使用 EPSV(RFC 2428),其 229 应答只返回端口不返回 IP,客户端直接复用控制连接的目标 IP,天然规避此问题。

  4. FTP 为什么对防火墙不友好? 数据连接的端口号写在应用层载荷里(PORT 命令和 227 应答),防火墙必须做深度包检测(ALG/conntrack 模块)解析并动态放行。一旦启用 FTPS 加密,ALG 无法解析,就只能手工静态放行整段被动端口范围。

  5. FTPS 和 SFTP 有什么区别? 名字像但毫无关系。FTPS 是 FTP 加上 TLS,仍是双连接、仍用 21/990 端口、仍有被动模式问题;SFTP 是 SSH 协议的一个子系统,单条 TCP 22 连接、二进制协议、天然穿 NAT,与 RFC 959 没有任何继承关系。生产环境推荐 SFTP。

  6. ASCII 模式和二进制模式选错会怎样? ASCII 模式会转换换行符(CRLF ↔ LF)。用它传 zip、exe、图片等二进制文件时,文件中恰好为 0x0D/0x0A 的字节会被改写,导致文件损坏、大小不符、校验失败。规则:非纯文本一律先 binaryTYPE I)。

  7. 什么是 FTP Bounce 攻击? 攻击者用 PORT 命令让 FTP 服务器向任意第三方主机的任意端口发起数据连接,从而借服务器之手进行端口扫描或绕过防火墙访问内网。现代 FTP 服务器默认拒绝 PORT 指向与控制连接源 IP 不一致的地址,nmap --script ftp-bounce 可检测。

  8. 匿名 FTP 的安全注意事项? 必须 chroot 隔离;默认只读;若需开放上传,上传目录应设为只写不可读不可列(防止被当作违规内容中转站);限制并发与带宽;定期审计上传内容。

  9. ls 卡住但登录正常,是什么问题? 一定是数据连接问题——LIST 命令同样需要建立数据连接。排查方向:切换到被动模式、检查服务器被动端口范围是否放行、检查 227 返回的 IP 是否可达。

  10. 为什么浏览器不再支持 FTP 了? 明文传输、无完整性保护、双连接模型与现代安全模型(安全上下文、混合内容策略)冲突、使用率极低而维护成本高。Chrome 95、Firefox 90 起已彻底移除,文件分发场景已由 HTTPS 完全接管。