Beispiel #1
0
def accounts_grid():
    response.title = "%s :: Accounts" % (settings.title)
    if session.hostfilter is None:
        session.hostfilter = [(None, None), False]

    query = (db.t_accounts.id > 0) & (db.t_accounts.f_services_id == db.t_services.id)
    query = create_hostfilter_query(session.hostfilter, query, "t_services")
    columns = [
        db.t_hosts.f_ipv4,
        db.t_hosts.f_hostname,
        db.t_services.f_proto,
        db.t_services.f_number,
        db.t_accounts.f_fullname,
        db.t_accounts.f_domain,
        db.t_accounts.f_password,
        db.t_accounts.f_hash1_type,
        db.t_accounts.f_hash1,
        db.t_accounts.f_hash2_type,
        db.t_accounts.f_hash2,
        db.t_accounts.f_uid,
        db.t_accounts.f_gid,
        db.t_accounts.f_level,
        db.t_accounts.f_active,
        db.t_accounts.f_lockout,
        db.t_accounts.f_duration,
        db.t_accounts.f_source,
        db.t_accounts.f_message,
        db.t_accounts.f_description,
        db.t_accounts.id,
    ]
    rows = SQLFORM.grid(query, columns, deletable=True, selectable=True, details=False, field_id=db.t_accounts.id)

    return dict(rows=rows)
Beispiel #2
0
def vuln_hosts():
    """
    Returns a grid of hosts based on f_vulndata_id
    """
    vuln_id = request.args(0) or None
    query = (db.t_hosts.id > 0)
    query = create_hostfilter_query(session.hostfilter, query, 't_services')
    query &= (db.t_services.f_hosts_id == db.t_hosts.id)
    query &= (db.t_service_vulns.f_services_id == db.t_services.id)
    query &= (db.t_service_vulns.f_vulndata_id == vuln_id)
    hosts = SQLFORM.grid(
        query,
        args=[vuln_id],
        fields = [
            db.t_hosts.f_ipv4,
            db.t_hosts.f_ipv6,
            db.t_hosts.f_hostname,
            db.t_services.f_proto,
            db.t_services.f_number,
            db.t_service_vulns.f_proof,
        ],
        maxtextlength=255,
        searchable=True,
        deletable=True,
        details=False,
        selectable=True,
        create=False,
        csv=True,
        formstyle='bootstrap',
        formname='vuln_hosts_grid',
        client_side_delete=True,
        paginate=None,
    )
    return hosts
Beispiel #3
0
def service_vulns_list():
    # XXX: this doesn't work yet. . .
    if session.hostfilter is None:
        session.hostfilter = [(None, None), False]

    query = (db.t_service_vulns.id > 0) & (db.t_service_vulns.f_services_id == db.t_services.id) & (db.t_service_vulns.f_vulndata_id == db.t_vulndata.id)
    query = create_hostfilter_query(session.hostfilter, query, 't_services')

    columns = [
        db.t_hosts.f_ipv4, db.t_hosts.f_ipv6, db.t_hosts.f_hostname, db.t_services.f_proto, db.t_services.f_number,
        db.t_vulndata.f_vulnid, db.t_service_vulns.f_status, db.t_service_vulns.f_proof,
        #db.t_service_vulns.id
    ]
    rows = SQLFORM.grid(query, columns, deletable=True, selectable=True, details=False, field_id=db.t_service_vulns.id)
    response.title = "Services with Vulnerabilities"
    return dict(rows=rows)
Beispiel #4
0
def vulnlist(query="%", hostfilter=None):
    """
    Returns a vulnerability dictionary with counts:

    { 'vulnerability id': [ status, count, severity, cvss ] }
    """

    db = current.globalenv['db']
    session = current.globalenv['session']

    status = db.t_service_vulns.f_status
    svcv_id = db.t_service_vulns.id
    vulnid = db.t_vulndata.id
    f_vulnid = db.t_vulndata.f_vulnid
    sev = db.t_vulndata.f_severity
    cvss = db.t_vulndata.f_cvss_score

    hostfilter = hostfilter or session.hostfilter

    if hostfilter is None:
        # if no filter is set then we blank it out
        if session.hostfilter is None:
            session.hostfilter = [(None, None), False]

    query = (db.t_vulndata.f_vulnid.contains(query))
    query &= (db.t_service_vulns.f_services_id == db.t_services.id) & (db.t_service_vulns.f_vulndata_id == db.t_vulndata.id)
    query = create_hostfilter_query(hostfilter, query, 't_services')
    #query = (db.t_service_vulns.f_vulndata_id == db.t_vulndata.id)

    vulnlist = {}
    for rec in db(query).select(status, vulnid, f_vulnid, svcv_id, sev, cvss):
        q2 = (query & ((db.t_service_vulns.f_vulndata_id == rec.t_vulndata.id) &
             (db.t_service_vulns.f_status == rec.t_service_vulns.f_status)))
        count = db(q2).count()
        vstats = vulnlist.setdefault(rec.t_vulndata.f_vulnid, list())
        if rec.t_service_vulns.f_status not in map(lambda a:a[0], vstats):
            vstats.append([rec.t_service_vulns.f_status,
                            count,
                            rec.t_vulndata.f_severity,
                            rec.t_vulndata.f_cvss_score
                         ] )
            vulnlist[rec.t_vulndata.f_vulnid] = vstats

    return vulnlist
Beispiel #5
0
def services():
    """
    Service statistics
    """

    t_hosts = db.t_hosts
    t_svcs = db.t_services

    hostfilter = session.hostfilter
    if hostfilter is None:
        # if no filter is set then we blank it out
        if session.hostfilter is None:
            session.hostfilter = [(None, None), False]

    q = (t_hosts.id>0)
    q = create_hostfilter_query(session.hostfilter, q, t_svcs)

    rows = db(q).select(t_svcs.f_proto, t_svcs.f_number, t_svcs.f_name, cache=(cache.ram, 60))
    port_counts = {}
    name_counts = {}
    for r in rows:
        port = "%s/%s" % (r.f_proto, r.f_number)
        sname = r.f_name

        count = port_counts.setdefault(port, 0)
        count += 1
        port_counts[port] = count

        count = name_counts.setdefault(sname, 0)
        count += 1
        name_counts[sname] = count

    response.title = "%s :: Service Statistics" % (settings.title)

    return dict(
        port_counts=port_counts,
        name_counts=name_counts,
    )
