Category: Security

  • Add routing to L2TP VPN in Mac OS X

    L2TP over IPSec is available in MAC OS X, and is very stable in Ventura with OpenBSD server. However, if your network is in the same subnet as the remote network you’re reaching with the VPN is tricky. Let me try to explain:

    me (with home network 192.168.1.0/24) —- L2TP VPN with IP 10.0.0.2 —– Internet —— Office L2TP VPN with 10.0.0.1 gateway —- Office network 192.168.1.0/24 {some machines you want to reach 192.168.1.9 and 192.168.1.124 for example}

    Now, when you establish the VPN, you can ping 10.0.0.1 from your laptop at home, but you can not ping 192.168.1.9 on the other side of the VPN (my office network).

    The easiest way is to add these routes in the point-to-point config in Mac OS.

    1. Open a shell and go to /etc/ppp directory
    # cd /etc/ppp
    2. Create a file called ip-up with:
    # sudo nano ip-up
    3. Put inside these additional routings you want to pop-up when you establish the VPN:
    #!/bin/sh
    /sbin/route add 192.168.1.116/32 -interface ppp0
    /sbin/route add 192.168.1.117/32 -interface ppp0
    /sbin/route add 192.168.1.124/32 -interface ppp0
    4. Exit and save.

    Now, when a VPN is setup, these 3 routes 192.168.1.116, .117, .124 will be available thru the VPN interface ppp0 (the default in Mac Os X).

    How easy it is to make an OpenBSD L2TP VPN server? Very easy, just need to touch three files 🙂

    Let’s first enable IPSEC and ISAKMPD on the OpenBSD box:
    # rcctl enable ipsec
    # rcctl enable isakmpd
    # rcctl set isakmpd flags -K

    In OpenBSD 7.2, all you need to do is:

    1. In /etc/npppd folder open the npppd-users file and add:
    dilyan:\
    :password=123456:
    This will add user “dilyan” with password “123456”

    2. In the same directory, you need to to touch the npppd.conf file to configure DNS, IP addresses and listening ports, etc:

    authentication LOCAL type local {
    users-file “/etc/npppd/npppd-users”
    }

    tunnel L2TP protocol l2tp {
    listen on 0.0.0.0
    listen on ::
    }

    ipcp IPCP {
    pool-address 10.0.0.2-10.0.0.254
    dns-servers 192.168.1.9 8.8.8.8
    }

    interface pppx0 address 10.0.0.1 ipcp IPCP
    bind tunnel from L2TP authenticated by LOCAL to pppx0

    with this basically we’re saying – listen on the host for IPv4 and v6, have a gateway address of 10.0.0.1, assign to the coming connections addresses from 10.0.0.2 till 254, and use DNSs 192.168.1.9 and 8.8.8.8.

    3. The last is to touch /etc/ipsec.conf with adding the following text:
    ike passive esp tunnel from X.Y.Z.Q to any \
    main group “modp1024” \
    quick group “modp1024” \
    psk “0987654”

    where X.Y.Z.Q is the public IP address of the VPN server, and 0987654 is the password for the tunnel (the shared secret).

    In Mac OS X, the L2TP over IPSec is in the default VPN configurations (System Setting -> VPN -> Add VPN Configuration), add the server address (the X.Y.Z.Q from the step above), user authorization is “Password” and put the 123456 from the npppd configuration, the Machine Authentication shall be chose as “Shared Secret” and is the 0987654 one you put in ipsec.conf. Voila.

    More details in the OpenBSD FAQ: https://www.openbsd.org/faq/faq17.html

  • Firewall rules on OpenBSD security bastion

    The setup is like that:

    Internet (public IP) — ISP router — FreeBSD 13.1 host — OpenBSD 7.2 virtual machine

    the OpenBSD is running a) ssh server with Yubikey authorization, b) Wireguard VPN server, c) L2TP VPN as a back-up on the Wireguard. The ISP router is forwarding ports tcp 22 (ssh), tcp 443 (Wireguard), udp 400 and 4500 for the L2TP VPN to the OpenBSD address directly.

    The pf.conf rules to make this setup work:

    [root@openbsd dilyan]$ cat /etc/pf.conf
    set block-policy return
    set limit table-entries 400000 #due to pfbadhost
    set skip on lo
    ext_if = “vio0”
    vpn_if = “pppx”
    vpn_net = “10.0.0.0/24”
    home_net = “192.168.0.0/24” #home network thru VPN
    office_net = “192.168.1.0/24” # office network
    table <bruteforce> persist #table for ssh-attackers
    table <pfbadhost> persist file “/etc/pf-badhost.txt”

    antispoof for { $ext_if, $vpn_if }
    match in all scrub (no-df random-id )

    block return # block stateless traffic
    block quick from <bruteforce> #block the ssh-attackers
    block in quick on egress from <pfbadhost>
    block out quick on egress to <pfbadhost>

    # By default, do not permit remote connections to X11
    block return in on ! lo0 proto tcp to port 6000:6010
    # Port build user does not need network
    block return out log proto {tcp udp} user _pbuild
    block all

    pass # establish keep-state
    pass inet proto icmp synproxy state #allow ICMP protocol – all
    pass proto { tcp, udp } from { wg0:network, $home_net, $vpn_net, $office_net } to port { ssh, domain }
    pass proto { tcp, udp } to port { ssh, 500, 4500 } keep state (max-src-conn 5, max-src-conn-rate 3/60, overload <bruteforce> flush global)
    pass proto udp from {$ext_if, $office_net} to port { 123 } #allow network time protocol (NTP) port

    # Rule for WireGuard VPN to NAT traffic to public net#
    match out on $ext_if from wg0:network to any nat-to $ext_if

    # Rules for L2TP VPN to work and NAT traffic #
    pass on $ext_if proto esp # allow ESP protocol on public interface
    pass on $ext_if proto udp to port { isakmp, ipsec-nat-t } # allow isakmpd UDP traffic through the public interface on ports 500 and 4500
    pass on enc0 keep state (if-bound) # filter all IPSec traffic on the enc interface
    pass on $vpn_if from { $vpn_net, $home_net } # allow all trafic in on and out to the VPN network
    pass on $vpn_if to { $vpn_net, $home_net }
    match out on $ext_if from $vpn_net to any nat-to $ext_if # nat VPN traffic going out on the public interface with the public IP

    These rules will _not_ work on FreeBSD, as their implementation requires grouping the rules in particular order – Macros, Tables, Options, Normalization, NAT/Redirections and then Filtering (i.e. you need to rearrange the rules).

    Once you open port 22 for ssh service on a public IP address, attackers will start attempts like ~17-20k tries per day. This is why I implemented the table, so an IP that tries to guess a username/password more than 3 times per 60 minutes to be blocked for a day. This reduced the attacks to less than 12k per day. Then I followed this how-to https://geoghegan.ca/pfbadhost.html to block malicious IPs thru the table and the attempts dropped below 9k per day.

  • Yubikey for ssh authentication with FIDO2

    Yubikey is my preferred solution for securing social account (Twitter, Facebook, Google), WordPress admin accounts, Git, Apple ID (since the iOS 16.3, and you need two keys) and OpenSSH (since v 8.2p1).

    The Yubico how-to is great, I will just add couple of specifics on configuring the server and the clients.

    I chose the “discoverable” config and followed the steps in the how-to. For MacOS Ventura 13.1, the latest is OpenSSH_9.1p1, OpenSSL 1.1.1s, so you can generate the key with ecdsa-sk.

    The second specific that is not well covered in the Yubico how-to is the server config.

    – For Debian 11.6 (with OpenSSH_8.4p1 Debian-5+deb11u1, OpenSSL 1.1.1n) add the following in your /etc/ssh/sshd_config

    #Yubikey FIDO authentification
    PubkeyAuthentication yes
    PubkeyAuthOptions verify-required
    PubkeyAcceptedKeyTypes ssh-ed25519,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com

    you also need to disable PAM in the config with:
    UsePAM no

    – for OpenBSD 7.2 (with OpenSSH_9.1, LibreSSL 3.6.0) is the same, but it works even if you comment the PAM option:

    #Yubikey FIDO authentification
    PubkeyAuthentication yes
    PubkeyAuthOptions verify-required
    PubkeyAcceptedKeyTypes ssh-ed25519,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com
    #UsePAM no

    I have added the options ssh-ed25519,sk-ssh-ed25519 to PubkeyAcceptedKeyTypes because I have several Yubikeys with different firmware versions, and several generated keys types. For Yubikey with NFC support and firmware 5.4.3 I just need sk-ecdsa-sha2-nistp256.

    Limitations:
    – you need the Yubikey all the time (obviously). BUT if you need to login to a bastion A for example, and from the bastion A to another host B, you can not do it with this setup. You can do the config on your local client and your bastion A with the above setup, but you can not do it on host B thru a bastion. Because when you login in bastion A, you lose the Yubico verification (PIN and touch) as the ssh can not “see” your Yubikey plugged on your local client.
    – you better have two Yubikeys in case you lose your primary one.