Beispiel #1
0
    def save(self):
        if self.session.config.savereport:
            if len(self.session.report.keys()) > 0:

                if self.session.config.enablefilevisualization:
                    self.session.report.meta.visual.pnggray = utils.to_base64(
                        self.session.report.meta.visual.pnggray)
                    self.session.report.meta.visual.pngrgb = utils.to_base64(
                        self.session.report.meta.visual.pngrgb)
                    self.session.report.meta.visual.identicon = utils.to_base64(
                        self.session.report.meta.visual.identicon
                    ) if self.session.report.meta.visual.identicon else None

                fileutils.file_save(filename="%s/%s.json" %
                                    (self.session.config.currreportpath,
                                     self.session.config.currreportfile),
                                    data=json.dumps(self.session.report,
                                                    default=self.cast,
                                                    sort_keys=True,
                                                    encoding="latin-1"))
                if self.session.config.verbose:
                    utils.debug("Dumped reports to %s" %
                                self.session.config.currreportpath)
            else:
                utils.warn("Nothing to save! Run analyze() and then save()")
Beispiel #2
0
    def run(self, report):
        if report.misc.config.enablefilevisualization and report.meta.visual:
            fileutils.file_save(
                filename="%s/%s.pnggray" % (report.misc.config.currreportpath,
                                            report.misc.config.currreportfile),
                data=utils.from_base64(report.meta.visual.pnggray),
                mode="wb")
            fileutils.file_save(
                filename="%s/%s.pngrgb" % (report.misc.config.currreportpath,
                                           report.misc.config.currreportfile),
                data=utils.from_base64(report.meta.visual.pngrgb),
                mode="wb")
            fileutils.file_save(filename="%s/%s.bfh" %
                                (report.misc.config.currreportpath,
                                 report.misc.config.currreportfile),
                                data=report.meta.visual.bytefreqhistogram,
                                mode="wb")
            if report.meta.visual.identicon:
                fileutils.file_save(filename="%s/%s.identicon" %
                                    (report.misc.config.currreportpath,
                                     report.misc.config.currreportfile),
                                    data=utils.from_base64(
                                        report.meta.visual.identicon),
                                    mode="wb")

        return
Beispiel #3
0
 def run(self, report):
     if report.meta.subfiles and len(report.meta.subfiles) > 1:
         with open(report.meta.filename, "rb") as fo:
             filedata = fo.read()
         for entry in report.meta.subfiles:
             if entry["offset"] > 0 and entry["size"] and entry["size"] > 0:
                 fileutils.file_save(
                     filename="%s/%s_%s" %
                     (report.misc.config.currreportpath,
                      report.misc.config.currreportfile,
                      entry["hashes"]["sha256"]),
                     data=filedata[entry["offset"]:entry["offset"] +
                                   entry["size"]],
                     mode="w" if "text" in entry["mimetype"] else "wb")
     return
Beispiel #4
0
    def run(self, report):
        if self.details[
                "mimetypes"] and report.meta.filemimetype in self.details[
                    "mimetypes"]:
            if report.pe.static.overlay and report.pe.static.overlay.size:
                with open(report.meta.filename, "rb") as fo:
                    filedata = fo.read()
                fileutils.file_save(
                    filename="%s/%s.overlay" %
                    (report.misc.config.currreportpath,
                     report.misc.config.currreportfile),
                    data=filedata[report.pe.static.overlay.
                                  offset:report.pe.static.overlay.offset +
                                  report.pe.static.overlay.size],
                    mode="w" if report.pe.static.overlay.mimetype
                    and "text" in report.pe.static.overlay.mimetype else "wb")

        return
    def run(self, report):
        if self.details[
                "mimetypes"] and report.meta.filemimetype in self.details[
                    "mimetypes"]:
            if report.pe.static.authenticode:
                if report.pe.static.authenticode.offset > 0 and report.pe.static.authenticode.size > 0:
                    with open(report.meta.filename, "rb") as fo:
                        filedata = fo.read()
                    authenticoderaw = filedata[
                        report.pe.static.authenticode.
                        offset:report.pe.static.authenticode.offset +
                        report.pe.static.authenticode.size]
                    mtype = utils.data_mimetype(authenticoderaw)
                    mode = "w" if mtype and "text" in mtype else "wb"
                    fileutils.file_save(filename="%s/%s.der" %
                                        (report.misc.config.currreportpath,
                                         report.misc.config.currreportfile),
                                        data=authenticoderaw,
                                        mode=mode)

        return
