Skip to content

Instantly share code, notes, and snippets.

@itsecworks
Created October 9, 2023 09:27
Show Gist options
  • Save itsecworks/400697f586532b84ba34f7b03ffdbc47 to your computer and use it in GitHub Desktop.
Save itsecworks/400697f586532b84ba34f7b03ffdbc47 to your computer and use it in GitHub Desktop.
Palo Alto Panorama - Object Auditing scripts
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Author: Ist wurst...
#
# Description:
# -------------
# This script finds the reverse duplicates like:
# /-h_9.9.9.9
#IP:9.9.9.9\32 =
# \-h_quadnine
#
# people tend to recreate objects that exists already with a new name...
#
import xml.etree.ElementTree as ET
xml_input = 'C:/Users/joe/Downloads/Panorama_20230926/panorama.xml'
file_output = 'C:/Users/joe/Downloads/objlist_exact_duplicates_by_content.txt'
tree = ET.parse(xml_input)
root = tree.getroot()
dict = {}
for node_addr in root.findall("./shared/address/entry"):
dg_name = "shared"
for node in node_addr:
if node.tag in ["ip-netmask", "fqdn", "ip-range"]:
if dg_name not in dict:
dict[dg_name] = {}
if node.text not in dict[dg_name]:
dict[dg_name][node.text] = {}
dict[dg_name][node.text]["type"] = node.tag
dict[dg_name][node.text]["objects"] = [node_addr.attrib["name"]]
else:
dict[dg_name][node.text]["objects"].append(node_addr.attrib["name"])
for node_dg in root.findall("./devices/entry/device-group/entry"):
dg_name = node_dg.attrib["name"]
for dg_node in node_dg:
if (dg_node.tag) == "address":
for node_addr2 in dg_node:
for node2 in node_addr2:
if node2.tag in ["ip-netmask", "fqdn", "ip-range"]:
if dg_name not in dict:
dict[dg_name] = {}
if node2.text not in dict[dg_name]:
dict[dg_name][node2.text] = {}
dict[dg_name][node2.text]["type"] = node2.tag
dict[dg_name][node2.text]["objects"] = [node_addr2.attrib["name"]]
else:
dict[dg_name][node2.text]["objects"].append(node_addr2.attrib["name"])
nuc = 0
uc = 0
dict2 = {}
with open(file_output, 'w') as fp1:
for dg in dict:
for key in dict[dg]:
if len(dict[dg][key]["objects"]) > 1:
for entry in dict[dg][key]["objects"]:
fp1.write(dg + "," + str(key) + "," + dict[dg][key]["type"] + "," + str(entry) + "\n")
nuc += 1
if len(dict[dg][key]["objects"]) not in dict2:
dict2[len(dict[dg][key]["objects"])] = 1
else:
dict2[len(dict[dg][key]["objects"])] += 1
else:
uc += 1
print("unique-nonu-counts," + dg + "," + str(uc) + "," + str(nuc))
for counts in dict2:
print("multiplied," + dg + "," + str(counts) + "," + str(dict2[counts]))
dict2 = {}
nuc = 0
uc = 0
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Author: Ist wurst...
#
# Description:
# -------------
# This script find objects that exist in shared and on device-group level with the same name or content.
# The script delivers:
# exact matches (exclusive tag and description)
# type mismatches (same name but different type)
# value mismatches (same name same type but different value)
# Actually this is not possible, via the GUI you should get an error message, but still such objects can exist somehow...?
#
import xml.etree.ElementTree as ET
xml_input = 'C:/Users/joe/Downloads/Panorama_20230926/panorama.xml'
file_output_ed = 'C:/Users/joe/Downloads/objlist_exact_duplicates.txt'
file_output_dv = 'C:/Users/joe/Downloads/objlist_diff_val.txt'
file_output_dt = 'C:/Users/joe/Downloads/objlist_diff_typ.txt'
tree = ET.parse(xml_input)
root = tree.getroot()
objlist_exact_duplicates = {}
objlist_diff_val = {}
objlist_diff_typ = {}
for node_addr in root.findall("./shared/address/entry"):
shared_addr_name = node_addr.attrib["name"]
for node_dg in root.findall("./devices/entry/device-group/entry"):
dg_name = node_dg.attrib["name"]
if dg_name not in objlist_exact_duplicates:
objlist_exact_duplicates[dg_name] = []
if dg_name not in objlist_diff_val:
objlist_diff_val[dg_name] = []
if dg_name not in objlist_diff_typ:
objlist_diff_typ[dg_name] = []
for dg_node in node_dg:
if (dg_node.tag) == "address":
for node_addr2 in dg_node:
if node_addr2.attrib["name"] == shared_addr_name:
for node in node_addr:
for node2 in node_addr2:
if node2.tag not in ["description","tag"] and node.tag not in ["description","tag"]:
if node.tag == node2.tag and node.text == node2.text:
objlist_exact_duplicates[dg_name].append(shared_addr_name)
elif node.tag == node2.tag and node.text != node2.text:
objlist_diff_val[dg_name].append(shared_addr_name + " - " + str(node2.text) + " - " + str(node.text))
elif node.tag != node2.tag:
objlist_diff_typ[dg_name].append(shared_addr_name + " - " + str(node2.tag) + " - " + str(node.tag))
else:
print("bomb has been planted...")
with open(file_output_ed, 'w') as fp:
for dg_name in objlist_exact_duplicates:
if len(objlist_exact_duplicates[dg_name]) > 0:
print("exact_dupl," + dg_name + "," + str(len(objlist_exact_duplicates[dg_name])))
for item in objlist_exact_duplicates[dg_name]:
fp.write("{0}, {1}\n".format(dg_name, item))
fp.close()
with open(file_output_dv, 'w') as fp:
for dg_name in objlist_diff_val:
if len(objlist_diff_val[dg_name]) > 0:
print("diff_val," + dg_name + "," + str(len(objlist_diff_val[dg_name])))
for item in objlist_diff_val[dg_name]:
fp.write("{0}, {1}\n".format(dg_name, item))
fp.close()
with open(file_output_dt, 'w') as fp:
for dg_name in objlist_diff_typ:
if len(objlist_diff_typ[dg_name]) > 0:
print("diff_typ," + dg_name + "," + str(len(objlist_diff_typ[dg_name])))
for item in objlist_diff_typ[dg_name]:
fp.write("{0}, {1}\n".format(dg_name, item))
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Author: Ist wurst...
#
# Description:
# -------------
# This script find the unused objects with in panorama device-group hierarchy.
#
import xml.etree.ElementTree as ET
xml_input = 'C:/Users/joe/Downloads/Panorama_20230926/panorama.xml'
fileoutput_nu = 'C:/Users/joe/Downloads/objlist_notused.txt'
def getallchild(dg, dict, llist):
if dg not in dict:
return llist
else:
llist += dict[dg]
for ch_dg in dict[dg]:
return getallchild(ch_dg, dict, llist)
tree = ET.parse(xml_input)
root = tree.getroot()
readonly_node = root.find("./readonly")
dg_children = {}
for dg in readonly_node.findall("./devices/entry/device-group/entry"):
dg_name = dg.attrib["name"]
if dg.find("./parent-dg") is not None:
parent_dg_name = dg.find("./parent-dg").text
if parent_dg_name not in dg_children:
dg_children[parent_dg_name] = [dg_name]
else:
dg_children[parent_dg_name].append(dg_name)
with open(fileoutput_nu, 'w') as fp1:
for dg in root.findall("./devices/entry/device-group/entry"):
dg_name = dg.attrib["name"]
mylist = []
dg_allchild_names = getallchild(dg_name, dg_children, mylist)
addresses = dg.find("./address")
post_rulebase = dg.find("./post-rulebase")
pre_rulebase = dg.find("./pre-rulebase")
address_group = dg.find("./address-group")
if addresses is not None:
for addr in addresses:
addr_name = addr.attrib["name"]
if pre_rulebase is None or (len(pre_rulebase) > 0 and str(ET.tostring(pre_rulebase)).find(addr_name) == -1):
if post_rulebase is None or (len(post_rulebase) > 0 and str(ET.tostring(post_rulebase)).find(addr_name) == -1):
if address_group is None or (len(address_group) > 0 and str(ET.tostring(address_group)).find(addr_name) == -1):
notfound = True
if len(dg_allchild_names) > 0:
for child_dg_name in dg_allchild_names:
child_dg = root.find("./devices/entry/device-group/entry[@name='" + child_dg_name + "']")
post_rulebase = child_dg.find("./post-rulebase")
pre_rulebase = child_dg.find("./pre-rulebase")
address_group = dg.find("./address-group")
if pre_rulebase is None or (len(pre_rulebase) > 0 and str(ET.tostring(pre_rulebase)).find(addr_name) == -1):
notfound = False
if post_rulebase is None or (len(post_rulebase) > 0 and str(ET.tostring(post_rulebase)).find(addr_name) == -1):
notfound = False
if address_group is None or (len(address_group) > 0 and str(ET.tostring(address_group)).find(addr_name) == -1):
notfound = False
if notfound is True:
fp1.write("{0}, {1}\n".format(dg_name, addr_name))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment