From 1b3e8a611eca06d043a31c7f3552a21f275a44d2 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Mon, 20 Feb 2023 15:32:27 +0100 Subject: [PATCH] ftp/main: Skip get_pending_command() for intermediate reply lines Intermediate lines of multiline replies usually do not contain valid status codes (even if servers may opt to include them). Their content may be anything and likely unrelated to the original command. There's little reason for us trying to match them with a corresponding command. OSS-Fuzz generated a large command reply with very many intermediate lines which caused long processing times due to matching every line with all currently pending commands. This is a DoS vector against Zeek. The new ipv6-multiline-reply.trace and ipv6-retr-samba.trace files have been extracted from the external ipv6.trace. --- scripts/base/protocols/ftp/main.zeek | 14 ++++++++-- .../ftp.log | 15 +++++++++++ .../out | 25 ++++++++++++++++++ .../ftp.log | 14 ++++++++++ .../out | 16 +++++++++++ .../scripts.policy.protocols.ftp.ftp/.stderr | 1 + .../scripts.policy.protocols.ftp.ftp/ftp.log | 12 +++++++++ .../Traces/ftp/ipv6-multiline-reply.trace | Bin 0 -> 6154 bytes .../btest/Traces/ftp/ipv6-retr-samba.trace | Bin 0 -> 4103 bytes .../protocols/ftp/ftp-multiline-reply.zeek | 13 +++++++++ .../base/protocols/ftp/ftp-samba-retr.zeek | 13 +++++++++ .../scripts/policy/protocols/ftp/ftp.zeek | 7 +++++ 12 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.ftp-multiline-reply/ftp.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.ftp-multiline-reply/out create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.ftp-samba-retr/ftp.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.ftp-samba-retr/out create mode 100644 testing/btest/Baseline/scripts.policy.protocols.ftp.ftp/.stderr create mode 100644 testing/btest/Baseline/scripts.policy.protocols.ftp.ftp/ftp.log create mode 100644 testing/btest/Traces/ftp/ipv6-multiline-reply.trace create mode 100644 testing/btest/Traces/ftp/ipv6-retr-samba.trace create mode 100644 testing/btest/scripts/base/protocols/ftp/ftp-multiline-reply.zeek create mode 100644 testing/btest/scripts/base/protocols/ftp/ftp-samba-retr.zeek create mode 100644 testing/btest/scripts/policy/protocols/ftp/ftp.zeek diff --git a/scripts/base/protocols/ftp/main.zeek b/scripts/base/protocols/ftp/main.zeek index d56c276886..1ebb8cf16c 100644 --- a/scripts/base/protocols/ftp/main.zeek +++ b/scripts/base/protocols/ftp/main.zeek @@ -316,12 +316,22 @@ event ftp_request(c: connection, command: string, arg: string) &priority=5 event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) &priority=5 { set_ftp_session(c); + + # Skip matching up intermediate reply lines (that do not have a + # valid status code) with pending commands. Because they may not + # have a proper status code, there's little point setting whatever + # their reply_code and reply_msg are on the command unless to ensure + # c$ftp$reply_code is actually populated with "something". + if ( cont_resp && code == 0 && c$ftp?$reply_code ) + return; + c$ftp$cmdarg = get_pending_cmd(c$ftp$pending_commands, code, msg); c$ftp$reply_code = code; c$ftp$reply_msg = msg; - # TODO: figure out what to do with continued FTP response (not used much) - if ( cont_resp ) return; + # Do not parse out information from any but the first reply line. + if ( cont_resp ) + return; # TODO: do some sort of generic clear text login processing here. local response_xyz = parse_ftp_reply_code(code); diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-multiline-reply/ftp.log b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-multiline-reply/ftp.log new file mode 100644 index 0000000000..3901e065d3 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-multiline-reply/ftp.log @@ -0,0 +1,15 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ftp +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p user password command arg mime_type file_size reply_code reply_msg data_channel.passive data_channel.orig_h data_channel.resp_h data_channel.resp_p fuid +#types time string addr port addr port string string string string string count count string bool addr addr port string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:d69a:20ff:fefd:6b88 58895 2400:3000:20:100::46 21 - - - - 220 FTP server ready. - - - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:d69a:20ff:fefd:6b88 58895 2400:3000:20:100::46 21 anonymous - USER anonymous - - 331 Guest login ok, send your email address as password. - - - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:d69a:20ff:fefd:6b88 58895 2400:3000:20:100::46 21 anonymous root@sponge.es.net PASS root@sponge.es.net - - 230 Guest login ok, access restrictions apply. - - - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:d69a:20ff:fefd:6b88 58895 2400:3000:20:100::46 21 anonymous root@sponge.es.net EPSV - - - 229 Entering Extended Passive Mode (|||60931|) T 2001:470:1f05:17a6:d69a:20ff:fefd:6b88 2400:3000:20:100::46 60931 - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:d69a:20ff:fefd:6b88 58895 2400:3000:20:100::46 21 anonymous root@sponge.es.net RETR ftp://[2400:3000:20:100::46]/pub/FreeBSD/ports/local-distfiles/avl/libssh-0.5.2.tar.gz - - 221 You could at least say goodbye. - - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-multiline-reply/out b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-multiline-reply/out new file mode 100644 index 0000000000..b7d9c53a55 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-multiline-reply/out @@ -0,0 +1,25 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ftp_reply, T, 220, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, T, 0, Welcome to FTP.JPIX.ad.jp, +ftp_reply, F, 220, FTP server ready. +ftp_reply, F, 331, Guest login ok, send your email address as password. +ftp_reply, F, 230, Guest login ok, access restrictions apply. +ftp_reply, F, 257, "/" is current directory. +ftp_reply, F, 250, CWD command successful. +ftp_reply, F, 200, MODE S accepted. +ftp_reply, F, 200, Type set to I. +ftp_reply, F, 550, libssh-0.5.2.tar.gz: No such file or directory. +ftp_reply, F, 200, MODE S accepted. +ftp_reply, F, 200, Type set to I. +ftp_reply, F, 229, Entering Extended Passive Mode (|||60931|) +ftp_reply, F, 550, libssh-0.5.2.tar.gz: No such file or directory. +ftp_reply, F, 221, You could at least say goodbye. diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-samba-retr/ftp.log b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-samba-retr/ftp.log new file mode 100644 index 0000000000..0171f548f6 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-samba-retr/ftp.log @@ -0,0 +1,14 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ftp +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p user password command arg mime_type file_size reply_code reply_msg data_channel.passive data_channel.orig_h data_channel.resp_h data_channel.resp_p fuid +#types time string addr port addr port string string string string string count count string bool addr addr port string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:213:72ff:fe0d:a566 16730 2001:6f8:200:1::5:33 21 anonymous - USER anonymous - - 331 Anonymous login ok, send your complete email address as your password - - - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:213:72ff:fe0d:a566 16730 2001:6f8:200:1::5:33 21 anonymous root@freebsd-5453 PASS root@freebsd-5453 - - 230 Anonymous access granted, restrictions apply - - - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:213:72ff:fe0d:a566 16730 2001:6f8:200:1::5:33 21 anonymous root@freebsd-5453 EPSV - - - 229 Entering Extended Passive Mode (|||63282|) T 2001:470:1f05:17a6:213:72ff:fe0d:a566 2001:6f8:200:1::5:33 63282 - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:213:72ff:fe0d:a566 16730 2001:6f8:200:1::5:33 21 anonymous root@freebsd-5453 RETR ftp://[2001:6f8:200:1::5:33]/samba/samba-3.4.17.tar.gz - 34826629 226 Transfer complete - - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-samba-retr/out b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-samba-retr/out new file mode 100644 index 0000000000..b6f51e7bcc --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-samba-retr/out @@ -0,0 +1,16 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ftp_reply, F, 220, 2001:6f8:200:1::5:33 FTP server ready +ftp_reply, F, 331, Anonymous login ok, send your complete email address as your password +ftp_reply, F, 230, Anonymous access granted, restrictions apply +ftp_reply, F, 257, "/" is the current directory +ftp_reply, T, 250, See http://samba.org/ for a list of mirror sites +ftp_reply, F, 250, CWD command successful +ftp_reply, F, 200, Mode set to S +ftp_reply, F, 200, Type set to I +ftp_reply, F, 213, 34826629 +ftp_reply, F, 213, 20120430122210 +ftp_reply, F, 200, Mode set to S +ftp_reply, F, 200, Type set to I +ftp_reply, F, 229, Entering Extended Passive Mode (|||63282|) +ftp_reply, F, 150, Opening BINARY mode data connection for samba-3.4.17.tar.gz (34826629 bytes) +ftp_reply, F, 226, Transfer complete diff --git a/testing/btest/Baseline/scripts.policy.protocols.ftp.ftp/.stderr b/testing/btest/Baseline/scripts.policy.protocols.ftp.ftp/.stderr new file mode 100644 index 0000000000..49d861c74c --- /dev/null +++ b/testing/btest/Baseline/scripts.policy.protocols.ftp.ftp/.stderr @@ -0,0 +1 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. diff --git a/testing/btest/Baseline/scripts.policy.protocols.ftp.ftp/ftp.log b/testing/btest/Baseline/scripts.policy.protocols.ftp.ftp/ftp.log new file mode 100644 index 0000000000..9b6ac207c3 --- /dev/null +++ b/testing/btest/Baseline/scripts.policy.protocols.ftp.ftp/ftp.log @@ -0,0 +1,12 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ftp +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p user password command arg mime_type file_size reply_code reply_msg data_channel.passive data_channel.orig_h data_channel.resp_h data_channel.resp_p fuid +#types time string addr port addr port string string string string string count count string bool addr addr port string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:d69a:20ff:fefd:6b88 58895 2400:3000:20:100::46 21 anonymous root@sponge.es.net EPSV - - - 229 Entering Extended Passive Mode (|||60931|) T 2001:470:1f05:17a6:d69a:20ff:fefd:6b88 2400:3000:20:100::46 60931 - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 2001:470:1f05:17a6:d69a:20ff:fefd:6b88 58895 2400:3000:20:100::46 21 anonymous root@sponge.es.net RETR ftp://[2400:3000:20:100::46]/pub/FreeBSD/ports/local-distfiles/avl/libssh-0.5.2.tar.gz - - 221 You could at least say goodbye. - - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/ftp/ipv6-multiline-reply.trace b/testing/btest/Traces/ftp/ipv6-multiline-reply.trace new file mode 100644 index 0000000000000000000000000000000000000000..a5296f437f9d1865f462dc0b4f9786e3f0833c70 GIT binary patch literal 6154 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 out +# @TEST-EXEC: btest-diff ftp.log +# @TEST-EXEC: btest-diff out + +@load base/protocols/conn +@load base/protocols/ftp + +redef FTP::logged_commands += { "", "USER", "PASS" }; + +event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) { + print "ftp_reply", cont_resp, code, cat(c$ftp$reply_msg); +} diff --git a/testing/btest/scripts/base/protocols/ftp/ftp-samba-retr.zeek b/testing/btest/scripts/base/protocols/ftp/ftp-samba-retr.zeek new file mode 100644 index 0000000000..1ad8c6863a --- /dev/null +++ b/testing/btest/scripts/base/protocols/ftp/ftp-samba-retr.zeek @@ -0,0 +1,13 @@ +# @TEST-DOC: Tests interemediate lines to not confuse cwd tracking. +# @TEST-EXEC: zeek -b -r $TRACES/ftp/ipv6-retr-samba.trace %INPUT > out +# @TEST-EXEC: btest-diff ftp.log +# @TEST-EXEC: btest-diff out + +@load base/protocols/conn +@load base/protocols/ftp + +redef FTP::logged_commands += { "USER", "PASS", "RETR" }; + +event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) { + print "ftp_reply", cont_resp, code, cat(c$ftp$reply_msg); +} diff --git a/testing/btest/scripts/policy/protocols/ftp/ftp.zeek b/testing/btest/scripts/policy/protocols/ftp/ftp.zeek new file mode 100644 index 0000000000..bfdc88b2d0 --- /dev/null +++ b/testing/btest/scripts/policy/protocols/ftp/ftp.zeek @@ -0,0 +1,7 @@ +# @TEST-DOC: Smoke the policy/protocols/ftp scripts don't fall apart. +# @TEST-EXEC: zeek -b -r $TRACES/ftp/ipv6-multiline-reply.trace %INPUT +# @TEST-EXEC: btest-diff ftp.log +# @TEST-EXEC: btest-diff .stderr + +@load protocols/ftp/detect +@load protocols/ftp/detect-bruteforcing