You've broadly covered it. However, I want to highlight a few points.
First of all, it's not just "forgotten" open / forwarded ports; lots of software needs to act as a server at least some of the time (game server hosting, file servers, SSH/RDP/VNC servers, web servers, etc.) or at least might work better if it can (bittorrent and other peer-to-peer transfer software, Skype and other communication protocols that prefer to establish direct links rather than relaying over a server, etc.). This isn't necessarily insecure - those servers can be authenticated, hardened, use secure protocols, etc. - but a lot of them aren't (game servers are often terribly insecure), and even in the best case, it does offer attack surface behind your firewall.
Second, you note but largely dismiss malicious traffic coming from servers back to your clients. This is a mistake; TLS and VPNs aren't used for everything and don't fully solve this problem anyhow. A few things to consider:
- The server you're connecting to might itself be malicious. No need for an MitM if I (the attacker) control e.g. an ad server and you visit a webpage (over https) that tells your browser to make a request to my server (over https) and run the script it retrieves. That script could cause your browser to make network requests from inside your firewall. CSRF, essentially, but not necessarily targeting other websites; it could instead attempt to exploit local HTTP/HTTPS listeners on your network, even your router's internal administration portal, or just port-scan your host and network.
- Same idea as above, except the content I return could be even more malicious than that. 0-day vulnerabilities in browsers' JS engines, media parsers, and so on can all happen. Browsers are sandboxed to limit the damage, these days, but it could still potentially get me code execution on your machine even if only with minimal permissions.
- Your SSH/TLS/VPN client code is itself attackable. Either as a malicious server or a man-in-the-middle, I can attack your client via malicious handshake response data or side-channel data. Remember Heartbleed, way back in 2014? It was mostly known as an attack against servers, but a server (or MitM) could use it to attack clients as well, stealing all the data out of their process memory heap too.
- Lots of stuff doesn't use TLS or VPN or other secure protocols, at least not always. DNS is now sometimes over HTTPS (which is over TLS), but that's not the default configuration and lots of machines/software don't do that. Software package repositories (classically things like Linux .deb or .rpm repositories, but also other things like perl, python, node, .NET, etc.) don't always use TLS, relying instead on the packages having trusted signatures on them to ensure they're correct... but the code that parses that package and verifies its signature could be vulnerable too. Some services still use telnet, FTP, and other unsecured protocols. A lot of POP/IMAP/SMTP email clients still use unsecured connections by default, possibly upgrading to TLS only if the server says they should; a MitM can launch essentially an SSLStrip attack on that process.
- Your firewall won't save you if the legitimate response to your request is malicious. A supply chain attack could cause
npm to download a malicious package, which will then execute on
node, gaining full control over that process. As far as the firewall can tell, though, everything was legitimate; you made a connection to a server (even over HTTPS), got a response (encrypted) from that server, and maybe closed the connection; no funny business.