To perform audit tasks, you sometimes need to find all access rules for a certain server, for example, with the IP address A.B.C.D. 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 certain server, you need to find the corresponding rule and add the new client to this group.
There are commercial products for solving such tasks, such as Algosec, Tufin, etc. However, several Python scripts can perform these tasks no less effectively. Below, I will show examples of such Python programs.
Let me remind you that Python is pre-installed in any version of Linux and is available for free.
I have divided the process into several simple steps:
1. Converting access lists and network objects to a CSV file.
2. Finding 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 list to 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
# Copyright (c) 2023-2024 T.Temirgaliyev The MIT License
# usage " python asa_ip_check.py fw_name src_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
# Copyright (c) 2023-2024 T.Temirgaliyev The MIT License
# 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)