Lab 2. Stateful firewall - CBAC and ZBF

Setup

Story

In our basic topology scenario, due to small budget our company still uses the old Cisco equipment for routing and filtering, but this time the second branch closed and added instead a visitor network (may be used by people that come at interview). After seeing some attacks done in our internal network like DoS, we decided to test different approaches: started with TCP intercept, continuing with CBAC and in the end implemented successfully the better security solution - zone based firewall (ZBF).

Lab infra

The new end-point machine called kali is a Kali Linux version 2019.3 and represents the possible attacker. The old network from branch 2 is reused (3.3.3.0/24) for visitors - with the first IP from subnet assigned to router and the second one for end-device. Note that we may refer to the router as firewall during the course of the lab.

Again, the router model is 7200 (version: c7200-adventerprisek9-mz.124-9.T4 - link here).

You have to do the following:

- add IPs for network between the server and the network equipment (use range 1.1.1.0/24)

- add IPs for network between the client and kali and the network equipment (use ranges 2.2.2.0/24 and 3.3.3.0/24) First IP is allocated for router and the second one for client1/kali machine

- add routes to make sure the endpoints can ping each other

Topology:

Credentials for machines:

kali - root:toor

server and client1 - eve:eve (with sudo access)

cisco_7200 - enable passwd: cisco

Mapping ip-student: check your machine ip here

Stateful firewall implementations

t1. TCP intercept

This first scenario is just for getting used to DoS attacks in our topology and hping3 command. Suppose that an attacker (called Trudy) wants to make a server unavailable using a SYN flood attack (which is fairly easy to create). This is done by sending TCP segments with SYN flag and no intention to complete the handshake. The server hangs by waiting for these connections to be finished until the timeout expires, but creates problems with legitimate TCP connections which can be denied.

TCP intercept is a features found in IOS that is used for SYN flood protection. There are 2 modes of protection:

- intercept: the router does mitm by intercepting the user's connection request and pretends to be the server, by completing the connection. Only if the 3-way handshake is completed successfully, the second TCP connection is set with the server.

Note: This process is transparent to both server and client

Suppose a SYN flood attack happens. The router has a buffer for all opened connections on behalf of client, that will timeout after a period of time (it sends to client a RST) due to no completed 3-way handshake and removed from the connection table. By using this approach, the server remains unaffected by the attack and valid requests are answered.

- watch: the disadvantage of intercept is that most of the times the router does this mitm for fair clients and adds overhead. A solution can be watch mode, which is a reactive approach that is monitoring connections, keeping track of half-open ones. Again, after a timeout (default 30 seconds) if a connection is not completed, the router sends a RST to server to remove it. This will remove all unwanted incompleted connections and allows legitimate ones to complete.

In this lab, we will use hping3 to simulate the attack. On server machine we have SimpleHTTPServer up and running on port 8080.

For TCP intercepting, we need firstly to add on router an ACL to permit tcp for any ip:

cisco_7200(config)#ip access-list extended TCP_INTERCEPT
cisco_7200(config-ext-nacl)#permit tcp any host 1.1.1.2 eq 8080

Enable TCP intercept in global config mode and specify the traffic to be analyzed (using ACL from above):

cisco_7200(config)#ip tcp intercept list TCP_INTERCEPT

The default mode is intercept, which is the one we are goind to use here. To change it to watch:

cisco_7200(config)#ip tcp intercept mode watch

Note that a mix of them is not possible.

There are also 3 timeouts that can be also configured: watch (default 30 secs - waiting time for 3-way handshake to complete), finrst (default 5 secs - waiting time for a connection to finish) and connection (default 24 hours - the maximum time of connection management. This is for sure one with handshake completed, but it can be in idle mode).

A high and low threshold values can be configured to deal with a big number of requests. After the high value is reached, it begins to drop connections until the low one. Default for high is 1100 and for low 900. To set them in production, you need careful baseline analysis to avoid dropping legitimate connections. These can be changed using:

cisco_7200(config)#ip tcp intercept max-incomplete high 100
cisco_7200(config)#ip tcp intercept max-incomplete low 10

The default method in aggressive mode is to drop oldest connections first until the connections number is below the minimum value. This can be also changed to random:

cisco_7200(config)#ip tcp intercept drop-mode random 

Let's stress the webserver using hping3 command:

root@kali:# hping3 -n -c 1000 -d 120 -S -w 64 -p 8080 --flood 1.1.1.2 