Beispiel #6
0
def new_service_vulns():
    # server-side processing of service vulns.. faster..better?
    # TODO: This...?
    response.title = "%s :: Services and Vulnerabilities" % (settings.title)
    if request.extension == 'json':
        if session.hostfilter is None:
            session.hostfilter = [(None, None), False]

        query = (db.t_service_vulns.id > 0) & (db.t_service_vulns.f_services_id == db.t_services.id) & (db.t_service_vulns.f_vulndata_id == db.t_vulndata.id)
        query = create_hostfilter_query(session.hostfilter, query, 't_services')

        if request.vars.has_key('iDisplayStart'):
            start = int(request.vars.iDisplayStart)
        else:
            start = 0
        if request.vars.has_key('iDisplayLength'):
            if request.vars.iDisplayLength == '-1':
                limit = db(query).count()
            else:
                limit = start + int(request.vars.iDisplayLength)
        else:
            limit = int(auth.user.f_show_size)

        if request.vars.has_key('sSearch'):
            # sSearch global search box
            query &= db.t_vulndata.f_vulnid.like("%%%s%%" % request.vars.sSearch) | db.t_vulndata.f_title.like("%%%s%%" % request.vars.sSearch)

        if request.vars.iSortingCols == '1':
            # sorting by a column - this is a little trippy because tuples start at 0
            # and datatables starts at 1 so we have to subtract 1 from iSortCol_0
            cols = ( None,
                     db.t_vulndata.id,
                     db.t_vulndata.f_vulnid,
                     db.t_vulndata.f_title,
                     db.t_vulndata.f_severity,
                     None,
                     db.t_vulndata.f_cvss_score
                     )
Beispiel #7
0
def list():
    response.title = "%s :: Host Listing" % (settings.title)
    # hostfilter is a session variable that can be
    # None -- no host filtering
    # (userid, <x>) - limit on user id
    # (assetgroup, <x>) - limit on asset group
    # (range, <x>) - limit on subnet (eg: 192.168)
    hostfilter = session.hostfilter
    if hostfilter is None:
        # if no filter is set then we blank it out
        if session.hostfilter is None:
            session.hostfilter = [(None, None), False]

    if request.extension == 'json':
        # from datetime import datetime, timedelta
        # host_start = datetime.now()
        tot_vuln = 0
        tot_hosts = 0

        """
        # load all the vulndata from service_vulns into a dictionary
        # so we only have to query the memory variables instead of
        # the database each time. We need to collect:
        # svc_vulndata[f_service_id] = (f_vulnid, f_severity, f_cvss_score)
        svc_vulndata = {}

        rows = s_service_vuln_data.select( db.t_vulndata.id, db.t_vulndata.f_vulnid, db.t_vulndata.f_severity, db.t_vulndata.f_cvss_score, cache=(cache.ram, 60))
        for r in rows:
            #exploitcount = db(db.t_exploit_references.f_vulndata_id == r.id).count()
            svc_vulndata[r.id] = ( r.f_vulnid,
                                   r.f_severity,
                                   r.f_cvss_score,
                                   r.t_exploit_references.count())
        """

        # build the query variable.. first all hosts then check
        # if a hostfilter is applied
        q = (db.t_hosts.id > 0)
        q = create_hostfilter_query(session.hostfilter, q)

        aaData = []
        rows = db(q).select(db.t_hosts.ALL, db.t_host_os_refs.f_certainty, db.t_os.f_title, db.auth_user.username,
                            left=(db.t_host_os_refs.on(db.t_hosts.id==db.t_host_os_refs.f_hosts_id),
                                  db.t_os.on(db.t_os.id==db.t_host_os_refs.f_os_id),
                                  db.auth_user.on(db.t_hosts.f_engineer==db.auth_user.id)),
                            orderby=db.t_hosts.id|~db.t_host_os_refs.f_certainty)
        # datatable formatting is specific, crud results are not
        seen = set()
        for r in rows:
            if r.t_hosts.id not in seen and not seen.add(r.t_hosts.id): # kludge way to select only rows per host with the best OS-guess
                spanflags = []
                if r.t_hosts.f_confirmed:
                    confirmed = 'hosts_select_confirmed'
                    spanflags.append('<span class="badge"><i class="icon-check"></i></span>')
                else:
                    confirmed = 'hosts_select_unconfirmed'

                if r.t_hosts.f_accessed:
                    spanflags.append('<span class="badge badge-success"><i class="icon-heart"></i></span>')
                if r.t_hosts.f_followup:
                    spanflags.append('<span class="badge badge-important"><i class="icon-flag"></i></span>')

                confirmed = '<div class="%s">%s</div>' % (confirmed, " ".join(spanflags))

                if r.t_hosts.f_ipv4:
                    ipv4 = A(r.t_hosts.f_ipv4, _id='ipv4', _href=URL('detail', extension='html', args=[r.t_hosts.id]), _target="host_detail_%s" % (r.t_hosts.id)).xml()
                else:
                    ipv4 = ""
                if r.t_hosts.f_ipv6:
                    ipv6 = A(r.t_hosts.f_ipv6, _id='ipv6', _href=URL('detail', extension='html', args=[r.t_hosts.id]), _target="host_detail_%s" % (r.t_hosts.id)).xml()
                else:
                    ipv6 = ""

                if r.t_os.f_title is None:
                    os = "Unknown"
                else:
                    os = r.t_os.f_title

                atxt = {
                     '0': confirmed,
                     '1': ipv4,
                     '2': ipv6,
                     '3': r.t_hosts.f_service_count,
                     '4': r.t_hosts.f_vuln_count,
                     '5': "<span class=\"severity_sparkline\" values=\"%s\"></span>" % (r.t_hosts.f_vuln_graph),
                     '6': r.t_hosts.f_exploit_count,
                     '7': r.t_hosts.f_hostname,
                     '8': r.t_hosts.f_netbios_name,
                     '9': os,
                     '10': r.auth_user.username,
                     '11': r.t_hosts.f_asset_group,
                     'DT_RowId': "%s" % (r.t_hosts.id),
                }

                aaData.append(atxt)
                #print("Total time in vuln processing: %s seconds" % (tot_vuln))
                #print("Host record processed in %s seconds" % (timedelta.total_seconds(datetime.now() - row_start)))
                tot_hosts += 1

        result = { 'sEcho': request.vars.sEcho,
                   'iTotalRecords': len(aaData),
                   'iTotalDisplayRecords': len(aaData),
                   'aaData': aaData,
                   }

        #print("Host_select processed %s hosts in %s seconds" % (tot_hosts, timedelta.total_seconds(datetime.now() - host_start)))
        return result
    else:
        add_hosts = AddModal(
            db.t_hosts, 'Add Host', 'Add Host', 'Add Host',
            fields = [
                'f_ipv4',
                'f_ipv6',
                'f_hostname',
                'f_netbios_name',
                'f_macaddr',
                'f_engineer',
                'f_asset_group',
            ],
            cmd = 'hosttable.fnReloadAjax();'
        )
        db.t_hosts.id.comment = add_hosts.create()
        response.files.append(URL(request.application,'static','js/jquery.sparkline.js'))
        return dict(hostfilter=session.hostfilter, add_hosts=add_hosts)
Beispiel #8
0
def os():
    """
    Operating system statistics
    """

    hostfilter = session.hostfilter
    if hostfilter is None:
        # if no filter is set then we blank it out
        if session.hostfilter is None:
            session.hostfilter = [(None, None), False]

    q = create_hostfilter_query(session.hostfilter)

    rows = db(q).select(db.t_hosts.id, db.t_host_os_refs.f_certainty, db.t_os.f_title, db.t_os.f_vendor,
                        db.t_host_os_refs.f_family, db.t_host_os_refs.f_class,
                        left=(db.t_host_os_refs.on(db.t_hosts.id==db.t_host_os_refs.f_hosts_id),
                              db.t_os.on(db.t_os.id==db.t_host_os_refs.f_os_id)),
                        orderby=db.t_hosts.id|~db.t_host_os_refs.f_certainty, cache=(cache.ram, 60))

    seen = set()
    os_counts = {}
    vendor_counts = {}
    family_counts = {}
    class_counts = {}
    for r in rows:
        if r.t_hosts.id not in seen and not seen.add(r.t_hosts.id): # kludge way to select only rows per host with the best OS-guess
            os_title = r.t_os.f_title or 'Unknown'
            os_vendor = r.t_os.f_vendor or 'Unknown'
            os_family = r.t_host_os_refs.f_family or 'Unknown'
            os_class = r.t_host_os_refs.f_class or 'Unknown'

            # only capitalize if the first char of the string isn't already capitalized
            # this covers not destroying things like HP, IOS, etc
            #if os_vendor[0].islower(): os_vendor = os_vendor.capitalize()
            if os_family[0].islower(): os_family = os_family.capitalize()
            if os_class[0].islower(): os_class = os_class.capitalize()

            count = os_counts.setdefault(os_title, 0)
            count += 1
            os_counts[os_title] = count

            count = vendor_counts.setdefault(os_vendor, 0)
            count += 1
            vendor_counts[os_vendor] = count

            count = family_counts.setdefault(os_family, 0)
            count += 1
            family_counts[os_family] = count

            count = class_counts.setdefault(os_class, 0)
            count += 1
            class_counts[os_class] = count

    response.title = "%s :: Operating System Statistics" % (settings.title)

    return dict(
        vendor_counts=vendor_counts,
        os_counts=os_counts,
        family_counts=family_counts,
        class_counts=class_counts,
    )
Beispiel #9
0
def hosts_with_port():
    """
    Creates a CSV file of ipv4,ipv6 for hosts with a user-specified
    tcp/udp port
    """

    # XXX: This is broken and needs some TLC

    # buld the dropdown user list
    #users = db(db.auth_user).select()
    #userlist = []
    #for user in users:
    #    userlist.append( [ user.id, user.username ] )

    form = SQLFORM.factory(
        Field('f_proto', 'string', label=T('Protocol'), default="tcp", requires=IS_IN_SET(("tcp", "udp", "info"))),
        Field('f_number', type='string', label=T('Port')),
        Field('f_name', type='string', label=T('Name (exact)')),
        Field('f_banner', type='string', label=T('Banner (contains)')),
        Field('ignore_filter', type='boolean', default=False, label=T('Ignore Hostfilter')),
        #Field('f_ipv4', type='boolean', default=True, label=T('Show IPv4')),
        #Field('f_ipv6', type='boolean', default=False, label=T('Show IPv6')),
        #Field('f_hostname', type='boolean', default=False, label=T('Show Hostname')),
        #Field('f_engineer', type='integer', label=T('Engineer'), default=auth.user.id, requires=IS_IN_SET(userlist)),
        #Field('f_asset_group', type='string', label=T('Asset Group'), requires=IS_NOT_EMPTY()),
        _action=URL(request.application,'services','hosts_with_port.csv'),
    )

    db_svcs = db.t_services
    db_hosts = db.t_hosts
    if form.accepts(request.vars, session):
        q = (db_svcs.id > 0)
        q1 = None
        if form.vars.f_number:
            q1 = (db_svcs.f_number == form.vars.f_number)
        if form.vars.f_proto:
            q2 = (db_svcs.f_proto == form.vars.f_proto)
            if q1:
                q1 = q1 & q2
        if form.vars.f_name:
            q2 = (db_svcs.f_name == form.vars.f_name)
            if q1:
                q1 = q1 & q2
        if form.vars.f_banner:
            q2 = (db_svcs.f_banner.contains(form.vars.f_banner))
            if q1:
                q1 = q1 & q2

        if q1:
            q = q & q1

        if not form.vars.ignore_filter:
            q = create_hostfilter_query(session.hostfilter, q, 't_services')
        else:
            q &= (db_svcs.f_hosts_id == db_hosts.id)

        ip_list = db(q).select(db_hosts.f_ipv4, db_hosts.f_ipv6, db_svcs.f_number, db_hosts.f_hostname, cache=(cache.ram, 60))

        return dict(
            ip_list=ip_list,
        )
    elif form.errors:
        response.flash = 'Error in form'
        redirect(URL('hosts_with_port', extension=''))

    return dict(form=form)
Beispiel #10
0
def list():
    response.title = "%s :: Services" % (settings.title)

    # if no filter is set then we blank it out
    if session.hostfilter is None:
        session.hostfilter = [(None, None), False]

    if request.extension == 'json':

        q = (db.t_services.id > 0)
        proto = request.vars.f_proto
        pnum = request.vars.f_number
        if pnum:
            q &= (db.t_services.f_number == pnum)
        if proto:
            q &= (db.t_services.f_protocol == proto)

        q = create_hostfilter_query(session.hostfilter, q, 't_services')

        # Datatables Server-side: http://datatables.net/usage/server-side
        if request.vars.has_key('iDisplayStart'):
            start = int(request.vars.iDisplayStart)
        else:
            start = 0
        if request.vars.has_key('iDisplayLength'):
            if request.vars.iDisplayLength == '-1':
                limit = db(q).count()
            else:
                limit = start + int(request.vars.iDisplayLength)
        else:
            limit = int(auth.user.f_show_size)

        srch_data = request.vars.get('sSearch')
        if srch_data:
            # sSearch global search box

            # parse the search into fields (port:num proto:tcp etc)
            srch_vals = [
                ["port", db.t_services.f_number],
                ["proto", db.t_services.f_proto],
                ["status", db.t_services.f_status],
                ["name", db.t_services.f_name],
                ["banner", db.t_services.f_banner],
                ["ip", db.t_hosts.f_ipv4],
                ["ipv4", db.t_hosts.f_ipv4],
                ["ipv6", db.t_hosts.f_ipv6],
                ["hostname", db.t_hosts.f_hostname],
            ]

            parsed = False
            for val in srch_vals:
                srch_str = "%s:(?P<f>\w+)" % val[0]
                srch_res = re.findall(srch_str, srch_data)
                for res in srch_res:
                    parsed = True
                    if val[0] == 'banner':
                        q &= (val[1].contains(res))
                    else:
                        q &= (val[1].upper() == res.upper())

            if not parsed:
                q &= db.t_services.f_proto.like("%%%s%%" % request.vars.sSearch) | \
                    db.t_services.f_number.like("%%%s%%" % request.vars.sSearch) | \
                    db.t_services.f_name.like("%%%s%%" % request.vars.sSearch) | \
                    db.t_services.f_banner.like("%%%s%%" % request.vars.sSearch) | \
                    db.t_services.f_status.like("%%%s%%" % request.vars.sSearch)

        if request.vars.iSortingCols == '1':
            cols = (
                None,
                None,
                None,
                db.t_services.f_hosts_id,
                db.t_services.f_proto,
                db.t_services.f_number,
                db.t_services.f_status,
                None,
                None,
                None,
                None,
                db.t_services.f_name,
                db.t_services.f_banner,
            )

            orderby = cols[int(request.vars.iSortCol_0)]
            if request.vars.sSortDir_0 == 'asc':
                rows=db(q).select(orderby=orderby, limitby=(start, limit))
            else:
                rows=db(q).select(orderby=~orderby, limitby=(start, limit))
        else:
            rows=db(q).select(limitby=(start, limit))

        nolimit = db(q).count()

        aaData = []
        colormap = [ (1, 'grey'),
                     (2, 'grey'),
                     (3, 'grey'),
                     (4, 'blue'),
                     (5, 'blue'),
                     (6, 'magenta'),
                     (7, 'magenta'),
                     (8, 'magenta'),
                     (9, 'red'),
                     (10, 'red') ]

        # datatable formatting is specific
        # gather all the vulndata and exploits into a big row
        # later we'll do a find(lambda: row: row.<db>.<field> == <value>)
        # to slice it into the bits we need. Maybe it'll be faster?
        #vulndata = db().select(db.t_vulndata.f_vulnid, db.t_vulndata.id, db.t_exploit_references.f_exploit_id,
        #                       left=db.t_exploit_references.on(db.t_vulndata.id==db.t_exploit_references.f_vulndata_id))

        for r in rows:
            atxt = {}
            vulncount = 0
            vulns = db(db.t_service_vulns.f_services_id==r.t_services.id).select(db.t_service_vulns.f_vulndata_id, cache=(cache.ram, 60))

            vulnlist = []
            explist=[]
            for vuln in vulns:
                vuln_rec = db.t_vulndata[vuln.f_vulndata_id]
                if vuln_rec.f_vulnid not in vulnlist:
                    if settings.use_cvss:
                        vulnlist.append((vuln_rec.f_vulnid, vuln_rec.f_cvss_score))
                    else:
                        vulnlist.append((vuln_rec.f_vulnid, vuln_rec.f_severity))
                exploits = db(db.t_exploit_references.f_vulndata_id == vuln.f_vulndata_id).select(cache=(cache.ram, 60))
                if len(exploits) > 0:
                    for expinfo in exploits:
                        exp = db.t_exploits[expinfo.f_exploit_id]
                        explist.append(TR(TD(exp.f_name),
                                          TD(exp.f_title),
                                          TD(exp.f_source),
                                          TD(exp.f_rank)
                                          )  )

            q = r.t_services.t_service_info.select(cache=(cache.ram, 60))
            if (len(q) > 0) or (len(explist) > 0) or (len(vulnlist) > 0):
                atxt['0'] = IMG(_src=URL(request.application,'static','images/details_open.png')).xml()
            else:
                atxt['0'] = ""
            atxt['1'] = A("edit", _target="services_edit_%s" % (r.t_services.id), _href=URL('edit', args=[r.t_services.id], extension='html')).xml()
            if len(q) > 0:
                addl = []
                for svcinfo in q:
                    addl.append(TR(TD(svcinfo.f_name), TD(svcinfo.f_text)))
                atxt['2'] = TABLE(THEAD(TR(TH(T('Name')),
                                           TH(T('Text')))),
                                  TBODY(addl),
                                  _class="table table-condensed table-striped",
                                  _style="width:100%").xml()
            else:
                atxt['2'] = ''
            host_rec = db.t_hosts[r.t_services.f_hosts_id]
            atxt['3'] = host_a_maker(host_rec).xml(),
            atxt['4'] = r.t_services.f_proto

            # Append A tags around services with HTTP Ports
            if r.t_services.f_number in HTTP_PORTS and r.t_services.f_proto == "tcp" or r.t_services.f_name == "HTTP":
                atxt['5'] = A(r.t_services.f_number,
                              _href="http://%s:%s/" % (host_rec.f_ipv4, r.t_services.f_number),
                              _target="%s-tcp-%s" % (host_rec.f_ipv4, r.t_services.f_number)).xml()
            elif r.t_services.f_number in HTTPS_PORTS and r.t_services.f_proto == "tcp" or r.t_services.f_name == "HTTPS":
                atxt['5'] = A(r.t_services.f_number,
                              _href="https://%s:%s/" % (host_rec.f_ipv4, r.t_services.f_number),
                              _target="%s-tcp-%s" % (host_rec.f_ipv4, r.t_services.f_number)).xml()
            else:
                atxt['5'] = r.t_services.f_number

            atxt['6'] = r.t_services.f_status
            atxt['7'] = len(vulnlist)
            vulntxt = []
            for vuln in vulnlist:
                color = colormap[vuln[1]-1][1]
                vulntxt.append(A(vuln[0], _id="vuln", _target="vulninfo_by_vulnid_%s" % (vuln[0]), _href=URL('vulns', 'vulninfo_by_vulnid', args=[vuln[0]], extension='html'),
                                 _style="color:"+color).xml())
            atxt['8'] = " :: ".join(vulntxt)
            if len(explist) > 0:
                atxt['9'] = "Yes (%d)" % (len(explist))
            else:
                atxt['9'] = ''
            if len(explist) > 0:
                atxt['10'] = TABLE(THEAD(TR(TH(T('Name')),
                                           TH(T('Title')),
                                           TH(T('Source')),
                                           TH(T('Rank')))),
                                  TBODY(explist),
                                  _class="table table-condensed",
                                  _style="width:100%").xml()
            else:
                atxt['10'] = ''
            atxt['11'] = r.t_services.f_name
            atxt['12'] = r.t_services.f_banner
            atxt['DT_RowId'] = r.t_services.id

            aaData.append(atxt)

        result = {
            'sEcho': request.vars.sEcho,
            'iTotalRecords': db(db.t_services).count(),
            'iTotalDisplayRecords': nolimit,
            'aaData': aaData,
        }

        return result
    else:
        add = AddModal(
            db.t_services, 'Add', 'Add', 'Add Service',
            #fields=[
            #    'f_proto', 'f_number', 'f_status', 'f_name', 'f_banner'
            #],
            cmd='servicetable.fnReloadAjax();'
        )
        db.t_services.id.comment = add.create()
        return dict(add=add)
