#!/usr/bin/env python

"""
DPE - DEFAULT PASSWORD ENUMERATION
program: dpeparser.py
version: beta 002
purpose: Faciliate the use of DPE concept. Consolidate the default passwords and credentials. 

Created by NJ OUCHN on 2013-02-01
website: www.tooslwatch.org
twitter: @toolswatch

This is a very early beta release. Many improvement to come.
Beta features
+ search by specific CPE id (ex: cpe:/h:cisco:building_broadband_service_manager:5.0 ..)
+ search by vendor (ex: cisco, alcatel...)
+ search by type (keywords used: router,switch,firewall,voip,software, operating system, telephony, database, printer)
+ export automatically results to password.txt
+ update DPE xml database from the official DPE - Default Password Enumeration location

Changelog 2013-02-10
* Added a line to display the CVE-id

Changelog 2013-03-09
* Modified the _dpesearch function to reflect the changes in the scheme
* Modified the export format of txt file. Now it reports description, protocol port and (login/password).
* Added DpeID

note:
_update fct code is not mine. I got it from this location https://gist.github.com/medigeek/3176958
first i've a simple urllib.urlretrieve. It works good. But i need to make control on filesize for next release.

"""

import os
import optparse
import re
from optparse import OptionParser
import sys
import xml.dom.minidom
import urllib2


def _printbanner(ParserVersion,MydpeDB):
    
    xmldoc = xml.dom.minidom.parse(MydpeDB)
    build = xmldoc.getElementsByTagName('dpe')[0].attributes['build'].value
        
    # Print the Title
    
    Mybanner = ""
    Mybanner +="    ____  ____  _____   ____   \n "                      
    Mybanner +="  |  _ \|  _ \| ____| |  _ \ __ _ _ __ ___  ___ _ __ \n"
    Mybanner +="   | | | | |_) |  _|   | |_) / _` | '__/ __|/ _ \ '__|\n"
    Mybanner +="   | |_| |  __/| |___  |  __/ (_| | |  \__ \  __/ |   \n"
    Mybanner +="   |____/| |   |_____| |_|   \__,_|_|  |___/\___|_|   \n"
    Mybanner +="         |_|" + ParserVersion + " Database XML build "+ build +     "\n"
    Mybanner +="                     http://www.toolswatch.org/dpe   \n"
                                               
    print Mybanner    
    return    



# Official DPE Db Repository.
url = 'http://www.toolswatch.org/dpe/dpe_db.xml'

def _update():

# I used a code found here https://gist.github.com/medigeek/3176958.
# i dont reinvent the wheel

# The function urllib.urlretrieve works also very well.
    print
    print '[+] Updating from official location %s' % url
    file_name = url.split('/')[-1]
    u = urllib2.urlopen(url)
    f = open(file_name, 'wb')
    meta = u.info()
    file_size = int(meta.getheaders("Content-Length")[0])
    print "[*] Downloading: %s Bytes: %s" % (file_name, file_size)
    
    file_size_dl = 0
    block_sz = 8192
    while True:
        buffer = u.read(block_sz)
        if not buffer:
            break
    
        file_size_dl += len(buffer)
        f.write(buffer)
        status = r"%10d [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
        status = status + chr(8)*(len(status)+1)
        print status,
    
    f.close()


def _dpeSearch(MydpeDB,pattern,categorytosearch):

    print
    print '[+] Searching default credentials for %s' % pattern
    print '[+] Creating output file passlist.txt'

    f = open("passlist.txt","w")
    header = '# Password list for %s\n' % pattern
    header += '# Generated by DPE Default Passwords Enumeration Parser\n'
    header += '# http://www.toolswatch.org\n'
    header += '\n\n'
    f.writelines(header)

    xmldoc = xml.dom.minidom.parse(MydpeDB)
    entrylist = xmldoc.getElementsByTagName('vendor')
    credential = ""
            
    for s in entrylist:
        
        if categorytosearch == 'vendor':
            value = s.attributes['name'].value
                        
            for match in re.findall(pattern.lower(), value.lower()):        
                for models in s.getElementsByTagName("model"):
                    print '-----------------------------------------------------------------------------------------------'
                    print 'DPEid: %s' % models.attributes['dpeid'].value
                    print 'vendor:%s' % s.attributes['name'].value
                    print 'type: %s' % models.attributes['type'].value
                    print 'CPE: %s' % models.attributes['cpe'].value
                    print 'CVE: %s' % models.getElementsByTagName("info")[0].attributes['cve'].value          
                    print 'description: %s' % models.attributes['description'].value
                    print '\t protocol: %s' % models.getElementsByTagName("info")[0].attributes['protocol'].value
                    print '\t TCP/UDP port: %s' % models.getElementsByTagName("info")[0].attributes['port'].value
                    print '\t username: %s' % models.getElementsByTagName("credential")[0].attributes['username'].value
                    print '\t password: %s' % models.getElementsByTagName("credential")[0].attributes['password'].value
                    credential += '# Record for %s\n' % models.attributes['description'].value
                    credential += models.getElementsByTagName("info")[0].attributes['protocol'].value + ',' + models.getElementsByTagName("info")[0].attributes['port'].value + ','
                    credential += models.getElementsByTagName("credential")[0].attributes['username'].value + ',' + models.getElementsByTagName("credential")[0].attributes['password'].value + '\n'

            
        if categorytosearch == 'cpe' or categorytosearch == 'description' or categorytosearch == 'type' :
            for models in s.getElementsByTagName("model"):
                value = models.attributes[categorytosearch].value
                for match in re.findall(pattern.lower(), value.lower()):
                    print '-----------------------------------------------------------------------------------------------'
                    print 'DPEid: %s' % models.attributes['dpeid'].value
                    print 'vendor:%s' % s.attributes['name'].value
                    print 'type: %s' % models.attributes['type'].value
                    print 'CPE: %s' % models.attributes['cpe'].value
                    print 'CVE: %s' % models.getElementsByTagName("info")[0].attributes['cve'].value          
                    print 'description: %s' % models.attributes['description'].value
                    print '\t protocol: %s' % models.getElementsByTagName("info")[0].attributes['protocol'].value
                    print '\t TCP/UDP port: %s' % models.getElementsByTagName("info")[0].attributes['port'].value
                    print '\t username: %s' % models.getElementsByTagName("credential")[0].attributes['username'].value
                    print '\t password: %s' % models.getElementsByTagName("credential")[0].attributes['password'].value
                    credential += '# Record for %s\n' % models.attributes['description'].value
                    credential += models.getElementsByTagName("info")[0].attributes['protocol'].value + ',' + models.getElementsByTagName("info")[0].attributes['port'].value + ','
                    credential += models.getElementsByTagName("credential")[0].attributes['username'].value + ',' + models.getElementsByTagName("credential")[0].attributes['password'].value + '\n'

                                                      
    print
    print '--------------------------------------------------' 
    print '[+] Exporting passwords in %s to file passlist.txt'  % pattern
    f.writelines(credential)
    return

def main():
    
    ParserVersion = "Beta 002"
    
    
    parser = OptionParser(usage="usage: %prog [Options] filename", version="%prog " + ParserVersion)
    parser.add_option("-c", "--cpe", action="store", dest="searchCPE",
                      type="string", help="Search for CPE default passwords ex:cpe:/h:cisco:router_4000")
    
    parser.add_option("-v", "--vendor", action="store", dest="searchVendor",
                      type="string", help="Search for Vendors default passwords (ex: cisco, apple...)")
    
    parser.add_option("-t", "--type", action="store", dest="searchType",
                      type="string", help="Search for Type default passwords (ex:router, switch, hub...)")
    
    parser.add_option("-d", "--description", action="store", dest="searchDesc",
                      type="string", help="Search for description (ex:cisco router 2600...)")
    parser.add_option("-b", "--banner", action="store_true", default=False, dest="banner", help="Display Banner")
    parser.add_option("-u", "--update", action="store_true", default=False, dest="update", help="update DPE xml content")

    
    
    (opts, args) = parser.parse_args()
    
    searchCPE = opts.searchCPE
    searchVendor = opts.searchVendor
    searchType = opts.searchType
    searchDesc = opts.searchDesc
       
    if opts.update:
        _update()
        sys.exit()
        
     # some checks agaisnt xml db file. This file is mandatory.
   
    MydpeDB = "/usr/share/dpeparser/dpe_db.xml"
    
    if not os.path.isfile(MydpeDB):
        parser.error("[!]- %s does not exist. Try to get it with --update" % MydpeDB)

    if not os.access(MydpeDB, os.R_OK):
        parser.error("[!!]- Access denied to %s" % MydpeDB)


    if opts.banner:
        _printbanner(ParserVersion,MydpeDB)
        sys.exit()           



    if not searchCPE and not searchVendor and not searchType and not searchDesc:
        parser.print_help()
        parser.error("[!]- You must supply a pattern to search for.")
    
    if MydpeDB != None:
        
        if searchCPE:
            pattern = searchCPE
            categorytosearch = 'cpe'
        if searchVendor:
            pattern = searchVendor
            categorytosearch = 'vendor'            
        if searchType:
            pattern = searchType
            categorytosearch = 'type'            
        if searchDesc:
            pattern = searchDesc
            categorytosearch = 'description'                
        
        _dpeSearch(MydpeDB,pattern,categorytosearch)
        
    print '[+] Exiting program.'

  

if __name__ == '__main__':
    main()
        

            
