Trap23待办3: 异常释放(TIMEOUT/RST)挂起recv以CONNRESET了结, STOR异常结束回450并删除截断文件, 探针加--check-abort

This commit is contained in:
2026-09-25 02:04:46 +08:00
parent a1f1f46262
commit c12139da06
5 changed files with 85 additions and 10 deletions
+18 -4
View File
@@ -9,9 +9,13 @@
# 3. the device's relisten actually happened (observable via a successful follow-up).
#
# Usage: ftp_abort_probe.py [--ip ..] [--port 21] [--rounds 10] [--send 8192] [--gap 2]
# [--graceful] [--check-abort]
# Output: TS <epoch> / ABORT <n> sent=<b> ctrl=<reply> alive=<yes|no> followup=<OK|FAIL:x>
# abort5xx=<OK|FAIL|-> (only with --check-abort: RST expects 4xx/5xx on the
# aborted STOR = no false 226 (Trap 23 hardening); graceful FIN expects 2xx
# = protocol boundary, still reported as success)
# SUMMARY rounds=<n> pass=<n> fail=<n>
# Exit 0 all follow-ups pass, 1 otherwise.
# Exit 0 all rounds pass, 1 otherwise.
import argparse, hashlib, io, random, re, socket, struct, sys, time
from ftplib import FTP, all_errors
@@ -67,6 +71,9 @@ def main():
ap.add_argument("--gap", type=float, default=2.0)
ap.add_argument("--graceful", action="store_true",
help="close the data connection with FIN instead of RST")
ap.add_argument("--check-abort", action="store_true",
help="also assert the aborted STOR's control reply: RST -> 4xx/5xx "
"(no false 226, Trap 23 hardening); graceful FIN -> 2xx (boundary)")
a = ap.parse_args()
npass = nfail = 0
@@ -108,11 +115,18 @@ def main():
except Exception:
alive = "no"
fu = followup_ok(a.ip, a.port)
ok = (alive == "yes" and fu)
abort_ok = True
if a.check_abort:
code = ctl_reply[0] if (ctl_reply and ctl_reply[0].isdigit()) else "?"
# RST: device must report 4xx/5xx on the aborted STOR (450); graceful
# FIN still gets 226 (STOR has no length declaration - protocol boundary)
abort_ok = (code == "2") if a.graceful else (code in ("4", "5"))
ok = (alive == "yes" and fu and abort_ok)
npass += 1 if ok else 0
nfail += 0 if ok else 1
log("ABORT %d sent=%d ctrl=%s alive=%s followup=%s" %
(n, a.send, ctl_reply.replace("\r\n", "|")[:40], alive, "OK" if fu else "FAIL"))
log("ABORT %d sent=%d ctrl=%s alive=%s followup=%s abort5xx=%s" %
(n, a.send, ctl_reply.replace("\r\n", "|")[:40], alive,
"OK" if fu else "FAIL", "OK" if abort_ok else "FAIL" if a.check_abort else "-"))
if a.gap > 0 and n < a.rounds:
time.sleep(a.gap)
log("SUMMARY rounds=%d pass=%d fail=%d" % (a.rounds, npass, nfail))