Cisco ASA, Automate Access List String Search with Python

If you work in a large data center and your task is to support firewalls (Cisco ASA), then you probably encountered a huge number of lines in their configurations. These configurations can include thousands of objects and access rules (Access Lists).

To perform audit tasks, you sometimes need to find all access rules for a specific server, for example, with the IP address ABCD. In other cases, you need to add a new access rule, but before that, you need to make sure that a similar rule already exists. For example, if there is a group of clients connecting to a server, you need to find the corresponding rule and add the new client to this group.

There are commercial products to solve such problems, such as Algosec, Tufin, etc. However, several Python scripts can perform these tasks no less effectively. Below I will show examples of such programs in Python.

Let me remind you that Python is pre-installed in any version of Linux and is available for free.

I have broken the process down into a few simple steps:

  1. Convert access lists and network objects to CSV file.

  2. Find all rules that allow access from address 10.0.3.10 to address 5.5.15.100. To do this, you need to find all subnets containing these IP addresses.

In the Cisco ASA access list, you can specify the source and destination IP addresses, but you can also specify a network object or a group of objects. A group of objects can include other groups of objects. If you run the show access-list command, you will see a decoding of all objects in IP prefixes, which simplifies conversion to a CSV file

ciscoasa# show access-list
access-list gl1 line 1 extended permit tcp object-group og1 object-group og12 eq ssh (hitcnt=0) 0xf57a470f
  access-list gl1 line 1 extended permit tcp 10.0.3.0 255.255.255.0 host 10.0.0.3 eq ssh (hitcnt=0) 0x23c38b59
  access-list gl1 line 1 extended permit tcp 10.0.3.0 255.255.255.0 10.0.0.0 255.255.255.0 eq ssh (hitcnt=0) 0x3bc77b3d
  access-list gl1 line 1 extended permit tcp 10.0.41.0 255.255.255.0 host 10.0.0.3 eq ssh (hitcnt=0) 0xed8dff32
  access-list gl1 line 1 extended permit tcp 10.0.41.0 255.255.255.0 10.0.0.0 255.255.255.0 eq ssh (hitcnt=0) 0xcde224d1
access-list gl1 line 2 extended permit tcp host 10.0.0.3 host 100.100.100.1 eq www (hitcnt=0) 0xf80a10d6
access-list gl1 line 3 extended permit tcp object on1 object on2 eq ssh (hitcnt=0) 0x70f8adb4
  access-list gl1 line 3 extended permit tcp host 10.0.0.3 10.0.0.0 255.255.255.0 eq ssh (hitcnt=0) 0x70f8adb4
access-list gl2 line 1 extended permit tcp object-group og1 object-group og12 eq https (hitcnt=0) 0xd0d468b5
  access-list gl2 line 1 extended permit tcp 10.0.3.0 255.255.255.0 host 10.0.0.3 eq https (hitcnt=0) 0xae19c8fe
  access-list gl2 line 1 extended permit tcp 10.0.3.0 255.255.255.0 10.0.0.0 255.255.255.0 eq https (hitcnt=0) 0x93b63bc0
  access-list gl2 line 1 extended permit tcp 10.0.41.0 255.255.255.0 host 10.0.0.3 eq https (hitcnt=0) 0x07c7a712
  access-list gl2 line 1 extended permit tcp 10.0.41.0 255.255.255.0 10.0.0.0 255.255.255.0 eq https (hitcnt=0) 0xa7ced8a9
access-list gl2 line 2 extended permit ip object-group og1 object-group og12 (hitcnt=0) 0x516db3da
  access-list gl2 line 2 extended permit ip 10.0.3.0 255.255.255.0 host 10.0.0.3 (hitcnt=0) 0x258b842a
  access-list gl2 line 2 extended permit ip 10.0.3.0 255.255.255.0 10.0.0.0 255.255.255.0 (hitcnt=0) 0xd82afa19
  access-list gl2 line 2 extended permit ip 10.0.41.0 255.255.255.0 host 10.0.0.3 (hitcnt=0) 0x3d4864ae
  access-list gl2 line 2 extended permit ip 10.0.41.0 255.255.255.0 10.0.0.0 255.255.255.0 (hitcnt=0) 0xf4e436ba