Beispiel #11
0
def vulninfo_by_vulnid():
    """
    Returns the vulnerablilty details
    """
    if request.args(0) is None:
        redirect(URL('default', 'error', vars={'msg': T('No Vulnerability ID sent')}))

    record = db(db.t_vulndata.f_vulnid==request.args(0)).select().first()
    if record is not None:
        # grab vuln references and format the table
        response.title = "%s :: Vulnerability Popup :: %s" % (settings.title, record.f_vulnid)
        #cvss_metrics = "AV:%s/AC:%s/Au:%s/C:%s/I:%s/A:%s" % (record.f_cvss_av,
        #                                                     record.f_cvss_ac,
        #                                                     record.f_cvss_au,
        #                                                     record.f_cvss_c,
        #                                                     record.f_cvss_i,
        #                                                     record.f_cvss_a)

        vulninfo = record
        cvssmetrics = cvss_metrics(record)

        refs = LOAD(request.controller, 'vuln_refs', args=[record.id], ajax=True)
        exploits = LOAD(request.controller, 'vuln_exploits', args=[record.id], ajax=True)

        # TODO: Add hosts with vulnerability -- include service info (proto/port) and
        # ability to delete vuln from service

        query = db.t_service_vulns.f_vulndata_id == record.id
        svc_vulns = db(query).select(db.t_service_vulns.f_services_id,
                                     db.t_service_vulns.f_proof,
                                     db.t_service_vulns.f_status,
                                     db.t_service_vulns.id,
                                     distinct=True)

        # if no filter is set then we blank it out
        if session.hostfilter is None:
            session.hostfilter = [(None, None), False]

        hosts_tr = []
        query = (db.t_hosts.id > 0)
        query = create_hostfilter_query(session.hostfilter, query, 't_services')
        hosts_dict = db(query).select(db.t_hosts.id, cache=(cache.ram, 30)).as_dict()
        hostlist = map(lambda x: x['id'], hosts_dict.itervalues())
        for svc_vuln in svc_vulns:
            svc = db.t_services[svc_vuln.f_services_id]
            if svc is None:
                logger.error("t_servics_vuln #%s does not link to a t_services.id!" % (svc_vuln.id))
                continue

            if svc.f_hosts_id not in hostlist:
                continue

            host_rec = db.t_hosts[svc.f_hosts_id]
            hosts_tr.append(TR(TD(SPAN(I(_class="icon-trash"), _name="host_del", _id=svc_vuln.id)),
                               TD(A(IMG(_src=URL(request.application, 'static/images', 'terminal.png'),
                                        _width="20",
                                        _height="20",
                                        _style="float:left"), "  ",
                                    _href="#", _onclick="launchterm('%s')" % (host_rec.id)),
                                   host_a_maker(host_rec)),
                               TD("%s/%s" % (svc.f_proto, svc.f_number)),
                               TD(MARKMIN(svc_vuln.f_proof)),
                               TD(svc_vuln.f_status),
                               _id=svc_vuln.id ) )

        if len(hosts_tr) > 0:
            hosts = TABLE(THEAD(TR(TH(T('Del'), _width="5%"),
                                   TH(T('Host Information')),
                                   TH(T('Port')),
                                   TH(T('Proof')),
                                   TH(T('Status')),
                                )  ),
                          TBODY(hosts_tr),
                          _id="vulntable", _class="datatable", _width="100%")
        else:
            hosts = None
    else:
        response.title = "%s :: Invalid Vulnerability ID"
        return dict(vulninfo={}, refs={}, exploits={}, hosts={})

    # vuln form data
    vuln=crud.read(db.t_vulndata, record) #returns read-only for for t_vulndata
    vuln.attributes['_id'] = "vuln_record"
    return dict(vuln=vuln, vulninfo=vulninfo, cvssmetrics=cvssmetrics, refs=refs, exploits=exploits, hosts=hosts)
