def manda_correo(para, cc, cco, msg): """ Se envia un correo con el mensaje especificado """ server = None b = True try: if settings.CORREO_SSL: server = smtplib.SMTP_SSL(settings.CORREO_SERVIDOR, settings.CORREO_PUERTO) else: server = smtplib.SMTP(settings.CORREO_SERVIDOR, settings.CORREO_PUERTO) server.starttls() usr = settings.CORREO_USR passw = settings.CORREO_PASS if usr and passw: server.login(usr, passw) server.sendmail(usr, para + cc + cco, msg) log.log('Correo enviado. To:%s, Cc:%s, Bcc:%s' % (', '.join(para if para else []), ', '.join(cc if cc else []), ', '.join(cco if cco else [])), "correo.log") except Exception as e: log.log('Error: %s' % str(e), "correo.log") b = False finally: if server: server.quit() return b
def obten_urls(body, html=False): textos = [body] if html: try: soup = BeautifulSoup(body, 'html.parser') textos = [] for x in soup.findAll(text=True): x = x.strip() if x: textos.append(x) for link in soup.find_all('a'): textos.append(link.get('href', '')) except Exception as e: log.log("Error al leer HTML: %s" % str(e), "correo.log") regex1 = re.compile(r"hxxp://") regex2 = re.compile(r"hxxps://") regex3 = re.compile(r" ?[(\[][.][)\]] ?") regex4 = re.compile(r" ?[(\[]dot[)\]] ?") urls = [] for t in textos: try: t = regex1.sub('http://', t) t = regex2.sub('https://', t) t = regex3.sub('.', t) t = regex3.sub('.', t) urls += re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', t) except Exception as e: log.log("Error al extraer urls de correo: %s" % str(e), "correo.log") return urls
def get_mime(archivo): try: f = magic.Magic(mime=True) return f.from_buffer(archivo) except Exception as e: log.log("Error al leer archivo de entrada: %s" % str(e), "verifica_urls.log") return ''
def parsecorreo_aux(texto, nombre, archivos, urls, usuario_autenticado): try: mensaje = email.message_from_string(texto) except Exception as e: log.log("Error al leer correo %s: %s" % (nombre, str(e)), "correo.log") return None analiza_correo(mensaje, archivos, urls, usuario_autenticado) return mensaje
def verifica_urls(request): if request.method == 'POST': if request.POST.get("boton_urls"): form = UrlsForm(request.POST) if form.is_valid(): urls = form.cleaned_data['urls'] urls_limpias = [] for x in urls.split('\n'): x = x.strip() if x: for y in x.split(','): for z in y.split(' '): z = z.strip() if z: urls_limpias.append(z) urls_limpias = list(set(urls_limpias)) sitios = phishing.verifica_urls(urls_limpias, "verifica_urls.log") urls = Url.objects.filter(pk__in=[x.pk for x in sitios]).distinct() context = aux.context_reporte(urls) return render(request, 'verifica_urls/reporte_verificacion.html', context) elif request.POST.get("boton_archivo") and request.FILES.get( 'file', None): form = ArchivoForm(request.POST) f = request.FILES['file'].read() if not get_mime(f).startswith('text'): archivo = request.FILES['file'].name log.log( "Ingresado archivo de entrada invalido: '%s'" % archivo, "verifica_urls.log") context = {'archivo': archivo} return render(request, 'verifica_urls/error_archivo.html', context) f = f.decode('utf-8', errors='ignore') name = request.FILES['file'].name urls = [] if name.endswith('.json'): urls = entrada.lee_json(f) elif name.endswith('.csv'): urls = entrada.lee_csv(f) else: urls = entrada.lee_txt(f) urls = [x for x in list(set(urls)) if x] sitios = phishing.verifica_urls(urls, "verifica_urls.log") urls = Url.objects.filter(pk__in=[x.pk for x in sitios]).distinct() context = aux.context_reporte(urls) return render(request, 'verifica_urls/reporte_verificacion.html', context) form1 = UrlsForm() form2 = ArchivoForm() return render(request, 'verifica_urls/verifica_urls.html', { 'form1': form1, 'form2': form2 })
def url_ignora(url): url.ignorado = True url.timestamp_actualizacion = timezone.localtime(timezone.now()) url.save() i = url.obten_info if i: i.deteccion = 'N' i.save() log.log("URL '%s' ignorada" % url.url, "monitoreo.log")
def url_reporta(url, ticket): url.ticket = ticket url.timestamp_actualizacion = ticket.timestamp url.save() i = url.obten_info if i and (i.deteccion != 'P' or i.deteccion != 'M'): i.deteccion = 'P' i.timestamp_deteccion = ticket.timestamp i.save() log.log("URL '%s' reportada" % url.url, "monitoreo.log")
def handle(self, *args, **options): log.log('Comienza generación de reportes de salida', "salida.log") hoy = timezone.localtime(timezone.now()).date() urls_hoy = Url.objects.filter(timestamp_creacion__date=hoy).order_by( 'url', '-timestamp_creacion').distinct('url') urls_pk = [] for x in urls_hoy: i = x.obten_info if i and (i.deteccion == 'P' or i.deteccion == 'M'): urls_pk.append(x.pk) urls = Url.objects.filter(pk__in=urls_pk) d = os.path.join(settings.DIR_SALIDA, str(hoy)) if not os.path.exists(d): os.makedirs(d) with open(os.path.join(d, 'ips.txt'), 'a') as ips, \ open(os.path.join(d, 'phishing.txt'), 'a') as phishing, \ open(os.path.join(d, 'redirecciones.txt'), 'a') as red, \ open(os.path.join(d, 'maliciosos.txt'), 'a') as mal, \ open(os.path.join(d, 'firewall.txt'), 'a') as fire, \ open(os.path.join(d, 'snort.txt'), 'a') as snort, \ open(os.path.join(d, 'formato.txt'), 'a') as form, \ open(os.path.join(d, 'sitios.json'), 'w') as sitios: for u in urls: if u.es_redireccion: red.write('%s\n' % u.url) i = u.obten_info if i and i.deteccion == 'P': phishing.write('%s\n' % u.url) elif i and i.deteccion == 'M': mal.write('%s\n' % u.url) asn = '-' nom = '-' if u.dominio.asn: a = u.dominio.asn asn = a.asn nom = a.nombre ip = '-' if u.dominio.ip: ip = u.dominio.ip t = time.strftime('%Y-%m-%d %H:%M:%S') form.write('%s | %s | %s | %d saapm %d %s | %s\n' % (asn, ip, t, u.pk, u.pk, u.url, nom)) urls_dom = urls.distinct('dominio') for u in urls_dom: snort.write( 'Alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ' '(msg:"Regla sitio malicioso"; flow:to_server,established; content:' '"%s"; nocase; sid:%d; rev:1;)\n' % (u.dominio.dominio, randint(10000000, 20000000))) if u.dominio.ip: ips.write('%s\n' % u.dominio.ip) fire.write('iptables -A INPUT -s %s -j DROP\n' % u.dominio.ip) json.dump(self.json_urls(urls), sitios, indent=4) log.log('Generados reportes de salida', "salida.log")
def es_malicioso(HASH_sha256): resultado = None try: vt = VirusTotalPublicApi(settings.VIRUSTOTAL_API_KEY) response = vt.get_file_report(HASH_sha256) resultado = json.loads(json.dumps(response)) except Exception as e: log.log('Error: %s' % str(e), "correo.log") return False resultados = resultado.get('results', None) if resultado else None return resultados and resultados.get('positives', 0) > 0
def adjunta_imagen(msg, sitio): """ Se ajunta un archivo al mensaje msg """ try: with sitio.captura.open(mode='rb') as a_file: basename = os.path.basename(sitio.captura_url) part = MIMEApplication(a_file.read(), Name=basename) part['Content-Disposition'] = 'attachment; filename="%s"' % basename msg.attach(part) except Exception as e: log.log('Error: %s' % str(e), "correo.log")
def cambia_frecuencia(funcion, n): n = 1 if n < 1 or n > 24 else n comando = "/bin/bash -c 'source %s/bin/activate && python %s/manage.py %s'" % \ (settings.DIR_ENV, settings.BASE_DIR, funcion) process = Popen('crontab -l | egrep -v "%s" | crontab -' % (comando), shell=True, stdout=PIPE, stderr=PIPE) out, err = process.communicate() if err: log.log("Error: %s" % err.decode('utf-8', errors='ignore'), "ajustes.log") if out: log.log(out.decode('utf-8', errors='ignore'), "ajustes.log") i = "*/%d" % n if n < 24 else '0' process = Popen( '(crontab -l ; echo "0 %s * * * %s") | sort - | uniq - | crontab -' % (i, comando), shell=True, stdout=PIPE, stderr=PIPE) out, err = process.communicate() if err: log.log("Error: %s" % err.decode('utf-8', errors='ignore'), "ajustes.log") if out: log.log(out.decode('utf-8', errors='ignore'), "ajustes.log")
def obten_plantilla(mensaje, dominio, urls, ticket=''): dicc = crea_diccionario(dominio, urls) dicc['ticket'] = ticket try: plantilla = settings.PLANTILLA_CORREO_ASUNTO if mensaje: plantilla = settings.PLANTILLA_CORREO_MENSAJE if (dominio.ip and (dominio.ip.startswith('132.248') or dominio.ip.startswith('132.247'))) \ or dominio.dominio.endswith('unam.mx'): plantilla = settings.PLANTILLA_UNAM_ASUNTO if mensaje: plantilla = settings.PLANTILLA_UNAM_MENSAJE s = obten_texto(mensaje, plantilla).format_map(dicc) return s except Exception as e: log.log('Error: %s' % str(e), "correo.log") return 'Error en formato de texto'
def guarda_payload(nombre, payload, malicioso): adjunto = None try: adjunto = ArchivoAdjunto(malicioso=malicioso) z_payload = gzip.compress(payload) adjunto.archivo.save(nombre, ContentFile(z_payload)) adjunto.save() except IntegrityError: hoy = timezone.localtime(timezone.now()) adjuntos = ArchivoAdjunto.objects.filter(timestamp__date=hoy.date()) for archivo in adjuntos: if archivo.filename == nombre: return archivo return None except Exception as e: log.log("Error al guardar archivo adjunto '%s': %s" % (archivo, str(e)), "correo.log") return None return adjunto
def agrega_imagen(fig, documento, titulo, descripcion): try: a = ''.join( random.choice(string.ascii_uppercase + string.digits) for _ in range(8)) path = '/tmp/%s.png' % a fig.savefig(path) plt.clf() q = documento.add_paragraph() q.alignment = WD_ALIGN_PARAGRAPH.CENTER q.add_run(titulo.upper()).bold = True q.add_run("\n%s" % descripcion) documento.add_picture(path) q = documento.add_paragraph() run = q.add_run() run.add_break(WD_BREAK.PAGE) os.remove(path) except Exception as e: log.log('Error: %s' % str(e), 'reportes.log')
def handle(self, *args, **options): log.log('Comieza verificación de URLs', 'monitoreo.log') urls = Url.objects.filter(timestamp_desactivado__isnull=True) sitios = phishing.verifica_urls_cron(urls) for x in sitios: log.log("URL '%s' verificada" % str(x), 'monitoreo.log') log.log('Termina verificación de URLs', 'monitoreo.log')
def analisis_archivo(attachment, usuario_autenticado): """ Esta funcion analiza los archivos contenidos en los correos """ datos = {} try: datos['Tipo'] = attachment.get_content_type() payload = attachment.get_payload(decode=True) datos['Tamaño'] = humanize.naturalsize(0) if payload: datos['Tipo'] = magic.from_buffer(payload, mime=True) sha256_h = sha256(payload) archivo = "%s.gz" % sha256_h malicioso = es_malicioso(sha256_h) guarda = guarda_payload(archivo, payload, malicioso) if guarda and usuario_autenticado: datos['Archivo'] = guarda datos['Tamaño'] = humanize.naturalsize(len(payload)) datos['Es malicioso'] = 'Sí' if malicioso else 'No' datos['Referencia'] = "https://www.virustotal.com/#/search/%s" % sha256_h content_disposition = attachment.get("Content-Disposition", None) if content_disposition: dispositions = content_disposition.strip().split(";") for param in dispositions[1:]: param = param.strip() k, v = param.split("=") k = k.lower() if k == "filename": datos['Nombre'] = v elif k == "create-date": datos['Fecha de creación'] = v elif k == "modification-date": datos['Fecha de modificación'] = v elif k == "read-date": datos['Fecha de lectura'] = v except Exception as e: log.log('Error: %s' % str(e), "correo.log") return None return datos
def handle(self, *args, **options): log.log("Inicia ejecucion de script de notificacion", "notificacion.log") dir_correos = settings.DIR_CORREOS log.log("Directorio base de correos: %s" % dir_correos, "notificacion.log") p = os.path.join(dir_correos, "procesados") if not os.path.exists(p): os.mkdir(p) archivos = [ f for f in os.listdir(dir_correos) if os.path.isfile(os.path.join(dir_correos, f)) ] for archivo in archivos: log.log("Leyendo archivo %s" % archivo, "notificacion.log") a = os.path.join(dir_correos, archivo) with open(a) as f: headers, urls, _, _, error = correo.parsecorreo( f.read(), archivo, False) urls = list(set(urls)) sitios = phishing.verifica_urls(urls, "notificacion.log") for u in urls: log.log("Verificada URL %s" % u, "notificacion.log") if headers.get('Subject', '') == 'Reporte Phishing - TSU': dominios = [] for s in sitios: dominios.append(s.dominio) dominios = list(set(dominios)) for d in dominios: urls0 = d.urls_activas urls = [] sitios = [] for u in urls0: i = u.obten_info if i and (i.deteccion == 'P' or i.deteccion == 'M') and \ i.entidad_afectada: sitios.append(i) urls.append(u) if len(urls) == 0: continue sitios = list(set(sitios)) hoy = timezone.localtime(timezone.now()) cadena_urls = ''.join([x.identificador for x in urls]) md = phishing.md5((d.dominio + cadena_urls).encode( 'utf-8', 'backslashreplace')) ticket = ( '%d%02d%02d%s' % (hoy.year, hoy.month, hoy.day, md[:7])).upper() de = settings.CORREO_DE para = [ '*****@*****.**', '*****@*****.**' ] cc = [] cco = ['*****@*****.**' ] #settings.CORREO_CCO.split() urls_qs = Url.objects.filter( pk__in=[u.pk for u in urls]) asunto = correo.obten_asunto(d, urls_qs, ticket) mensaje = correo.obten_mensaje(d, urls_qs, ticket) msg = correo.genera_mensaje(de, para, cc, cco, asunto, mensaje, sitios) enviado = correo.manda_correo(para, cc, cco, msg) if not enviado: log.log("Error al reportar dominio %s" % d.dominio, "notificacion.log") else: ts = timezone.localtime(timezone.now()) try: ticketO = Ticket.objects.get(ticket=ticket) except: ticketO = Ticket(ticket=ticket, timestamp=ts) ticketO.save() for u in urls: url_reporta(u, ticketO) log.log("URL %s reportada" % u.url, "notificacion.log") os.rename(a, os.path.join(p, archivo)) log.log("Termino ejecucion del script", "notificacion.log")
def handle(self, *args, **options): archivo = options['archivo'][0] if not os.path.exists(archivo): self.stderr.write( self.style.ERROR('El archivo "%s" no existe.' % archivo)) return with open(archivo, 'rb') as f: texto = f.read().decode('utf-8', errors='ignore') resultados, urls, headers, archivos, error = correo.parsecorreo( texto, archivo, False) if error: log.log("Error al leer correo '%s'" % archivo, "correo.log") return sitios = phishing.verifica_urls(urls, "correo.log") if options['verbosity'] > 1: for u in sitios: self.stdout.write("URL '%s' verificada" % u.url) self.stdout.write(self.style.SUCCESS('Correo procesado exitósamente.')) if options['cabeceras']: self.stdout.write("CABECERAS\n\n") for k, v in resultados.items(): self.stdout.write("%s: %s" % (k, v)) if options['raw']: self.stdout.write("\nRAW\n\n") self.stdout.write(headers) if options['adjuntos']: self.stdout.write("\nARCHIVOS ADJUNTOS") for archivo in archivos: self.stdout.write("") for k, v in archivo.items(): self.stdout.write("%s: %s" % (k, v)) if options['reporte-urls']: self.stdout.write("\nREPORTE DE URLS\n\n") urls = Url.objects.filter(pk__in=[x.pk for x in sitios]).distinct() context = aux.context_reporte(urls) self.stdout.write("# Sitios analizados: %d" % context['urls_total']) self.stdout.write("# Sitios activos: %d" % context['num_urls_activas']) self.stdout.write("# Sitios inactivos: %d" % context['num_urls_inactivas']) self.stdout.write("# Redirecciones: %d" % context['num_urls_redirecciones']) self.stdout.write("# Dominios afectados: %d\n" % len(context['dominios'])) self.stdout.write("\nENTIDADES") for e in context['entidades']: self.stdout.write(" %s: %d" % (e[0], e[1])) self.stdout.write("\nTÍTULOS") for e in context['titulos']: self.stdout.write(" %s: %d" % (e[0], e[1])) self.stdout.write("\nDOMINIOS") for e in context['dominios']: self.stdout.write(" %s: %d" % (e[0], e[1])) self.stdout.write("\nPAÍSES") for e in context['paises']: self.stdout.write(" %s: %d" % (e[0], e[1])) for u in urls: self.stdout.write("\nURL: %s" % u.url) self.stdout.write("IP: %s" % u.dominio.ip_str) self.stdout.write("Código: %s" % u.codigo_str) self.stdout.write("Estado: %s" % u.estado) self.stdout.write("Correos de abuso: %s" % u.dominio.correos_str) self.stdout.write("ISP: %s" % u.dominio.isp_str) self.stdout.write("País: %s" % u.dominio.pais_str) self.stdout.write("ASN: %s" % u.dominio.asn_str) self.stdout.write("Servidor web: %s" % u.dominio.servidor_str) self.stdout.write("RIR: %s" % u.dominio.rir_str) self.stdout.write("Sevidores DNS: %s" % u.dominio.dns_str) self.stdout.write("Fecha de creción: %s" % u.timestamp_creacion) self.stdout.write("Ignorado: %s" % u.ignorado_str) self.stdout.write("Reportado: %s" % u.reportado_str) self.stdout.write("Detección: %s" % u.deteccion_str) self.stdout.write("Entidad afectada: %s" % u.entidad_afectada_str) ua = u.obten_info_activa if ua: self.stdout.write("Título: %s" % ua.titulo_str) self.stdout.write("Ofuscación: %s" % ua.ofuscaciones_str) self.stdout.write("Hash MD5 de archivo: %s" % ua.hash_archivo_str) self.stdout.flush()
def handle(self, *args, **options): log.log("Inicia ejecucion de script de correos", "correo.log") d = settings.DIR_CORREOS log.log("Directorio base de correos: %s" % d, "correo.log") p = os.path.join(d, "procesados") if not os.path.exists(p): os.mkdir(p) archivos = [ f for f in os.listdir(d) if os.path.isfile(os.path.join(d, f)) ] for x in archivos: log.log("Leyendo archivo %s" % x, "correo.log") a = os.path.join(d, x) with open(a) as f: _, urls, _, _, error = correo.parsecorreo(f.read(), x, False) if error: log.log("Error al leer correo '%s'" % a, "correo.log") else: urls = list(set(urls)) phishing.verifica_urls(urls, "correo.log") for u in urls: log.log("Verificada URL %s" % u, "correo.log") os.rename(a, os.path.join(p, x)) log.log("Termino ejecucion del script", "correo.log")