@eugeniabahit GLAMP HACKER Y PROGRAMADORA EXTREMA HACKER ESPECIALIZADA EN PROGRAMACIN EXTREMA E INGENIERA INVERSA DE CDIGO SOBRE GNU/LINUX, APACHE, MYSQL, PYTHON Y PHP. EUGENIABAHIT.COM DOCENTE E INSTRUCTORA DE TECNOLOGAS GLAMP CURSOS.EUGENIABAHIT.COM CURSOSDEPROGRAMACIONADISTANCIA.COM MIEMBRO DE LA FREE SOFTWARE FOUNDATION FSF.ORG, THE LINUX FOUNDATION LINUXFOUNDATION.ORG E INTEGRANTE DEL EQUIPO DE DEBIAN HACKERS DEBIANHACKERS.NET. CREADORA DE PYTHON-PRINTR, EUROPIO ENGINE, JACKTHESTRIPPER. VIM CONTRI- BUTOR. FUNDADORA DE HACKERS N' DEVELOPERS MAGAZINE Y RESPONSABLE EDITORIAL HASTA OCTUBRE '13. Buenos Aires, 29 de Abril de 2014 NDICE DE LA EDICIN NRO5 INGENIERA DE SOFTWARE: MANIPULACIN DE WEB FORMS Y CARGA DE ARCHIVOS CON PYTHON Y WSGI SBRE APACHE..................................3 EUROPIO ENGINE LAB: DICT OBJECT, UN NUEVO CONCEPTO EN OBJETOS PARA LAS VISTAS EN PHP.16 SEGURIDAD INFORMTICA: MODELOS DE SEGURIDAD PERMISIVOS COMO MECANISMOS DE PREVENCIN DE VULNERABILIDADES.............................20 BASH SCRIPTING AVANZADO: DIVERSAS FORMAS DE IMPLEMENTACIN DE MENS DINMICOS............28 The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 3 INGENIERA DE SOFTWARE: MANIPULACIN DE WEB FORMS Y CARGA DE ARCHIVOS CON PYTHON Y WSGI SBRE APACHE TRABAJAR CON FORMULARIOS HTML DESDE PYTHON Y SOBRE TODO, MANEJAR LA CARGA DE ARCHIVOS, ES UNA DE LAS TAREAS MENOS SENCILLAS A LA HORA DE CREAR APLICACIONES WEB SIN UTILIZAR FRAMEWORKS. SIN EMBARGO, QUE NO SEA LA MS SENCILLA NO SIGNIFICA QUE SEA IMPOSIBLE. esde que Python comenz a implementarse en el diseo de aplicaciones Web frameworks como Django o e!2"# han parecido ser la !nica alternati"a posible para desarrollar #o$tware accesible mediante un na"egador. % &l auge de estos frameworks y por sobre todo la gran publicidad que los programadores menos e'perimentados en la (ngenier)a de #o$tware basado en Web le han hecho a %jango lograron acercar a miles de de usuarios que sin conocimientos de programacin en Python pod)an desarrollar aplicaciones Web con tan solo aprender a usar el framework. #abemos que $a humani%a% se mueve a !ase %e a!usos de todo tipo y la (ngenier)a de #o$tware no es ajena a ello. *anto es as) que $os usuarios &ue %esarro$$an a'$i(a(iones e! uti$i)an%o Django, %es(ono(en 'or (om'$eto e$ $enguaje y carecen de nociones b+sicas de programacin a un punto tal que en mucho casos se llega a creer imposible que puedan desarrollarse aplicaciones Web en Python sin el uso de frameworks. ,ace un tiempo publiqu- un paper en De!ian *a(+ers . sobre cmo crear un sitio Web en Python bajo /pache sin utilizar frameworks 2 . &ste art)culo pretende continuar esta idea otorgando al lector las herramientas necesarias para manipular todo tipo de $ormularios Web incluyendo la carga de archi"os al ser"idor. *oda esta in$ormacin puede complementarse con el material 0 del (urso %e Desarro$$o %e A'$i(a(iones e! (on "#thon # ,#S-. que dict- durante 12.1 y 12.0 en cursos.eugeniabahit.com . www.debianhac3ers.net 1 http455www.debianhac3ers.net5una6web6en6python6sobre6apache6sin6$ramewor3s6y6en6solo606pasos 0 http455www.cursosdeprogramacionadistancia.com5static5pd$5material6sin6personalizar6python.pd$ The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 4 DECLARANDO EL ENCTYPE CORRECTO &n los $ormularios ,*7L el atributo enctype se de$ine cuando el m-todo ha sido establecido como POST y su $inalidad es la de indicar en qu- $orma ser+n codi$icados los datos al en"iarse el $ormulario. <form id='something' method='post' action='/some/file' enctype='multipart/form-data'> </form> &l atributo enctype puede tener 0 va$ores di$erentes4 multipart/form-data 8odi$icacin4 ninguna 9los caracteres son en"iados tal cual est+n sin codi$icacin pre"ia: ;so4 recomendado para manipular la carga de archi"os %elimitador de campos4 aleatorio 9se obtiene mediante la cla"e 8<=*&=*6*>P& del diccionario en"iron: delimitador = environ['CONTNT!T"P'#$replace%'m<ipart/form!data' (o&ndary=') ''* # retornar algo como: -----------------------------17553758491697998425554867382 ?ormato recepcin de datos4 &jemplo para un $ormulario con dos campos de te'tos 9nombre y edad: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!+,--.,-/01+21,11/03---0/2,./3 Content!4isposition5 form!data' name=6nom(re6 7&an P8re9 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!+,--.,-/01+21,11/03---0/2,./3 Content!4isposition5 form!data' name=6edad6 1: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!+,--.,-/01+21,11/03---0/2,./3!! application/x-www-form-urlencoded 8odi$icacin4 /#8(( ,e'adecimal. Los espacios en blanco se reemplazan por el signo @ ;so4 es el "alor por de$ecto de todo $ormulario. #e recomienda para todos los $ormularios que no requieran manipular la carga de archi"os. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 5 %elimitador de campos4 #igno A ?ormato recepcin de datos4 &jemplo para un $ormulario con dos campos de te'tos 9nombre y edad: nom(re=7&an;P<C.<=1re9>edad=1: =otar que la "ocal BeC acentuada ha sido codi$icada como D80D mientras que el espacio en blanco $ue sustituido por el signo @ text/plain 8odi$icacin4 ninguna 9los caracteres son en"iados tal cual est+n sin codi$icacin pre"ia: ;so4 desaconsejado %elimitador de campos4 retorno de carro ?ormato recepcin de datos4 &jemplo para un $ormulario con dos campos de te'tos 9nombre y edad: nom(re=7&anP8re9 edad=1: &l uso del "alor te't5plain se desaconseja ya que al emplear el retorno de carro como delimitador di$iculta la obtencin de datos en bloques de te'to que incluyan el salto de l)nea. Para el comn de los formularios, no es necesario declarar el enctype. Declararlo como multipart/form-data si se trabajar con la carga de archivos. MANIPULANDO DATOS DESDE PYTHON Y WSGI 8uando se reciben datos mediante P<#* siempre se necesita tener acceso a dos $actores4 el nombre de los campos y su correspondiente "alor. &n Python la $orma lgica de asociar un nombre de campo a un "alor es utilizar un diccionario4 datos = dict%campo+='valor del campo +') campo3='valor del campo 3'* The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 6 Lo que se debe lograr entonces es crear un diccionario con dicha in$ormacin con"irtiendo los datos recibidos en un diccionario. La $orma de lograr esta con"ersin depende directamente del modelo de codi$icacin con el que la in$ormacin haya sido en"iada es decir que depende del enctype que se haya declarado en el $ormulario. 8uando se trabaja con W#E( los datos en"iados por POST se almacenan en la cla"e ?sgi$inp&t del diccionario environ 9que W#E( entrega a la $uncin application* y se obtienen leyendo dicho elemento con el m-todo read%* tal como se muestra a cotinuacin4 datos = environ['?sgi$inp&t'#.read() Retornatar algo como: campo1=valor1&campo2=valor2 APPLICATION/X-WWW-FORM-URLENCODED Fecordemos que -ste es el "alor por de$ecto de todo $ormulario. #i no se ha asignado un enctype los datos ser+n codi$icados siguiendo este $ormato. 8omo el delimitador de campos es el signo > podemos obtener una lista donde cada elemento sea un par clave=valor datos = environ['?sgi$inp&t'#$read%*.split('&') Luego en cada elemento de la lista el signo = separa al nombre del campo de su "alor correspondiente con lo que ya tenemos todos los elementos necesarios para armar el diccionario4 datos = environ['?sgi$inp&t'#$read%*$split%'>'* POST = @A for par in datos5 campo) valor = par$split%'='* POST[campo# = valor Fecordemos que los datos son codi$icados en $ormato /#8(( ,e'adecimal y los espacios en blanco sustituidos por el signo @. Podemos "ol"er los "alores a su estado puro utilizando la $uncin &nB&ote del mdulo &rlli(3 y reemplazando el signo @ por un espacio en blanco4 from urllib2 import unquote datos = environ['?sgi$inp&t'#$read%*$split%'>'* The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 7 POST = @A for par in datos5 campo) valor = par$split%'='* POST[campo# = unquote(alor).replace('!'" ' ') %e esta $orma habremos obtenido un diccionario como el siguiente4 @ 'nom(re'5 '7&Cn P8re9') 'edad'5 '2-') 'nacionalidad'5 '&r&g&aya' A /l cual podremos acceder utilizando el nombre de los campos como nombre de cla"e4 nom(re = POST['nom(re'# if 'nom(re' in POST else '' edad = POST['edad'# if 'edad' in POST else '' nacionalidad = POST['nacionalidad'# if 'nacionalidad' in POST else '' /EC01E/ 1/2"0S DE DA30S &n cualquier $ormulario Web es $recuente tener grupos de opciones bajo un mismo nombre. &s el caso de los campos de tipo chec3bo' y los de tipo select m!ltiple4 <inp&t type='checD(oE' name='gr&poFa' val&e='+' checDed>OpciGn +<(r> <inp&t type='checD(oE' name='gr&poFa' val&e='3'>OpciGn 3<(r> <inp&t type='checD(oE' name='gr&poFa' val&e='.' checDed>OpciGn .<(r> <select name='com(o' si9e='.' m<iple> <option val&e='+'>OpciGn +</option> <option val&e='3'>OpciGn +</option> <option val&e='.'>OpciGn +</option> <option val&e='0'>OpciGn +</option> <option val&e='-'>OpciGn +</option> </select> 8uando -ste es el caso $os va$ores e$egi%os no son agru'a%os a$ momento %e enviarse. Por el contrario el nombre del campo se repetir+ tantas "eces como opciones se hayan elegido. Lo que se pretende entonces es capturar las opciones elegidas dentro de una lista asignada a la misma cla"e del diccionario. ;n ejemplo de lo que se quiere obtener ser)a como el siguiente4 The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 8 @ 'gr&poFa'5 [+) .#) 'com(o'5 [3) 0) -# A Para lograrlo si simplemente asign+ramos el "alor a la cla"e el !ltimo "alor sobre escribir)a a los anteriores. &ntonces antes de asignar un "alor a una cla"e debemos "eri$icar que la cla"e no e'ista. POST = @A for par in datos5 campo) valor = par$split%'='* if not campo in #$%&' POST[campo# = &nB&ote%valor*$replace%';') ' '* #i la cla"e e'iste podemos encontrar dos posibilidades4 .. Gue su "alor sea un !nico dato 9el dato $ue almacenado cuando if not campo in POST $ue "erdadero: 1. Gue su "alor sea una lista 9cuando if not campo in POST $uese $also: &sto habr+ que "eri$icarlo y4 .. &n el primer caso habr+ que con"ertir al "alor de dicha cla"e en una lista y agregarle el "alor que ya ten)a asignado m+s el nue"o "alorH 1. y en el segundo agregar directamente el nue"o "alor. 8ompletaremos el cdigo agrup+ndolo ya mismo en una $uncin y haremos que esta retorne el diccionario con los datos para que pueda ser llamada desde cualquier $uncin que necesite obtener datos en"iados desde un $ormulario4 from &rlli(3 import &nB&ote def getFsimpleFformFdata%environ*5 datos = environ['?sgi$inp&t'#$read%*$split%'>'* POST = @A for par in datos5 campo) valor = par$split%'='* valor = &nB&ote%valor*$replace%';') ' '* if not campo in POST5 POST[campo# = valor else5 if not isinstance%POST[campo#) list*5 # an no es na l!sta POST[campo# = [POST[campo#) valor# else5 # "a es na l!sta POST[campo#$append%valor* The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 9 ret&rn POST Luego podr)amos llamarla desde cualquier otra $uncin4 def enviarFform%environ*5 #$%& = (et)simple)form)data(eniron) # ### MULTIPART/FORM-DATA 7anipular datos en este caso es mucho m+s complejo ya que parte de esos datos es la carga de archi"os. Para poder gestionar archi"os cargados desde un $ormulario se necesita recurrir a dos mdulos adicionales4 tempfile 9para trabajar con archi"os temporales: y c(i 9para $acilitar el acceso a todos los datos y obtener toda la in$ormacin adicional sobre los mismos:. %e cada mdulo haremos uso de una sola clase4 TemporaryHile y HieldStorage respecti"amente. from cgi import HieldStorage from tempfile import TemporaryHile La clase *ield%tora(e sir"e para almacenar una secuencia de campos leyendo justamente los datos en"iados desde un $ormulario codi$icado como m<ipart/form!data. &sta clase genera un diccionario como el que creamos anteriormente de $orma manual pero con una di$erencia muy importante4 cada elemento de este diccionario contiene in$ormacin rele"ante como el tipo 7(7& del dato e incluye el contenido de archi"os incluso cuando -stos sean binarios. Pero esta clase requiere inde$ectiblemente que se le indique un puntero y no puede utilizarse ?sgi$inp&t para ser apuntado como archi"o. &s necesario entonces crear un archi"o temporal para poder trabajar con HieldStorage la clase que nos permitir+ manejar la carga de archi"os. Lo primero que debemos hacer entonces es grabar el contenido de ?sgi$inp&t en un archi"o temporal ya que no nos ser+ posible trabajar directamente con ?sgi$inp&t ya que solo podr)amos acceder al nombre del archi"o. Erab+ndolo en un archi"o temporal podremos utilizarlo como puntero desde HileStorage para crear el archi"o en el ser"idor. Pero "amos de a poco. 8omencemos por grabar el contenido de ?sgi$inp&t en un archi"o temporal4 # $rea n arc%!vo temporal " lo a&re 'por (e)ecto* en mo(o +,r archivoFtemporal = TemporaryHile%* # -scr!&!mos el conten!(o (e +sg!#!npt en el arc%!vo temporal archivoFtemporal$?rite%environ['?sgi$inp&t'#$read%** # .ovemos al crsor al !n!c!o "a /e neces!taremos leer este arc%!vo (es(e el com!en0o archivoFtemporal$seeD%:* The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 10 ;na "ez creado el archi"o temporal podemos inicializar un objeto HieldStorage indicando como puntero al archi"o temporal que acabamos de crear4 datos = HieldStorage%fp=archivoFtemporal* Por de$ecto HieldStorage obtiene el diccionario environ desde el mdulo os pero como estamos trabajando con W#E( sabemos que el diccionario environ es modi$icado por W#E( as) que se lo pasaremos para que pueda obtener la in$ormacin correcta4 datos = HieldStorage%fp=archivoFtemporal) environ=environ* /hora la "ariable datos se ha con"ertido en un diccionario sobre el que podremos iterar para obtener los pares de cla"e y sus "alores correspondientes. &l nombre del campo 9o cla"e para nuestro diccionario: lo obtendremos iterando entonces sobre la "ariable datos trat+ndola como si $uese un diccionario com!n y corriente4 for clave in datos5 # ### /ntes de obtener el "alor de un campo necesitaremos saber si se trata o no de un archi"o porque de ser as) no solo necesitar)amos el contenido del archi"o sino otros datos como el tipo 7(7& y el nombre del archi"o. Para saber si se trata o no de un archi"o debemos "eri$icar si la propiedad filename es None4 for clave in datos5 if datos+clae,.filename is -one' # 12 -3 n arc%!vo #i no se tratase de un archi"o podr)amos obtener el "alor de este campo mediante la propiedad val&e4 for clave in datos5 if datos[clave#$filename is None5 alor = datos+clae,.alue #i en cambio se tratara de un archi"o quisi-ramos que el "alor $uese otro diccionario con los siguientes datos4 nombre del archi"o tipo 7(7& y contenido 9para poder crearlo posteriormente en el ser"idor:. Para ello necesitaremos acceder a las propiedades filename type y val&e respecti"amente4 The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 11 for clave in datos5 if datos[clave#$filename is None5 valor = datos[clave#$val&e else5 alor = dict( filename=datos+clae,.filename" filetype=datos+clae,.type" content=datos+clae,.alue ) ?inalmente solo resta utilizar las cla"es y "alores para crear nuestro propio diccionario igual que hicimos anteriormente4 POST = @A for clave in datos5 if datos[clave#$filename is None5 valor = datos[clave#$val&e else5 valor = dict% filename=datos[clave#$filename) filetype=datos[clave#$type) content=datos[clave#$val&e * POST[clave# = valor /EC01E/ 1/2"0S DE DA30S =ue"amente nos podemos encontrar con que tenemos grupos de datos que pertenecen a un mismo nombre. &n este caso el tratamiento di$iere del que hemos hecho antes ya que HieldStorage nos permite acceder a los grupos de datos como una lista mediante el m-todo getlist%*. Lo que haremos entonces es "eri$icar si se trata o no de un grupo de datos llamando a este m-todo y de ser as) el "alor ya no ser+ el obtenido mediante la propiedad val&e) sino el obtenido mediante este m-todo. /l igual que en el caso anterior "amos a apro"echar a colocar todo en una $uncin que retorne el diccionario P<#* para que pueda ser llamada desde cualquier otra que la necesite4 from cgi import HieldStorage from tempfile import TemporaryHile def getFm<ipartFformFdata%environ*5 archivoFtemporal = TemporaryHile%* archivoFtemporal$?rite%environ['?sgi$inp&t'#$read%** archivoFtemporal$seeD%:* datos = HieldStorage%fp=archivoFtemporal) environ=environ* POST = @A for clave in datos5 if datos[clave#$filename is None5 lista = datos.(etlist(clae) valor = datos+clae,.alue if len(lista) . 2 else lista else5 The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 12 valor = dict% filename=datos[clave#$filename) filetype=datos[clave#$type) content=datos[clave#$val&e * POST[clave# = valor ret&rn POST 8omo podemos "er "alor ser+ igual a lo obtenido mediante la propiedad val&e siempre y cuando la lista tenga menos de dos elementos 9es decir uno o ninguno:. %e lo contrario el "alor ser+ la lista de datos. /EC01E/ 1/2"0S DE A/C*450S &n el ejemplo anterior se contempla que los grupos de datos 9campos con el mismo nombre y distintos "alores: no ser+n de tipo file. #in embargo puede suceder que un mismo $ormulario tenga m+s de un campo de tipo file con el mismo nombre y aqu) la metodolog)a de implementar getlist%* para reconocer Igrupos de in$ormacinJ ya no ser+ "iable. Por consiguiente la primera condicin a e"aluar ya no ser)a preguntar si datos[clave#$filename es nulo sino si datos[claves# es una lista. Para que la $uncin no se haga repetiti"a y engorrosa crearemos una $uncin adicional encargada de retornar los "alores como diccionario o string seg!n se trate de un campo de tipo $ile o no y luego la llamaremos desde getFm<ipartFformFdata%*. from cgi import HieldStorage from tempfile import TemporaryHile def getFm<ipartFformFdata%environ*5 archivoFtemporal = TemporaryHile%* archivoFtemporal$?rite%environ['?sgi$inp&t'#$read%** archivoFtemporal$seeD%:* datos = HieldStorage%fp=archivoFtemporal) environ=environ* POST = @A for clave in datos5 if isinstance(datos+clae," list)' POST[clave# = [# for elemento in datos[clave#5 #$%&+clae,.append(traer)alor(elemento)) else5 #$%&+clae, = traer)alor(datos+clae,) ret&rn POST def traer)alor(dato)' valor = dict%filetype=dato$type) filename=dato$filename) content=dato$val&e* ret&rn dato$val&e if dato$filename is None else valor The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 13 UN DECORADOR QUE DECIDA SOLO ,emos logrado abarcar todas las posibilidades en cuanto a manipulacin de $ormularios respecta desde Python con W#E(. 8reamos dos $unciones que contemplan todas las posibilidades que e'isten y podemos con ellas crear un decorador para que mediante un simple llamado en"uel"a a cada $uncin que reciba datos desde un $ormulario. Si te perdiste la edicin anterior sobre wrappers y decoradores en Python, te recomiendo descargues The Original Hacker N4 y leas el artculo de pgina 30. Para descargar *he <riginal ,ac3er =KL ingresa en http455library.originalhac3er.org5biblioteca5re"ista5"er512 8rearemos un decorador gen-rico que identi$icando el enctype del $ormulario se encargue de llamar a una u otra $uncin desde el ?rapper. =o necesitamos modi$icar las $unciones que ya creamos aunque recomiendo hacerlas pri"adas y utilizar un mdulo $py para las $unciones y el decorador. from cgi import HieldStorage from tempfile import TemporaryHile from &rlli(3 import &nB&ote def (et)post)data(funcion)' def ?rapper%environ*5 FPOST = @A try5 if not environ['CONTNTFT"P'#$starts?ith%'m<ipart/form!data'*5 FPOST = FFgetFsimpleFformFdata%environ* else5 FPOST = FFgetFm<ipartFformFdata%environ* eEcept5 pass ret&rn f&ncion%FPOST* ret&rn ?rapper def ))(et)simple)form)data(eniron)' datos = environ['?sgi$inp&t'#$read%*$split%'>'* POST = @A for par in datos5 campo) valor = par$split%'='* valor = &nB&ote%valor*$replace%';') ' '* if not campo in POST5 POST[campo# = valor else5 if not isinstance%POST[campo#) list*5 The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 14 POST[campo# = [POST[campo#) valor# else5 POST[campo#$append%valor* ret&rn POST def ))(et)multipart)formdata(eniron)' POST = @A archivoFtemporal = TemporaryHile%* archivoFtemporal$?rite%environ['?sgi$inp&t'#$read%** archivoFtemporal$seeD%:* datos = HieldStorage%fp=archivoFtemporal) environ=environ* for clave in datos5 campo = datos[clave# if isinstance%campo) list*5 POST[clave# = [# for elemento in campo5 POST[clave#$append%FFgetFval&e%elemento** else5 POST[clave# = FFgetFval&e%campo* ret&rn POST def ))(et)alue(campo)' archivo = dict%filetype=campo$type) filename=campo$filename) content=campo$val&e* ret&rn campo$val&e if campo$filename is None else archivo Luego simplemente deber+s decorar a cualquier $uncin que reciba datos desde un $ormulario independientemente del enctype que se le haya declarado4 /(et)post)data def enviarFform%POST*5 pass CARGA DE ARCHIVOS DESDE FORMULARIOS Y ALMACENAMIENTO EN EL SERVIDOR >a tenemos todo listo para poder manipular los archi"os. Lo !nico que nos resta es algo tan simple como seguir unos cortos pasos. 8rear un directorio pri"ado con permisos de escritura4 mDdir privateFdir >> chmod ,,, !I privateFdir Erabar el contenido del archi"o en uno nue"o dentro el directorio pri"ado4 The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 15 JgetFpostFdata def enviarFform%environ*5 carpeta = '/r&ta/a/directorio/privado/' r&taFarchivo = carpeta ; POST['archivo'#['filename'# ?ith open%r&taFarchivo) '?'* as archivo5 archivo$?rite%POST['archivo'#['content'#* Por supuesto que si se debe "alidar el tipo 7(7& del archi"o se lo har+ mediante POST['archivo'# ['filetype'# antes del bloque ?ith y solo se ejecutar+ -ste si el tipo 7(7& es el esperado4 JgetFpostFdata def enviarFform%environ*5 carpeta = '/r&ta/a/directorio/privado/' r&taFarchivo = carpeta ; POST['archivo'#['filename'# mime = #$%&+'archio',+'filetype', if mime == 'application/pdf'' ?ith open%r&taFarchivo) '?'* as archivo5 archivo$?rite%POST['archivo'#['content'#* ret&rn '=rchivo g&ardado' else5 ret&rn 'Solo se permiten archivos P4H' Contratan%o un 5"S (on e$ en$a(e %e esta 'u!$i(i%a%, me a#u%as a mantener 3he 0rigina$ *a(+er 67 Servi%ores a solo 2SD 8 9 mes4 20 1B de disco %iscos SSD . *B de trans$erencia 812 7B /A, 4nsta$a(i:n en menos %e 1; &lige 2!untu Server 12<04 .3S y despreoc!pate de la seguridad optimiz+ndolo con =a(+3heStri''er Luego de instalarlo (on>ig?ra$o (on =a(+3heStri''er4 http455www.eugeniabahit.com5proyectos5jac3thestripper Contratan%o (on este en$a(e, me a#u%as a mantener 3he 0rigina$ *a(+er6 http455bit.ly5promo6digitalocean The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 16 EUROPIO ENGINE LAB: DICT OBJECT, UN NUEVO CONCEPTO EN OBJETOS PARA LAS VISTAS EN PHP EUROPIO ENGINE EN LA REVISIN 17 DE SU VERSIN BETA 3.4, INCORPORA UN NUEVO CONCEPTO QUE REVOLUCIONA EL TRATAMIENTO DE LAS VISTAS EN PHP. SE TRATA DE OBJETOS DE TIPO DICCIONARIO QUE EN ESTAS NOTAS, TE CUENTO LA MOTIVACIN, SU CONCEPCIN Y FORMA DE IMPLEMENTARLOS. n "arios papers y art)culos en general en los cuales hablo de 7M8 no me canso de repetir que $as vistas en ,5C son un arte. & &n 7M8 todo el arte de las "istas se encuentra siempre en (onvertir $o &ue se tiene en $o &ue se ne(esita. Lo que se tiene siempre es distinto. #in embargo siempre es un objeto 9o coleccin de objetos: mucho m+s all+ de su complejidad interna y ni"eles de dependencia. > siempre lo que se necesita es con"ertir todos esos objetos y sus propiedades en diccionarios que no son m+s que arrays asociati"os para P,P. 7oti"ado por la necesidad de e"itar la redundancia de cdigo en las "istas =imm# Danie$ Barran(o me propuso crear un helper a ni"el del core que eliminara la redundancia. > as) entre ambos creamos un nue"o concepto en P,P4 objetos de tipo diccionario. E$ o!jeto Dict. MOTIVACIN 8omo coment- al comienzo la moti"acin principal $ue la necesidad de suprimir la redundancia de cdigo en las "istas. La misma se genera $recuentemente en las siguientes circunstancias4 0!jetos (om'uestos %e otros &ue (om'arten 'ro'ie%a%es (on $a misma %enomina(i:n6 $recuentemente sucede que se tiene un objeto / compuesto de un objeto B y ambos poseen una propiedad denomina 8. &sto produce que en las E;( a $in de e"itar el solapamiento de identi$icadores id-nticos se deban utilizar comodines compuestos que por lo general se constituyen del nombre de las propiedades acompaadas por el nombre del objeto adquiriendo $ormatos similares a @o(Keto$propiedadA. Por consiguiente es muy habitual en las "istas "er $racciones de cdigo destinadas a crear nue"as propiedades 9o cla"es en un diccionario:. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 17 Ne(esi%a% %e visua$i)ar %atos so!re o!jetos (on varios nive$es %e %e'en%en(ia6 la denominacin de las propiedades puede no ser igual pero sin embargo tener un objeto / que se compone de uno B que a la "ez se compone de uno 8 etc. y necesitar mostrar en las E;( los datos del objeto N es de lo m+s $recuente. > esta necesidad tambi-n genera en las "istas $racciones de cdigo destinadas solo a crear nue"as propiedades o cla"es en un diccionario. De>orma(i:n # ma$ uso %e o!jetos6 amparados por el hecho de saber que las "istas en 7M8 son m+s un arte que una ciencia para satis$acer las dos necesidades anteriores lo $recuente se trans$ormaba en una de$ormacin absoluta de los objetos lo cual tarde o temprano termina no IoliendoJ bien. *odo lo anterior no hace m+s que generar grandes bloques de cdigo en la mayor)a de las "istas que no solo podr)a e"itarse sino que adem+s deber)a e"itarse ya que $a sim'$i(i%a%, siem're %e!er@a ser $a ?ni(a so$u(i:n (orre(ta. UN OBJETIVO, UNA SOLUCIN... *en)amos que lograr entonces crear un helper que no actuase de $orma IdesesperadaJ en pro de Ino repetir cdigoJ. %eb)a solucionar el problema de una $orma correcta es decir solucionarlo empleando un argumento lgico "+lido simpleza y prolijidad. ?ue entonces que al pensar en que si aquello que se necesita en las "istas es un diccionario Opor qu- no crear el concepto de diccionario como objetoP > de hacerlo Oqu- caracter)sticas deber)a tener -ste como objetoP La solucin hallada se e'plica a continuacin. CARACTERSTICAS QUE DEBE POSEER UN OBJETO DICCIONARIO 8omo caracter)sticas del objeto hab)a que proponer algo simple que no $uese necesario e'plicar y que pudiese deducirse por s) solo. 8omo !nicas caracter)sticas de este objeto se emplearon las siguientes4 "/0"4EDADES6 #us !nicas propiedades ser+n denominaciones $ormadas por pares o(Keto$propiedad justi$icando -stas en que un diccionario debe ser un mapa de las propiedades de uno o "arios de los objetos que se desea parsear en una "ista. ,A30D0S6 haciendo honor a los objetos hallados en los inicios cl+sicos de la programacin orientada a objetos tradicional solo deber)a contar con un m-todo set. &l m-todo get no tendr)a razn de ser ya que los diccionarios deber)an ser "ol+tiles y solo gestarse en base a objetos reales persistentes por otras ")as. RESULTADOS (mplementando los objetos de tipo %iccionario en las "istas se obtienen resultados sumamente elegantes y de esta $orma se pone $in a los complejos algoritmos y los largos bloques de cdigo que habitualmente solemos tener. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 18 &l objeto 4ict es un objeto instanciable que al in"ocar a su m-todo set%* se le pasa un objeto real como par+metro. %e esta $orma tras in"ocar a set%* el objeto 4ict tendr+ disponible un mapa de propiedades compuesto por los nombres de los objetos y las propiedades de -stos. Para entenderlo mejor obser"ar el siguiente ejemplo. %ado un objeto compuesto con los siguientes ni"eles de pro$undidad4 Hoo O(Kect % [a# => + [(# => 3 [c# => . [(ar# => Lar O(Kect % [a# => + [(# => 3 * [far# => Har O(Kect % [a# => + [(# => 3 [c# => . [d# => 0 * * <btendremos el siguiente diccionario4 4ict O(Kect % [foo$a# => + [foo$(# => 3 [foo$c# => . [(ar$a# => + [(ar$(# => 3 [far$a# => + [far$(# => 3 [far$c# => . [far$d# => 0 * &l cual nos permitir+ en las E;( utilizar identi$icadores como en el siguiente ejemplo4 <h+>0foo.a1</h+> <h3>0foo.b1</h3> <(locDB&ote> <(>Lar5</(> 0bar.b1<(r> <(>Har5</(> 0far.d1 </(locDB&ote> The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 19 USO E IMPLEMENTACIN ;tilizar el objeto 4ict es suma simple. #olo debe ser instanciado y luego se debe in"ocar al m-todo set%: en"iando un objeto como par+metro y luego utilizar el objeto 4ict para e$ectuar la sustitucin de los ,*7L los cu+les deber+n implementar el nombre de los objetos adem+s del de las propiedades. (ndependientemente del ni"el de pro$undidad al que se llegue con la composicin de objetos $os i%enti>i(a%ores B(omo%ines7 %e $os *3,. %e!erCn em'$ear e$ >ormato6 @o(Keto$propiedadA Para generar e$ %i((ionario solo se requieren dos instrucciones4 Mdict = ne? 4ict%*' Mdict!>set%Mo(Keto*' printFr%Mdict* #i se quieren o!tener %i((ionarios so!re una (o$e((i:n %e o!jetos se debe apelar al objeto 2ict3ollection$ &l mismo tambi-n cuenta con un m-todo set%* al que se le debe pasar una coleccin de objetos 9propiedad colectora:. &l objeto 4ictCollection pro"eer+ de una propiedad colectora 4ictCollection!>collection compuesta de una coleccin de objetos 4ict5 MdictFcollection = ne? 4ictCollection%*' MdictFcollection!>set%Mcoleccion*' printFr%MdictFcollection!>collection*' The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 20 SEGURIDAD INFORMTICA: MODELOS DE SEGURIDAD PERMISIVOS COMO MECANISMOS DE PREVENCIN DE VULNERABILIDADES LOS MODELOS DE SEGURIDAD PERMISIVOS, A PESAR DE LO COMPLEJO DE SU ANLISIS, SON LOS NICOS CAPACES DE GENERAR APLICACIONES INVULNERABLES, YA QUE AL NO ESTAR BASADOS EN LA PREVENCIN DE RIESGOS CONOCIDOS NO DAN LUGAR A DESCUBRIR NUEVOS AGUJEROS , PUES LOS PROPIOS MODELOS, NO SON MS QUE ILUSIONES PTICAS . uando comenzamos a programar una de las primeras cosas que aprendemos en materia de seguridad de aplicaciones es a $iltrar entradas del usuario quit+ndoles todo aquel caracter prohibido. ,oy me pregunto D%e ver%a% en a$g?n momento nos hemos senti%o mCs $istos &ue e$ resto %e$ mun%oE 8 "rohi!ir es una tarea te%iosa e in>initaH cuanto m+s se analizan e in"estigan los posibles I$lancos de ataqueJ en una aplicacin la tarea de prohibir puede llegar a hacerse interminable ya que en la (ngenier)a de #o$tware aplica indirectamente el mismo principio que en el derecho penal4 Ino e'iste prohibicin sin penaJ. &n los sistemas in$orm+ticos al igual que un cdigo penal cada prohibicin debe especi$icarse minuciosa y detalladamente. Pero la peor parte 6para la in$orm+tica6 es que al prohibir necesariamente se debe indicar Icu+l ser+ la penaJ solo que para el #o$tware esto es meta$rico. > cuando hablamos de Iestablecer una penaJ nos estamos re$iriendo a im'$ementar (om'$ejos a$goritmos &ue res'on%an >rente a (a%a a(to 'rohi!i%o. Prohibimos el ingreso de comillas simples entonces al igual que en el derecho no basta con decirle a un indi"iduo que Iest+ prohibido matarJ porque en realidad no est+ prohibido est+ IpenadoJ. Con (o$o(ar un (arte$ &ue %iga F'or >avor, no ingrese (omi$$as sim'$esG no a$(an)aH %e!emos (rear un a$goritmo &ue se en(argue %e erra%i(ar$as< Pero esto no termina aqu) y debe repetirse el mismo esquema de procedimientos con cada IcosaJ que deseemos prohibir en nuestro sistema. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 21 Cuando implementamos modelos de seguridad por prohibicin, no estamos teniendo en cuenta que no somos omnipotentes &n .QQQ la mayor)a de las aplicaciones Web que implementaban sistemas de registro de usuarios buscadores basados en bases de datos y a$ines no e$ectuaban ning!n tipo de $iltro como los de hoy en d)a. ,asta que alg!n d)a alguien habr+ "isto que un maldito < en un buscador pod)a romper el NOP de una sentencia #GL. > eso mismo sucede todos los d)as. Lamentablemente, cada vez ms gente invierte su tiempo en mejorar tcnicas de pentesting y en crear herramientas de exploiting, en vez de ampliar sus capacidades cognitivas intentando hallar verdaderas soluciones mediante investigacin cientfica 3o%os $os %@as se F%es(u!renG nuevas >ormas %e %estruir $os sistemas in>ormCti(os. #e les suele llamar I"ulnerabilidadesJ pero desde mi punto de "ista todo sistema in$orm+tico aunque se encuentre libre de toda "ulnerabilidad tendr+ al menos una !nica "ulnerabilidad si se implementa un modelo de seguridad prohibiti"o4 $a >a$sa omni'oten(ia %e sus %esarro$$a%ores. El modelo de seguridad prohibitivo es la primera vulnerabilidad de un sistema informtico La humanidad suele no tomarse la molestia de analizar y descubrir cone'iones lgicas entre dos o m+s hechos que en apariencia no se encontrar)an relacionados. %icho de $orma m+s simple $a ma#or@a %e $as 'ersonas no se mo$esta en Fatar (a!osG. Pues de hacerlo la seguridad in$orm+tica deber)a ser una ciencia e'acta ya que en nuestra vi%a (oti%iana, tenemos so!ra%os ejem'$os %e (:mo Fe$ 'rohi!irG siem're se &ue%a %etrCs %e $os a(onte(imientos ya que como marca un "iejo dicho popular hecha la Ley, hecha la trampa. Pero a di$erencia del derecho en el caso de la (ngenier)a de #o$tware esto tiene solucin y consiste en implementar Fmo%e$os %e seguri%a% 'ermisivosG. QU SON Y EN QU CONSISTEN LOS MODELOS DE SEGURIDAD PERMISIVOS? =o es nada di$)cil deducir. #e trata de modelos de seguridad que para establecer sus pol)ticas se basan en aquello que se permite en una aplicacin en "ez de in"ertir cientos y miles de bytes de$iniendo algoritmos centrados en lo que se proh)be. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 22 CARACTERSTICAS DE LOS MODELOS DE SEGURIDAD PERMISIVOS &stos modelos suelen dar libertades al usuario que com!nmente se le niegan y hasta incluso podr)an considerarse impensables como ser)a el caso de permitirle elegir un nombre de usuario con$ormado por caracteres no al$anum-ricos como podr)an ser comillas simples. &s por ello que son (onsi%era%os mo%e$os %e seguri%a% F$i!era$esG en los cuales la criptogra$)a 6tanto desde la codi$icacin hasta la encriptacin6 juegan un papel protagnico puesto que son el pilar del modelo. La criptografa y la codificacin son el pilar de los modelos de seguridad permisivos &s entonces que como principales caracter)sticas podemos listar las siguientes4 .. %an amplia libertad de accin y mo"imiento al usuarioH 1. &mplean sistemas criptogr+$icos con mucha $recuenciaH 0. ;tilizan la 9re:codi$icacin como base del modelo liberal. VENTAJAS Y DESVENTAJAS DE LOS MODELOS DE SEGURIDAD PERMISOS Los modelos de seguridad permisi"os 9o liberales: suelen traer aparejadas much)simas m+s "entajas y por consiguiente bene$icios que des"entajas. .as %esventajas sue$en ser mCs !ien %e @n%o$e so(ia$ ya que las aplicaciones que implementan modelos de seguridad permisi"os suelen ser blanco $+cil de los Iaprendices de crackersJ o de conductas delicti"as semejantes ya que inicialmente los $uturos delincuentes suelen dejarse lle"ar por el entusiasmo de creer que Iel e'ceso de libertadesJ se debe a una conducta negligente de los programadores. #in embargo e$ (ese %e $os intentos %e ata&ue sue$e 'ro%u(irse mu(ho mCs rC'i%o que en las aplicaciones que implementan modelos de seguridad restricti"os 9o prohibiti"os: ya que en su mayor)a este ti'o %e %e$in(uentes !us(an satis>a(er sus >antas@as %e >orma inme%iata # a$ no (onseguir$o, a!an%onan 'ara !us(ar una v@(tima mCs vu$nera!$e &ue $es >a(i$ite e$ '$a(er inme%iato. =o obstante es "+lido recordar que si bien todo per$il criminal busca la satis$accin inmediata de sus $antas)as e'iste porcin m+s reducida de delincuentes con una psiquis mucho m+s compleja que podr)an permanecer aos tratando de "iolar la seguridad de un sistema por el mero hecho de sentir el placer que no logran alcanzar en otros aspectos de sus "idas. Por consiguiente ser@a un error asumir &ue $os mo%e$os %e seguri%a% 'ermisivos evitan 'or (om'$eto $os intentos %e ata&ues a (orto '$a)o. #i bien hasta aqu) toda des"entaja parece estar compensada por una "entaja o bene$icio e'iste un $actor que con"ierte a los modelos de seguridad permisi"os en algo di$)cil de ser implementados pues solo ser+n realmente seguros si la pol)tica de permisos es delineada por pro$esionales que poseen un conocimiento pro$undo del $uncionamiento interno de un sistema in$orm+tico completo y de la teor)a de ordenadores pues una 'o$@ti(a 'ermisiva ma$ 'ensa%a 'o%r@a generar una a'$i(a(i:n mu(ho mCs vu$nera!$e que aquella que implemente un modelo restricti"o. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 23 EJEMPLOS PRCTICOS DE POLTICAS DE SEGURIDAD BASADAS EN MODELOS PERMISIVOS /unque todo parezca 6en principio6 demasiado no"edoso algunas pol)ticas resultar+n $amiliares ya que en alg!n momento se habr+n puesto en pr+ctica y seguramente en m+s de una oportunidad. #in embargo im'$ementar 'o$@ti(as 'ermisivas %e >orma ais$a%a en un mo%e$o restri(tivo, 'ue%e ser tan riesgoso (omo no im'$ementar ninguna< Por lo tanto los siguientes ejemplos solo se e'ponen a $in de alcanzar una mejor comprensin sobre los modelos de seguridad permisi"os y no deben ser interpretados como una gu)a de seguridad !nica. #in duda la pol)tica permisi"a m+s implementada en aplicaciones es el paso de nombres de archi"o por la ;F( $recuentemente utilizado para la muestra o descarga de contenido est+tico. #in embargo $a misma 'o$@ti(a 'o%r@a estar '$antea%a tanto en un mar(o 'ermisivo (omo en uno restri(tivo, %e'en%ien%o %e $a :'ti(a %es%e $a (ua$ se $o ha#a e$a!ora%o. Msolicit&d = isset%MFQT['page'#* 5 strtolo?er%MFQT['page'#* 5 'defa<'' Marchivo = SORFP=TS $ 6/html/@Msolicit&dA$html6' McontenidoFinterno = fileFgetFcontents%Marchivo*' print strFreplace%'@contenidoA') McontenidoFinterno) SORFTRPN=T*' ,asta aqu) "emos el concepto sin ninguna medida de seguridad de$inida. #uponiendo que en la carpeta SORFP=TS $ 6/html/6 todos los archi"os con e'tensin html que se almacenan puedan ser accesibles por el usuario a lo sumo se podr)a incluir una "alidacin de e'istencia del archi"o para e"itar un $allo en el cdigo que re"elase in$ormacin del sistema4 Msolicit&d = isset%MFQT['page'#* 5 strtolo?er%MFQT['page'#* 5 'defa<'' Marchivo = SORFP=TS $ 6/html/@Msolicit&dA$html6' if%file)exists(4archio)* @ McontenidoFinterno = fileFgetFcontents%Marchivo*' A else @ McontenidoFinterno = ''' A print strFreplace%'@contenidoA') McontenidoFinterno) SORFTRPN=T*' & incluso el algoritmo anterior podr)a optimizarse a!n m+s de$iniendo un contenido interno por de$ecto y haciendo el algoritmo mucho m+s seguro y legible4 Msolicit&d = isset%MFQT['page'#* 5 strtolo?er%MFQT['page'#* 5 'defa<'' Marchivo = SORFP=TS $ 6/html/@Msolicit&dA$html6' 4contenido)interno = ''5 if(file)exists(4archio)) 4contenido)interno = file)(et)contents(4archio)5 print strFreplace%'@contenidoA') McontenidoFinterno) SORFTRPN=T*' 8onceptualmente a pesar de estar IpermitiendoJ al usuario pasar el nombre de un archi"o por la ;F( le The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 24 estar)amos dando un en$oque Iprohibiti"oJ ya que si la carpeta SORFP=TS $ 6/html/6 almacenara un archi"o que no se quisiese poder tratar como Icontenido internoJ habr)a que Iprohibir su accesoJ4 Msolicit&d = isset%MFQT['page'#* 5 strtolo?er%MFQT['page'#* 5 'defa<'' Marchivo = SORFP=TS $ 6/html/@Msolicit&dA$html6' McontenidoFinterno = ''' 4es)template = (4solicitud == 'template')5 4es)menu)admin = (4solicitud == 'menu)admin')5 if%fileFeEists%Marchivo* && 64es)template && 64es)menu)admin) 0 McontenidoFinterno = fileFgetFcontents%Marchivo*' A print strFreplace%'@contenidoA') McontenidoFinterno) SORFTRPN=T*' > en el mejor de los casos el almacenamiento de archi"os que no se quisiesen tratar como contenido interno dentro de esa carpeta se estar@an restringien%o Fso$o 'or 'o$@ti(as %e seguri%a% # no 'or (uestiones ar&uite(t:ni(asG. &sto es una clara consecuencia de las pol)ticas restricti"as. #in embargo no debe con$undirse Ipermisi"oJ con IdescuidadoJ. 2na 'o$@ti(a 'ermisiva, es a&ue$$a &ue F%e>ine $o &ue se 'ue%e ha(er en ve) %e %e>inir a&ue$$o &ue estC 'rohi!i%oG. &ntonces de$inir cu+les archi"os est+n permitidos ser+ mucho m+s limpio y seguro que crear algoritmos para custodiar Ilas prohibicionesJ4 4archios)permitidos = array('default'" 'contacto'" 'newsletter'" 'noticias'" 'lo(in')5 Msolicit&d = isset%MFQT['page'#* 5 strtolo?er%MFQT['page'#* 5 'defa<'' if(6in)array(4solicitud" 4archios)permitidos)) 4solicitud = 'default'5 Marchivo = SORFP=TS $ 6/html/@Msolicit&dA$html6' McontenidoFinterno = fileFgetFcontents%Marchivo*' print strFreplace%'@contenidoA') McontenidoFinterno) SORFTRPN=T*' 8omo se puede "er en el !ltimo ejemplo estableciendo una pol)tica permisi"a obtenemos4 un (:%igo &ue no re&uiere %e mantenimientos >uturos ya que el algoritmo se mantiene intacto incluso aunque se modi$ique el contenido de la carpeta en cuestin. %e hecho el array de Iarchi"os permitidosJ deber)a ser con$igurable desde un settingsH a$goritmos (on menos instru((iones ya que no ser+ necesario "eri$icar la e'istencia del archi"o en nombre de la seguridad. #i se decidiese e$ectuar dicha "alidacin ser)a por cuestiones de usabilidad pero no de seguridad. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 25 /nteriormente tambi-n hab)a comentado que se pod)a llegar a e'tremos impensables como permitir todo tipo de caracteres en el nombre de usuario de un sistema de registro y autenticacin. &se es otro ejemplo de pol)tica permisi"a. &n este caso no solo nos ahorramos largas "alidaciones en el cdigo sino que adem+s e"itamos tener que IlimpiarJ la entrada del usuario. 8on solo encriptar 9hashear: el nombre del usuario guardarlo encriptado y luego al momento de autenticar compararlo mediante su hash al igual que se hace con las contraseas ser)a su$iciente4 M&sername = md-%MFPOST['&sername'#*' /qu) lo permisi"o a pesar de lo que se podr)a creer en un principio no es el ingreso de caracteres Ie'traosJ. &n realidad de $orma indirecta estamos de$iniendo que solo se permiten caracteres al$anum-ricos puesto que un hash 7%R ci$rar+ la cadena resultando en otra que solo es al$anum-rica. UN BUEN PROGRAMADOR ES AQUEL QUE MEJOR ENGAA AL USUARIO 8on"ertirse en un timador suena tr+gicamente espantoso. #in embargo como todo lo I"irtualJ en nuestros queridos resultantes Iceros y unosJ no necesariamente con"ertir+ un ItimoJ en algo malo sino que ser+ aquello que otorgue gran libertad de mo"imiento a los usuarios generando una signi$icati"a reduccin en la cur"a de aprendizaje que un usuario transita hasta entender la aplicacin que lo haga sentir cmodo pero que al mismo tiempo no ponga en riesgo la aplicacin. #e trata de Fo>re(er es'ejos %e (o$oresG 9pero sin el cruel objeti"o de la colonizacin:. 7e sucede con $recuencia que al momento de analizar requerimientos con mis alumnos al igual que los usuarios se dejan lle"ar solo y !nicamente por aspectos "isuales. *a(e %I(a%as atrCs, era 'rC(ti(amente im'ensa!$e &ue un 'rograma%or ana$i)ase un re&uerimiento (on Fojos %e usuarioG< #in embargo desde la llegada de Ilas "entanasJ en modo gr+$ico y dispositi"os como el mouse la in$orm+tica se hizo accesible a todos nosotros mediante ordenadores personales y en de$initi"a $a visin amigable e intuitiva &ue $os grC>i(os otorgan a$ (om?n %e $as 'ersonas, >a(i$itaron e$ a((eso a $a 'rograma(i:n, %e gran 'arte %e $a 'o!$a(i:n. %esde entonces se ha con"ertido en Imoneda corrienteJ obser"ar a programadores con$undir el problema a resol"er 9requerimiento "isual en el QQD de los casos: con la solucin del mismo. > esto es importante entenderlo ya que justamente $os mo%e$os %e seguri%a% 'ermisivos se !asan en Fmostrar a$ usuario $o &ue %esea verG pero aquello que el usuario desea "er debe o$rec-rsele como una ilusin ptica una $antas)a. Para nosotros lo que el usuario "ea deber+ ser el resultado de con"ertir Iaquello que permitimosJ en lo que el usuario Icrea estar "iendoJ. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 26 Por ejemplo le hago creer al usuario que est+ "iendo esto4 Pero en realidad lo anterior es una ilusin ptica resultado de haber con"ertido esto otro4 f&nctionCO4Q+2:CO4CaddCO4Q1-CO4CconfirmCO4Q0:CO4CCO4Q0+CO4CCO4Q+2:CO4CCO4Q+3.CO4CCO4S CO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4ClinDsCO4Q+2:CO4CCO4Q2+CO4CCO4Q+2:CO4Cdoc &mentCO4Q02CO4CgetlementsLyTagNameCO4Q0:CO4CCO4Q.1CO4CaCO4Q.1CO4CCO4Q0+CO4CCO4Q-1CO4C CO4SCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CforCO4Q0:CO4CiCO4Q2+CO4C:CO4Q-1CO4C CO4Q+2:CO4CiCO4Q2:CO4ClinDsCO4Q02CO4ClengthCO4Q-1CO4CCO4Q+2:CO4CiCO4Q0.CO4CCO4Q0.CO4 CCO4Q0+CO4CCO4Q+2:CO4CCO4Q+3.CO4CCO4SCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CC O4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CifCO4Q0:CO4ClinDsCO4Q1+CO4CiCO4Q1.CO4CCO4 Q02CO4CtitleCO4Q02CO4CindeEOfCO4Q0:CO4CCO4Q.1CO4CeliminarCO4Q.1CO4CCO4Q0+CO4CCO4Q+2:C O4CCO4Q2+CO4CCO4Q2+CO4CCO4Q+2:CO4C:CO4Q0+CO4CCO4Q+2:CO4CCO4Q+3.CO4CCO4SCO4Q+2:CO4C CO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2: CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4ClinDsCO4Q1+CO4CiCO4Q1.CO4CCO4Q02CO4ConclicDCO4Q +2:CO4CCO4Q2+CO4CCO4Q+2:CO4Cf&nctionCO4Q0:CO4CCO4Q0+CO4CCO4Q+2:CO4CCO4Q+3.CO4CCO4SC O4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2: CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO 4Q+2:CO4CpartesCO4Q+2:CO4CCO4Q2+CO4CCO4Q+2:CO4CthisCO4Q02CO4ChrefCO4Q02CO4CsplitCO4Q0: CO4CCO4Q.1CO4CCO4Q0,CO4CCO4Q.1CO4CCO4Q0+CO4CCO4Q-1CO4CCO4SCO4Q+2:CO4CCO4Q+2:CO4CC O4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2: CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CpregCO4Q+2:CO4 CCO4Q2+CO4CCO4Q+2:CO4CCO4Q.0CO4CCO4Q+1+CO4CConfirmaCO4Q+2:CO4CB&eCO4Q+2:CO4CdeseaCO4Q +2:CO4CeliminarCO4Q+2:CO4CesteCO4Q+2:CO4CCO4Q.0CO4CCO4Q+2:CO4CCO4Q0.CO4CCO4Q+2:CO4Cpa rtesCO4Q1+CO4C0CO4Q1.CO4CCO4Q+2:CO4CCO4Q0.CO4CCO4Q+2:CO4CCO4Q.0CO4CCO4Q2.CO4CCO4Q.0 CO4CCO4Q-1CO4CCO4SCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO 4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q +2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CifCO4Q0:CO4CconfirmCO4Q0:CO4CpregCO4Q0+CO4CCO4Q0+CO4CCO 4Q+2:CO4CCO4Q+3.CO4CCO4Q+2:CO4CCO4SCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q +2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4 CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+ 2:CO4ClocationCO4Q02CO4ChrefCO4Q+2:CO4CCO4Q2+CO4CCO4Q+2:CO4CthisCO4Q02CO4ChrefCO4Q-1C O4CCO4Q+2:CO4CCO4SCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4 CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+ 2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+3-CO4CCO4Q+2:CO4CelseCO4Q+2:CO4CCO4Q+3.CO4CCO4SCO4 Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO 4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q +2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4Cret&rnCO4Q+2:CO4CfalseCO4Q-1CO4CC O4SCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4 Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO 4CCO4Q+2:CO4CCO4Q+3-CO4CCO4SCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4C CO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+3 -CO4CCO4Q-1CO4CCO4SCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:C O4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+3-CO4CCO4SCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4CCO4Q+2:CO4 CCO4Q+3-CO4CCO4SCO4Q+3-CO4C The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 27 8omo puede "erse en el ejemplo anterior es un simple e inocuo conjunto de caracteres al$anum-ricos que solo y !nicamente del lado del cliente Iadoptan $ormaJ la $orma que nosotros como programadores le hacemos "er al usuario. CONCLUSIN 4m'$ementar mo%e$os %e seguri%a% 'ermisivos no es a$go sen(i$$o. Por el contrario su estrategia requiere de cierta complejidad de an+lisis a la que tal "ez la mayor)a de los programadores no est+ acostumbrado. #in embargo no es imposible. Las grandes "entajas y sobre todo la innumerable cantidad de bene$icios que los modelos de seguridad permisi"os aportan a los sistemas in$orm+ticos justi$ican la in"ersin de tiempo y es$uerzo que la de$inicin desarrollo e implementacin de estos modelos demandan al programador. =o e'isten $rmulas !nicas y por consiguiente mucho menos las hay m+gicas para de$inir estos modelos. *oda pol)tica de seguridad toda medida a implementar deber+n ser el producto de un anC$isis o!jetivo, a!stra(to # (ui%a%o de lo que realmente se necesita. Es im'osi!$e im'$ementar ver%a%eros mo%e$os %e seguri%a% 'ermisivos si se ana$i)an $as a'$i(a(iones (on $a misma :'ti(a %e$ usuario< &s importante entender que aquello que el usuario "e no necesariamente ser+ real. %e la misma $orma en la que nosotros hallamos 12 objetos complejos en lo que el usuario solo "e como un sencillo $ormulario con .2 campos en los cu+les escribir 9o elegir: datos debemos "er toda la aplicacin. Basarnos en la premisa de que todo absolutamente todo lo que el usuario "ea ser+ una gran $antas)a. 4nsisto a mis a$umnos %e >orma (onstante en que desarrollen sobre la misma plata$orma en la que $inalmente se ejecutar+ la aplicacin y en que e"iten tanto como les sea posible el uso de herramientas gr+$icas para trabajar. > no lo hago por IcaprichoJ sino por el contrario $o hago 'ara ir a(ostum!ran%o a$ (ere!ro a ra)onar (a%a ve) %e >orma $o mCs a!stra(ta, in%e'en%iente # ais$a%a %e F>antas@as :'ti(asG 'osi!$e< Porque cuanto m+s IamigableJ sea el entorno de trabajo menos es$uerzo mental requerir+ por parte del programador pues cuanto menos es$uerzo mental est- haciendo el programador en su trabajo m+s estar+ siendo ")ctima -l mismo de las Iilusiones pticasJ producidas por un programador m+s astuto y entonces la pregunta es4 cmo lograr un programador, hacer aplicaciones seguras si l mismo es vctima de ilusiones pticas que no es capaz de entender ni descifrar? ;n usuario que programa no es lo mismo que un programador. #i te animas a ser programador lograr+s darte cuenta de que en rea$i%a%, $as a'$i(a(iones invu$nera!$es eJisten # son 'osi!$es. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 28 BASH SCRIPTING: DIVERSAS FORMAS DE IMPLEMENTACIN DE MENS DINMICOS DESDE SIMPLES LECTURAS DE LA ENTRADA ESTNDAR HASTA COMPLEJOS ALGORITMOS; CON GNU/BASH, CREAR MENS DINMICOS PUEDE CONVERTIRSE EN UN ENTRETENIDO ARTE. uando el scripting en E=;5Bash no es nuestra acti"idad principal y solo lo utilizamos como herramienta complementaria para nuestros programas es de lo m+s $recuente que le demos poca importancia al men! de nuestro script. Pero tarde o temprano nos encontraremos con la necesidad de mejorarlo y emplear un men! que realmente cumpla una $uncin protagnica para el script. 8 Por suerte E=;5Bash es un lenguaje muy completo que nos brinda un amplio abanico de opciones para crear men!s que puedan satis$acer cada una de nuestras necesidades cubriendo as) una gran cantidad de alternati"as posibles. &n este art)culo "eremos la $orma de implementar %es%e sen(i$$os men?s que tan solo act!en leyendo la in$ormacin de entrada est+ndar hasta hacks &ue me%iante e$ em'$eo %e m?$ti'$es (onstru(tores %e$ $enguaje, generen men?s (on una (om'$eji%a% a$gor@tmi(a &ue 'ue%a (ontem'$ar hasta e$ mCs m@nimo %eta$$e. La $orma m+s com!n y tradicional con la que la mayor)a de los programadores suele trabajar en un script es con la lectura de una entrada est+ndar4 #45&!n5&as% OPCOONS=6=(rir Cerrar ditar Lorrar Q&ardar Salir6 echo MOPCOONS echo echo !n 'liKa &na opciGn5 '' read opcion echo 6Tsted eligiG Mopcion$6 B+sicamente todo consiste en imprimir en pantalla una cadena de te'to de la cual el usuario Icopiar+J una palabra 9qu- hace las "eces de IopcinJ: la ingresar+ nuestro script la leer+ y en base a ella har+ determinada accin. #imple sencillo y resuel"e de $orma r+pida los requerimientos m+s primiti"os de la The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 29 interaccin con un usuario. / lo sumo como gran complejidad se le suele agregar una estructura de control condicional4 #45&!n5&as% OPCOONS=6=(rir Cerrar ditar Lorrar Q&ardar Salir6 echo MOPCOONS echo echo !n 'liKa &na opciGn5 '' read opcion if + 74opcion7 = 78brir7 ,5 then echo 6sto a(re &n archivo6 else echo 6Tsted eligiG la opciGn Mopcion6 fi #in embargo (uan%o $a (anti%a% %e o'(iones a considerar en las estructuras de control condicionales se van in(rementan%o se comienza a o'tar 'or (onstru(tores %e se$e((i:n mCs 're(isos como es el caso del (onstru(tor case4 #45&!n5&as% OPCOONS=6=(rir Cerrar ditar Lorrar Q&ardar Salir6 echo MOPCOONS echo echo !n 'liKa &na opciGn5 '' read opcion case 4opcion in 8brir) echo 6sto a(re &n archivo6 55 3errar) echo 6so cierra &n archivo6 55 %alir) echo 6sto sale del programa6 eEit 55 9) # $al/!er opc!6n no contempla(a echo 6No eligiG ning&na opciGn correcta6 55 esac Pero en E=;5Bash el constructor case es tan solo uno de los tantos constructores pro"istos por el lenguaje. *ambi-n podemos encontrarnos con el constructor select. EL CONSTRUCTOR SELECT &l constructor select adoptado por primera "ez por Sorn #hell nos da resuelto en un solo paso4 La enumeracin de opciones posiblesH La impresin ordenada de opciones en pantallaH La lectura est+ndar de la opcin elegida por el usuarioH La repeticin constante del men! en pantalla. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 30 La sinta'is de este constructor es la siguiente4 select 78R98:;-<18.- [in l!sta<(e<opc!ones#5 do # !nstrcc!ones [(reaD# done Los corchetes [# indican Isinta'is opcionalJ &l constructor select reproduce el men! de $orma permanente incluso despu-s de haber $inalizado con las instrucciones internas. La instruccin (reaD romper+ ese bucle. #45&!n5&as% OPCOONS=6=(rir Cerrar ditar Lorrar Q&ardar Salir6 PS.=6liKa &na opciGn5 6 # 3! no se !n(!ca mostrar =#>= por (e)ecto select opcion in MOPCOONS' do echo 6Tsted ligiG la opciGn Mopcion6 brea: # Rompe el &cle done # -?ecc!6n en &cle 'cont!na(a* @ no se !n(!ca el &reaA select opcion in MOPCOONS' do echo 6Tsted ligiG la opciGn Mopcion6 done &l algoritmo anterior producir+ una salida similar a la siguiente4 &serJhost5UM $/men&s!dnamicos$sh +* =(rir 3* Cerrar .* ditar 0* Lorrar -* Q&ardar 2* Salir liKa &na opciGn5 8omo puede "erse nos ahorra much)simo es$uerzo al momento de presentar las opciones en pantallas. El constructor select es el generador de mens de opciones por excelencia de !"#$%ash 8ombinando el constructor con una estructura de control condicional simple es posible determinar si el usuario ha ingresado 6o no6 una opcin "+lida4 The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 31 VW/(in/(ash OPCOONS=6=(rir Cerrar ditar Lorrar Q&ardar Salir6 PS.=6liKa &na opciGn5 6 select opcion in MOPCOONS' do if + 4opcion ,5 then echo 6Tsted ligiG la opciGn Mopcion6 (reaD fi done &sto nos da una gran "entaja ya que de tratarse de una opcin "+lida switchear la eleccin del usuario no requerir)a de "alidaciones adicionales4 VW/(in/(ash OPCOONS=6=(rir Cerrar ditar Lorrar Q&ardar Salir6 PS.=6liKa &na opciGn5 6 select opcion in MOPCOONS' do if + 4opcion ,5 then case 4opcion in =(rir* echo 6sto a(re &n archivo6 '' Cerrar* echo 6so cierra &n archivo6 '' Salir* echo 6sto sale del programa6 eEit '' esac brea: fi done SELECT HACK: CAPTURAR LA OPCIN INVLIDA ?recuentemente cuando en la bibliogra$)a se habla del constructor select 6o del tan conocido case6 solo se hace re$erencia a un conjunto de opciones posibles. #in embargo much)simas "eces una opcin select in"+lida podr)a requerir un tratamiento distinto al de otra opcin select in"+lida. 4maginemos este es(enario6 el usuario se encuentra con un men! de opciones delante y la imposibilidad de elegir la indicada puesto desconoce la utilidad de cada una. &l script espera una entrada del usuario pero el usuario necesita conocer el n!mero de "ersin del script antes de decidir qu- opcin elegir. O8mo se entera del n!mero de "ersin sin salir del scriptP Podr)a o$recerse la misma como una opcin m+s del men! pero sin embargo se estar)a des"irtuando la $inalidad del programa. &n cambio un argumento ingresado en la entrada est+ndar podr)a solucionar el problema. The Original Hacker www.originalhacker.org 2013, 2014 Eugenia Bahit www.eugeniabahit.com Bajo Licencia Creative Commons BY-NC-SA 32 &e puede capturar la respuesta del usuario accediendo a la variable de contexto '(E)L* VW/(in/(ash OPCOONS=6=(rir Cerrar ditar Lorrar Q&ardar Salir6 PS.=6liKa &na opciGn5 6 select opcion in MOPCOONS' do if [ Mopcion #' then case Mopcion in =(rir* echo 6sto a(re &n archivo6 '' Cerrar* echo 6so cierra &n archivo6 '' Salir* echo 6sto sale del programa6 eEit '' esac (reaD else case 4;<#=> in !hX!!help* echo 6=y&da so(re el programa6 '' -?--ersion) echo 6mi!programa versiGn +$:$+6 '' !BXYB* eEit '' Z* echo 6OpciGn invClida6 esac fi done ACE/34=0 OPor qu- un hombre nacido el .2 de agosto del ao .R /8 a las .T422 ,# y $allecido el .2 de agosto del ao .R %8 a las .U4RQ ,# no lleg a cumplir los 02 aosP A#u%a6 La respuesta no est+ en la matem+tica. %ebes razonar de $orma lateral. Fesponde AN3ES del 2890892014 a tra"-s de 3Kitter utilizando el hashtag LA(ertijo30*8 E$ nom!re %e $os gana%ores serC 'u!$i(a%o en $a siguiente e%i(i:n La respuesta correcta ser+ publicada en *he <riginal ,ac3er =KU junto con los ganadores 1404240651975 1404240651975 5