Only the first open port in the <ports> </ports> tag is listed in the CSV output file; no other open ports are listed. The output is printed to the csv file but only the first line in the ports tag is output to the csv file. You can try by run the nmap command "nmap -sV -Pn -oX Output_3.xml scanme.nmap.org"
`import xml.etree.ElementTree as ET
import csv
def main():
in_xml_port = 'Output_1.xml'
xml_tree_port = ET.parse(in_xml_port)
xml_root_port = xml_tree_port.getroot()
# To save the output to csv file
with open('detected_hosts.csv', 'w', newline='') as file:
writer = csv.writer(file)
writer.writerow(['IP', 'Hostname', 'Status', 'Port', 'Service', 'Protocol', 'Product'])
for host in xml_root_port.findall('host'):
# finding all the necessary details from the xml tags
master_ip = host.find('address').get('addr')
master_hostnames = host.findall('hostnames')
master_hostname = master_hostnames[0].findall('hostname')[0].attrib['name']
port_status = host.findall('ports')
port_status_1 = port_status[0].findall('port')
port_state = port_status_1[0].findall('state')[0].attrib['state']
port_element = host.findall('ports')
port_id = port_element[0].findall('port')[0].attrib['portid']
open_service = host.findall('ports')
open_service_1 = open_service[0].findall('port')
service_name = open_service_1[0].findall('service')[0].attrib['name']
potocol_element = host.findall('ports')
port_protocol = potocol_element[0].findall('port')[0].attrib['protocol']
product_element = host.findall('ports')
product_element_1 = product_element[0].findall('port')
product_name = product_element_1[0].findall('service')[0].attrib['product']
if port_state == 'open':
host_status = 'open'
writer.writerow([master_ip, master_hostname, port_state, port_id, service_name, port_protocol, product_name])
if __name__ == '__main__':
main()`
The issue is that when searching for 'ports'
, the code only gets the first response. For instance, these two lines:
port_status_1 = port_status[0].findall('port')
port_state = port_status_1[0].findall('state')[0].attrib['state']
port_status_1
is a list of ports, yet when querying for port_state
, the code restricts itself to only the first port port_status_1[0]
. Hence, in the generated CSV file, only the info of the first open port is recorded.
Give the following script a try. The main logic is not changed, except that it uses a loop to get all 'port'
from all 'ports'
. In addition, it uses find()
and get()
to simplify the querying of an attribute.
import xml.etree.ElementTree as ET
import csv
def main():
in_xml_port = 'Output_1.xml'
xml_tree_port = ET.parse(in_xml_port)
xml_root_port = xml_tree_port.getroot()
# To save the output to csv file
with open('detected_hosts.csv', 'w', newline='') as file:
writer = csv.writer(file)
writer.writerow(['IP', 'Hostname', 'Status', 'Port', 'Service', 'Protocol', 'Product'])
for host in xml_root_port.findall('host'):
# finding all the necessary details from the xml tags
master_ip = host.find('address').get('addr')
master_hostnames = host.findall('hostnames')
master_hostname = master_hostnames[0].findall('hostname')[0].attrib['name']
for ports in host.findall('ports'):
for port in ports.findall('port'):
port_state = port.find('state').get('state')
port_id = port.get('portid')
service_name = port.find('service').get('name')
port_protocol = port.get('protocol')
product_name = port.find('service').get('product')
if port_state == 'open':
writer.writerow([master_ip, master_hostname, port_state, port_id, service_name, port_protocol, product_name])
if __name__ == '__main__':
main()