TFTP is quite difficult to secure, but let's try anyway.
Before we dive in, let's reason why this is hard.
We learned from the packet captures that after the
initial UDP port 69 control message,
the server chooses a random source port and uses the client's
original source port as its destination.
Some stateful firewalls will see this as a new flow,
and thus don't match the return ingress traffic.
Stateless firewalls in our case would need to permit
the entire range of random UDP ports,
which is almost a worthless level of security.
What can we do?
Some TFTP clients provide control over which UDP source port they
choose when originating their TFTP control sessions.
Because the server uses this source port as the destination port
for any further communication with a client,
being able to constrain these values may help overcome security woes.
Let's check out the man page briefly.
The -r option provides a mechanism to specify a port range in min:max format.
We can retool our TFTP scripts using this mechanism.
Much like I did in the FTP security testing,
I've consolidated both our upload and download operations into a
single script to serve as an easy regression test.
Not surprisingly, there are two lines in the script,
one for the download of R1.cfg and one for the upload of R3.cfg.
I've added a port range of 42500 to 42599,
allowing for up to 100 concurrent transfers.
Before running the script,
let's jump over to R3 where our stateless firewall policy has been applied.
The inside-in ACL is applied inbound on R3 facing R1 and allows port 69,
which is TFTP from our clients to our server.
The next entry allows any UDP flow between the same set of
hosts using our configured source port range.
This permits the data traffic used for the file transfer.
The outside-in ACL simply reverses the data channel
rule from the inside-in access list.
This allows the server to send traffic destined to ports
42500 through 42599 towards the client.
I'm sure you can find other ways to implement this policy,
but this is just one example.
Let's move back to the TFTP client.
Running the script will produce no new output,
but we can check the ACL counters on our firewall to
verify that it is configured correctly.
The output indicates that R1.cfg was downloaded and R3.cfg was uploaded.
Let's see what R3's ACL counters say.
This looks correct to me,
as we see matches on the permit entries and no matches on the deny entries.
As a final note,
I want to stress that many TFTP clients do not
support this custom port range feature,
so relying on it enterprise-wide is unwise.
Using network-based firewalls in between TFTP endpoints is not recommended. Stick around because I'll be talking about TFTP use cases shortly.