access-list gl2 line 3 extended permit tcp object on1 object on2 eq 121 (hitcnt=0) 0xac470d2c
  access-list gl2 line 3 extended permit tcp host 10.0.0.3 10.0.0.0 255.255.255.0 eq 121 (hitcnt=0) 0xac470d2c
access-list gl2 line 4 extended permit tcp host 10.0.0.3 10.0.0.0 255.255.255.0 eq ssh (hitcnt=0) 0x5ce66931
access-list gl2 line 5 extended permit tcp object on4_16 object on4_8 eq https (hitcnt=0) 0xd1faa964
  access-list gl2 line 5 extended permit tcp 10.0.0.0 255.255.0.0 10.0.0.0 255.0.0.0 eq https (hitcnt=0) 0xd1faa964
access-list gl2 line 6 extended permit tcp object on4_16 object-group og5 eq https (hitcnt=0) 0x99c5cc7d
  access-list gl2 line 6 extended permit tcp 10.0.0.0 255.255.0.0 host 1.1.1.1 eq https (hitcnt=0) 0xe802825a
  access-list gl2 line 6 extended permit tcp 10.0.0.0 255.255.0.0 host 5.5.5.1 eq https (hitcnt=0) 0x80a1e5b3
  access-list gl2 line 6 extended permit tcp 10.0.0.0 255.255.0.0 5.5.15.0 255.255.255.0 eq https (hitcnt=0) 0x25de07fd

Next, python converts the access sheet into a CSV file:

gl1,1,10.0.3.0,255.255.255.0,10.0.0.3,255.255.255.255,ssh
gl1,1,10.0.3.0,255.255.255.0,10.0.0.0,255.255.255.0,ssh
gl1,1,10.0.41.0,255.255.255.0,10.0.0.3,255.255.255.255,ssh
gl1,1,10.0.41.0,255.255.255.0,10.0.0.0,255.255.255.0,ssh
gl1,2,10.0.0.3,255.255.255.255,100.100.100.1,255.255.255.255,www
gl1,3,10.0.0.3,255.255.255.255,10.0.0.0,255.255.255.0,ssh
gl2,1,10.0.3.0,255.255.255.0,10.0.0.3,255.255.255.255,https
gl2,1,10.0.3.0,255.255.255.0,10.0.0.0,255.255.255.0,https
gl2,1,10.0.41.0,255.255.255.0,10.0.0.3,255.255.255.255,https
gl2,1,10.0.41.0,255.255.255.0,10.0.0.0,255.255.255.0,https
gl2,2,10.0.3.0,255.255.255.0,10.0.0.3,255.255.255.255,ip
gl2,2,10.0.3.0,255.255.255.0,10.0.0.0,255.255.255.0,ip
gl2,2,10.0.41.0,255.255.255.0,10.0.0.3,255.255.255.255,ip
gl2,2,10.0.41.0,255.255.255.0,10.0.0.0,255.255.255.0,ip
gl2,3,10.0.0.3,255.255.255.255,10.0.0.0,255.255.255.0,121
gl2,4,10.0.0.3,255.255.255.255,10.0.0.0,255.255.255.0,ssh
gl2,5,10.0.0.0,255.255.0.0,10.0.0.0,255.0.0.0,https
gl2,6,10.0.0.0,255.255.0.0,1.1.1.1,255.255.255.255,https
gl2,6,10.0.0.0,255.255.0.0,5.5.5.1,255.255.255.255,https
gl2,6,10.0.0.0,255.255.0.0,5.5.15.0,255.255.255.0,https

A regular text search can find the desired IP address, but it is not possible to find all the prefixes that include this IP address. For this purpose, there is a library ipaddress. The following Python script does this search:

#!/usr/bin/python3
#  usage " python asa_ip_check.py fw_name src_ip dst_ip"