Beispiel #12
0
def list():
    response.title = "%s :: Accounts" % (settings.title)
    # if no filter is set then we blank it out
    if session.hostfilter is None:
        session.hostfilter = [(None, None), False]

    if request.extension == "json":
        query = (db.t_accounts.id > 0) & (db.t_accounts.f_services_id == db.t_services.id)
        query = create_hostfilter_query(session.hostfilter, query, "t_services")
        if request.vars.hash_type is not None:
            query &= (db.t_accounts.f_hash1_type == request.vars.hash_type) | (
                db.t_accounts.f_hash2_type == request.vars.hash_type
            )

        if request.vars.has_key("iDisplayStart"):
            start = int(request.vars.iDisplayStart)
        else:
            start = 0
        if request.vars.has_key("iDisplayLength"):
            if request.vars.iDisplayLength == "-1":
                limit = db(query).count()
            else:
                limit = start + int(request.vars.iDisplayLength)
        else:
            limit = int(auth.user.f_show_size)

        srch_data = request.vars.get("sSearch")
        if srch_data:
            # sSearch global search box

            # parse the search into fields (port:num proto:tcp etc)
            srch_vals = [
                ["port", db.t_services.f_number],
                ["proto", db.t_services.f_proto],
                ["user", db.t_accounts.f_username],
                ["name", db.t_accounts.f_fullname],
                ["domain", db.t_accounts.f_domain],
                ["hash", db.t_accounts.f_hash1],
                ["hash1", db.t_accounts.f_hash1],
                ["hash2", db.t_accounts.f_hash2],
                ["htype", db.t_accounts.f_hash1_type],
                ["uid", db.t_accounts.f_uid],
                ["gid", db.t_accounts.f_gid],
                ["level", db.t_accounts.f_level],
                ["source", db.t_accounts.f_source],
                ["desc", db.t_accounts.f_description],
                ["msg", db.t_accounts.f_message],
                ["ip", db.t_hosts.f_ipv4],
                ["ipv4", db.t_hosts.f_ipv4],
                ["ipv6", db.t_hosts.f_ipv6],
                ["hostname", db.t_hosts.f_hostname],
            ]

            parsed = False
            for val in srch_vals:
                srch_str = "%s:(?P<f>\w+)" % val[0]
                srch_res = re.findall(srch_str, srch_data)
                for res in srch_res:
                    parsed = True
                    if val[0] in ["source", "desc", "hostname"]:
                        query &= val[1].upper().contains(res.upper())
                    else:
                        query &= val[1].upper() == res.upper()

            if not parsed:
                query &= (
                    db.t_accounts.f_username.like("%%%s%%" % request.vars.sSearch)
                    | db.t_accounts.f_password.like("%%%s%%" % request.vars.sSearch)
                    | db.t_accounts.f_fullname.like("%%%s%%" % request.vars.sSearch)
                    | db.t_accounts.f_domain.like("%%%s%%" % request.vars.sSearch)
                    | db.t_accounts.f_hash1.like("%%%s%%" % request.vars.sSearch)
                    | db.t_accounts.f_hash2.like("%%%s%%" % request.vars.sSearch)
                    | db.t_accounts.f_source.like("%%%s%%" % request.vars.sSearch)
                    | db.t_accounts.f_message.like("%%%s%%" % request.vars.sSearch)
                    | db.t_accounts.f_description.like("%%%s%%" % request.vars.sSearch)
                    | db.t_hosts.f_ipv4.like("%%%s%%" % request.vars.sSearch)
                    | db.t_hosts.f_ipv6.like("%%%s%%" % request.vars.sSearch)
                    | db.t_hosts.f_hostname.like("%%%s%%" % request.vars.sSearch)
                )

            # total_count = db.t_vulndata.id.count()
        if request.vars.iSortingCols == "1":
            # sorting by a column - this is a little trippy because tuples start at 0
            # and datatables starts at 1 so we have to subtract 1 from iSortCol_0
            cols = (
                db.t_accounts.f_compromised,
                db.t_hosts.f_ipv4,
                db.t_services.f_number,
                db.t_accounts.f_username,
                db.t_accounts.f_fullname,
                db.t_accounts.f_domain,
                db.t_accounts.f_password,
                db.t_accounts.f_hash1_type,
                db.t_accounts.f_hash1,
                db.t_accounts.f_hash2_type,
                db.t_accounts.f_hash2,
                db.t_accounts.f_uid,
                db.t_accounts.f_gid,
                db.t_accounts.f_level,
                db.t_accounts.f_active,
                db.t_accounts.f_lockout,
                db.t_accounts.f_source,
                db.t_accounts.f_message,
                db.t_accounts.f_description,
            )

            orderby = cols[int(request.vars.iSortCol_0)]
            if request.vars.sSortDir_0 == "asc":
                rows = db(query).select(
                    db.t_accounts.ALL,
                    db.t_hosts.id,
                    db.t_hosts.f_ipv4,
                    db.t_hosts.f_ipv6,
                    db.t_hosts.f_hostname,
                    db.t_services.f_proto,
                    db.t_services.f_number,
                    orderby=orderby,
                    limitby=(start, limit),
                    cache=(cache.with_prefix(cache.ram, "accounts_list"), 180),
                )
            else:
                rows = db(query).select(
                    db.t_accounts.ALL,
                    db.t_hosts.id,
                    db.t_hosts.f_ipv4,
                    db.t_hosts.f_ipv6,
                    db.t_hosts.f_hostname,
                    db.t_services.f_proto,
                    db.t_services.f_number,
                    orderby=~orderby,
                    limitby=(start, limit),
                    cache=(cache.with_prefix(cache.ram, "accounts_list"), 180),
                )
        else:
            rows = db(query).select(
                db.t_accounts.ALL,
                db.t_hosts.id,
                db.t_hosts.f_ipv4,
                db.t_hosts.f_ipv6,
                db.t_hosts.f_hostname,
                db.t_services.f_proto,
                db.t_services.f_number,
                limitby=(start, limit),
                cache=(cache.with_prefix(cache.ram, "accounts_list"), 180),
            )

        # rows=db(q).select(
        #    db.t_accounts.ALL,
        #    db.t_hosts.id,
        #    db.t_hosts.f_ipv4,
        #    db.t_hosts.f_ipv6,
        #    db.t_hosts.f_hostname,
        #    db.t_services.f_proto,
        #    db.t_services.f_number,
        #    #cache=(cache.ram,60)
        # )

        aaData = []
        # datatable formatting is specific
        for r in rows:
            atxt = {}
            if r.t_accounts.f_compromised == True:
                atxt["0"] = (
                    '<div class="acct_compromised" name="row_id" id="%s"><span class="icon-check"></span></div>'
                    % r.t_accounts.id
                )
            else:
                atxt["0"] = '<div class="acct_uncompromised" name="row_id" id="%s"/>' % r.t_accounts.id

            # svc = db.t_services[r.f_services_id]

            atxt["1"] = host_a_maker(r.t_hosts).xml()
            atxt["2"] = "%s/%s" % (r.t_services.f_proto, r.t_services.f_number)
            atxt["3"] = DIV(
                A(
                    I(_class="icon-pencil", _style="display: inline-block;"),
                    _target="accounts_update_%s" % (r.t_accounts.id),
                    _href="edit.html/%s" % (r.t_accounts.id),
                ),
                A(
                    "%s" % (r.t_accounts.f_username),
                    _target="_blank",
                    _id="username",
                    _href=URL("by_username", vars={"username": r.t_accounts.f_username}, extension="html"),
                ),
            ).xml()
            atxt["4"] = r.t_accounts.f_fullname
            atxt["5"] = r.t_accounts.f_domain
            atxt["6"] = r.t_accounts.f_password
            atxt["7"] = r.t_accounts.f_hash1_type
            atxt["8"] = r.t_accounts.f_hash1
            atxt["9"] = r.t_accounts.f_hash2_type
            atxt["10"] = r.t_accounts.f_hash2
            atxt["11"] = r.t_accounts.f_uid
            atxt["12"] = r.t_accounts.f_gid
            atxt["13"] = r.t_accounts.f_level
            atxt["14"] = r.t_accounts.f_active
            atxt["15"] = r.t_accounts.f_source
            atxt["16"] = r.t_accounts.f_message
            atxt["17"] = r.t_accounts.f_description
            atxt["DT_RowId"] = str(r.t_accounts.id)

            aaData.append(atxt)

        result = {
            "sEcho": request.vars.sEcho,
            "iTotalDisplayRecords": db(query).count(),
            "iTotalRecords": db(db.t_accounts).count(),
            "aaData": aaData,
            "query": db._lastsql,
        }

        return result

    rows = db(db.t_accounts).select(
        db.t_accounts.f_hash1_type, groupby=db.t_accounts.f_hash1_type, cache=(cache.ram, 60)
    )
    hash_types = []
    for r in rows:
        # if r.f_hash2_type is not None:
        #    hash_types.append("%s/%s" % (r.f_hash1_type, r.f_hash2_type))
        # else:
        hash_types.append(r.f_hash1_type)

    form = TABLE(
        THEAD(
            TR(
                TH(T("C"), _width="1%"),
                TH(T("Host")),
                TH(T("Port")),
                TH(T("Username")),
                TH(T("Fullname")),
                TH(T("Domain")),
                TH(T("Password")),
                TH(T("Hash 1 Type")),
                TH(T("Hash 1")),
                TH(T("Hash 2 Type")),
                TH(T("Hash 2")),
                TH(T("UID")),
                TH(T("GID")),
                TH(T("Level")),
                TH(T("Active")),
                TH(T("Source")),
                TH(T("Message")),
                TH(T("Description")),
            )
        ),
        _class="datatable",
        _id="accounttable",
        _style="width:100%",
    )

    add = AddModal(
        db.t_accounts,
        "Add",
        "Add",
        "Add Account",
        # fields=[],
        cmd="accounttable.fnReloadAjax();",
    )
    services = db(db.t_services.f_hosts_id > 0).select(cache=(cache.ram, 30))

    svc_set = []
    for svc in services:
        svc_set.append(
            [svc.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[svc.f_hosts_id]), svc.f_proto, svc.f_number)]
        )
    db.t_accounts.f_services_id.requires = IS_IN_SET(svc_set)
    db.t_accounts.id.comment = add.create()

    return dict(form=form, hash_types=hash_types, add=add)