Explanations for the flags used:

  1. -n = numeric output only (no lookup is done for host names)
  2. -c 1000 = number of packets to send
  3. -d 120 = size of each packet to target machine
  4. -S = send SYN only (SYN attack)
  5. -w 64 = TCP window size
  6. -p 80 = port 80 (http)
  7. –flood = send packets as fast as possible without taking care about the replies

Monitor the connections on router device (see that all are marked as incomplete):

cisco_7200#sh tcp intercept connections 
Incomplete:
Client                Server                State    Create   Timeout  Mode
3.3.3.2:47922         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47923         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47920         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47921         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47926         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47927         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47924         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47925         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47930         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47931         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
3.3.3.2:47928         1.1.1.2:8080          SYNRCVD  00:00:00 00:00:00 I
[...]

*Oct 29 02:29:33.847: %TCP-6-INTERCEPT: getting aggressive, count (1100/1100) 1 min 0

See that each conn has SYNRCVD state, because a SYN-ACK was sent by the router and the mode is I (intercept).

Note that this will drop any other connection request sent to server (in our case, there were generated ~500k in few secs, but only 1100 left for analysis). This can be seen here:

cisco_7200#sh tcp intercept statistics 
Intercepting new connections using access-list TCP_INTERCEPT
1100 incomplete, 0 established connections (total 1100)

After 1 minute, the connections will drop until low value and the rest are retransmitted to client with SYN+ACK until timeout (due to aggresive mode, the value is reduced by half):

cisco_7200#
*Oct 29 02:30:54.195: %TCP-6-INTERCEPT: calming down, count (0/900) 1 min 0

t2. CBAC

Before continuing with CBAC, make sure to delete old tcp intercept configuration:

cisco_7200(config)#no ip tcp intercept list
cisco_7200(config)#no ip tcp intercept max-incomplete  high
cisco_7200(config)#no ip tcp intercept max-incomplete  low 

CBAC stands for Context-Based Access Control and represents a feature of Cisco products that is used for verifying protocol of application layer and dynamic modification of firewall rules that are based on it.

Using this feature, the number of connections opened by outside machines can be limited (to stop a DoS attack). This task proposes to create a CBAC rule that is used for monitoring TCP connections and added on outbound interface to UbuntuVM (traffic to that machine).

It provides 4 main functions:

- filtering traffic: TCP, UDP, ICMP connections. As seen on lab 1, ACLs can filter only at layers 3 and 4 and reflexive ones (RACL) at layer 5. CBAC can also inspect at application level.

- inspecting traffic: CBAC maintains its stateful firewall by looking at layer 7. It can also prevent SYN flood attacks by shutting connections down after a specific threshold is reached.

- detecting intrusions: DoS protection, limit phishing attacks.

- generate alerts and audits: it can generate real-time alerts and detect attacks. Logs can later be inspected

CBAC configuration steps:

Part 1: find which interface is external for router. In our case this is e1/0.

Part 2 [optional for us]: Before the traffic gets inspected by CBAC, the traffic must be permitted by ACLs. In our case, there are no ACLs added to simplify the usage.

Try now to access the webserver from client1 and kali. It should work.

Part 3: global timeout values for tcp, udp, icmp can also be changed (like synwait-time, finwait-time, idle-time etc.). Another value that can be changed is the maximum number of incomplete connections:

cisco_7200(config)#ip inspect tcp max-incomplete host 4 block-time 1

There is a bug on this IOS version - for a host VAL < 4, the blocked packets is VAL + 1.

Part 4: port application mapping (PAM) - used to determine which type of inspection to perform on a connection. Example: for SMTP is 25 and CBAC knows that is email and what kinds of commands are exchanged.

There are multiple default mappings on ios:

cisco_7200#sh ip port-map 
Default mapping:  snmp                 udp port 161                        system defined
Default mapping:  echo                 tcp port 7                          system defined
[...]

You can also create nonstandard ones, like 8080 in our case or a host-specific one (for example: there are 2 machines listening on port 4444, but I want only the first one to be inspected).

We can create here for 1.1.1.2:8080 - this will do http inspection:

cisco_7200(config)#ip port-map http port 8080 list 1
cisco_7200(config)#access-list 1 permit 1.1.1.2

Part 5: create the inspection rules to filter the connections that are added to state table and what returning traffic is allowed back to client. If no rules are added, then all traffic is treated as usual.

We will use here inspection of http - mostly used when nonstandard ports are used (like us , 8080) or filter urls: Create firstly an inspect rule for tcp and apply it to an interface.

CISCO_7200(config)#ip inspect name INSPECT_TCP tcp alert on