Beispiel #6
0
    def run(self, report):
        if self.details[
                "mimetypes"] and report.meta.filemimetype in self.details[
                    "mimetypes"]:
            htmldata = ""
            htmlstarts = """<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link href="http://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,700" rel="stylesheet" type="text/css" />

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css" integrity="sha384-aUGj/X2zp5rLCbBxumKTCw2Z50WgIr1vs/PFN4praOTvYXWlVyh2UtNUU0KAUhAX" crossorigin="anonymous">
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script>

    <!-- Include jQuery (Syntax Highlighter Requirement) -->
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <!-- Include jQuery Syntax Highlighter -->
    <script type="text/javascript" src="http://balupton.github.com/jquery-syntaxhighlighter/scripts/jquery.syntaxhighlighter.min.js"></script>
    <!-- Initialise jQuery Syntax Highlighter -->
    <script type="text/javascript">$.SyntaxHighlighter.init();</script>
    <!-- Initialise jQuery Syntax Highlighter -->
    <script type="text/javascript">
      $.SyntaxHighlighter.init({
        'wrapLines':true,
        'lineNumbers':false,
        'theme':'doxy'
      });
    </script>

    <style>
      body {
        font-family: "Roboto", "Helvetica Neue", Helvetica, Arial;
        background: url("/media/img/sandstone/bg-gradient-sand.26ec6264163e.png") repeat-x scroll 0% 0%, url("/media/img/sandstone/bg-sand.5f2ca98ac180.png") repeat scroll 0% 0%, #2D2D2D none repeat scroll 0% 0%;}div#hmenu {margin: 0;padding: .3em 0 .3em 0;width: 100%;text-align: center;}div#hmenu ul {list-style: none;margin: 0;padding: 0;}div#hmenu ul li {margin: 0;padding: 0;display: inline;}div#hmenu ul a:link {margin: 0;padding: .3em .4em .3em .4em;text-decoration: none;font-weight: bold;font-size: medium;}div#hmenu ul a:visited {margin: 0;padding: .3em .4em .3em .4em;text-decoration: none;font-weight: bold;font-size: medium;}div#hmenu ul a:active {margin: 0;padding: .3em .4em .3em .4em;text-decoration: none;font-weight: bold;font-size: medium;}div#hmenu ul a:hover {margin: 0;padding: .3em .4em .3em .4em;text-decoration: none;font-weight: bold;font-size: medium;}a {outline: 0;}.values {padding: 2px 4px;text-decoration: none;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.sectionheader {background-color: #F8F8F8;border-color: #E7E7E7;border-style: dashed;border-width: 1px;border-radius: 3px;padding: 5px;}.highlight_cts {color: #A94442;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.highlight_stc {color: #337AB7;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.highlight_def {padding: 2px 4px;text-decoration: none;font-size: 110%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.scroll_cts {overflow: auto;white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;max-height: 200px;color: #A94442;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.scroll_stc {overflow: auto;white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;max-height: 200px;color: #337AB7;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.scroll_def {overflow: auto;white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;max-height: 200px;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}th {background-color:#f5f5f5;}td {text-decoration: none;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}
      }
    </style>
    <title>{{TITLE}}</title>
  </head>
  <body>
    <br/>
    <div class="container-fluid">""".replace("{{TITLE}}",
                                             report.meta.hashes["sha256"])

            htmlends = """    </div>

  <footer class="footer">
    <div class="container"><center><b>
      <p class="text-muted">
        Generated on %s via Rudra v%s.<br/>This work is under <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA</a>. To report issues, reach out: <a href="mailto://[email protected]">7h3rAm</a>
      </p>
    </b></center></div>
  </footer>

  </body>
</html>""" % (utils.current_datetime_string(), report.misc.config.version)

            htmldata = "%s\n" % (htmlstarts)

            if report.meta:
                borderflag = False
                headerflag = False
                padwidth = 1
                # show file metainfo
                metasummarytab = PrettyTable(["Attribute", "Value"])
                metasummarytab.border = borderflag
                metasummarytab.header = headerflag
                metasummarytab.padding_width = padwidth
                metasummarytab.align["Attribute"] = "l"
                metasummarytab.align["Value"] = "l"
                metasummarytab.add_row(["File", report.meta.filebasename])
                metasummarytab.add_row(["Location", report.meta.filedirname])
                metasummarytab.add_row(["MIMEType", report.meta.filemimetype])
                metasummarytab.add_row(["Magic", report.meta.filemagic])
                metasummarytab.add_row(["Size", report.meta.filesize])
                metasummarytab.add_row([
                    "Minsize",
                    "%s (%s%%)" %
                    (report.meta.fileminsize, report.meta.filecompressionratio)
                ])
                if report.meta.fileentropycategory in ["SUSPICIOUS", "PACKED"]:
                    metasummarytab.add_row([
                        "Entropy",
                        "%s <span class='label label-warning'>%s</span>" %
                        (report.meta.fileentropy,
                         report.meta.fileentropycategory)
                    ])
                else:
                    metasummarytab.add_row([
                        "Entropy",
                        "%s <span class='label label-info'>%s</span>" %
                        (report.meta.fileentropy,
                         report.meta.fileentropycategory)
                    ])

                robotab = """

<div class="col-md-2">
  <table class="table table-condensed table-hover table-striped">
    <tr rowspan="7" >
      <td><center><a href="%s.identicon"><img src="%s.identicon" height="200" width="200" title="identicon for %s"></a></center></td>
    </tr>
  </table>
</div>

""" % (report.misc.config.currreportfile, report.misc.config.currreportfile,
                report.misc.config.currreportfile)

                normalizeddata = metasummarytab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Meta Information</strong></div>\n<div class='panel-body'>\n<div class='row'>\n%s<div class='col-md-10'>\n<table class='table table-condensed table-hover table-striped'>"
                    % robotab)
                htmldata += "%s\n" % (normalizeddata)

                visual = """
<div class="panel panel-info">
<div class="panel-heading"><strong>Visual</strong></div>
<div class="panel-body">
<div class="row">
<table class="table">
  <tr>
    <div class="col-md-3">
      <td><center><a href="%s.pnggray"><img src="%s.pnggray" height="522" width="256" title="Byte representation in grayscale"></a></center></td>
    </div>
    <div class="col-md-3">
      <td><center><a href="%s.pngrgb"><img src="%s.pngrgb" height="522" width="256" title="Byte representation in RGB"></a></center></td>
    </div>
    <div class="col-md-6">
      <td><center><a href="%s.bfh" title="Byte frequency histogram">%s</a></center></td>
    </div>
  </tr>
</table>
</div></div></div>\n"""

                htmldata += "%s\n" % (visual %
                                      (report.misc.config.currreportfile,
                                       report.misc.config.currreportfile,
                                       report.misc.config.currreportfile,
                                       report.misc.config.currreportfile,
                                       report.misc.config.currreportfile,
                                       report.meta.visual.bytefreqhistogram))

            # show hashes
            hashtab = PrettyTable(["Hash", "Value"])
            hashtab.border = borderflag
            hashtab.header = headerflag
            hashtab.padding_width = 1
            hashtab.align["Hash"] = "l"
            hashtab.align["Value"] = "l"
            hashtab.add_row(["CRC32", report.meta.hashes["crc32"]])
            hashtab.add_row(["MD5", report.meta.hashes["md5"]])
            hashtab.add_row(["SHA128", report.meta.hashes["sha1"]])
            hashtab.add_row(["SHA256", report.meta.hashes["sha256"]])
            hashtab.add_row(["SSDEEP", report.meta.hashes["ssdeep"]])
            hashtab.add_row(["Imphash", report.pe.static.hashes.imphash])
            hashtab.add_row(["PEhash", report.pe.static.hashes.pehash])
            normalizeddata = hashtab.get_html_string(
            ).replace("&lt;", "<").replace("&gt;", ">").replace(
                "&amp;", "&"
            ).replace("</table>", "</table></div></div></div></div>").replace(
                "<table>",
                "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Hashes</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
            )
            htmldata += "%s\n" % (normalizeddata)

            # show header and meta info
            pemetatab = PrettyTable(["Atrribute", "Value"])
            pemetatab.border = borderflag
            pemetatab.header = headerflag
            pemetatab.padding_width = padwidth
            pemetatab.align["Atrribute"] = "l"
            pemetatab.align["Value"] = "l"
            if report.pe.static.versioninfo:
                if report.pe.static.versioninfo.FileVersion:
                    pemetatab.add_row(
                        ["Version", report.pe.static.versioninfo.FileVersion])
                if report.pe.static.versioninfo.FileDescription:
                    pemetatab.add_row([
                        "Description",
                        report.pe.static.versioninfo.FileDescription
                    ])
                if report.pe.static.versioninfo.OriginalFilename:
                    pemetatab.add_row([
                        "OriginalFilename",
                        report.pe.static.versioninfo.OriginalFilename
                    ])
                if report.pe.static.versioninfo.CompanyName:
                    pemetatab.add_row([
                        "CompanyName", report.pe.static.versioninfo.CompanyName
                    ])
                if report.pe.static.versioninfo.LegalCopyright:
                    pemetatab.add_row([
                        "LegalCopyright",
                        report.pe.static.versioninfo.LegalCopyright
                    ])
                if report.pe.static.versioninfo.Language_verbose:
                    pemetatab.add_row([
                        "Language",
                        report.pe.static.versioninfo.Language_verbose
                    ])
            if report.pe.static:
                pemetatab.add_row([
                    "Magic",
                    report.pe.static.ntheaders.optionalheader.Magic_verbose
                ])
                pemetatab.add_row([
                    "Machine",
                    report.pe.static.ntheaders.fileheader.Machine_verbose
                ])
                pemetatab.add_row([
                    "Subsystem",
                    report.pe.static.ntheaders.optionalheader.Subsystem_verbose
                ])
                pemetatab.add_row([
                    "Compiletime",
                    report.pe.static.ntheaders.fileheader.TimeDateStamp_verbose
                ])
                pemetatab.add_row([
                    "Entrypoint",
                    "0x%x" % report.pe.static.ntheaders.optionalheader.
                    AddressOfEntryPoint if report.pe.static.ntheaders.
                    optionalheader.AddressOfEntryPoint else 0
                ])
                pemetatab.add_row([
                    "ImageBase",
                    "0x%x" %
                    report.pe.static.ntheaders.optionalheader.ImageBase if
                    report.pe.static.ntheaders.optionalheader.ImageBase else 0
                ])
                pemetatab.add_row([
                    "Sections",
                    "0x%x" %
                    report.pe.static.ntheaders.fileheader.NumberOfSections
                    if report.pe.static.ntheaders.fileheader.NumberOfSections
                    else 0
                ])
                pemetatab.add_row([
                    "Checksum",
                    "0x%x" %
                    report.pe.static.ntheaders.optionalheader.CheckSum if
                    report.pe.static.ntheaders.optionalheader.CheckSum else 0
                ])
            normalizeddata = pemetatab.get_html_string(
            ).replace("&lt;", "<").replace("&gt;", ">").replace(
                "&amp;", "&"
            ).replace("</table>", "</table></div></div></div></div>").replace(
                "<table>",
                "<div class='panel panel-info'>\n<div class='panel-heading'><strong>PE Information</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
            )
            htmldata += "%s\n" % (normalizeddata)

            # show PE indicators
            if report.pe.indicators.checks:
                indicatorstab = PrettyTable(
                    ["Indicator", "Classification", "Reason"])
                indicatorstab.border = borderflag
                indicatorstab.header = headerflag
                indicatorstab.header = True
                indicatorstab.padding_width = padwidth
                indicatorstab.align["Indicator"] = "l"
                indicatorstab.align["Classification"] = "l"
                indicatorstab.align["Reason"] = "l"
                for indicator in report.pe.indicators.checks.keys():
                    if "classification" in report.pe.indicators.checks[
                            indicator] and report.pe.indicators.checks[
                                indicator]["classification"] in ["SUSPICIOUS"]:
                        # indicator reason could include unicode chars (section names, etc.) and as such need sanitization before printing
                        # http://stackoverflow.com/questions/2365411/python-convert-unicode-to-ascii-without-errors
                        indicatorstab.add_row([
                            indicator,
                            "<span class='label label-warning'>%s</span>" %
                            (report.pe.indicators.checks[indicator]
                             ["classification"].decode("windows-1252").encode(
                                 "ascii", "ignore")),
                            "%s" %
                            report.pe.indicators.checks[indicator]["reason"].
                            decode("windows-1252").encode("ascii", "ignore")
                        ])
                    else:
                        indicatorstab.add_row([
                            indicator,
                            "<span class='label label-info'>%s</span>" %
                            (report.pe.indicators.checks[indicator]
                             ["classification"].decode("windows-1252").encode(
                                 "ascii", "ignore")),
                            "%s" %
                            report.pe.indicators.checks[indicator]["reason"].
                            decode("windows-1252").encode("ascii", "ignore")
                        ])
                normalizeddata = indicatorstab.get_html_string(
                    sortby="Indicator", reversesort=False
                ).replace("&lt;", "<").replace("&gt;", ">").replace(
                    "&amp;", "&"
                ).replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Indicators</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            # show PE warnings
            if report.pe.indicators.warnings:
                warningstab = PrettyTable(["Warnings"])
                warningstab.border = borderflag
                warningstab.header = headerflag
                warningstab.padding_width = padwidth
                warningstab.align["Warnings"] = "l"
                for warning in report.pe.indicators.warnings:
                    warningstab.add_row([warning])
                normalizeddata = warningstab.get_html_string(
                    sortby="Warnings", reversesort=False
                ).replace("&lt;", "<").replace("&gt;", ">").replace(
                    "&amp;", "&"
                ).replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Warnings</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            # show PE flags
            if report.pe.indicators.flags:
                flagtab = PrettyTable(["Flag", "Status"])
                flagtab.border = borderflag
                flagtab.header = headerflag
                flagtab.padding_width = padwidth
                flagtab.align["Flag"] = "l"
                flagtab.align["Status"] = "l"
                onflags, offflags = list(), list()
                for flag in report.pe.indicators.flags.keys():
                    if report.pe.indicators.flags[flag]:
                        onflags.append(flag)
                    else:
                        offflags.append(flag)
                flagtab.add_row(["ON", ", ".join(sorted(onflags))])
                flagtab.add_row(["OFF", ", ".join(sorted(offflags))])

                normalizeddata = flagtab.get_html_string(
                    sortby="Status", reversesort=True
                ).replace("&lt;", "<").replace("&gt;", ">").replace(
                    "&amp;", "&"
                ).replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Flags</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            # show PE authenticode details
            if report.pe.static.authenticode and report.pe.static.authenticode.size:
                authenticodetab = PrettyTable(["Atrribute", "Value"])
                authenticodetab.border = borderflag
                authenticodetab.header = headerflag
                authenticodetab.padding_width = padwidth
                authenticodetab.align["Atrribute"] = "l"
                authenticodetab.align["Value"] = "l"
                if hasattr(report.pe.static.authenticode,
                           "certs") and report.pe.static.authenticode.certs:
                    for certentry in report.pe.static.authenticode.certs:
                        authenticodetab.add_row(
                            ["Issuer", certentry["issuer"]])
                        authenticodetab.add_row(
                            ["Subject", certentry["subject"]])
                        authenticodetab.add_row([
                            "Validity",
                            "%s - %s" %
                            (certentry["notbefore"], certentry["notafter"])
                        ])
                        authenticodetab.add_row(["", ""])
                normalizeddata = authenticodetab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Authenticode</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            # show PE section details
            if report.pe.static.ntheaders.sections:
                sectiontab = PrettyTable([
                    "Name", "VirtualAddress", "VirtualSize", "SizeOfRawData",
                    "Entropy", "Permission", "Classification", "Reason"
                ])
                sectiontab.border = borderflag
                sectiontab.header = True
                sectiontab.padding_width = padwidth
                sectiontab.align["Name"] = "l"
                for entry in report.pe.static.ntheaders.sections:
                    secname = entry.keys()[0]
                    reasons = "\n".join(
                        entry[secname].classificationreasons
                    ) if entry[secname].classificationreasons else ""
                    sectiontab.add_row([secname, "0x%x" % entry[secname].VirtualAddress, "0x%x" % entry[secname].Misc_VirtualSize, \
                      "0x%x" % entry[secname].SizeOfRawData, entry[secname].entropy, entry[secname].permissions, \
                      "<span class='label label-info'>%s</span>" % (entry[secname].classification) if entry[secname].classification == "CLEAN" else "<span class='label label-warning'>%s</span>" % (entry[secname].classification),
                      reasons])
                normalizeddata = sectiontab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Sections</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            # show PE data directories
            if report.pe.static.ntheaders.datadirectory:
                datadirtab = PrettyTable(
                    ["Name", "Section", "Size", "VirtualAddress"])
                datadirtab.border = borderflag
                datadirtab.header = True
                datadirtab.padding_width = padwidth
                datadirtab.align["Name"] = "l"
                for datadir in report.pe.static.ntheaders.datadirectory:
                    datadirtab.add_row([
                        datadir["Name"], datadir["Section"],
                        "0x%x" % datadir["Size"],
                        "0x%x" % datadir["VirtualAddress"]
                    ])
                normalizeddata = datadirtab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Data Directories</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

                # show stack/heap reserve/commit size
                memsizetab = PrettyTable(["Area", "CommitSize", "ReserveSize"])
                memsizetab.border = borderflag
                memsizetab.header = True
                memsizetab.padding_width = padwidth
                memsizetab.align["CommitSize"] = "l"
                memsizetab.align["ReserveSize"] = "l"
                memsizetab.add_row([
                    "Stack",
                    "0x%x" %
                    report.pe.static.ntheaders.optionalheader.SizeOfStackCommit
                    if
                    report.pe.static.ntheaders.optionalheader.SizeOfStackCommit
                    else 0,
                    "0x%x" % report.pe.static.ntheaders.optionalheader.
                    SizeOfStackReserve if report.pe.static.ntheaders.
                    optionalheader.SizeOfStackReserve else 0
                ])
                memsizetab.add_row([
                    "Heap",
                    "0x%x" %
                    report.pe.static.ntheaders.optionalheader.SizeOfHeapCommit
                    if
                    report.pe.static.ntheaders.optionalheader.SizeOfHeapCommit
                    else 0,
                    "0x%x" %
                    report.pe.static.ntheaders.optionalheader.SizeOfHeapReserve
                    if
                    report.pe.static.ntheaders.optionalheader.SizeOfHeapReserve
                    else 0
                ])
                normalizeddata = memsizetab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Memory Allocations</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            if report.pe.scan.adobemalwareclassifier:
                adobetab = PrettyTable(["Algorithm", "Classification"])
                adobetab.border = borderflag
                adobetab.header = True
                adobetab.padding_width = padwidth
                adobetab.align["Algorithm"] = "l"
                for algorithm in report.pe.scan.adobemalwareclassifier:
                    if report.pe.scan.adobemalwareclassifier[
                            algorithm] == "CLEAN":
                        adobetab.add_row([
                            algorithm,
                            "<span class='label label-info'>%s</span>" %
                            report.pe.scan.adobemalwareclassifier[algorithm]
                        ])
                    else:
                        adobetab.add_row([
                            algorithm,
                            "<span class='label label-warning'>%s</span>" %
                            report.pe.scan.adobemalwareclassifier[algorithm]
                        ])
                normalizeddata = adobetab.get_html_string(
                    sortby="Algorithm", reversesort=False
                ).replace("&lt;", "<").replace("&gt;", ">").replace(
                    "&amp;", "&"
                ).replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Adobe Malware Classifier</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            if report.pe.scan.antivm:
                antivmtab = PrettyTable(["StartEnd", "Name"])
                antivmtab.border = borderflag
                antivmtab.header = headerflag
                antivmtab.padding_width = padwidth
                antivmtab.align["Name"] = "l"
                for entry in report.pe.scan.antivm:
                    antivmtab.add_row([
                        "[%d:%d]" % (entry["start"], entry["end"]),
                        entry["name"]
                    ])
                normalizeddata = antivmtab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>AntiVM</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            if report.pe.scan.mutex:
                mutextab = PrettyTable(["Mutex", "Threat"])
                mutextab.border = borderflag
                mutextab.header = True
                mutextab.padding_width = padwidth
                mutextab.align["Mutex"] = "l"
                for entry in report.pe.scan.mutex:
                    mutextab.add_row([entry["value"], entry["threat"]])
                normalizeddata = mutextab.get_html_string(
                    sortby="Mutex", reversesort=False
                ).replace("&lt;", "<").replace("&gt;", ">").replace(
                    "&amp;", "&"
                ).replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Mutexes</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            if report.pe.scan.regex:
                regextab = PrettyTable(["StartEnd", "Description"])
                regextab.border = borderflag
                regextab.header = True
                regextab.padding_width = padwidth
                regextab.align["Name"] = "l"
                for entry in report.pe.scan.regex:
                    regextab.add_row([
                        "[%d:%d]" % (entry["start"], entry["end"]),
                        entry["description"]
                    ])
                result = regextab.get_string()
                normalizeddata = regextab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Regexes</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            if report.pe.scan.shellcode:
                shellcodetab = PrettyTable(["Attribute", "Value"])
                shellcodetab.border = borderflag
                shellcodetab.header = headerflag
                shellcodetab.padding_width = padwidth
                shellcodetab.align["Attribute"] = "l"
                shellcodetab.align["Value"] = "l"
                scantab.add_row(
                    ["Offset",
                     "0x%x" % report.pe.scan.shellcode.offset])
                scantab.add_row(["Profile", report.pe.scan.shellcode.profile])
                normalizeddata = shellcodetab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Shellcode</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            if report.pe.scan.online and report.pe.scan.online["virustotal"]:
                virustotaltab = PrettyTable(["ScanDate", "Score"])
                virustotaltab.border = borderflag
                virustotaltab.header = headerflag
                virustotaltab.padding_width = padwidth
                virustotaltab.align["ScanDate"] = "l"
                virustotaltab.align["Score"] = "l"
                virustotaltab.add_row([
                    "%s" % report.pe.scan.online["virustotal"]["filereport"]
                    ["scan_date"],
                    "%d/%d" %
                    (report.pe.scan.online["virustotal"]["filereport"]
                     ["positives"], report.pe.scan.online["virustotal"]
                     ["filereport"]["total"])
                ])
                normalizeddata = virustotaltab.get_html_string().replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>VirusTotal</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            if report.pe.scan.whitelist:
                whitelisttab = PrettyTable(["Source", "Status"])
                whitelisttab.border = borderflag
                whitelisttab.header = True
                whitelisttab.padding_width = padwidth
                whitelisttab.align["Source"] = "l"
                whitelisttab.align["Status"] = "l"
                whitelisttab.add_row([
                    "NSRL", "<span class='label label-info'>FOUND</span>"
                    if report.pe.scan.whitelist["nsrl"] else
                    "<span class='label label-warning'>NOTFOUND</span>"
                ])
                whitelisttab.add_row([
                    "Mandiant", "<span class='label label-info'>FOUND</span>"
                    if report.pe.scan.whitelist["mandiant"] else
                    "<span class='label label-warning'>NOTFOUND</span>"
                ])
                normalizeddata = whitelisttab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Whitelist</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            if report.pe.scan.yara:
                yaratab = PrettyTable(["Rule", "Description", "Tags"])
                yaratab.border = borderflag
                yaratab.header = True
                yaratab.padding_width = padwidth
                yaratab.align["Rule"] = "l"
                yaratab.align["Description"] = "l"
                yaratab.align["Tags"] = "l"
                for rulename in report.pe.scan.yara.keys():
                    desc = report.pe.scan.yara[rulename][
                        "description"] if "description" in report.pe.scan.yara[
                            rulename].keys() and report.pe.scan.yara[rulename][
                                "description"] else ""
                    tags = ", ".join(
                        report.pe.scan.yara[rulename]["tags"]
                    ) if "tags" in report.pe.scan.yara[rulename].keys(
                    ) and report.pe.scan.yara[rulename]["tags"] else ""
                    yaratab.add_row([rulename, desc, tags])
                normalizeddata = yaratab.get_html_string(
                    sortby="Rule", reversesort=False
                ).replace("&lt;", "<").replace("&gt;", ">").replace(
                    "&amp;", "&"
                ).replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Yara</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            htmldata += "%s" % (htmlends)

            thregex = re.compile(r"<tr>(\s+)<td>(.*)</td>")
            htmldata = thregex.sub(r"<tr>\1<th class='col-md-2'>\2</th>",
                                   htmldata)
            tdregex = re.compile(r"<td>(.*)</td>")
            normalizedhtmldata = tdregex.sub(
                r"<td class='highlight_def'>\1</td>", htmldata)

            fileutils.file_save(filename="%s/%s.html" %
                                (report.misc.config.currreportpath,
                                 report.misc.config.currreportfile),
                                data="%s" % (normalizedhtmldata),
                                mode="w")