Beispiel #13
0
def customer_xml():
    """
    Generates an XML file suitable for Customer usage
    """

    from lxml import etree

    # grab the filter type and value if provided or from the session
    if session.hostfilter is None:
        f_type  = request.vars.f_type or None
        f_value = request.vars.f_value or None
    else:
        f_type  = session.hostfilter[0]
        f_value = session.hostfilter[1]

    location_attribute = '{%s}noNameSpaceSchemaLocation' % "http://www.w3.org/2001/XMLSchema-instance"
    kvasir_results_xml = etree.Element('KvasirResults', attrib={ location_attribute: 'kvasir.xsd', })

    summary_xml = etree.SubElement(kvasir_results_xml, 'summary')
    customer = etree.SubElement(summary_xml, 'customer')
    customer.text = settings.customer or 'CUSTOMER NAME'
    assessment = etree.SubElement(summary_xml, 'assessment')
    assessment.set('type', settings.assessment_type)
    start_date = etree.SubElement(assessment, 'start-date')
    start_date.text = settings.start_date or 'START DATE'
    end_date = etree.SubElement(assessment, 'end-date')
    end_date.text = settings.end_date or 'END DATE'

    hosts_xml = etree.SubElement(kvasir_results_xml, 'hosts')
    os_xml = etree.SubElement(kvasir_results_xml, 'os_records')
    vulns_xml = etree.SubElement(kvasir_results_xml, 'vulns')

    # this is a little hack to ensure a record is either blank or None
    # use it as "if variable not in notin:"
    notin = [ None, '' ]
    unknown_cpeid_counter = 0

    # go through each host, adding the os, services and vulns accordingly
    query = create_hostfilter_query([(f_type, f_value), False])
    for host_rec in db(query).select():
        host_xml = etree.SubElement(hosts_xml, 'host')
        host_xml.set('ipv4', host_rec.f_ipv4)
        host_xml.set('assetgroup', host_rec.f_asset_group)
        if host_rec.f_ipv6:
            host_xml.set('ipv6', host_rec.f_ipv6)
        if host_rec.f_macaddr:
            host_xml.set('macaddr', host_rec.f_macaddr)
        if host_rec.f_hostname:
            host_xml.set('hostname', host_rec.f_hostname.decode('utf-8'))
        if host_rec.f_netbios_name:
            host_xml.set('netbios', host_rec.f_netbios_name.decode('utf-8'))

        # build the os information using the highest certainty record
        highest = (0, None)
        for os_rec in db(db.t_host_os_refs.f_hosts_id == host_rec.id).select():
            if os_rec.f_certainty > highest[0]:
                highest = (os_rec.f_certainty, os_rec)

        if highest[0] > 0:
            # add os element to the host
            record = highest[1]
            os = etree.SubElement(host_xml, 'os')
            os.set('certainty', str(highest[0]))
            if record.f_class not in notin:
                os.set('class', record.f_class)
            if record.f_family not in notin:
                os.set('family', record.f_family)

            # since some os records may not have a cpe id we'll mask them with
            # using their title, replacing spaces with underscores
            t_os_rec = db.t_os[record.f_os_id]
            if t_os_rec.f_cpename in notin:
                cpeid = t_os_rec.f_title.replace(' ', '_')
            else:
                cpeid = t_os_rec.f_cpename

            os.set('id', cpeid)

            # if the id isn't in os_records, add it
            if len(os_xml.findall('.//os[@id="%s"]' % (os.get('id', None)))) < 1:
                os_info_xml = etree.SubElement(os_xml, 'os')
                os_rec = db.t_os[highest[1].f_os_id]
                os_info_xml.set('id', cpeid)
                os_info_xml.set('title', os_rec.f_title)

                if os_rec.f_vendor not in notin:
                    vendor = etree.SubElement(os_info_xml, 'vendor')
                    vendor.text = os_rec.f_vendor

                if os_rec.f_product not in notin:
                    product = etree.SubElement(os_info_xml, 'product')
                    product.text = os_rec.f_product

                if os_rec.f_version not in notin:
                    version = etree.SubElement(os_info_xml, 'version')
                    version.text = os_rec.f_version

                if os_rec.f_update not in notin:
                    update = etree.SubElement(os_info_xml, 'update')
                    update.text = os_rec.f_update

                if os_rec.f_edition not in notin:
                    edition = etree.SubElement(os_info_xml, 'edition')
                    edition.text = os_rec.f_edition

                if os_rec.f_language not in notin:
                    language = etree.SubElement(os_info_xml, 'language')
                    language.text = os_rec.f_language

        # snmp strings
        snmp_recs = db(db.t_snmp.f_hosts_id == host_rec.id).select()
        if len(snmp_recs) > 0:
            snmp_top_xml = etree.SubElement(hosts_xml, 'snmps')
            for record in snmp_recs:
                snmp_xml = etree.SubElement(snmp_top_xml, 'snmp')
                if record.f_community not in notin:
                    snmp_xml.set('community', record.f_community.decode('utf-8'))
                    snmp_xml.set('version', record.f_version)
                    snmp_xml.set('access', record.f_access)

        # netbios information
        netb_record = db(db.t_netbios.f_hosts_id == host_rec.id).select().first() or None
        if netb_record:
            netbios_xml = etree.SubElement(hosts_xml, 'netbios')
            if netb_record.f_type not in notin:
                netbios_xml.set('type', netb_record.f_type)
            if netb_record.f_domain not in notin:
                netbios_xml.set('domain', netb_record.f_domain.decode('utf-8'))
            if netb_record.f_lockout_limit not in notin:
                netbios_xml.set('lockout_limit', str(netb_record.f_lockout_limit))
            if netb_record.f_lockout_duration not in notin:
                netbios_xml.set('lockout_duration', str(netb_record.f_lockout_duration))

            if netb_record.f_advertised_names is not None:
                adv_names_xml = etree.SubElement(netbios_xml, 'advertised_names')
                for name in netb_record.f_advertised_names:
                    name_xml = etree.SubElement(adv_names_xml, 'name')
                    name.text = name.decode('utf-8')

        # build the services and vulnerabilities
        services_xml = etree.SubElement(host_xml, 'services')
        for svc_rec in db(db.t_services.f_hosts_id == host_rec.id).select():
            service_xml = etree.SubElement(services_xml, 'service')
            service_xml.set('proto', svc_rec.f_proto)
            service_xml.set('number', svc_rec.f_number)

            if svc_rec.f_name not in notin:
                name = etree.SubElement(service_xml, 'name')
                name.text = svc_rec.f_name.decode('utf-8')

            if svc_rec.f_banner not in notin:
                banner = etree.SubElement(service_xml, 'banner')
                banner.text = svc_rec.f_banner.decode('utf-8')

            # service configuration records
            svc_info_recs = db(db.t_service_info.f_services_id == svc_rec.id).select()
            if len(svc_info_recs) > 0:
                config_xml = etree.SubElement(service_xml, 'configuration')
                for info_rec in svc_info_recs:
                    rec_xml = etree.SubElement(config_xml, 'config')
                    if info_rec.f_name not in notin:
                        rec_xml.set('name', info_rec.f_name)
                        if info_rec.f_text not in notin:
                            rec_xml.text = info_rec.f_text.decode('utf-8')

            # vulnerabilities
            svc_vuln_recs = db(db.t_service_vulns.f_services_id == svc_rec.id).select()
            if len(svc_vuln_recs) > 0:
                svc_vulns_xml = etree.SubElement(service_xml, 'vulns')
                for vuln_rec in svc_vuln_recs:
                    vuln_xml = etree.SubElement(svc_vulns_xml, 'vuln')
                    vuln_xml.set('status', vuln_rec.f_status)
                    vuln_xml.set('id', db.t_vulndata[vuln_rec.f_vulndata_id].f_vulnid)
                    proof = etree.SubElement(vuln_xml, 'proof')
                    proof.text = etree.CDATA(unicode(MARKMIN(vuln_rec.f_proof).xml(), 'utf-8'))

                    # search for the nexpose id in vulns_xml
                    if len(vuln_xml.findall('.//vuln[@id="%s"]' % vuln_xml.get('id', None))) < 1:
                        new_vuln_xml = etree.SubElement(vulns_xml, 'vuln')
                        vulndata = db.t_vulndata[vuln_rec.f_vulndata_id]
                        new_vuln_xml.set('id', vulndata.f_vulnid)
                        new_vuln_xml.set('title', vulndata.f_title)
                        new_vuln_xml.set('severity', str(vulndata.f_severity))
                        new_vuln_xml.set('pci_sev', str(vulndata.f_pci_sev))
                        new_vuln_xml.set('cvss_score', vulndata.f_cvss_score)
                        new_vuln_xml.set('cvss_metric', cvss_metrics(vulndata))
                        description = etree.SubElement(new_vuln_xml, 'description')
                        description.text = etree.CDATA(unicode(MARKMIN(vulndata.f_description).xml(), 'utf-8'))
                        solution = etree.SubElement(new_vuln_xml, 'solution')
                        solution.text = etree.CDATA(unicode(MARKMIN(vulndata.f_solution).xml(), 'utf-8'))

                        # find vulnerability references and add them
                        vuln_refs = db(db.t_vuln_references.f_vulndata_id == vulndata.id).select()
                        if len(vuln_refs) > 0:
                            refs_xml = etree.SubElement(new_vuln_xml, 'references')
                            for ref_rec in vuln_refs:
                                record = db.t_vuln_refs[ref_rec.f_vuln_ref_id]
                                ref_xml = etree.SubElement(refs_xml, 'reference')
                                ref_xml.set('source', record.f_source)
                                ref_xml.text = record.f_text.decode('utf-8')

            # accounts
            accounts = db(db.t_accounts.f_services_id == svc_rec.id).select()
            if len(accounts) > 0:
                accounts_xml = etree.SubElement(service_xml, 'accounts')
                for acct_rec in accounts:
                    acct_xml = etree.SubElement(accounts_xml, 'account')

                    if acct_rec.f_username not in notin:
                        elem = etree.SubElement(acct_xml, 'username')
                        elem.text = acct_rec.f_username.decode('utf-8')

                    if acct_rec.f_fullname not in notin:
                        elem = etree.SubElement(acct_xml, 'fullname')
                        elem.text = acct_rec.f_fullname.decode('utf-8')

                    if acct_rec.f_password not in notin:
                        elem = etree.SubElement(acct_xml, 'password')
                        elem.text = acct_rec.f_password.decode('utf-8')

                    if acct_rec.f_hash1 not in notin:
                        elem = etree.SubElement(acct_xml, 'hash1')
                        elem.text = acct_rec.f_hash1

                    if acct_rec.f_hash1_type not in notin:
                        elem = etree.SubElement(acct_xml, 'hash1_type')
                        elem.text = acct_rec.f_hash1_type

                    if acct_rec.f_hash2 not in notin:
                        elem = etree.SubElement(acct_xml, 'hash2')
                        elem.text = acct_rec.f_hash2

                    if acct_rec.f_hash2_type not in notin:
                        elem = etree.SubElement(acct_xml, 'hash2_type')
                        elem.text = acct_rec.f_hash2_type

                    if acct_rec.f_uid not in notin:
                        elem = etree.SubElement(acct_xml, 'uid')
                        elem.text = acct_rec.f_uid

                    if acct_rec.f_gid not in notin:
                        elem = etree.SubElement(acct_xml, 'gid')
                        elem.text = acct_rec.f_gid

                    if acct_rec.f_level not in notin:
                        elem = etree.SubElement(acct_xml, 'level')
                        elem.text = acct_rec.f_level

                    if acct_rec.f_domain not in notin:
                        elem = etree.SubElement(acct_xml, 'domain')
                        elem.text = acct_rec.f_domain.decode('utf-8')

                    if acct_rec.f_description not in notin:
                        elem = etree.SubElement(acct_xml, 'description')
                        elem.text = acct_rec.f_description.decode('utf-8')

    result = etree.tostring(kvasir_results_xml, pretty_print=True, encoding=unicode)
    return result