Lab 1. Packet filtering - ACL

Setup

Story

In an imaginary scenario, our company is at the beginning and has few money to invest in infrastructure. We have a HQ with 1 Linux machine serving as the web server and 2 branches represented with 1 client per each one. The routing between them is done using a Cisco router and minimum filtering provided by ACLs.

Lab infra

The topology consists of one Cisco router model 7200 with one networking card module PA-4E and 3 Ubuntu machines which serves as server and clients (client1 and client2).

To simulate this, we are using an eve-ng virtual machine that should be already started for you with both binary image for Cisco router and iso for Ubuntu already added (for more, see the path /opt/unetlab/addons/dynamips).

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 clients 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 Linux machine

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

Topology:

Credentials webui eve-ng: user: admin; password: eve

Enable password router: cisco

Credentials ubuntu machines: user: eve; password: eve

Exercises using ACLs

1. Standard ACL - basic filtering:

We have the following scenario: suppose I have on the client1 2 interfaces linked to the router (we will use a subinterface here) and I want only from the first one to ping the server and client2:

root@client1:/home/eve/Desktop# ip a a 2.2.2.3/24 dev eth0:0
root@client1:/home/eve/Desktop# ip a s dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:50:00:00:03:00 brd ff:ff:ff:ff:ff:ff
    inet 2.2.2.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet 2.2.2.3/24 scope global secondary eth0
       valid_lft forever preferred_lft forever

Check that ping from both client1 works from both interfaces (use -I flag).

root@client1:/home/eve/Desktop# ping -c 1 -I 2.2.2.3 1.1.1.2
PING 1.1.1.2 (1.1.1.2) from 2.2.2.3 : 56(84) bytes of data.
64 bytes from 1.1.1.2: icmp_seq=1 ttl=63 time=11.0 ms
[...]

Add on the router the first ACL (stanard - called 1) that will permit only the first ip address:

cisco_7200(config)#ip access-list standard 1   
cisco_7200(config-std-nacl)#permit host 2.2.2.2
cisco_7200(config-std-nacl)#deny any
cisco_7200(config-std-nacl)#exit
cisco_7200(config)#int e1/1
cisco_7200(config-if)#ip access-group 1 in

Check again from client1 and see how for the second ip 2.2.2.3, the router responds with an icmp packet with code 13 (packet filtered):

root@client1:/home/eve/Desktop# ping -c 1 -I 2.2.2.2 1.1.1.2
PING 1.1.1.2 (1.1.1.2) from 2.2.2.2 : 56(84) bytes of data.
64 bytes from 1.1.1.2: icmp_seq=1 ttl=63 time=11.6 ms

--- 1.1.1.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 11.659/11.659/11.659/0.000 ms
root@client1:/home/eve/Desktop# ping -c 1 -I 2.2.2.3 1.1.1.2
PING 1.1.1.2 (1.1.1.2) from 2.2.2.3 : 56(84) bytes of data.
From 2.2.2.1 icmp_seq=1 Packet filtered

--- 1.1.1.2 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

You can also use tcpdump with verbosity on:

eve@client1:~/Desktop$ sudo tcpdump -i eth0 -vv src 2.2.2.1
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
15:52:33.644250 IP (tos 0x0, ttl 255, id 105, offset 0, flags [none], proto ICMP (1), length 56)
    2.2.2.1 > client1: ICMP host 1.1.1.2 unreachable - admin prohibited filter, length 36
	IP (tos 0x0, ttl 63, id 19367, offset 0, flags [DF], proto ICMP (1), length 84)

2. Filter traffic from client2:

Remove the old ACL (1) from interface e1/1 (the acl can be kept and make sure not to reuse the name):

cisco_7200(config-if)#exit 
cisco_7200(config)#int e1/1
cisco_7200(config-if)#no ip access-group 1 in

The server machine has a web server (listens on port 8080) with some CCNs and romanian SSNs (CNP) - note that they are all fake.

Module SimpleHTTPServer is used for simulating a web server with files to be accessed. The server is already running as in .bashrc there is created a new screen with this server:

pushd /home/eve/important_data; screen -d -m python -m SimpleHTTPServer 8080; popd

Try firstly locally to send a GET request to localserver:

eve@server:~$ sudo netstat -atupn | grep 8080
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      2071/python         
eve@server:~$ curl localhost:8080
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ul>
<li><a href="CCN">CCN</a>
<li><a href="CNP">CNP</a>
</ul>
<hr>
</body>
</html>