import csv
import ipaddress
import sys
from sys import argv

args = sys.argv
csv_file_src = args[1]+'.csv'    # "
ip_src = args[2]                 # 
ip_dst = args[3]
                                 #app = args[4]

with open(csv_file_src, 'r') as file:           # ip_src
    reader = csv.reader(file, delimiter=",")
    for row in reader:
        if (ipaddress.ip_address(ip_src) in ipaddress.ip_network(f"{row[2]}/{row[3]}", strict=False) and ipaddress.ip_address(ip_dst) in ipaddress.ip_network(f"{row[4]}/{row[5]}", strict=False)):
            print ( ip_src ," and ", ip_dst , ' in ', row)

Which line allows access from address 10.0.3.10 to address 5.5.15.100?

E:\asa_rules_test>python asa_ip_check.py asa 10.0.3.10 5.5.15.100
10.0.3.10  and  5.5.15.100  in  ['gl2', '6', '10.0.0.0', '255.255.0.0', '5.5.15.0', '255.255.255.0', 'https']

next python converts the output of the show access-list command to a CSV file


#!/usr/bin/python3
#  usage " python asa_acl_to_csv.py fw_name " it will open configuration file fw_name.conf

import csv
import sys
from sys import argv

args = sys.argv

# Set the input and output file names
input_file = args[1] + '.conf'                           # asa show access-list to file fw_name.conf
output_file = args[1] + '.csv'                           # address-set  to   fw_name.csv"

# Open the input and output files
with open(input_file, "r") as f, open(output_file, "w", newline="") as out_file:
    reader = csv.reader(f, delimiter=" ")
    writer = csv.writer(out_file)

    add_name = None
    for row in reader: 
        aclname=""
        aclline=""
        aclsrc=""
        aclspr=""
        acldst=""
        acldpr=""
        aclapp  = ''
        try:
            if ( not ("object" in row) and not ("object-group" in row) and not ("remark" in row) ):
                if ((row[0] == "access-list") and (row[2] == "line") and (row[5] == "permit") ):
                    aclname = row[1]
                    aclline = row[3]
                    if (row[7] == "host"):
                        aclsrc  = row[8]
                        aclspr="255.255.255.255"
                        if (row[9] == "host"):
                            acldst  = row[10]
                            acldpr="255.255.255.255"
                            aclapp  = row[12]
                        else:
                            acldst  = row[9]
                            acldpr  = row[10]
                            aclapp  = row[12]                            
                    else:
                        aclsrc  = row[7]
                        aclspr  = row[8]
                        if (row[9] == "host"):
                            acldst  = row[10]
                            acldpr="255.255.255.255"
                            aclapp  = row[12]     
                        else:
                            acldst  = row[9]
                            acldpr  = row[10]
                            aclapp  = row[12]
                    if (row[6] == "ip"):
                            aclapp  = row[6]                      
                elif ((row[2] == "access-list") and (row[4] == "line") and (row[7] == "permit") ):
                    aclname = row[3]
                    aclline = row[5]     
                    if (row[9] == "host"):
                        aclsrc  = row[10]
                        aclspr="255.255.255.255"
                        if (row[11] == "host"):
                            acldst  = row[12]
                            acldpr="255.255.255.255"
     
                        else:
                            acldst  = row[11]
                            acldpr  = row[12]
                            aclapp  = row[14]                            
                    else:
                        aclsrc  = row[9]
                        aclspr  = row[10]
                        if (row[11] == "host"):
                            acldst  = row[12]
                            acldpr="255.255.255.255"
                            aclapp  = row[14]     
                        else:
                            acldst  = row[11]
                            acldpr  = row[12]                        
                            aclapp  = row[14]
                    if (row[8] == "ip"):
                            aclapp  = row[8]                                                    
                print(aclname,aclline,aclsrc,aclspr,acldst,acldpr,aclapp)
                writer.writerow([aclname,aclline,aclsrc,aclspr,acldst,acldpr,aclapp]) 
        except:
            print(row)
out_file.close()

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *