├── README.md ├── netscan.py ├── requirements.txt ├── scantastic.py ├── showRange.py ├── urls └── .gitkeep ├── words ├── ASP ├── ASPX ├── HTML ├── PHP └── blank ├── xml └── .gitkeep └── xmltourl.py /README.md: -------------------------------------------------------------------------------- 1 | # scantastic-tool 2 | 3 | ## It's bloody scantastic 4 | 5 | If you like this and are feeling a bit(coin) generous - 1JdSGqg2zGTbpFMJPLbWoXg7Nng3z1Qp58 6 | 7 | It works for me: http://makthepla.net/scantastichax.png 8 | 9 | - Dependencies: (DIY - I ain't supportin shit) 10 | - Masscan - https://github.com/robertdavidgraham/masscan 11 | - Nmap - https://nmap.org/download.html 12 | - ElasticSearch - http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/_installing_elasticsearch.html 13 | - Kibana - http://www.elasticsearch.org/overview/kibana/installation/ 14 | 15 | 16 | This tool can be used to store masscan or nmap data in elasticsearch, 17 | (the scantastic plugin in the image is not here) 18 | 19 | It allows performs distributed directory brute-forcing. 20 | 21 | All your base are belong to us. I might maintain or improve this over time. MIGHT. 22 | 23 | ## Quickstart 24 | 25 | ### Example usage 26 | 27 | Run and import a scan of home /24 network 28 | 29 | ``` 30 | ./scantastic.py -s -H 192.168.1.0/24 -p 80,443 -x homescan.xml (with masscan) 31 | ./scantastic.py -ns -H 192.168.1.0/24 -p 80,443 -x homescan.xml (with nmap) 32 | ``` 33 | 34 | Export homescan to a list of urls 35 | 36 | ``` 37 | ./scantastic.py -eurl -x homescan.xml > urlist (with masscan) 38 | ./scantastic.py -nurl -x homescan.xml > urlist (with nmap) 39 | ``` 40 | 41 | Brute force the url list using wordlist and put results into index homescan 42 | using 10 threads (By default it uses 1 thread) 43 | 44 | ``` 45 | ./scantastic.py -d -u urlist -w some_wordlist -i homescan -t 10 46 | ``` 47 | 48 | ``` 49 | root@ubuntu:~/scantastic-tool# ./scantastic.py -h 50 | usage: scantastic.py [-h] [-v] [-d] [-s] [-noes] [-sl] [-in] [-e] [-eurl] 51 | [-del] [-H HOST] [-p PORTS] [-x XML] [-w WORDS] [-u URLS] 52 | [-t THREADS] [-esh ESHOST] [-esp PORT] [-i INDEX] 53 | [-a AGENT] 54 | 55 | optional arguments: 56 | -h, --help show this help message and exit 57 | -v, --version Version information 58 | -d, --dirb Run directory brute force. Requires --urls & --words 59 | -s, --scan Run masscan on single range. Specify --host & --ports 60 | & --xml 61 | -ns, --nmap Run Nmap on a single range specify -H & -p 62 | -noes, --noelastics Run scan without elasticsearch insertion 63 | -sl, --scanlist Run masscan on a list of ranges. Requires --host & 64 | --ports & --xml 65 | -nsl, --nmaplist Run Nmap on a list of ranges -H & -p & -x 66 | -in, --noinsert Perform a scan without inserting to elasticsearch 67 | -e, --export Export a scan XML into elasticsearch. Requires --xml 68 | -eurl, --exporturl Export urls to scan from XML file. Requires --xml 69 | -nurl, --exportnmap Export urls from nmap XML, requires -x 70 | -del, --delete Specify an index to delete. 71 | -H HOST, --host HOST Scan this host or list of hosts 72 | -p PORTS, --ports PORTS 73 | Specify ports in masscan format. (ie.0-1000 or 74 | 80,443...) 75 | -x XML, --xml XML Specify an XML file to store output in 76 | -w WORDS, --words WORDS 77 | Wordlist to be used with --dirb 78 | -u URLS, --urls URLS List of Urls to be used with --dirb 79 | -t THREADS, --threads THREADS 80 | Specify the number of threads to use. 81 | -esh ESHOST, --eshost ESHOST 82 | Specify the elasticsearch host 83 | -esp PORT, --port PORT 84 | Specify ElasticSearch port 85 | -i INDEX, --index INDEX 86 | Specify the ElasticSearch index 87 | -a AGENT, --agent AGENT 88 | Specify a User Agent for requests 89 | ``` 90 | 91 | Use -noes and -in scans to not import scans by default upon completion of a scan 92 | -------------------------------------------------------------------------------- /netscan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # A class to run masscan and import the results to ES 3 | 4 | import subprocess 5 | import socket 6 | import xmltodict 7 | from elasticsearch import Elasticsearch 8 | from datetime import datetime 9 | 10 | 11 | class Masscan: 12 | # Initialize with range, output, ports 13 | 14 | def __init__(self, ip_r, xml_o, ps): 15 | self.ip_range = ip_r 16 | self.xml_output = xml_o 17 | self.ports = ps 18 | 19 | def run(self): 20 | self.args = ("masscan", "-sS", "-Pn", self.ip_range, 21 | "-oX", self.xml_output, "--rate=15000", "-p", 22 | self.ports, "--open") 23 | popen = subprocess.Popen(self.args, stdout=subprocess.PIPE) 24 | popen.wait() 25 | self.output = popen.stdout.read() 26 | print "Scan completed!" 27 | 28 | def runfile(self): 29 | self.args = ("masscan", "-sS", "-Pn", "-iL", self.ip_range, 30 | "-oX", self.xml_output, "--rate=15000", "-p", self.ports, 31 | "--open") 32 | popen = subprocess.Popen(self.args, stdout=subprocess.PIPE) 33 | popen.wait() 34 | self.output = popen.stdout.read() 35 | print "Scan completed!" 36 | 37 | def import_es(self, es_index, host, port): 38 | es = Elasticsearch([{u'host': host, u'port': port}]) 39 | try: 40 | with open(self.xml_output, "r") as xmlfile: 41 | data = xmlfile.read().replace('\n', '') 42 | xml = xmltodict.parse(data) 43 | nmaprun = xml['nmaprun'] 44 | host = nmaprun['host'] 45 | except: 46 | print "IO Error" 47 | for entry in host: 48 | port = entry['ports']['port'] 49 | try: 50 | name, alias, addrlist = socket.gethostbyaddr(entry['address']['@addr']) 51 | except socket.herror: 52 | name = entry['address']['@addr'] 53 | dataentry = { 54 | 'timestamp': datetime.now(), 55 | 'ip': entry['address']['@addr'], 56 | 'port': port['@portid'], 57 | 'name': name, 58 | 'link': 'http://' + name + '/' 59 | } 60 | result = es.index(index=es_index, doc_type='hax', body=dataentry) 61 | 62 | 63 | class Nmap: 64 | # Initialize with range, output, ports 65 | 66 | def __init__(self, ip_r, xml_o, ps): 67 | self.ip_range = ip_r 68 | self.xml_output = xml_o 69 | self.ports = ps 70 | 71 | def run(self): 72 | self.args = ("nmap", "-sS", "-Pn", self.ip_range, 73 | "-oX", self.xml_output, "-p", self.ports, "--open") 74 | popen = subprocess.Popen(self.args, stdout=subprocess.PIPE) 75 | popen.wait() 76 | self.output = popen.stdout.read() 77 | print "Scan completed!" 78 | 79 | def runfile(self): 80 | self.args = ("nmap", "-sS", "-Pn", "-iL", self.ip_range, 81 | "-oX", self.xml_output, "-p", self.ports, "--open") 82 | popen = subprocess.Popen(self.args, stdout=subprocess.PIPE) 83 | popen.wait() 84 | self.output = popen.stdout.read() 85 | print "Scan completed!" 86 | 87 | def toES(address, ports, es_index, host, port): 88 | es = Elasticsearch([{u'host': host, u'port': port}]) 89 | try: 90 | name, alias, addrlist = socket.gethostbyaddr(address) 91 | 92 | except socket.herror: 93 | name = address 94 | dataentry = { 95 | 'timestamp': datetime.now(), 96 | 'ip': address, 97 | 'port': ports, 98 | 'name': name, 99 | 'link': 'http://' + name + '/' 100 | } 101 | print dataentry 102 | 103 | def import_es(self, es_index, host, port): 104 | try: 105 | with open(self.xml_output, "r") as xmlfile: 106 | data = xmlfile.read().replace('\n', '') 107 | xml = xmltodict.parse(data) 108 | nmaprun = xml['nmaprun'] 109 | scanhost = nmaprun['host'] 110 | for i in scanhost: 111 | address = i['address'][0]['@addr'] 112 | port1 = dict(i) 113 | try: #if one result 114 | if int(port1['ports']['port']['@portid']) > 0: 115 | port2 = port1['ports']['port']['@portid'] 116 | toES(address, str(port2), es_index, host, port) 117 | except: #if multiple 118 | port2 = i['ports']['port']#[0]['@portid'] 119 | for z in port2: 120 | x = z['@portid'] 121 | toES(address, str(x), es_index, host, port) 122 | except IOError, e: 123 | print e 124 | 125 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | elasticsearch==1.3.0 2 | requests==2.20.0 3 | netaddr==0.7.13 4 | xmltodict==0.9.2 5 | numpy==1.9.1 6 | -------------------------------------------------------------------------------- /scantastic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import multiprocessing 4 | import argparse 5 | import sys 6 | import requests 7 | import string 8 | from datetime import datetime 9 | from time import sleep 10 | from elasticsearch import Elasticsearch 11 | from netscan import Masscan 12 | from netscan import Nmap 13 | from xmltourl import Xml2urls 14 | from xmltourl import Xml2urls2 15 | from numpy import array_split 16 | 17 | requests.packages.urllib3.disable_warnings() 18 | 19 | def version_info(): 20 | VERSION_INFO = 'Scantastic v2.0' 21 | AUTHOR_INFO = 'Author: Ciaran McNally - https://makthepla.net' 22 | print ' _ _ _' 23 | print ' ___ ___ ___ ___| |_ ___ ___| |_|_|___' 24 | print '|_ -| _| .\'| | _| .\'|_ -| _| | _|' 25 | print '|___|___|__,|_|_|_| |__,|___|_| |_|___|' 26 | print '=======================================' 27 | print VERSION_INFO 28 | print AUTHOR_INFO 29 | 30 | 31 | # Split the list of urls into chunks for threading 32 | def split_urls(u, t): 33 | print 'Number of URLS: ' + str(len(u)) 34 | print 'Threads: ' + str(t) 35 | print 'URLS in each split: ' + str(len(u) / t) 36 | print '=========================' 37 | sleep(1) 38 | return array_split(u, t) 39 | 40 | 41 | def returnIPaddr(u): 42 | ip = "" 43 | if u.startswith('http://'): 44 | remainhttp = u[7:] 45 | ip = string.split(remainhttp, '/')[0] 46 | if u.startswith('https://'): 47 | remainhttps = u[8:] 48 | ip = string.split(remainhttps, '/')[0] 49 | return ip 50 | 51 | 52 | def returnTitle(content): 53 | t1 = '' 54 | t2 = '' 55 | if '' in content: 56 | t1 = string.split(content, '<title>')[1] 57 | t2 = string.split(t1, '')[0] 58 | return t2 59 | 60 | 61 | # Make requests 62 | def requestor(urls, dirb, host, port, agent, esindex, usees): 63 | data = {} 64 | es = Elasticsearch([{u'host': host, u'port': port}]) 65 | user_agent = {'User-agent': agent} 66 | for url in urls: 67 | urld = url + dirb 68 | try: 69 | r = requests.get(urld, timeout=10, headers=user_agent, verify=False) 70 | stat = r.status_code 71 | time = datetime.utcnow() 72 | cont_len = len(r.content) 73 | title = returnTitle(r.content) 74 | if len(r.content) >= 500: 75 | content = r.content[0:500] 76 | else: 77 | content = r.content 78 | ip = returnIPaddr(url) 79 | if 'image' in r.headers['content-type']: 80 | content = 'image' 81 | if r.status_code == 200: 82 | print urld + ' - ' + str(r.status_code) + ':' + str(len(r.content)) 83 | except requests.exceptions.Timeout: 84 | # print urld+' - Timeout' 85 | stat = -1 86 | except requests.exceptions.ConnectionError: 87 | # print url+dirb+' - Connection Error!' 88 | stat = -2 89 | except requests.exceptions.TooManyRedirects: 90 | # print urld+' - Too many redirects!' 91 | stat = -3 92 | except: 93 | stat = 0 94 | 95 | if stat > 0: 96 | data = { 97 | 'timestamp': time, 98 | 'ip': ip, 99 | 'status': stat, 100 | 'content-length': cont_len, 101 | 'content': content, 102 | 'title': title, 103 | 'link': url + dirb, 104 | 'directory': dirb 105 | } 106 | try: 107 | if data['status'] == 200: 108 | if usees == False: 109 | result = es.index(index=esindex, doc_type='hax', 110 | body=data) 111 | else: 112 | pass 113 | else: 114 | pass 115 | except: 116 | data['title'] = 'Unicode Error' 117 | data['content'] = 'Unicode Error' 118 | if data['status'] == 200: 119 | if usees == False: 120 | result = es.index(index=esindex, doc_type='hax', 121 | body=data) 122 | else: 123 | pass 124 | else: 125 | pass 126 | 127 | 128 | # Run regular masscan on specified range 129 | def scan(host, ports, xml, index, eshost, esport, noin): 130 | ms = Masscan(host, 'xml/' + xml, ports) 131 | ms.run() 132 | if noin == False: 133 | ms.import_es(index, eshost, esport) 134 | print ms.output 135 | 136 | 137 | # Run masscan on file of ranges 138 | def scanlst(hostfile, ports, xml, index, eshost, esport, noin): 139 | ms = Masscan(hostfile, 'xml/' + xml, ports) 140 | ms.runfile() 141 | if noin == False: 142 | ms.import_es(index, eshost, esport) 143 | print ms.output 144 | 145 | # Run regular masscan on specified range 146 | def nscan(host, ports, xml, index, eshost, esport, noin): 147 | ms = Nmap(host, 'xml/' + xml, ports) 148 | ms.run() 149 | if noin == False: 150 | ms.import_es(index, eshost, esport) 151 | print ms.output 152 | 153 | 154 | # Run masscan on file of ranges 155 | def nscanlst(hostfile, ports, xml, index, eshost, esport, noin): 156 | ms = Nmap(hostfile, 'xml/' + xml, ports) 157 | ms.runfile() 158 | if noin == False: 159 | ms.import_es(index, eshost, esport) 160 | print ms.output 161 | 162 | def export_xml(xml, index, eshost, esport): 163 | ms = Masscan('x', 'xml/' + xml, 'y') 164 | ms.import_es(index, eshost, esport) 165 | 166 | def nexport_xml(xml, index, eshost, esport): 167 | ms = Nmap('x', 'xml/' + xml, 'y') 168 | ms.import_es(index, eshost, esport) 169 | 170 | def delete_index(dindex, eshost, esport): 171 | url = 'http://' + eshost + ':' + str(esport) + '/' + dindex 172 | print 'deleting index: ' + url 173 | r = requests.delete(url) 174 | print r.content 175 | 176 | 177 | def export_urls(xml): 178 | x = Xml2urls(xml) 179 | x.run() 180 | 181 | def nexport_urls(xml): 182 | x = Xml2urls2(xml) 183 | x.run() 184 | 185 | if __name__ == '__main__': 186 | parse = argparse.ArgumentParser() 187 | parse.add_argument('-v', '--version', action='store_true', default=False, 188 | help='Version information') 189 | parse.add_argument('-d', '--dirb', action='store_true', default=False, 190 | help='Run directory brute force. Requires --urls & --words') 191 | parse.add_argument('-s', '--scan', action='store_true', default=False, 192 | help='Run masscan on single range. Specify --host & --ports & --xml') 193 | parse.add_argument('-ns', '--nmap', action='store_true', default=False, 194 | help='Run Nmap on a single range specify -H & -p') 195 | parse.add_argument('-noes', '--noelastics', action='store_true', default=False, 196 | help='Run scan without elasticsearch insertion') 197 | parse.add_argument('-sl', '--scanlist', action='store_true', default=False, 198 | help='Run masscan on a list of ranges. Requires --host & --ports & --xml') 199 | parse.add_argument('-nsl', '--nmaplist', action='store_true', default=False, 200 | help='Run Nmap on a list of ranges -H & -p & -x') 201 | parse.add_argument('-in', '--noinsert', action='store_true', default=False, 202 | help='Perform a scan without inserting to elasticsearch') 203 | parse.add_argument('-e', '--export', action='store_true', default=False, 204 | help='Export a scan XML into elasticsearch. Requires --xml') 205 | parse.add_argument('-eurl', '--exporturl', action='store_true', default=False, 206 | help='Export urls to scan from XML file. Requires --xml') 207 | parse.add_argument('-nurl', '--exportnmap', action='store_true', default=False, 208 | help='Export urls from nmap XML, requires -x') 209 | parse.add_argument('-del', '--delete', action='store_true', default=False, 210 | help='Specify an index to delete.') 211 | parse.add_argument('-H', '--host', type=str, help='Scan this host or list of hosts') 212 | parse.add_argument('-p', '--ports', type=str, 213 | default='21,22,80,443,8000,8080,8443,2080,2443,9090,6000,8888,50080,50443,5900', 214 | help='Specify ports in masscan format. (ie.0-1000 or 80,443...)') 215 | parse.add_argument('-x', '--xml', type=str, default='scan.xml', 216 | help='Specify an XML file to store output in') 217 | parse.add_argument('-w', '--words', type=str, default='words', 218 | help='Wordlist to be used with --dirb') 219 | parse.add_argument('-u', '--urls', type=str, default='urls', 220 | help='List of Urls to be used with --dirb') 221 | parse.add_argument('-t', '--threads', type=int, default=1, 222 | help='Specify the number of threads to use.') 223 | parse.add_argument('-esh', '--eshost', type=str, default=u'127.0.0.1', 224 | help='Specify the elasticsearch host') 225 | parse.add_argument('-esp', '--port', type=int, default=5900, 226 | help='Specify ElasticSearch port') 227 | parse.add_argument('-i', '--index', type=str, default='scantastic', 228 | help='Specify the ElasticSearch index') 229 | parse.add_argument('-a', '--agent', type=str, default='Scantastic O_o', 230 | help='Specify a User Agent for requests') 231 | args = parse.parse_args() 232 | 233 | if len(sys.argv) <= 1: 234 | parse.print_help() 235 | sys.exit(0) 236 | 237 | if args.version: 238 | version_info() 239 | 240 | if args.scan and (args.host is not None): 241 | scan(args.host, args.ports, args.xml, args.index, args.eshost, 242 | args.port, args.noinsert) 243 | elif args.nmap and (args.host is not None): 244 | nscan(args.host, args.ports, args.xml, args.index, args.eshost, 245 | args.port, args.noinsert) 246 | 247 | if args.scanlist and (args.host is not None): 248 | scanlst(args.host, args.ports, args.xml, args.index, args.eshost, 249 | args.port, args.noinsert) 250 | elif args.nmaplist and (args.host is not None): 251 | nscanlst(args.host, args.ports, args.xml, args.index, args.eshost, 252 | args.port, args.noinsert) 253 | 254 | if args.export: 255 | export_xml(args.xml, args.index, args.eshost, args.port) 256 | 257 | if args.delete: 258 | delete_index(args.index, args.eshost, args.port) 259 | 260 | if args.exporturl: 261 | export_urls(args.xml) 262 | elif args.exportnmap: 263 | nexport_urls(args.xml) 264 | 265 | if args.dirb: 266 | try: 267 | with open(args.urls) as f: 268 | urls = f.read().splitlines() 269 | with open(args.words) as f: 270 | words = f.read().splitlines() 271 | except IOError: 272 | print 'File not found!' 273 | threads = [] 274 | splitlist = list(split_urls(urls, args.threads)) 275 | 276 | for word in words: 277 | print 'Word: ' + word 278 | for i in range(0, len(splitlist)): 279 | p = multiprocessing.Process(target=requestor, 280 | args=( 281 | list(splitlist[i]), word, args.eshost, args.port, args.agent, 282 | args.index, 283 | args.noelastics)) 284 | threads.append(p) 285 | try: 286 | for p in threads: 287 | p.start() 288 | for p in threads: 289 | p.join() 290 | except KeyboardInterrupt: 291 | print 'Killing Threads...' 292 | for p in threads: 293 | p.terminate() 294 | sys.exit(0) 295 | threads = [] 296 | -------------------------------------------------------------------------------- /showRange.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #./showRange.py [127.0.0.0/RANGE] 3 | import sys 4 | from netaddr import * 5 | 6 | addr=sys.argv[1] 7 | 8 | ip = IPNetwork(addr) 9 | print "from: ",str(ip.network) 10 | print "to: ",str(ip.broadcast) 11 | 12 | -------------------------------------------------------------------------------- /urls/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maK-/scantastic-tool/37dc863e9285cf156a42847d61f884434f42ad91/urls/.gitkeep -------------------------------------------------------------------------------- /words/ASP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maK-/scantastic-tool/37dc863e9285cf156a42847d61f884434f42ad91/words/ASP -------------------------------------------------------------------------------- /words/ASPX: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maK-/scantastic-tool/37dc863e9285cf156a42847d61f884434f42ad91/words/ASPX -------------------------------------------------------------------------------- /words/HTML: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maK-/scantastic-tool/37dc863e9285cf156a42847d61f884434f42ad91/words/HTML -------------------------------------------------------------------------------- /words/PHP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maK-/scantastic-tool/37dc863e9285cf156a42847d61f884434f42ad91/words/PHP -------------------------------------------------------------------------------- /words/blank: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /xml/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maK-/scantastic-tool/37dc863e9285cf156a42847d61f884434f42ad91/xml/.gitkeep -------------------------------------------------------------------------------- /xmltourl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Generate URLS from scanfile 3 | # =============================== 4 | 5 | import xmltodict 6 | 7 | 8 | class Xml2urls: 9 | def __init__(self, xmlfile): 10 | self.xmlf = xmlfile 11 | self.data = '' 12 | try: 13 | with open('xml/' + self.xmlf) as myf: 14 | self.data = myf.read().replace('\n', '') 15 | except IOError: 16 | print 'File IO Error' 17 | self.xml = xmltodict.parse(self.data) 18 | 19 | 20 | def run(self): 21 | nmaprun = self.xml['nmaprun'] 22 | host = nmaprun['host'] 23 | 24 | for entry in host: 25 | port = entry['ports']['port'] 26 | if int(port['@portid']) == 80: 27 | name = entry['address']['@addr'] 28 | print 'http://' + name + '/' 29 | elif int(port['@portid']) == 443: 30 | name = entry['address']['@addr'] 31 | print 'https://' + name + '/' 32 | elif int(port['@portid']) == 21: 33 | name = entry['address']['@addr'] 34 | print 'ftp://' + name + '/' 35 | else: 36 | name = entry['address']['@addr'] 37 | print 'http://' + name + ':' + str(port['@portid']) + '/' 38 | 39 | class Xml2urls2: 40 | def __init__(self, xmlfile): 41 | self.xmlf = xmlfile 42 | self.data = '' 43 | try: 44 | with open('xml/' + self.xmlf) as myf: 45 | self.data = myf.read().replace('\n', '') 46 | except IOError: 47 | print 'File IO Error' 48 | self.xml = xmltodict.parse(self.data) 49 | 50 | def run(self): 51 | nmaprun = self.xml['nmaprun'] 52 | scanhost = nmaprun['host'] 53 | for i in scanhost: 54 | address = i['address'][0]['@addr'] 55 | port1 = dict(i) 56 | try: 57 | if int(port1['ports']['port']['@portid']) > 0: 58 | port2 = port1['ports']['port']['@portid'] 59 | if port2 == '80': 60 | print 'http://'+address+'/' 61 | elif port2 == '443': 62 | print 'https://'+address+'/' 63 | else: 64 | print 'http://'+address+':'+port2+'/' 65 | except: 66 | port2 = i['ports']['port'] 67 | for z in port2: 68 | x = z['@portid'] 69 | if x == '80': 70 | print 'http://'+address+'/' 71 | elif x == '443': 72 | print 'https://'+address+'/' 73 | else: 74 | print 'http://'+address+':'+x+'/' 75 | 76 | --------------------------------------------------------------------------------