Networks with OpenVPN and Suricata
If you enjoy my work, sponsor or hire me! I work hard keeping oxasploits running!Bitcoin Address:
bc1qclqhff9dlvmmuqgu4907gh6gxy8wy8yqk596yp
Thank you so much and happy hacking!
Intro
Most of my recent posts have been centered around red team security, but this article will be more from a blue team perspective of network security. I’ll cover setting up an offsite server to be an encrypted network internet gateway for local endpoints secured with an active Intrusion Prevention System (Suricata IPS) coupled Oinkmaster rule pulling software for automatic updates. Everything will be encrypted over the air and wire via an OpenVPN configuration. All data also goes through iptables, which does the packet forwarding.
A related article on log aggregation of everything the IPS generates.
OpenVPN
First you’ll need to install OpenVPN and it’s dependancies. I suggest using your distribution’s package manager. Since my gateway is running Debian, we’ll be using apt.
sudo apt-get update
sudo apt-get install openvpn
You should also create a vpn group in case OpenVPN gets owned.
groupadd vpn
Next you’ll need to generate some keys. We’ll be using easy-rsa.
cd /usr/share/easy-rsa/
. ./vars
./clean-all
./build-ca
./build-dh
./build-req yourclientsname
./build-key yourclientsname
./build-key-server
Make sure your permission are correct so no unauthorized users can read the ca and server key or you’ll open yourself up to a man in the middle attack. Now you’ll need to configure the OpenVPN server. You can tweak this to your liking, but our lab server config looks something like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
cipher AES-256-CBC # network's encryption
auth SHA256 # authentication encryption
dh /etc/openvpn/server/dh.pem # diffie pem
user nobody # unpriviledged user
group vpn # group to run in
proto udp # i'm using the UDP protocol because of low overhead
dev tun # we want to use a tun device for udp
cert /etc/openvpn/server/server.crt # server's cert generated by easy-rsa
key /etc/openvpn/server/server.key # server's key generated by easy-rsa
ca /etc/openvpn/server/ca.crt # certificate authority gen'd by easy-rsa
tls-server # tells clients this is a tls server
server 10.0.0.0 255.255.255.0 # client's dhcp pool
push "redirect-gateway def1" # this pushes the gateway to the client (needed if exit)
push "dhcp-option DNS 8.8.8.8" # dns server to go to clients (needed if an exit)
To get the OpenVPN server to actually be a gateway we need to do a couple more steps, such as turning IP forwarding on, as well as configuration of iptables for masquerade.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Generated by iptables-save v1.8.4 on Tue May 18 16:35:45 2021
*nat
:PREROUTING ACCEPT [8965:625941]
:INPUT ACCEPT [343:19575]
:OUTPUT ACCEPT [10:757]
:POSTROUTING ACCEPT [343:22904]
-A POSTROUTING -s 10.0.0.0/8 -o eth0 -j MASQUERADE
COMMIT
# Completed on Tue May 18 16:35:45 2021
# Generated by iptables-save v1.8.4 on Tue May 18 16:35:45 2021
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:LOGGING - [0:0]
-A INPUT -i lo -j ACCEPT
-I INPUT -j NFQUEUE --queue-num 0
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
-A INPUT -p udp -m udp --dport 1194 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j LOGGING
-I FORWARD -j NFQUEUE --queue-num 0
-A FORWARD -s 10.0.0.0/8 -p tcp -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -d 10.0.0.0/8 -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -j LOGGING
-A OUTPUT -o lo -j ACCEPT
-I OUTPUT -j NFQUEUE --queue-num 0
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -p icmp -m icmp --icmp-type 0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -p icmp -m icmp --icmp-type 8 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -j LOGGING
-A LOGGING -m limit --limit 2/min -j LOG --log-prefix "iptables_drop: "
-A LOGGING -j DROP
COMMIT
# Completed on Tue May 18 16:35:45 2021
Then pull in the rules with:
iptables-restore < iptablesfile
I also suggest installing iptables-persistent if available.
Also finally we need to turn on IP forwarding:
sudo sysctl
-w net.ipv4.ip_forward=1
sudo vim /etc/sysctl.conf # (then add net.ipv4.ip_forward = 1 to make it perminate)
Then spin up OpenVPN with:
sudo systemctl start openvpn-server
You’ll also need to generate .ovpn files for your clients connecting. You can use this script to genearte the files, then securely transfer them to your clients.
#!/bin/sh
##
## Usage: ./ovpn-writer.sh SERVER CA_CERT CLIENT_CERT CLIENT_KEY > client.ovpn
##
server=${1?
"The server address is required"}
cacert=${2?
"The path to the ca certificate file is required"}
client_cert=${3?
"The path to the client certificate file is required"}
client_key=${4?
"The path to the client private key file is required"}
#tls_key=${5?"The path to the TLS shared secret file is required"}
cat << EOF
client
dev tun0
remote ${server}
resolv-retry infinite
nobind
persist-key
persist-tun
verb 1
auth SHA256
keepalive 10 120
port 1194
proto udp
remote-cert-tls server
cipher AES-256-CBC
tls-client
pull
<ca>
EOF
cat ${cacert}
cat << EOF
</ca>
<cert>
EOF
cat ${client_cert}
cat << EOF
</cert>
<key>
EOF
cat ${client_key}
cat << EOF
</key>
EOF
Lastly, install the client .ovpn files on each machine you want to connect. (repeat the above steps for generating a client key for each client!) OpenVPN should now work. If you have any trouble, check
/var/log/openvpn/openvpn.log
, and that should point you in the general direction of your problem.
Suricata IPS
To secure the network from the internet, we should install an IPS. In this case we’re using Suricata coupled with Oinkmaster and iptables.
First we need to install Suricata and Oinkmaster:
sudo apt-get install suricata oinkmaster
We also need to install the rules (all the .rules files from suricata.yaml). Let’s do this with Oinkmaster.
useradd suri
groupadd suri
Then edit
/etc/suricata/suricata.yaml
to your liking. Mine looks like:
%YAML 1.1
---
vars:
address-groups:
HOME_NET: "[10.0.0.0/8]"
EXTERNAL_NET: "!$HOME_NET"
HTTP_SERVERS: "$HOME_NET"
SMTP_SERVERS: "$HOME_NET"
SQL_SERVERS: "$HOME_NET"
DNS_SERVERS: "$HOME_NET"
TELNET_SERVERS: "$HOME_NET"
AIM_SERVERS: "$EXTERNAL_NET"
DC_SERVERS: "$HOME_NET"
DNP3_SERVER: "$HOME_NET"
DNP3_CLIENT: "$HOME_NET"
MODBUS_CLIENT: "$HOME_NET"
MODBUS_SERVER: "$HOME_NET"
ENIP_CLIENT: "$HOME_NET"
ENIP_SERVER: "$HOME_NET"
port-groups:
HTTP_PORTS: "80"
SHELLCODE_PORTS: "!80"
ORACLE_PORTS: 1521
SSH_PORTS: 22
DNP3_PORTS: 20000
MODBUS_PORTS: 502
FILE_DATA_PORTS: "
[$HTTP_PORTS,110,143]"
FTP_PORTS: 21
GENEVE_PORTS: 6081
VXLAN_PORTS: 4789
TEREDO_PORTS: 3544
default-log-dir: /var/log/suricata
stats:
enabled: yes
interval: 8
outputs:
- fast:
enabled: yes
filename: fast.log
append: yes
- eve-log:
enabled: yes
filename: eve.json
pcap-file: false
community-id: false
community-id-seed: 0
xff:
enabled: no
mode: extra-data
deployment: reverse
header: X-Forwarded-For
types:
- alert:
tagged-packets: yes
- anomaly:
enabled: yes
types:
- http:
- dns:
- tls:
- files:
- drop:
- smtp:
- ftp
- rdp
- nfs
- smb
- tftp
- ikev2
- dcerpc
- krb5
- snmp
- rfb
- sip
- dhcp:
enabled: yes
extended: no
- ssh
- mqtt:
- stats:
- flow
- http-log:
enabled: yes
filename: http.log
append: yes
- tls-log:
append: yes
- tls-store:
enabled: no
- pcap-log:
enabled: no
filename: log.pcap
limit: 1000mb
max-files: 2000
compression: none
- alert-debug:
enabled: no
filename: alert-debug.log
append: yes
- alert-prelude:
enabled: no
profile: suricata
log-packet-content: no
log-packet-header: yes
- stats:
enabled: yes
filename: stats.log
- syslog:
enabled: no
facility: local5
- file-store:
version: 2
enabled: no
xff:
enabled: no
mode: extra-data
deployment: reverse
header: X-Forwarded-For
- tcp-data:
enabled: no
type: file
filename: tcp-data.log
- http-body-data:
enabled: no
type: file
filename: http-data.log
- lua:
enabled: no
scripts:
logging:
default-log-level: notice
default-output-filter:
outputs:
- console:
enabled: yes
- file:
enabled: yes
level: info
filename: suricata.log
- syslog:
enabled: no
facility: local5
format: "[%i] <%d> --
"
app-layer:
protocols:
rfb:
enabled: yes
detection-ports:
dp:
5900, 5901, 5902, 5903, 5904, 5905, 5906, 5907, 5908, 5909
mqtt:
krb5:
enabled: yes
snmp:
enabled: yes
ikev2:
enabled: yes
tls:
enabled: yes
detection-ports:
dp: 443
dcerpc:
enabled: yes
ftp:
enabled: yes
rdp:
ssh:
enabled: yes
http2:
enabled: no
smtp:
enabled: yes
raw-extraction: no
mime:
decode-mime: yes
decode-base64: yes
decode-quoted-printable: yes
header-value-depth: 2000
extract-urls: yes
body-md5: no
inspected-tracker:
content-limit: 100000
content-inspect-min-size: 32768
content-inspect-window: 4096
imap:
enabled: detection-only
smb:
enabled: yes
detection-ports:
dp: 139, 445
nfs:
enabled: yes
tftp:
enabled: yes
dns:
tcp:
enabled: yes
detection-ports:
dp: 53
udp:
enabled: yes
detection-ports:
dp: 53
http:
enabled: yes
libhtp:
default-config:
personality: IDS
request-body-limit: 100kb
response-body-limit: 100kb
request-body-minimal-inspect-size: 32kb
request-body-inspect-window: 4kb
response-body-minimal-inspect-size: 40kb
response-body-inspect-window: 16kb
response-body-decompress-layer-limit: 2
http-body-inline: auto
swf-decompression:
enabled: yes
type: both
compress-depth: 100kb
decompress-depth: 100kb
double-decode-path: no
double-decode-query: no
server-config:
modbus:
enabled: no
detection-ports:
dp: 502
stream-depth: 0
dnp3:
enabled: no
detection-ports:
dp: 20000
enip:
enabled: no
detection-ports:
dp: 44818
sp: 44818
ntp:
enabled: yes
dhcp:
enabled: yes
sip:
asn1-max-frames: 256
run-as:
user: suri
group: suri
pid-file: /run/suricata/suricata.pid
coredump:
max-dump: unlimited
host-mode: auto
unix-command:
enabled: auto
legacy:
uricontent: enabled
action-order:
- pass
- drop
- reject
- alert
engine-analysis:
rules-fast-pattern: yes
rules: yes
pcre:
match-limit: 3500
match-limit-recursion: 1500
host-os-policy:
windows: [0.0.0.0/0]
bsd: []
bsd-right: []
old-linux: []
linux: []
old-solaris: []
solaris: []
hpux10: []
hpux11: []
irix: []
macos: []
vista: []
windows2k3: []
defrag:
memcap: 32mb
hash-size: 65536
prealloc: yes
timeout: 60
flow:
memcap: 128mb
hash-size: 65536
prealloc: 10000
emergency-recovery: 30
vlan:
use-for-tracking: true
flow-timeouts:
default:
new: 30
established: 300
closed: 0
bypassed: 100
emergency-new: 10
emergency-established: 100
emergency-closed: 0
emergency-bypassed: 50
tcp:
new: 60
established: 600
closed: 60
bypassed: 100
emergency-new: 5
emergency-established: 100
emergency-closed: 10
emergency-bypassed: 50
udp:
new: 30
established: 300
bypassed: 100
emergency-new: 10
emergency-established: 100
emergency-bypassed: 50
icmp:
new: 30
established: 300
bypassed: 100
emergency-new: 10
emergency-established: 100
emergency-bypassed: 50
stream:
memcap: 64mb
reassembly:
memcap: 256mb
toserver-chunk-size: 2560
toclient-chunk-size: 2560
randomize-chunk-size: yes
host:
hash-size: 4096
prealloc: 1000
memcap: 32mb
decoder:
teredo:
enabled: true
vxlan:
enabled: true
geneve:
enabled: true
detect:
profile: medium
custom-values:
toclient-groups: 3
toserver-groups: 25
sgh-mpm-context: auto
inspection-recursion-limit: 3000
prefilter:
default: mpm
grouping:
profiling:
grouping:
dump-to-disk: false
include-mpm-stats: false
mpm-algo: auto
spm-algo: auto
threading:
set-cpu-affinity: no
cpu-affinity:
- management-cpu-set:
- receive-cpu-set:
- worker-cpu-set:
cpu: [ "
all" ]
mode: "exclusive"
prio:
low: [ 0 ]
medium: [ "1-2" ]
high: [ 3 ]
default: "medium"
detect-thread-ratio: 1.0
luajit:
states: 128
profiling:
rules:
enabled: yes
filename: rule_perf.log
append: yes
limit: 10
json: yes
keywords:
enabled: yes
filename: keyword_perf.log
append: yes
prefilter:
enabled: yes
filename: prefilter_perf.log
append: yes
rulegroups:
enabled: yes
filename: rule_group_perf.log
append: yes
packets:
enabled: yes
filename: packet_stats.log
append: yes
csv:
enabled: no
filename: packet_stats.csv
locks:
enabled: no
filename: lock_stats.log
append: yes
pcap-log:
enabled: no
filename: pcaplog_stats.log
append: yes
nfq:
mode: repeat
fail-open: no
nflog:
- group: 2
buffer-size: 18432
- group: default
qthreshold: 1
qtimeout: 100
max-size: 20000
capture:
netmap:
- interface: eth2
- interface: default
pfring:
- interface: eth0
threads: auto
cluster-id: 99
cluster-type: cluster_flow
- interface: default
ipfw:
napatech:
streams: ["
0-3"]
enable-stream-stats: no
auto-config: yes
hardware-bypass: yes
inline: no
ports: [0-1,
2-3]
hashmode: hash5tuplesorted
default-rule-path: /var/lib/suricata/rules
rule-files:
- emerging-policy.rules
- botcc.portgrouped.rules
- emerging-sql.rules
- emerging-activex.rules
- emerging-user_agents.rules
- emerging-info.rules
- emerging-malware.rules
- emerging-exploit.rules
- emerging-worm.rules
- emerging-mobile_malware.rules
- emerging-misc.rules
- emerging-web_server.rules
- emerging-web_client.rules
- emerging-phishing.rules
- emerging-scada.rules
- emerging-rpc.rules
- emerging-web_specific_apps.rules
- emerging-shellcode.rules
- emerging-netbios.rules
- compromised.rules
- emerging-icmp_info.rules
- botcc.rules
- emerging-coinminer.rules
- emerging-adware_pup.rules
- emerging-icmp.rules
- emerging-p2p.rules
- emerging-scan.rules
- emerging-dns.rules
- emerging-attack_response.rules
- emerging-snmp.rules
- emerging-chat.rules
- emerging-exploit_kit.rules
- emerging-imap.rules
- emerging-hunting.rules
- emerging-current_events.rules
- emerging-dos.rules
classification-file: /etc/suricata/classification.config
reference-config-file: /etc/suricata/reference.config
We also need to install the rules (all the .rules files from suricata.yaml). Lets do this with Oinkmaster.
1
2
3
4
5
6
7
url = https://rules.emergingthreats.net/open/suricata-5.0/emerging.rules.tar.gz
skipfile local.rules
skipfile deleted.rules
skipfile snort.conf
modifysid emerging-exploit.rules, emerging-exploit_kit.rules, drop.rules, emerging-worm.rules "^alert " | "drop "
modifysid emerging-exploit.rules, drop.rules, emerging-worm.rules "^#alert " | "drop "
modifysid 2013457 "alert" | "#alert" # whitelist bitcoin wallet
Then pull the rules in with:
oinkmaster -c /etc/oinkmaster.conf -o
/etc/suricata/rules/ # install rules
pkill -u suri -USR2 # live rule reload
I also recommend putting the last two commands in serial in the root user’s crontab so that the IPS will automatically update its rules. Then a systemd script:
1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=Suricata Intrusion Detection Service
After=syslog.target network-online.target
[Service]
ExecStartPre=/bin/rm -f /run/suricata/suricata.pid
ExecStart=/usr/bin/suricata -c /etc/suricata/suricata.yaml --pidfile /run/suricata/suricata.pid -q 0
ExecReload=/bin/kill -USR2 $MAINPID
[Install]
WantedBy=multi-user.target
Then install it:
sudo systemctl start suricata
sudo systemctl enable suricata
Now you can finally run tail -f /var/log/suricata/fast.log
and see Suricata filtering your VPN traffic! Enjoy a little peace of mind. I am also a for-hire security professional, see my resume.