Part 6: activate the rule on an interface

CISCO_7200(config)#int e1/0
CISCO_7200(config-if)#ip inspect INSPECT_TCP out

Part 7: troubleshooting From client1, ssh the server and see the sessions:

cisco_7200#sh ip inspect sessions 
Established Sessions
 Session 66180AB0 (2.2.2.2:39808)=>(1.1.1.2:22) tcp SIS_OPEN

If you want to learn more about CBAC, I recommend you this documentation.

t3. ZBF

A big drawback of the solution presented above is that it can become very complex when there is need to manage multiple interfaces. Also, it does not offer rules per host or network, all being bound to inbound or outbound traffic. Zone based firewall (or ZBF) is the next proposed security solution.

The model of ZBF is as following:

  • each interface is part of a group, called zone
  • traffic between zones is monitored by the device

ZBF allows the configuration of policies at a granular level, per protocol, host. Each policy can take one of these three actions:

  • DROP action - DENY any traffic from moving between zones
  • PERMIT action - ALLOW traffic to flow in a stateless manner (no monitor)
  • INSPECT action - handle application sessions

The table from below summaries the actions taken by ZBF when monitoring traffic:

The router is not attached to any zone, instead a special self zone is created from traffic to/from device and a policy can be used for filtering it.

The configuration steps are as followed:

  1. create the zones (add also a description in configuration mode for zone)
  2. define the zone-pairs (a pair defined with source and destination zones)
  3. define traffic classes (what type of traffic is of interest and allowed to pass the firewall)
  4. define firewall policies (named policy maps on cisco routers)
  5. assign policy maps to zone pairs
  6. assign router interfaces to zones (this can be done also after the second step)

In the setup presented above, we will consider:

  • client1 is in LAN zone
  • server is in DMZ zone
  • kali is in VISITOR zone

Before going through exercises 3 and 4 (from this tutorial, not your own tasks), remove all CBAC config using:

cisco_7200(config)#no ip inspect

A. Create zones on firewall:

cisco_7200(config)#zone security LAN
cisco_7200(config-sec-zone)#description Local Area Network - client1
cisco_7200(config-sec-zone)#exit
cisco_7200(config)#zone security DMZ
cisco_7200(config-sec-zone)#description local Servers
cisco_7200(config-sec-zone)#exit
cisco_7200(config)#zone security VISITOR
cisco_7200(config-sec-zone)#description Visitor area - kali
cisco_7200(config-sec-zone)#exit

B. Add the pairs between zones:

cisco_7200(config)#zone-pair security LAN-TO-VISITOR source LAN destination VISITOR 
cisco_7200(config-sec-zone-pair)#exit
cisco_7200(config)#zone-pair security LAN-TO-DMZ source LAN destination DMZ
cisco_7200(config-sec-zone-pair)#exit
cisco_7200(config)#zone-pair security VISITOR-TO-DMZ source VISITOR destination DMZ
cisco_7200(config-sec-zone-pair)#exit

C. Go directly to step 6 and configure interfaces to each zones:

cisco_7200(config)#int e1/0
cisco_7200(config-if)#zone-member security DMZ
cisco_7200(config)#int e1/1
cisco_7200(config-if)#zone-member security  LAN
cisco_7200(config-if)#int e1/2
cisco_7200(config-if)#zone-member security VISITOR

This will apply to zone-pairs defined above the default policy rule and all traffic is denied (like a firewall - deny all by def):

eve@client1:~/Desktop$ ping -c 3 1.1.1.2
PING 1.1.1.2 (1.1.1.2) 56(84) bytes of data.
^C
--- 1.1.1.2 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2051ms

# same for kali client

D. Define what type of traffic is of interest and should be allowed to pass the firewall. In our case, we would like to let our VISITOR members to send icmp-echo req to DMZ.

cisco_7200(config)#class-map type inspect match-any ICMP-CMAP
cisco_7200(config-cmap)#match protocol icmp

The class map from above is going to match any protocols defined within it OR match all of them. You can force some source IP addresses to match by using an ACL.

E. Define firewall policies: add to policy map the class map defined on point D)

cisco_7200(config)#policy-map type inspect VISITOR-TO-DMZ-PMAP
cisco_7200(config-pmap)#class ICMP-CMAP
cisco_7200(config-pmap-c)#inspect

F. Add to VISITOR-TO-DMZ zone-pair the policy map:

cisco_7200(config)#zone-pair security VISITOR-TO-DMZ 
cisco_7200(config-sec-zone-pair)#service-policy type inspect VISITOR-TO-DMZ-PMAP

After sending successfully 2 icmp-echo-requests from kali to server (from VISITOR to DMZ) - the traffic is allowed, the policy using is as follows:

cisco_7200#show policy-map type inspect zone-pair
 Zone-pair: VISITOR-TO-DMZ

  Service-policy inspect : VISITOR-TO-DMZ-PMAP

    Class-map: ICMP-CMAP (match-any)
      Match: protocol icmp
        1 packets, 64 bytes
        30 second rate 0 bps
      Inspect
        Packet inspection statistics [process switch:fast switch]
        icmp packets: [0:4]

        Session creations since subsystem startup or last reset 1
        Current session counts (estab/half-open/terminating) [0:0:0]
        Maxever session counts (estab/half-open/terminating) [0:1:0]
        Last session created 00:00:12
        Last statistic reset never
        Last session creation rate 1
        Maxever session creation rate 1
        Last half-open session total 0

    Class-map: class-default (match-any)
      Match: any 
      Drop (default action)
        0 packets, 0 bytes

See the match for protocol icmp (incremented with 1).

Try to send a GET request to server. Does it work?

t4. Extra ZBF

To allow access to DMZ for http (web servers) for VISITOR and LAN zones, there is need to create a class-map for matching only HTTP traffic and a policy-map to allow data inspection.

Class map:

cisco_7200(config)#class-map type inspect HTTP-ONLY-CMAP
cisco_7200(config-cmap)#match protocol http

Policy map:

cisco_7200(config)#policy-map type inspect HTTP-ONLY-PMAP
cisco_7200(config-pmap)#class HTTP-ONLY-CMAP
cisco_7200(config-pmap-c)#inspect 

Add policy-map to zone-pairs LAN-TO-DMZ and VISITOR-TO-DMZ:

cisco_7200(config)#zone-pair security LAN-TO-DMZ
cisco_7200(config-sec-zone-pair)#service-policy type inspect HTTP-ONLY-PMAP
cisco_7200(config-sec-zone-pair)#exit
cisco_7200(config)#zone-pair security VISITOR-TO-DMZ  
cisco_7200(config-sec-zone-pair)#service-policy type inspect HTTP-ONLY-PMAP

This allows kali (supposed for now to be a good person) and client1 to access HTTP service from DMZ zone on port 8080:

cisco_7200#show policy-map type inspect zone-pair  VISITOR-TO-DMZ
 Zone-pair: VISITOR-TO-DMZ

  Service-policy inspect : HTTP-ONLY-PMAP

    Class-map: HTTP-ONLY-CMAP (match-all)
      Match: protocol http
      Inspect
        Packet inspection statistics [process switch:fast switch]
        tcp packets: [0:10]

        Session creations since subsystem startup or last reset 1
        Current session counts (estab/half-open/terminating) [0:0:0]
        Maxever session counts (estab/half-open/terminating) [1:1:1]
        Last session created 00:00:19
        Last statistic reset never
        Last session creation rate 1
        Maxever session creation rate 1
        Last half-open session total 0

    Class-map: class-default (match-any)
      Match: any 
      Drop (default action)
        0 packets, 0 bytes

The port for webserver is a nonstandard one, so the router will not know about it. Make sure to have the PAM from CBAC here.

However, this does not limit the number of tcp sessions opened. Using a session-filter, we can block more than X sessions opened (X=4 in this case, as it was for CBAC):

cisco_7200(config)#parameter-map type inspect TCP-SYN-LIMIT
cisco_7200(config-profile)#tcp max-incomplete host 4 block-time 1

Modify the policy-map to use inspect TCP-SYN-LIMIT:

cisco_7200(config)#policy-map type inspect HTTP-ONLY-PMAP
cisco_7200(config-pmap)#class HTTP-ONLY-CMAP
cisco_7200(config-pmap-c)#inspect TCP-SYN-LIMIT

After this, we can start our DoS attack on KaliVM (now becomes again Trudy):

root@kali:~# hping3 -n -c 10 -w 64 -S -p 8080 1.1.1.2
HPING 1.1.1.2 (eth0 1.1.1.2): S set, 40 headers + 0 data bytes
len=44 ip=1.1.1.2 ttl=63 DF id=0 sport=8080 flags=SA seq=0 win=64240 rtt=20.3 ms
len=44 ip=1.1.1.2 ttl=63 DF id=0 sport=8080 flags=SA seq=1 win=64240 rtt=20.0 ms
len=44 ip=1.1.1.2 ttl=63 DF id=0 sport=8080 flags=SA seq=2 win=64240 rtt=19.7 ms
len=44 ip=1.1.1.2 ttl=63 DF id=0 sport=8080 flags=SA seq=3 win=64240 rtt=19.6 ms

