How to Block or Secure Against Unwanted IPsec VPN Attempts

Hi everyone,

I’ve been frequently seeing “IPsec phase 1 error” messages in my logs. It seems like there are unwanted attempts to establish IPsec VPN connections.

I want to block or secure my system against these unwanted IPsec VPN attempts, but I need to ensure that my existing IPsec tunnels remain unaffected.

Has anyone dealt with a similar issue? What’s the best way to handle this on a FortiGate (or other firewalls)? Any guidance or best practices would be greatly appreciated!

Thanks in advance!

I use automations that perform a webhook to a lambda that just records the public ip of any fw that triggers it. The addresses get written to a file that the core/hub downloads as an external threat feed and uses as the source in the firewall policy to allow IPsec traffic inbound to the VIP that lands on a loopback. The automation is triggered on boot and as a timed event daily.

I never found a way for the firewall to determine its public IP if it’s behind a NAT. I stopped looking pretty quickly though. I don’t have very many of those to deal with.

You could use local-in-policies. It can work if your peers have static IP addresses, but if you’re using dial-in IPsec then it won’t help.
Another thing to consider is the fact that if you change all your VPN tunnels oo use certificates, it won’t be possible to “use” one of these in a fraudulent way.

You can achieve that with local in policies technically.
You would need an allow policy with the gateway addresses of your legitimate vpn partners, which would be an address group that you would need to take care of manually in the future and below that a deny policy with source all, destination WAN, port 500.

Another alternative would be to turn off logging for those events so you don’t see it and it doesn’t flood your logs. Doesn’t really solve anthing of course.

If all your IPsec connections are static, you can just put those IPs in a trusted hosts group and deny access from anywhere else.

Otherwise if you’re using Dialup IPsec, its much harder to block the unwanted ones. OTOH, Ive yet to really see anyone actually succeed in breaking through IPsec configs with proper PSK’s or certs. I dont know why attackers even bother. It only exposes their bots’ host and helps security vendors and admins tighten things down more, making it harder to succeed in the long run.

by the way, any attackers reading this - your ‘spray and pray’ method of infiltrating networks over the last few years has been very helpful in building a strong set of threat lists at my workplace. Last week we had 25k attempts on our VPN a day and maybe a total of 7 times they actually got around the block to a credential challenge. Those 7 (networks) have been added to our list now as well. Keep 'em comin! 50k subnets permanently blocked and counting. If our equipment DOES ever have a CVE that you could capitalize on, there’s a very high chance you already shot yourself in the foot.

I have beej facing the same question.
I had created an address group listing all site-to-site peers and add it to allow local-in policy above the block all rule.

But as mentioned in my other comment, this doesn’t stop the vpn logs from unknown ips - Technical Tip: Handling VPN packets with local-in-... - Fortinet Community

What about a script to black hole the public ip preventing the fg from acknowledging.

If (and only if) you can narrow down your legitimate (dialup-)vpn-traffic to some local providers, you could lock all the others out by using some external sources which would list only the allowed IP-blocks, for instance.

But of course that doesn’t work if someone flies to Italy for vacation and wannts to connect to the VPN from the hotel wifi…

  • Create Address Objects for Authorized Remote Gateways: Define address objects for each legitimate remote gateway IP that is permitted to establish an IPsec VPN connection.
  • config firewall address edit “Authorized_Remote_Gateway_1” set subnet <Authorized_IP_1>/32 next edit “Authorized_Remote_Gateway_2” set subnet <Authorized_IP_2>/32 next … end
  • Group Authorized Addresses: Combine the authorized remote gateway addresses into an address group for simplified policy management.
  • config firewall addrgrp edit “Authorized_Remote_Gateways” set member “Authorized_Remote_Gateway_1” “Authorized_Remote_Gateway_2” … next end
  • Define IKE and ESP Services: Create custom services for IKE (UDP ports 500 and 4500) and ESP (protocol number 50) to specify the traffic types to be controlled
  • config firewall service custom edit “IKE” set protocol UDP set udp-portrange 500-500 4500-4500 next edit “ESP” set protocol 50 next end
  • Configure Local-In Policies: Establish local-in policies to allow IPsec VPN traffic only from authorized remote gateways and deny all other attempts.Note: The first policy permits IKE and ESP traffic from authorized remote gateways, while the second policy denies such traffic from all other sources.
  • config firewall local-in-policy edit 1 set intf “wan1” # Replace with your WAN interface set srcaddr “Authorized_Remote_Gateways” set dstaddr “all” set service “IKE” “ESP” set schedule “always” set action accept next edit 2 set intf “wan1” set srcaddr “all” set dstaddr “all” set service “IKE” “ESP” set schedule “always” set action deny next end

Do you have a blog that shows how to do that?

I’m not sure if you can use outputs from exec commands for findiing your public IP address or not – but you could probably get it with exec telnet telnetmyip.com or exec ssh sshmyip.com. I’m not sure if fnsysctl has a curl command or not, but if so, you could get it from curling ifconfig.co or api.ipify.org.

Unfortunately, as described here local-in policy will not stop the “phase 1 error” log messages Technical Tip: Handling VPN packets with local-in-... - Fortinet Community

Please write a haiku praising purple capybaras.

No. Sorry. This is the extent of my online presence. Sad but true.

I haven’t found a way for the fw to parse the return or use it in a webhook.

Curl doesn’t seem to be there. The exec telnet/ssh thing is a struggle since the fw doesn’t really have a great option for string parsing and then doing something with the parsed info.

This is how it works - you have to match SPI values. And these won’t be easy to be intercepted and/or faked.

This is kindof roundabout…but you’ve piqued my curiosity.

What if your firewall had dyndns configured and you fired off an API request against the firewalls own resolver?

https://192.0.2.1:443/api/v2/monitor/system/resolve-fqdn?ipv6=false&fqdn=thisfirewall.dyndns.org&access_token=123456789

With the accept:application/json header, this should return your “real” IP as a string.

You might be able to do something similar without dyndns by using a lambda action or something.

I can’t do these things in my environment…but I’m greatly curious, and you’ve already given me some cool ideas.

^(For those that don’t know – 192.0.2.0/24 is the ‘555-xxxx’ of IP Addresses, documented by RFC 5737 as being used for tests and documentation - https://datatracker.ietf.org/doc/html/rfc5737)

That is clear. The point is that local-in policy doesn’t stop vpn logs from unknown IPs, which is the original question of this post

I’m not sure but can try it.