If the server is not up, create a new terminal and start it using the command from above (in .bashrc).

This second scenario is based on client2 old behavior. During some period of time, we saw that he is not behaving as expected (he is constantly accessing hacking websites and learning how to create fake identities) and as we do not have currently a firewall in our network, we will use again ACLs to stop him from accessing our important data from HQ.

To simulate another service (like a chat), we will use nc on server.

From another terminal, start the nc process listening on port 4444.

eve@server:~$ nc -l 4444 

[...]

On this taks, you need write a new ACL (extended with value 101) with the following requirements: - deny traffic from client2 (with ip: 3.3.3.2) to server (with ip: 1.1.1.2) on port 8080

- deny traffic from client2 to server on port 4444

- allow any other type of traffic

Apply this to the client2 network and try to access from browser or cli the webserver and also to connect to chat:

root@client2:/home/eve/Desktop# nc 1.1.1.2 4444 # see how no response is seen here
root@client2:/home/eve/Desktop# wget 1.1.1.2:8080
--2020-10-22 17:26:22--  http://1.1.1.2:8080/
Connecting to 1.1.1.2:8080... failed: No route to host.

Try also from the client1 side to be sure it still working:

root@client1:~# nc 1.1.1.2 4444
test
test2
^C
# and on the server side
eve@server:~$ nc -l 4444 
test
test2
[...]
root@client1:~# curl -I 1.1.1.2:8080
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/2.7.17
[...]

3. Filter based on QoS information on the IP header:

Another field that can be matched in an IP header is the QoS information. If you want to match traffic with TOS value = 2, use the following commands:

cisco_7200(config)#ip access-list extended 102
cisco_7200(config-ext-nacl)#permit ip any any tos 2
cisco_7200(config-ext-nacl)#deny ip any any

Add extended ACL 102 to outbound direction on intf e1/0.

cisco_7200(config)#int e1/0
cisco_7200(config-if)#ip access-group 102 out

Try to send an icmp-echo request to server.

See that without adding the TOS value to ping command, the packets are filtered. Let’s try again with -Q flag added (try to look over ping manual also):

root@client2:/home/eve/Desktop# ping 1.1.1.2
PING 1.1.1.2 (1.1.1.2) 56(84) bytes of data.
From 3.3.3.1 icmp_seq=1 Packet filtered
From 3.3.3.1 icmp_seq=2 Packet filtered
[...]
root@client2:/home/eve/Desktop# ping 1.1.1.2 -Q 4
PING 1.1.1.2 (1.1.1.2) 56(84) bytes of data.
64 bytes from 1.1.1.2: icmp_seq=1 ttl=63 time=16.6 ms
64 bytes from 1.1.1.2: icmp_seq=2 ttl=63 time=14.4 ms
# check the same on client1

4. Standard and extended access lists:

On Cisco routers, the standard ACLs are numbered from 1 to 99 and the extended ones from 100 to 199. These numbers represent an older notation (yes, there are also used in the previous exercises) and there is recommended to switch to named ones where they can be explicitly defined as standard or extended. For easier debugging, there is also recommended to use only capitalized letters.

For an ACL we can see how many times a rule was matched from privileged exec mode (for example, this can be used for collecting information about the behavior of users in a company):

cisco_7200(config-if)#do sh ip access-lists 102
Extended IP access list 102
    10 permit ip any any tos max-reliability (4 matches)
    20 deny ip any any (10 matches)

Another thing to note here are the line numbers - 10 and 20 in 102 ACL - (can be seen as priority values - the lowest value has the bigger priority) which are not incremented by default by one and instead there exists a gap for inserting new lines between them. In the case from above let’s say I want to introduce before ‘deny ip any any’ a new rule for permitting the source ip address 2.2.2.3:

cisco_7200(config)#ip access-list extended 102
cisco_7200(config-ext-nacl)#15 permit ip host 2.2.2.3 any

root@client1:~# ping -I 2.2.2.3 1.1.1.2
PING 1.1.1.2 (1.1.1.2) from 2.2.2.3 : 56(84) bytes of data.
64 bytes from 1.1.1.2: icmp_seq=1 ttl=63 time=16.0 ms
64 bytes from 1.1.1.2: icmp_seq=2 ttl=63 time=12.9 ms
[...]

cisco_7200(config)#do sh ip access 102
Extended IP access list 102
    10 permit ip any any tos max-reliability (4 matches)
    15 permit ip host 2.2.2.3 any (2 matches)
    20 deny ip any any (10 matches)
# see above the 2 matches from those 2 icmp-requests

Both standard and extended ACLs filter traffic based on static entries from layer 3 headers (IPs, QoS etc.) and layer 4 (TCP SYN flag, TCP MPTCP option etc.). However, this type of filtering is not very reliable as this information can be bypassed by an attacker by simply modifying the packets. One such example is scapy (a python library) which can be used to forge different packets and test the capabilities of firewalls.

5. Reflexive ACLs: Used for inspecting and monitor session data. An entry in the ACL can be used to reflect the traffic and create a second ACL, called reflexive IP access list. They are used to allow traffic based on them. Note that entries in them have a timeout value and are removed after it expires (dynamic entries in ACL).

Router config for inspecting icmp traffic:

cisco_7200(config)#ip access-list extended ONLY_CLIENT1
cisco_7200(config-ext-nacl)#10 permit icmp host 2.2.2.2 any reflect ICMP_OUT_CLIENT
cisco_7200(config-ext-nacl)#exit
cisco_7200(config)#ip access-list extended TO_CLIENT_LAN
cisco_7200(config-ext-nacl)#10 evaluate ICMP_OUT_CLIENT
cisco_7200(config-ext-nacl)#int e1/1
cisco_7200(config-if)#ip access-group ONLY_CLIENT1 in
cisco_7200(config-if)#ip access-group TO_CLIENT_LAN out

Send some icmp echo-requests from client1, new entries are created for ICMP_OUT_CLIENT:

cisco_7200(config-if)#do sh ip access ICMP_OUT_CLIENT
Reflexive IP access list ICMP_OUT_CLIENT

# from client1
root@client1:~# ping -c 3 1.1.1.2
PING 1.1.1.2 (1.1.1.2) 56(84) bytes of data.
64 bytes from 1.1.1.2: icmp_seq=1 ttl=63 time=43.7 ms
64 bytes from 1.1.1.2: icmp_seq=2 ttl=63 time=20.6 ms
64 bytes from 1.1.1.2: icmp_seq=3 ttl=63 time=16.4 ms
[...]

# check dynamic acl created
cisco_7200(config-if)#do sh ip access ICMP_OUT_CLIENT
Reflexive IP access list ICMP_OUT_CLIENT
     permit icmp host 1.1.1.2 host 2.2.2.2  (29 matches) (time left 247)

Exercise: do the same thing for HTTP traffic on port 8080. Permit traffic again from 2.2.2.2 to any (or 1.1.1.2) with reflect to a new ACL name. Send the GET request and check quickly the entries in the dynamic acl as it will last for few secs (due to finished session client-server).

Do not forget to remove the ACLs from inbound and outbound directions.

6. Temporary access control:

a. using time-range: Standard, extended and reflexive ACLs can be configured to activate at a specific time using time-range command in config mode. In the following example, the HTTP traffic is only allowed on weekdays between 12:00 and 20:00 (for example, in a company with 8 working hours with that period of time).

cisco_7200#sh clock
*19:17:25.555 UTC Thu Oct 15 2020
cisco_7200#conf t
cisco_7200(config)#time-range PERIODIC
cisco_7200(config-time-range)#periodic weekdays 12:00 to 20:00
cisco_7200(config-time-range)#exit
cisco_7200(config)#do sh time-range PERIODIC
time-range entry: PERIODIC (active)
   periodic weekdays 12:00 to 20:00

(yes, the times may not be set fully correct in our case, but for the sake of our example, it does not matter)

Rewrite the ACL ONLY_CLIENT (from above) to include time-range PERIODIC:

# see that the reflexive ACL is null
cisco_7200(config)#do sh ip access ICMP_OUT_CLIENT
Reflexive IP access list ICMP_OUT_CLIENT
cisco_7200(config)#ip access-list extended ONLY_CLIENT1
cisco_7200(config-ext-nacl)#no 10
cisco_7200(config-ext-nacl)#10 permit icmp host 2.2.2.2 any time-range PERIODIC reflect ICMP_OUT_CLIENT
cisco_7200(config-ext-nacl)#do sh ip access ONLY_CLIENT1
Extended IP access list ONLY_CLIENT1
    10 permit icmp host 2.2.2.2 any time-range PERIODIC (active) reflect ICMP_OUT_CLIENT # see the active between ()
    