--- 1.1.1.2 hping statistic ---
10 packets transmitted, 4 packets received, 60% packet loss
round-trip min/avg/max = 19.6/19.9/20.3 ms

Also, on router we can see some logs generated:

cisco_7200(config-pmap-c)#
*Oct 30 17:26:44.707: %FW-4-HOST_TCP_ALERT_ON: (target:class)-(VISITOR-TO-DMZ:HTTP-ONLY-CMAP):Max tcp half-open connections (4) exceeded for host 1.1.1.2.
*Oct 30 17:26:44.711: %FW-2-BLOCK_HOST: (target:class)-(VISITOR-TO-DMZ:HTTP-ONLY-CMAP):Blocking new TCP connections to host 1.1.1.2 for 1 minute (half-open count 4 exceeded).

Exercies

e1. [2p] Let's sit and watch the attack

For TCP intercept, change the mode to watch, high value for threshold to 100 and low to 10. Keep the list TCP_INTERCEPT.

Generate a new SYN flood attack from the kali machine and analyze the statistics and connections:

- are the threshold values used as configured and what is the state of connections ? [1p]

- capture on kali the RST packets using tcpdump (hint: 'tcp[13] & 4!=0' or 'tcp[tcpflags] == tcp-rst') and on server the SYN packets (hint: use 'tcp[13] & 2!=0'). Are SYN packets seen on server using watch mode ? [1p]

Use this doc for more informations regarding TCP intercept.

e2. [2p] There is still hope

The server opened again port 4444 for chatting. Client1 wants to use it, but the attacker wants to initiate another SYN attack.

Change tcp intercept mode to intercept, keep the same threshold values, add to the same acl (TCP_INTERCEPT) a new entry for tcp port 4444. Then, start it using nc on server:

root@serverhq:/# nc -l 4444

And send tcp requests with SYN flag set from kali:

root@kali:~# hping3 -c 100 -n -S -p 4444 --faster 1.1.1.2 

Open the connection (before all entries expire - in 15 secs) from client1, send some messages and check the connection from router:

cisco_7200#sh tcp intercept connections 
Incomplete:
Client                Server                State    Create   Timeout  Mode
3.3.3.2:1886          1.1.1.2:4444          SYNRCVD  00:00:07 00:00:03 I
[...]
Established:
Client                Server                State    Create   Timeout  Mode
2.2.2.2:39056         1.1.1.2:4444          ESTAB    00:00:04 23:59:55 I

From server, check if it received client1's messages.

e3. [2p] Back to business

As seen above on CBAC - part 3, we can modify also the maximum number of half-open connections for TCP and add a block-time (in minutes). Configure value 5 for host and block-time 1, 2 minutes.

From attacker, start 10 connections:

root@kali:~# hping3 -n -c 10 -w 64 -S -p 8080 1.1.1.2

See how from packet 6, all are dropped and the router generates an alert (Max tcp half-open connections (4) exceeded for host 1.1.1.2.).

Try now to acces from kali browser the website - does it work?

Do the same thing for client1.

Wait until timeout expires. Access again the website from kali and client1.

e4. [2p] Not this time

In the previous exercise, we saw that after the maximum value of half-open connections is reached, the resources can no longer be accessed, even by the valid clients. After cheking some logs, we identified the attacker's ip and interface and decided to block his access.

Remember that at part 4 on CBAC, we create a PAM for port 8080 for http.

We need now to create an urlfilter using:

cisco_7200(config)#ip urlfilter exclusive-domain deny 1.1.1.2
cisco_7200(config)#ip urlfilter allow-mode off

Then create a new inspection rule for http with urlfilter, add it to the required interface and direction (in/out), then generate GET requests from each machine - client1 and kali. You should find:

root@kali:~# curl 1.1.1.2:8080
<html>
<head>
<title>Forbidden</title></head>
<body bgcolor="#ffffff">
<center><h1><font color="#ff0000">HTTP Error 403 - Forbidden</font></h1>
<b>You do not have permission to access the document or program you requested.
</b></center>
</body></html>

eve@client1:~/Desktop$ curl 1.1.1.2:8080
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
[...]

e5. [2p] Extra ZBF

Do task t4 from Extra ZBF.

sred/laborator_2._cbac_and_zbf.txt · Last modified: 2020/11/06 23:08 by horia.stoenescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0