def _list(self, node): if node.hasAttribute('style'): list_style = self.styles.list_styles[node.getAttribute('style')] else: list_style = platypus.flowables.ListStyle('Default') list_items = [] for li in _child_get(node, 'li'): flow = [] for n in li.childNodes: if n.nodeType == node.ELEMENT_NODE: flow.append(self._flowable(n)) if not flow: if li.hasAttribute('style'): li_style = self.styles.styles[li.getAttribute('style')] else: li_style = reportlab.lib.styles.getSampleStyleSheet( )['Normal'] flow = platypus.paragraph.Paragraph(self._textual(li), li_style) list_item = platypus.ListItem(flow) list_items.append(list_item) return platypus.ListFlowable(list_items, style=list_style, start=list_style.__dict__.get('start'))
def save(self, directory, filetype): """Saves the attributes of the Country to a specified file. Parameters ---------- directory : str Path to save output filetype : str For output file with country data (json or pdf) Raises ------ NotImplementedError If unsupported filetype is passed in. """ filename = directory + self.name.replace(' ', '_') if filetype == 'json': filename += ".json" with open(filename, 'w') as f: json.dump(vars(self), f, indent=4) f.close() elif filetype == 'pdf': ss = getSampleStyleSheet() pdf = platy.SimpleDocTemplate(filename + ".pdf") flowables = [] flowables.append(platy.Paragraph(self.name, ss['Heading1'])) for k in vars(self): if k == 'id' or k == 'name': continue if type(vars(self)[k]) is str or type(vars(self)[k]) is int: p = f"{k.replace('_',' ').title()}: {str(vars(self)[k])}" flowables.append(platy.Paragraph(p, ss['BodyText'])) else: p = f"{k.replace('_',' ').title()}:" flowables.append(platy.Paragraph(p, ss['BodyText'])) bullets = [] for v in vars(self)[k]: p = v if type(vars(self)[k]) is not list: p += ": "+vars(self)[k][v] b = platy.Paragraph(p, ss['Normal']) bullets.append(platy.ListItem(b, leftIndent=35)) table = platy.ListFlowable(bullets, bulletType='bullet') flowables.append(table) pdf.build(flowables) elif filetype == 'html': filename += ".json" json_string = json.dumps(vars(self),indent=4) f = open(filename, 'w') f.write("var data = " + json_string) f.close() else: raise NotImplementedError( f"Output file type, {filetype}, not supported")
def pdf_response_rl(self, question, filename, download=False): """ Use the ReportLab api and the Model Objects provided by the context dict in this views pipeline. """ import reportlab.platypus as RL import reportlab.lib.styles as SL from io import BytesIO flo = [] out = BytesIO() # create a byte buffer to hold PDF data pdf = RL.SimpleDocTemplate(out) pdf.showBoundary = 1 pdf.leftMargin = pdf.rightMargin = pdf.leftMargin / 2 pdf.topMargin = pdf.bottomMargin = pdf.topMargin / 2 ss = SL.getSampleStyleSheet() h1 = RL.Paragraph("Question:", ss['Heading1']) h2 = RL.Paragraph(f"{str(question)}", ss['Heading2']) h3 = RL.Paragraph("Choices:", ss['Heading3']) hl = RL.HRFlowable(width='100%') if question.question_img: img = RL.Image(question.question_img.path, width=100, height=75, hAlign="LEFT") flo += [img, hl] flo += [h1, h2, hl, h3] ps = [ RL.Paragraph(f"{str(c)} [{c.votes} votes]", ss['BodyText']) for c in question.choice_set.all() ] ul = [RL.ListItem(x, value='sparkle') for x in ps] lf = RL.ListFlowable(ul, bulletType='bullet') flo += [lf] flo += [hl] try: pdf.build(flo) except Exception as e: message = (f"Unable to generate PDF from <hl><pre>{html}</pre>") return HttpResponse(message, status=500) out.seek(0) # reset byte buffer pointer to the start if download: return FileResponse(out, as_attachment=True, filename=filename) return FileResponse(out, filename=filename)
def save_org(org, directory, filetype, assessment): """ Saves information about the organization to a file. Paramters --------- org : stix2 Identity object the organization to save directory : str Path to save output filetype : str Type of output file (json or pdf) assessment : dictionary representation of NIST 800-171 assessment table """ filename = directory + org.name.replace(' ', '') org_desc = json.loads(org.description) org_dict = { "name": org.name, "background": org_desc['Background'], "network_size": org_desc['Network']['size'], "vulnerability_level": org_desc['Security Posture']['vulnerability'], "NIST vulnerabilities": org_desc['Security Posture']['vulns'], "sectors": org.sectors } if filetype == 'json': with open(filename+".json", 'w') as f: json.dump(org_dict, f) f.close() elif filetype == 'pdf': ss = getSampleStyleSheet() pdf = platy.SimpleDocTemplate(filename + ".pdf") flowables = [] flowables.append(platy.Paragraph(org.name, ss['Heading1'])) p = f'Sector: {", ".join(org.sectors)}' flowables.append(platy.Paragraph(p, ss['BodyText'])) flowables.append(platy.Paragraph("Background", ss['Heading2'])) p = ( f'{org.name} is headquartered in the country of ' f'{org_desc["Background"]["headquarters"]}. It has ' f'{org_desc["Background"]["number of employees"]} employees and an' f' annual revenue of {org_desc["Background"]["annual revenue"]}.' ) flowables.append(platy.Paragraph(p, ss['BodyText'])) flowables.append(platy.Paragraph("Computer Network", ss['Heading2'])) p = f"Network size: {org_desc['Network']['size']} (on a scale of 100)" flowables.append(platy.Paragraph(p, ss['BodyText'])) p = "NIST 800-171 Security Evaluation Results" flowables.append(platy.Paragraph(p, ss['Heading2'])) p = f"Score: {org_desc['Security Posture']['vulnerability']}/100" flowables.append(platy.Paragraph(p, ss['BodyText'])) p = "Vulnerabilities (failed requirements):" flowables.append(platy.Paragraph(p, ss['BodyText'])) bullets = [] nist_reqs = {} for cat in assessment: for req in assessment[cat]: nist_reqs[req["Requirement"]] = req["Description"] for vuln in org_desc['Security Posture']['vulns']: p = platy.Paragraph(f'({vuln}) {nist_reqs[vuln]}', ss['Normal']) bullets.append(platy.ListItem(p, leftIndent=35)) flowables.append(platy.ListFlowable(bullets, bulletType='bullet')) pdf.build(flowables) elif filetype == 'html': filename += ".json" f = open(filename, 'w') f.write("var data = " + str(org_dict)) f.close() else: raise NotImplementedError( f"Output file type, {filetype}, not supported")
def save(actor, directory, filetype, fs_gen, fs_real): """Saves the attributes of the Threat Actor to a specified file. Parameters ---------- actor : stix2 ThreatActor object the threat actor to save directory : str Path to save output filetype : str For output file with country data (json or pdf) fs_gen : FileSystemStore object Data store with info about threat actor fs_real : FileSystemSource object Data store with reference information about real world data """ filename = directory + actor.name.replace(' ', '') relationships = fs_gen.query([ Filter("type", "=", "relationship"), Filter("source_ref", "=", actor.id)]) ttps, tools, malwares = [], [], [] for r in relationships: if "attack-pattern" in r.target_ref: ttps.append(r.target_ref) elif "tool" in r.target_ref: tools.append(r.target_ref) elif "malware" in r.target_ref: malwares.append(r.target_ref) elif "location" in r.target_ref: countries = fs_gen.query([ Filter("type", "=", "location"), Filter("id", "=", r.target_ref)]) tool_names = [fs_real.query([ Filter("type", "=", "tool"), Filter("id", "=", t)])[0].name for t in tools] m_s = [fs_real.query([ Filter("type", "=", "malware"), Filter("id", "=", m)])[0].name for m in malwares] actor_dict = { "name": actor.name, "aliases": actor.aliases, "first_seen": actor.first_seen.strftime("%B %Y"), "last_seen": actor.last_seen.strftime("%B %Y"), "attribution": countries[0].name, "resource_level": actor.resource_level, "primary motivation": actor.primary_motivation, "secondary motivations": actor.secondary_motivations, "description": actor.description, "ttps": ttps, "tools": tool_names, "malware": m_s } if filetype == 'json': with open(filename+".json", 'w') as f: json.dump(actor_dict, f) f.close() elif filetype == 'pdf': ss = getSampleStyleSheet() pdf = platy.SimpleDocTemplate(filename + ".pdf") flowables = [] try: actor_dict = json.loads(actor.description) p = ( f'{actor.name} is a {actor_dict["actor_type"]} group also ' f'known as {" or ".join(actor.aliases)}. It was first seen in ' f'{actor.first_seen.strftime("%B %Y")}, and is attributed to ' f'the state of {countries[0].name}. Its level of ' f'sophistication is {actor_dict["sophistication"]}, and its ' f'primary motivation is {actor.primary_motivation}, though it ' f'is sometimes motivated by ' f'{" and ".join(actor.secondary_motivations)}.' ) except json.decoder.JSONDecodeError: actor_dict = None p = actor.description flowables.append(platy.Paragraph(actor.name, ss['Heading1'])) flowables.append(platy.Paragraph(p, ss['BodyText'])) if actor_dict is not None: p = actor.name + "'s goals are " flowables.append(platy.Paragraph(p, ss['BodyText'])) bullets = [] for g in actor.goals: p = platy.Paragraph(g, ss['Normal']) bullets.append(platy.ListItem(p, leftIndent=35)) flowables.append(platy.ListFlowable(bullets, bulletType='bullet')) flowables.append(platy.Paragraph('Tools', ss['Heading2'])) p = "This threat actor is known to use the following tools." flowables.append(platy.Paragraph(p, ss['BodyText'])) bullets = [] for tool in sorted(tool_names[:10], key=str.casefold): p = platy.Paragraph(tool, ss['Normal']) bullets.append(platy.ListItem(p, leftIndent=35)) flowables.append(platy.ListFlowable(bullets, bulletType='bullet')) flowables.append(platy.Paragraph('Malware', ss['Heading2'])) p = "This threat actor is known to use the following malware." flowables.append(platy.Paragraph(p, ss['BodyText'])) bullets = [] for malware in sorted(m_s[:5], key=str.casefold): p = platy.Paragraph(malware, ss['Normal']) bullets.append(platy.ListItem(p, leftIndent=35)) flowables.append(platy.ListFlowable(bullets, bulletType='bullet')) flowables.append( platy.Paragraph('Attack Patterns', ss['Heading2'])) for t in ttps: ttp = fs_real.query([ Filter("type", "=", "attack-pattern"), Filter("id", "=", t)])[0] p = f"{ttp.name}" flowables.append(platy.Paragraph(p, ss['Italic'])) p = [] for ref in ttp.external_references: if ref.source_name == "mitre-attack": p.append("Mitre Attack: "+ref.external_id) elif ref.source_name == "capec": p.append(ref.external_id) if len(p) > 0: p = "(" + ", ".join(p) + ")\n" flowables.append(platy.Paragraph(p, ss['BodyText'])) else: try: flowables.append(platy.Paragraph( ttp.description+'\n', ss['BodyText'])) except AttributeError: pass flowables.append(platy.Paragraph("", ss['Heading2'])) flowables.append( platy.Paragraph('Related Reporting', ss['Heading2'])) p = f"These reported incidents are likely or highly likely to be \ attributed to {actor.name}, though there may be others:" flowables.append(platy.Paragraph(p, ss['BodyText'])) sightings = fs_gen.query([ Filter("type", "=", "sighting"), Filter("sighting_of_ref", "=", actor.id)]) r_nums = [ str(s.first_seen).replace('-', '') for s in sightings][:15] bullets = [] for r in sorted(r_nums): p = platy.Paragraph( r.replace(' ', '_').replace(':', '')[:15], ss['Normal']) bullets.append(platy.ListItem(p, leftIndent=35)) flowables.append(platy.ListFlowable(bullets, bulletType='bullet')) pdf.build(flowables) elif filetype == 'html': filename += ".json" f = open(filename, 'w') f.write("var data = " + str(actor_dict)) f.close() else: raise NotImplementedError( f"Output file type, {filetype}, not supported")