# apply again ONLY_CLIENT1 to in and ICMP_OUT_CLIENT to out on e1/1

Send some ping from client1:

root@client1:~# ping 1.1.1.2
PING 1.1.1.2 (1.1.1.2) 56(84) bytes of data.
64 bytes from 1.1.1.2: icmp_seq=1 ttl=63 time=12.0 ms
64 bytes from 1.1.1.2: icmp_seq=2 ttl=63 time=19.2 ms
[...]
# check the reflexive acl on the router
cisco_7200(config-if)#do sh ip access ICMP_OUT_CLIENT
Reflexive IP access list ICMP_OUT_CLIENT
     permit icmp host 1.1.1.2 host 2.2.2.2  (7 matches) (time left 299)

Exercise: add another time-range (router time should be out of it - like 'outside working hours'), remove entry 10 and create a new one for ping to 1.1.1.2. Keep in mind the match number (7 above) before removing the old entry. Send again icmp-requests from client1, traffic should be filtered and also the match value should remain the same and after the timeout, the dynamic acl ICMP_OUT_CLIENT entry will disappear completely.

b. using lock-and-key: The second method consists in creating a temporary ACL using lock-and-key feature from Cisco, which is also known as dynamic ACL. It is activated automatically only when the user is authenticated. The next example is using telnet on router.

cisco_7200(config)#username student password student
cisco_7200(config)#line vty 0
cisco_7200(config-line)#login local
cisco_7200(config-line)#autocommand access-enable host timeout 1

This will create the credentials student:student (used for local login), add them for logging to vty 0 and add a command that is executed automatically: enable the access for the host that is authenticated (the ip of it is retained).

Next, create an inbound ACL for permitting ICMP and telnet connections.

cisco_7200(config)#ip access-list extended HOST_ONLY
cisco_7200(config-ext-nacl)#10 dynamic HOST_ICMP permit icmp any any
cisco_7200(config-ext-nacl)#15 permit tcp any any eq telnet
cisco_7200(config-ext-nacl)#20 deny ip any any

Create also the outbound one.

cisco_7200(config)#ip access-list extended TO_LOCAL_LAN
cisco_7200(config-ext-nacl)#10 dynamic HOST_ICMP_IN permit icmp any any
cisco_7200(config-ext-nacl)#20 deny ip any any

Add the ACLs to interface e1/1:

cisco_7200(config)#int e1/1
cisco_7200(config-if)#ip access-group HOST_ONLY in
cisco_7200(config-if)#ip access-group TO_LOCAL_LAN out

In the end try to ping (will fail firstly), connect and ping again.

root@client1:~# ping -c 3 1.1.1.2
PING 1.1.1.2 (1.1.1.2) 56(84) bytes of data.
From 2.2.2.1 icmp_seq=1 Packet filtered
From 2.2.2.1 icmp_seq=2 Packet filtered
From 2.2.2.1 icmp_seq=3 Packet filtered
[...]
root@client1:~# telnet 2.2.2.1
Trying 2.2.2.1...
Connected to 2.2.2.1.
Escape character is '^]'.


User Access Verification

Username: student
Password: Connection closed by foreign host.
root@client1:~# ping -c 3 1.1.1.2
PING 1.1.1.2 (1.1.1.2) 56(84) bytes of data.
64 bytes from 1.1.1.2: icmp_seq=1 ttl=63 time=19.2 ms
64 bytes from 1.1.1.2: icmp_seq=2 ttl=63 time=16.0 ms
64 bytes from 1.1.1.2: icmp_seq=3 ttl=63 time=13.1 ms
[...]

# on router
Extended IP access list HOST_ONLY
    10 Dynamic HOST_ICMP permit icmp any any
       permit icmp host 2.2.2.2 any (3 matches) (time left 40)
    15 permit tcp any any eq telnet (93 matches)
    20 deny ip any any (12 matches)
# see how the denies before auth to router

# also, the return traffic is let now as user is auth
Extended IP access list TO_LOCAL_LAN
    10 Dynamic HOST_ICMP_IN permit icmp any any
       permit icmp any host 2.2.2.2 (3 matches) (time left 39)
sred/laborator_1._acl.txt · Last modified: 2020/10/27 21:31 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