Beispiel #7
0
    def run(self, report):
        if self.details[
                "mimetypes"] and report.meta.filemimetype in self.details[
                    "mimetypes"]:
            htmldata = ""
            htmlstarts = """<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link href="http://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,700" rel="stylesheet" type="text/css" />

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css" integrity="sha384-aUGj/X2zp5rLCbBxumKTCw2Z50WgIr1vs/PFN4praOTvYXWlVyh2UtNUU0KAUhAX" crossorigin="anonymous">
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script>

    <!-- Include jQuery (Syntax Highlighter Requirement) -->
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <!-- Include jQuery Syntax Highlighter -->
    <script type="text/javascript" src="http://balupton.github.com/jquery-syntaxhighlighter/scripts/jquery.syntaxhighlighter.min.js"></script>
    <!-- Initialise jQuery Syntax Highlighter -->
    <script type="text/javascript">$.SyntaxHighlighter.init();</script>
    <!-- Initialise jQuery Syntax Highlighter -->
    <script type="text/javascript">
      $.SyntaxHighlighter.init({
        'wrapLines':true,
        'lineNumbers':false,
        'theme':'doxy'
      });
    </script>

    <style>
      body {
        font-family: "Roboto", "Helvetica Neue", Helvetica, Arial;
        background: url("/media/img/sandstone/bg-gradient-sand.26ec6264163e.png") repeat-x scroll 0% 0%, url("/media/img/sandstone/bg-sand.5f2ca98ac180.png") repeat scroll 0% 0%, #2D2D2D none repeat scroll 0% 0%;}div#hmenu {margin: 0;padding: .3em 0 .3em 0;width: 100%;text-align: center;}div#hmenu ul {list-style: none;margin: 0;padding: 0;}div#hmenu ul li {margin: 0;padding: 0;display: inline;}div#hmenu ul a:link {margin: 0;padding: .3em .4em .3em .4em;text-decoration: none;font-weight: bold;font-size: medium;}div#hmenu ul a:visited {margin: 0;padding: .3em .4em .3em .4em;text-decoration: none;font-weight: bold;font-size: medium;}div#hmenu ul a:active {margin: 0;padding: .3em .4em .3em .4em;text-decoration: none;font-weight: bold;font-size: medium;}div#hmenu ul a:hover {margin: 0;padding: .3em .4em .3em .4em;text-decoration: none;font-weight: bold;font-size: medium;}a {outline: 0;}.values {padding: 2px 4px;text-decoration: none;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.sectionheader {background-color: #F8F8F8;border-color: #E7E7E7;border-style: dashed;border-width: 1px;border-radius: 3px;padding: 5px;}.highlight_cts {color: #A94442;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.highlight_stc {color: #337AB7;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.highlight_def {padding: 2px 4px;text-decoration: none;font-size: 110%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.scroll_cts {overflow: auto;white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;max-height: 200px;color: #A94442;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.scroll_stc {overflow: auto;white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;max-height: 200px;color: #337AB7;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}.scroll_def {overflow: auto;white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;max-height: 200px;padding: 2px 4px;text-decoration: none;font-size: 90%;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}th {background-color:#f5f5f5;}td {text-decoration: none;font-weight: bold;font-family: Menlo, Monaco, Consolas, "Courier New", monospace;}
      }
    </style>
    <title>{{TITLE}}</title>
  </head>
  <body>
    <br/>
    <div class="container-fluid">""".replace("{{TITLE}}",
                                             report.meta.hashes["sha256"])

            htmlends = """    </div>

  <footer class="footer">
    <div class="container"><center><b>
      <p class="text-muted">
        Generated on %s via Rudra v%s.<br/>This work is under <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA</a>. To report issues, reach out: <a href="mailto://[email protected]">7h3rAm</a>
      </p>
    </b></center></div>
  </footer>

  </body>
</html>""" % (utils.current_datetime_string(), report.misc.config.version)

            htmldata = "%s\n" % (htmlstarts)

            if report.meta:
                borderflag = False
                headerflag = False
                padwidth = 1
                # show file metainfo
                metasummarytab = PrettyTable(["Attribute", "Value"])
                metasummarytab.border = borderflag
                metasummarytab.header = headerflag
                metasummarytab.padding_width = padwidth
                metasummarytab.align["Attribute"] = "l"
                metasummarytab.align["Value"] = "l"
                metasummarytab.add_row(["File", report.meta.filebasename])
                metasummarytab.add_row(["Location", report.meta.filedirname])
                metasummarytab.add_row(["MIMEType", report.meta.filemimetype])
                metasummarytab.add_row(["Magic", report.meta.filemagic])
                metasummarytab.add_row(["Size", report.meta.filesize])
                metasummarytab.add_row([
                    "Minsize",
                    "%s (%s%%)" %
                    (report.meta.fileminsize, report.meta.filecompressionratio)
                ])
                if report.meta.fileentropycategory in ["SUSPICIOUS", "PACKED"]:
                    metasummarytab.add_row([
                        "Entropy",
                        "%s <span class='label label-warning'>%s</span>" %
                        (report.meta.fileentropy,
                         report.meta.fileentropycategory)
                    ])
                else:
                    metasummarytab.add_row([
                        "Entropy",
                        "%s <span class='label label-info'>%s</span>" %
                        (report.meta.fileentropy,
                         report.meta.fileentropycategory)
                    ])

                robotab = """

<div class="col-md-2">
  <table class="table table-condensed table-hover table-striped">
    <tr rowspan="7" >
      <td><center><a href="%s.identicon"><img src="%s.identicon" height="200" width="200" title="identicon for %s"></a></center></td>
    </tr>
  </table>
</div>

""" % (report.misc.config.currreportfile, report.misc.config.currreportfile,
                report.misc.config.currreportfile)

                normalizeddata = metasummarytab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Meta Information</strong></div>\n<div class='panel-body'>\n<div class='row'>\n%s<div class='col-md-10'>\n<table class='table table-condensed table-hover table-striped'>"
                    % robotab)
                htmldata += "%s\n" % (normalizeddata)

                visual = """
<div class="panel panel-info">
<div class="panel-heading"><strong>Visual</strong></div>
<div class="panel-body">
<div class="row">
<table class="table">
  <tr>
    <div class="col-md-3">
      <td><center><a href="%s.pnggray"><img src="%s.pnggray" height="522" width="256" title="Byte representation in grayscale"></a></center></td>
    </div>
    <div class="col-md-3">
      <td><center><a href="%s.pngrgb"><img src="%s.pngrgb" height="522" width="256" title="Byte representation in RGB"></a></center></td>
    </div>
    <div class="col-md-6">
      <td><center><a href="%s.bfh" title="Byte frequency histogram">%s</a></center></td>
    </div>
  </tr>
</table>
</div></div></div>\n"""

                htmldata += "%s\n" % (visual %
                                      (report.misc.config.currreportfile,
                                       report.misc.config.currreportfile,
                                       report.misc.config.currreportfile,
                                       report.misc.config.currreportfile,
                                       report.misc.config.currreportfile,
                                       report.meta.visual.bytefreqhistogram))

            # show hashes
            hashtab = PrettyTable(["Hash", "Value"])
            hashtab.border = borderflag
            hashtab.header = headerflag
            hashtab.padding_width = 1
            hashtab.align["Hash"] = "l"
            hashtab.align["Value"] = "l"
            hashtab.add_row(["CRC32", report.meta.hashes["crc32"]])
            hashtab.add_row(["MD5", report.meta.hashes["md5"]])
            hashtab.add_row(["SHA128", report.meta.hashes["sha1"]])
            hashtab.add_row(["SHA256", report.meta.hashes["sha256"]])
            hashtab.add_row(["SSDEEP", report.meta.hashes["ssdeep"]])
            normalizeddata = hashtab.get_html_string(
            ).replace("&lt;", "<").replace("&gt;", ">").replace(
                "&amp;", "&"
            ).replace("</table>", "</table></div></div></div></div>").replace(
                "<table>",
                "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Hashes</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
            )
            htmldata += "%s\n" % (normalizeddata)

            # show pcap stats
            if report.pcap.parsed.stats:
                statstab = PrettyTable(["Attribute", "Value"])
                statstab.border = borderflag
                statstab.header = headerflag
                statstab.padding_width = padwidth
                statstab.align["Attribute"] = "l"
                statstab.align["Value"] = "l"
                statstab.add_row(
                    ["Magic", report.pcap.parsed.stats["pcapmagic"]])
                statstab.add_row([
                    "Encapsulation",
                    report.pcap.parsed.stats["pcapencapsulation"]
                ])
                statstab.add_row(
                    ["Snaplen", report.pcap.parsed.stats["snaplen"]])
                statstab.add_row([
                    "Starttime", report.pcap.parsed.stats["capturestarttime"]
                ])
                statstab.add_row(
                    ["Endtime", report.pcap.parsed.stats["captureendtime"]])
                statstab.add_row(
                    ["Duration", report.pcap.parsed.stats["captureduration"]])
                statstab.add_row(
                    ["Bitrate", report.pcap.parsed.stats["bitrate"]])
                statstab.add_row(
                    ["Byterate", report.pcap.parsed.stats["byterate"]])
                statstab.add_row(
                    ["Bytescount", report.pcap.parsed.stats["bytescount"]])
                statstab.add_row(
                    ["Packetscount", report.pcap.parsed.stats["packetscount"]])
                statstab.add_row([
                    "Packetrate (avg.)",
                    report.pcap.parsed.stats["avgpacketrate"]
                ])
                statstab.add_row([
                    "Packetsize (avg.)",
                    report.pcap.parsed.stats["avgpacketsize"]
                ])
                normalizeddata = statstab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Pcap Stats</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            if report.pcap.parsed.counts:
                countstab = PrettyTable(
                    ["Protocol/Direction", "Bytes", "Packets", "Bytes/Packet"])
                countstab.border = borderflag
                countstab.header = headerflag
                countstab.header = True
                countstab.padding_width = padwidth
                countstab.align["Protocol/Direction"] = "l"
                countstab.align["Bytes"] = "l"
                countstab.align["Packets"] = "l"
                countstab.align["Bytes/Packet"] = "l"
                countstab.add_row([
                    "CTS", report.pcap.parsed.counts["ctsbytes"],
                    report.pcap.parsed.counts["ctspackets"],
                    report.pcap.parsed.counts["ctsbytesperpacket"]
                ])
                countstab.add_row([
                    "STC", report.pcap.parsed.counts["stcbytes"],
                    report.pcap.parsed.counts["stcpackets"],
                    report.pcap.parsed.counts["stcbytesperpacket"]
                ])
                countstab.add_row([
                    "TCP", report.pcap.parsed.counts["tcpbytes"],
                    report.pcap.parsed.counts["tcppackets"],
                    report.pcap.parsed.counts["tcpbytesperpacket"]
                ])
                countstab.add_row([
                    "UDP", report.pcap.parsed.counts["udpbytes"],
                    report.pcap.parsed.counts["udppackets"],
                    report.pcap.parsed.counts["udpbytesperpacket"]
                ])
                normalizeddata = countstab.get_html_string().replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Proto Stats</strong></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                )
                htmldata += "%s\n" % (normalizeddata)

            # show pcap hosts
            if report.pcap.parsed.hosts:
                hosttab = PrettyTable(["Attribute", "Value"])
                hosttab.border = borderflag
                hosttab.header = headerflag
                hosttab.padding_width = padwidth
                hosttab.align["Attribute"] = "l"
                hosttab.align["Value"] = "l"
                for idx, host in enumerate(report.pcap.parsed.hosts):
                    hosttab.add_row([
                        "<span class='badge'>#%d</span>  %s" % (idx + 1, host),
                        ""
                    ])
                    if "geo" in report.pcap.parsed.hosts[
                            host] and report.pcap.parsed.hosts[host]["geo"]:
                        if report.pcap.parsed.hosts[host]["geo"]["time_zone"]:
                            hosttab.add_row([
                                "Timezone", report.pcap.parsed.hosts[host]
                                ["geo"]["time_zone"]
                            ])
                        if report.pcap.parsed.hosts[host]["geo"][
                                "latitude"] and report.pcap.parsed.hosts[host][
                                    "geo"]["longitude"]:
                            # https://www.google.com/maps?ll=lat,lon&z=5
                            hosttab.add_row([
                                "Lat/Lon",
                                "<a href='https://www.google.com/maps/preview/@%s,%s,6z'>%s/%s</a>"
                                % (report.pcap.parsed.hosts[host]["geo"]
                                   ["latitude"], report.pcap.parsed.hosts[host]
                                   ["geo"]["longitude"], report.pcap.parsed.
                                   hosts[host]["geo"]["latitude"], report.pcap.
                                   parsed.hosts[host]["geo"]["longitude"])
                            ])
                        loclist = []
                        if report.pcap.parsed.hosts[host]["geo"]["city"]:
                            loclist.append(
                                report.pcap.parsed.hosts[host]["geo"]["city"])
                        if report.pcap.parsed.hosts[host]["geo"][
                                "region_name"]:
                            loclist.append(report.pcap.parsed.hosts[host]
                                           ["geo"]["region_name"])
                        if report.pcap.parsed.hosts[host]["geo"][
                                "country_name"]:
                            loclist.append(report.pcap.parsed.hosts[host]
                                           ["geo"]["country_name"])
                        hosttab.add_row(["Location", ", ".join(loclist)])
                    if "whois" in report.pcap.parsed.hosts[
                            host] and report.pcap.parsed.hosts[host]["whois"]:
                        if report.pcap.parsed.hosts[host]["whois"]["asn"]:
                            hosttab.add_row([
                                "ASN",
                                "<a href='http://bgp.he.net/AS%s'>AS%s</a>" %
                                (report.pcap.parsed.hosts[host]["whois"]
                                 ["asn"], report.pcap.parsed.hosts[host]
                                 ["whois"]["asn"])
                            ])
                        if report.pcap.parsed.hosts[host]["whois"][
                                "asn_registry"]:
                            hosttab.add_row([
                                "Registry", report.pcap.parsed.hosts[host]
                                ["whois"]["asn_registry"]
                            ])
                        if report.pcap.parsed.hosts[host]["whois"]:
                            hosttab.add_row([
                                "Whois",
                                "<pre class='scroll_def'>%s</pre>" %
                                json.dumps(
                                    report.pcap.parsed.hosts[host]["whois"],
                                    sort_keys=True,
                                    indent=2)
                            ])
                        if report.pcap.parsed.hosts[host]["rdns"]:
                            hosttab.add_row([
                                "RDNS",
                                "<pre class='scroll_def'>%s</pre>" %
                                json.dumps(
                                    report.pcap.parsed.hosts[host]["rdns"],
                                    sort_keys=True,
                                    indent=2)
                            ])
                    hosttab.add_row(["", ""])
                normalizeddata = hosttab.get_html_string().replace(
                    "&lt;", "<"
                ).replace("&gt;", ">").replace("&amp;", "&").replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Host Stats</strong> <span class='badge'>%d</span></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                    % (len(report.pcap.parsed.hosts)))
                htmldata += "%s\n" % (normalizeddata)

            # show pcap flows
            if report.pcap.parsed.flows:
                flowtab = PrettyTable(["Flow", "Details"])
                flowtab.border = borderflag
                flowtab.header = headerflag
                flowtab.padding_width = padwidth
                flowtab.align["Attribute"] = "l"
                flowtab.align["Value"] = "l"
                for idx, flow in enumerate(report.pcap.parsed.flows):
                    if ("ctsbuf" in flow["protobuf"]
                            and flow["protobuf"]["ctsbuf"]) or (
                                "stcbuf" in flow["protobuf"]
                                and flow["protobuf"]["stcbuf"]):
                        srcip, srcport, dstip, dstport = flow["srcip"], flow[
                            "srcport"], flow["dstip"], flow["dstport"]
                        if flow["l7protocol"]:
                            flowtab.add_row([
                                "<span class='badge'>#%d</span>  %s:%s - %s:%s (%s/%s)"
                                % (idx + 1, srcip, srcport, dstip, dstport,
                                   flow["l7protocol"], flow["l4protocol"]), ""
                            ])
                        else:
                            flowtab.add_row([
                                "<span class='badge'>#%d</span>  %s:%s - %s:%s (%s)"
                                % (idx + 1, srcip, srcport, dstip, dstport,
                                   flow["l4protocol"]), ""
                            ])

                        if flow["stats"]:
                            if "cts" in flow["stats"] and flow["stats"]["cts"]:
                                if flow["stats"]["cts"]["entropycategory"] in [
                                        "SUSPICIOUS", "NATIVE-PACKED",
                                        "PACKED", "PACKED-COMPRESSED",
                                        "COMPRESSED", "COMPRESSED-ENCRYPTED",
                                        "ENCRYPTED"
                                ]:
                                    flowtab.add_row([
                                        "CTS Stats",
                                        "<span class='label label-info'>SIZE: %d</span> <span class='label label-info'>MINSIZE: %s</span> <span class='label label-info'>CR: %s%%</span> <span class='label label-warning'>H: %s %s</span>"
                                        % (flow["stats"]["cts"]
                                           ["datasizeinbytes"],
                                           flow["stats"]["cts"]["mindatasize"],
                                           flow["stats"]["cts"]
                                           ["compressionratio"],
                                           flow["stats"]["cts"]["entropy"],
                                           flow["stats"]["cts"]
                                           ["entropycategory"])
                                    ])
                                else:
                                    flowtab.add_row([
                                        "CTS Stats",
                                        "<span class='label label-info'>SIZE: %d</span> <span class='label label-info'>MINSIZE: %s</span> <span class='label label-info'>CR: %s%%</span> <span class='label label-info'>H: %s %s</span>"
                                        % (flow["stats"]["cts"]
                                           ["datasizeinbytes"],
                                           flow["stats"]["cts"]["mindatasize"],
                                           flow["stats"]["cts"]
                                           ["compressionratio"],
                                           flow["stats"]["cts"]["entropy"],
                                           flow["stats"]["cts"]
                                           ["entropycategory"])
                                    ])
                        if flow["l7protocol"] == "HTTP" and flow[
                                "l7protocoldecode"]:
                            if flow["l7protocoldecode"]["request"]:
                                body = None
                                if flow["l7protocoldecode"]["request"]["body"]:
                                    body = "\n\n%s" % utils.hexdump(
                                        flow["l7protocoldecode"]["request"]
                                        ["body"]
                                        [:report.misc.config.htmlhexdumpbytes])
                                headers = []
                                for header in flow["l7protocoldecode"][
                                        "request"]["headers"]:
                                    headers.append(
                                        "%s: %s" %
                                        (header.title(),
                                         flow["l7protocoldecode"]["request"]
                                         ["headers"][header]))
                                if body:
                                    flowtab.add_row([
                                        "HTTP Request",
                                        "<pre class='scroll_cts'>%s %s HTTP/%s\n%s%s</pre>"
                                        % (flow["l7protocoldecode"]["request"]
                                           ["method"], flow["l7protocoldecode"]
                                           ["request"]["uri"],
                                           flow["l7protocoldecode"]["request"]
                                           ["version"], "\n".join(headers),
                                           body.replace("<", "&lt;").replace(
                                               ">", "&gt;").replace(
                                                   "&amp;", "&"))
                                    ])
                                else:
                                    flowtab.add_row([
                                        "HTTP Request",
                                        "<pre class='scroll_cts'>%s %s HTTP/%s\n%s</pre>"
                                        % (flow["l7protocoldecode"]["request"]
                                           ["method"], flow["l7protocoldecode"]
                                           ["request"]["uri"],
                                           flow["l7protocoldecode"]["request"]
                                           ["version"], "\n".join(headers))
                                    ])
                        elif report.misc.config.enablebufhexdump:
                            if "ctsbuf" in flow["protobuf"] and flow[
                                    "protobuf"]["ctsbuf"]:
                                flowtab.add_row([
                                    "Hexdump",
                                    "<pre class='scroll_cts'>%s</pre>" %
                                    utils.hexdump(
                                        flow["protobuf"]["ctsbuf"]
                                        [:report.misc.config.htmlhexdumpbytes]
                                    ).replace("<", "&lt;").replace(
                                        ">", "&gt;").replace("&amp;", "&")
                                ])

                        if flow["scan"]["shellcode"]:
                            if "cts" in flow["scan"]["shellcode"] and flow[
                                    "scan"]["shellcode"]["cts"]:
                                flowtab.add_row([
                                    "CTS Shellcode",
                                    "<pre class='scroll_stc'>%s</pre>" %
                                    flow["scan"]["shellcode"]["cts"]["profile"]
                                ])
                        if flow["scan"]["yara"]:
                            if "cts" in flow["scan"]["yara"] and flow["scan"][
                                    "yara"]["cts"]:
                                ctsmatches = []
                                for entry in flow["scan"]["yara"]["cts"]:
                                    ctsmatches.append(entry["rule"])
                                flowtab.add_row([
                                    "CTS Yara Matches", "\n".join(ctsmatches)
                                ])

                        if flow["stats"]:
                            if "stc" in flow["stats"] and flow["stats"]["stc"]:
                                if flow["stats"]["stc"]["entropycategory"] in [
                                        "SUSPICIOUS", "NATIVE-PACKED",
                                        "PACKED", "PACKED-COMPRESSED",
                                        "COMPRESSED", "COMPRESSED-ENCRYPTED",
                                        "ENCRYPTED"
                                ]:
                                    flowtab.add_row([
                                        "STC Stats",
                                        "<span class='label label-info'>SIZE: %d</span> <span class='label label-info'>MINSIZE: %s</span> <span class='label label-info'>CR: %s%%</span> <span class='label label-warning'>H: %s %s</span>"
                                        % (flow["stats"]["stc"]
                                           ["datasizeinbytes"],
                                           flow["stats"]["stc"]["mindatasize"],
                                           flow["stats"]["stc"]
                                           ["compressionratio"],
                                           flow["stats"]["stc"]["entropy"],
                                           flow["stats"]["stc"]
                                           ["entropycategory"])
                                    ])
                                else:
                                    flowtab.add_row([
                                        "STC Stats",
                                        "<span class='label label-info'>SIZE: %d</span> <span class='label label-info'>MINSIZE: %s</span> <span class='label label-info'>CR: %s%%</span> <span class='label label-info'>H: %s %s</span>"
                                        % (flow["stats"]["stc"]
                                           ["datasizeinbytes"],
                                           flow["stats"]["stc"]["mindatasize"],
                                           flow["stats"]["stc"]
                                           ["compressionratio"],
                                           flow["stats"]["stc"]["entropy"],
                                           flow["stats"]["stc"]
                                           ["entropycategory"])
                                    ])
                        if flow["l7protocol"] == "HTTP" and flow[
                                "l7protocoldecode"]:
                            if flow["l7protocoldecode"]["response"]:
                                body = None
                                if flow["l7protocoldecode"]["response"][
                                        "body"]:
                                    body = "\n\n%s" % utils.hexdump(
                                        flow["l7protocoldecode"]["response"]
                                        ["body"]
                                        [:report.misc.config.htmlhexdumpbytes])
                                headers = []
                                for header in flow["l7protocoldecode"][
                                        "response"]["headers"]:
                                    headers.append(
                                        "%s: %s" %
                                        (header.title(),
                                         flow["l7protocoldecode"]["response"]
                                         ["headers"][header]))
                                if body:
                                    flowtab.add_row([
                                        "HTTP Response",
                                        "<pre class='scroll_stc'>HTTP/%s %s %s\n%s%s</pre>"
                                        %
                                        (flow["l7protocoldecode"]["response"]
                                         ["version"], flow["l7protocoldecode"]
                                         ["response"]["status"],
                                         flow["l7protocoldecode"]["response"]
                                         ["reason"], "\n".join(headers),
                                         body.replace("<", "&lt;").replace(
                                             ">", "&gt;").replace(
                                                 "&amp;", "&"))
                                    ])
                                else:
                                    flowtab.add_row([
                                        "HTTP Response",
                                        "<pre class='scroll_stc'>HTTP/%s %s %s\n%s</pre>"
                                        %
                                        (flow["l7protocoldecode"]["response"]
                                         ["version"], flow["l7protocoldecode"]
                                         ["response"]["status"],
                                         flow["l7protocoldecode"]["response"]
                                         ["reason"], "\n".join(headers))
                                    ])
                        elif report.misc.config.enablebufhexdump:
                            if "stcbuf" in flow["protobuf"] and flow[
                                    "protobuf"]["stcbuf"]:
                                flowtab.add_row([
                                    "Hexdump",
                                    "<pre class='scroll_stc'>%s</pre>" %
                                    utils.hexdump(
                                        flow["protobuf"]["stcbuf"]
                                        [:report.misc.config.htmlhexdumpbytes]
                                    ).replace("<", "&lt;").replace(
                                        ">", "&gt;").replace("&amp;", "&")
                                ])

                        if flow["scan"]["shellcode"]:
                            if "stc" in flow["scan"]["shellcode"] and flow[
                                    "scan"]["shellcode"]["stc"]:
                                flowtab.add_row([
                                    "STC Shellcode",
                                    "<pre class='scroll_stc'>%s</pre>" %
                                    flow["scan"]["shellcode"]["stc"]["profile"]
                                ])
                        if flow["scan"]["yara"]:
                            if "stc" in flow["scan"]["yara"] and flow["scan"][
                                    "yara"]["stc"]:
                                stcmatches = []
                                for entry in flow["scan"]["yara"]["stc"]:
                                    stcmatches.append(entry["rule"])
                                flowtab.add_row([
                                    "STC Yara Matches", "\n".join(stcmatches)
                                ])
                        flowtab.add_row(["", ""])

                    elif "udpbuf" in flow["protobuf"] and flow["protobuf"][
                            "udpbuf"]:
                        srcip, srcport, dstip, dstport = flow["srcip"], flow[
                            "srcport"], flow["dstip"], flow["dstport"]
                        if flow["l7protocol"]:
                            flowtab.add_row([
                                "<span class='badge'>#%d</span>  %s:%s - %s:%s (%s/%s)"
                                % (idx + 1, srcip, srcport, dstip, dstport,
                                   flow["l7protocol"], flow["l4protocol"]), ""
                            ])
                        else:
                            flowtab.add_row([
                                "<span class='badge'>#%d</span>  %s:%s - %s:%s (%s)"
                                % (idx + 1, srcip, srcport, dstip, dstport,
                                   flow["l4protocol"]), ""
                            ])
                        flowtab.add_row([
                            "Hexdump",
                            "<pre class='scroll_def'>%s</pre>" % utils.hexdump(
                                flow["protobuf"]["udpbuf"]
                                [:report.misc.config.htmlhexdumpbytes]).
                            replace("<", "&lt;").replace(">", "&gt;").replace(
                                "&amp;", "&")
                        ])
                        flowtab.add_row([
                            "ProtoDecode",
                            "<pre class='scroll_def'>%s</pre>" %
                            json.dumps(flow["l7protocoldecode"],
                                       sort_keys=True,
                                       indent=2).decode("windows-1252").encode(
                                           "ascii", "ignore")
                        ])

                normalizeddata = flowtab.get_html_string().replace(
                    "<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>",
                    ""
                ).replace("&lt;", "<").replace("&gt;", ">").replace(
                    "&amp;", "&"
                ).replace(
                    "</table>", "</table></div></div></div></div>"
                ).replace(
                    "<table>",
                    "<div class='panel panel-info'>\n<div class='panel-heading'><strong>Flow Stats</strong> <span class='badge'>%d</span></div>\n<div class='panel-body'>\n<div class='row'>\n<div class='col-md-12'>\n<table class='table table-condensed table-hover table-striped'>"
                    % (len(report.pcap.parsed.flows)), 1)
                htmldata += "%s\n" % (normalizeddata)

            htmldata += "%s" % (htmlends)

            thregex = re.compile(r"<tr>(\s+)<td>(.*)</td>")
            htmldata = thregex.sub(r"<tr>\1<th class='col-md-2'>\2</th>",
                                   htmldata)
            tdregex = re.compile(r"<td>(.*)</td>")
            normalizedhtmldata = tdregex.sub(
                r"<td class='highlight_def'>\1</td>", htmldata)

            fileutils.file_save(filename="%s/%s.html" %
                                (report.misc.config.currreportpath,
                                 report.misc.config.currreportfile),
                                data="%s" % (normalizedhtmldata),
                                mode="w")