lunes, 11 de junio de 2007

El calor y la PC

Alien [blackhat4all@gmail.com]

Si en algo tratamos de diferenciar a esta revista de otras publicaciones, es en dar soluciones a los problemas que nos afectan y crear nuevas técnicas que ayuden a facilitar el trabajo a los que se enfrentan ante un PC. Por estos tiempos vienen los meses de verano y esto, como es lógico, implica siempre un peligro para los que tenemos una máquina en la casa sin poseer las condiciones adecuadas.

Cuando una computadora se calienta a una temperatura determinada, no sólo se corre el riesgo de dañar ciertos dispositivos, sino que también provoca una notable reducción de sus recursos. Yo he hecho la prueba, y una máquina no funciona igual a 19 grados Celsius que a 28. Y sé que muchos de los que han visto los videos experimentales de comparaciones de micros a iguales temperaturas estarán de acuerdo conmigo.

Todavía hoy en día hay escépticos en cuanto a abrir la máquina, y no los critico. Yo mismo soy uno de los que por calor, he abierto la mía sólo tres veces... pero, ¿qué es preferible? ¿mantenerla abierta durante el tiempo que se esté usando y luego pasar un poquito más de trabajo en ponerle la tapa, o tenerla cerrada y demorarse mucho más tiempo en realizar tareas que en otros momentos hacíamos con mucha más facilidad -sin añadir el notable desgaste de los componentes?

Otra de las cosas que se pueden hacer para aliviar la temperatura de nuestros equipos, es proveerlos de sistemas de ventilación (fan), los cuales, puestos en las posiciones correctas, pueden contribuir en gran medida a este propósito.

No pienso que ignoren qué es un fan pero, aún así, si alguien no tiene conocimiento, sepan que no es más que un pequeño dispositivo similar a un ventilador que, al girar a grandes revoluciones por segundo, permite extraer aire caliente, o refrescar una pequeña porción de espacio.

Normalmente, todas las máquinas tienen al menos un fan en la fuente, ya que ésta es una de las zonas que por el flujo de electricidad, más calor genera. Otra zona priorizada por los fabricantes es el microprocesador, y pienso que éste no lleva explicación. Además, se debe proteger el disco duro, sobre todo aquellas personas que utilizan la computadora a menudo para realizar búsquedas en el sistema, o trabajan simultáneamente con carpetas situadas en distintas ubicaciones. Los discos duros vienen preparados para ponerles en su parte inferior una especie de bandeja metálica, dentro de la cual es fácilmente adaptable un fan.

Ahora, ¿dónde va a parar todo ese aire? Como habíamos dicho antes, en el micro y en el disco duro puede haber pequeños ventiladores, pero el calor que ellos extraen lo dejan dentro de la torre y, al final, el calor del sistema completo aumentaría de todas maneras. Si no queremos quitarle la tapa a nuestro ordenador, pudiéramos poner un tubo que vaya directo desde la tapa del chasis hasta el fan que tiene el micro, lo que conllevaría a que la mayor parte de calor que se extraiga del mismo vaya directamente hacia el exterior a través de dicho tubo.

En el caso del disco duro no podemos hacer esto, pero sí se puede -siempre y cuando la torre lo permita- poner un fan en la parte posterior, debajo de la fuente, que se encargue también de extraer el aire caliente.

Como hemos visto, hay varias formas de, sin tener que cortar el chasis o cosas por el estilo, crear un pequeño control de temperatura. Hasta ahora todo lo que hemos hecho es sacarle el aire, pero ¿por dónde le entra?

Un chasis normalmente viene completamente sellado, y los orificios que tiene para la entrada de aire son muy pequeños, así que, ¿por qué no colocar al menos un fan que introduzca aire fresco al sistema?

Muchas torres tienen en la tapa varios orificios o agujeros pequeños, quizás con este mismo propósito, y si en estas partes le colocamos unos pequeños ventiladores, el sistema estará controlado con unos dispositivos que eliminan el aire caliente, y otros que lo refrescan.

Éstas no son las únicas modificaciones que se le pueden hacer; los más arriesgados siempre tienen el chasis con tres o cuatro huecos abiertos a mano y luego tapados por ventiladores o con pequeños motorcitos haciendo circular gas freón (el que utilizan los refrigeradores) por todo el sistema, o cosas tan locas que ni me puedo imaginar. Pero por hoy sólo voy a hablarle a los más tímidos, a los menos atrevidos y a los más precavidos.

Para la semana que viene trataré de comentar algo sobre los monitores, en los que casi nadie se fija, pero que si ponemos un sartén sobre el después de 30 minutos de encendido, quizás nos prepare la comida.

No quisiera despedirme sin antes hacer un llamado a todos aquellos que tienen inventos curiosos en sus máquinas y que quieran compartirlo con el resto de la comunidad, teniendo en cuenta, claro está, que vivimos en Cuba, y que las soluciones como la que aparecen en los videos de "Tom algo", no son factibles ni aplicables para la mayoría de nosotros.

Para saber más...

Continuar leyendo

¿Qué es TDD?

Jesús Reina Carvajal [jesusrc@yahoo.com]

TDD son las siglas en inglés de Test-Driven Development, o sea, desarrollo orientado a pruebas. En lo adelante escribiré tests. La idea es bastante sencilla: primeramente se definen los test cases y los métodos que los ejecutarán; luego se escribe el código ejecutivo.

En mi más reciente proyecto he trabajado sobre algunas de las bases de TDD en .NET utilizando herramientas gratis al servicio de toda la comunidad. Una de ellas -quizá la más utilizada hoy en día- es NUnit .Como escribí en mi artículo anterior, muchas de las soluciones que hoy vemos en .NET han sido importadas o copiadas de la comunidad Java. Hoy no estoy tratando ninguna excepción de esta regla y tenemos que la plataforma que dio origen a NUnit es conocida como JUnit. Pues bien, ¿qué es NUnit? Simplificando un poco podemos afirmar que NUnit es una plataforma para tests, independiente del lenguaje en que se programe, siempre que sea .NET.

Hablando hipotéticamente, para hacernos una idea de la utilidad que reporta el TDD pongamos que en cierto proyecto tenemos que realizar una clase para enviar y/o recoger ficheros a/de un determinado servidor FTP. Primeramente definiremos los tests de esa clase que llamaremos Ftp. La clase que ejecutará los tests la llamaremos FtpTester.

¿Cuáles son los métodos que debemos comprobar? Inicialmente tendremos que crear la clase (constructores) y leer la configuración, cargar (upload), descargar (download), leer la lista de ficheros del servidor, cambiar catálogo, etc. Todo en dependencia de la funcionalidad que vayamos a implementar.

La imagen a continuación nos muestra parte de la clase FtpTester que comprueba la clase Ftp.
Tenemos el método privado pGetServer() que cada vez que es ejecutado nos devuelve una nueva instancia de la clase Ftp, configurada por los valores de un fichero .config. Luego, esa instancia es la que es utilizada por cada uno de los métodos que comprueban la funcionalidad de la clase Ftp. Por ejemplo, el método ConstructorTest() crea una instancia de la clase Ftp y la guarda en la variable local ftp. Luego llama el método GetFileList() que, justo en este caso, es innecesario, ya que no es lo que queremos comprobar. Finalmente hacemos un llamado al método IsInstanceOfType() de la clase Assert para asegurarnos de que la variable ftp verdaderamente contiene una instancia de la clase Ftp. Entonces tenemos que ConstructorTest() ejecutará satisfactoriamente si y sólo si la clase Ftp puede ser instanciada y si la variable ftp es del tipo Ftp.

Una vez que NUnit ha cargado la biblioteca (assembly) a comprobar, el programa busca todos los tags de tipo [Test(***)] y los ejecutará cuando, a través del interfaz gráfico pulsemos la tecla Run. Existe otra posibilidad de ejecutar los tests usando la línea de comando (nunit-console.exe) a la cual retornaré en un artículo venidero.

Los que son observadores habrán notado que los métodos de test marcados por el tag [Test(***)] terminan con un llamado a la clase Assert. Esta clase es parte de la plataforma NUnit y es utilizada precisamente para darle a conocer a NUnit el resultado del test. En dependencia de ello, NUnit coloreará la barra de progreso. Aquí voy a incluir un par de imágenes de mi biblioteca de funciones para que vean el resultado del ejemplo arriba ilustrado.

Este es el resultado de los tests de la clase Ftp:

Aquí veremos cómo NUnit nos muestra los tests que han fallado. Esta es una clase que comprueba mucha de la funcionalidad de Reporting Services, un paquete extra para SQL Server 2000, pero parte de la instalación estándar de SQL Server 2005. Trataré, en la medida de mis posibilidades, de retornar a Reporting Services en un próximo artículo.

A pesar de su versatilidad, NUnit tiene un talón de Aquiles: los métodos que son ejecutados asincrónicamente. No dudo que a partir de una equis versión de NUnit este problema sea solucionado, pero de momento esto requiere de esfuerzos extras por parte del programador. Es algo que he logrado hacer pero admito que no es fácil ni recomendable, sobre todo cuando tenemos varias capas en el stack de ejecución y varios hilos ejecutando a la vez.

Como hemos podido ver, es relativamente fácil hacer tests para casi la totalidad de las clases que desarrollemos. Un paso más en la optimización del proceso es automatizar los tests y builds con generación de documentación actualizada y todo.

Ahora, ¿a qué altura poner la barra? Podremos ponerla bien alta y ejecutar los tests atómicamente. Esto es recomendable para organizaciones con suficientes recursos, y varios programadores que puedan distribuir los tests y el código ejecutivo entre sí. Para organizaciones más pequeñas habrá que llegar a compromisos, indudablemente.

¿Cómo saber si los tests son suficientes entonces? ¡La pregunta de los cien pesos! Con un colega arquitecto llegamos a la conclusión de que todo método público accesible desde el interfaz gráfico o desde el nivel más alto debe ser comprobado, lo cual a su vez comprobará todos los métodos a niveles inferiores que sean consumidos por éste.

La principal ventaja de TDD sobre el desarrollo a ciegas -como yo le llamo-, es que cada cambio en el código puede ser comprobado de inmediato antes de hacer un check-in, eliminando la posibilidad de romper la compilación del sistema.

Lo anterior supone un cierto nivel de disciplina por parte de todos los miembros del proyecto y de la organización, pues, como sabemos, la anarquía no funciona.

Para saber más...

Continuar leyendo

Blu-ray vs HD-DVD: la lucha por la alta resolución

Krlo [blackhat4all@gmail.com]

La idea inicial de este artículo era hablar sobre el Blu-ray; era lo que conocía y me parecía un buen motivo para escribir en la revista. Pude leer más sobre el tema en Internet y profundicé en su más fuerte rival: el HD-DVD. Cambiaron mis objetivos. Esta lucha es más interesante que ver una tecnología por separado y espero que les sea más útil mi trabajo.

Inicios::

Desde el 4 de octubre del 2004, la Blu-ray Disc Association formalmente inició sus actividades. El principal objetivo de la misma era imponer el Blu-ray Disc (BD a partir de ahora) como estándar de los discos ópticos de última generación. Está compuesta por las empresas Apple, Dell, Hitachi, HP, JVC, LG, Mitsubishi, Panasonic, Pioneer, Philips, Samsung, Sharp, Sony, TDK y Thomson. Por el contrario, desde el 19 de noviembre de 2003, los miembros de DVD Forum decidieron que el HD-DVD sería el sucesor del DVD para la TV de alta definición. Es una tecnología de Thoshiba e impulsada por Microsoft, HP e Intel). Además, cuenta con la mayor parte de la industria de Hollywood: Warner Bros, Universal, Columbia, Eisner & Co. y Paramount, que aunque no darán exclusividad a ninguno de los dos formatos, apoyan con recursos y publicidad al HD-DVD.

Digamos por ahora que en principio los HD-DVD van delante.

Características::

Lo que distingue estas tecnologías de sus parientes actuales es que utiliza un láser azul, los cuales tienen una menor longitud de onda que los actuales rojos. De esta forma, permite que los puntos de información legibles en el disco sean mucho más pequeños y por tanto mayor información en igual espacio.

El Blu-Ray, además de esta técnica, posee un sistema de lentes duales y una cubierta protectora más delgada, que permite al rayo enfocar de forma mucho más precisa en la superficie del disco.

Otra característica importante de los discos Blu-ray es su resistencia a las rayaduras, marcas de dedos y la suciedad. Contienen no sé qué material (bajo el nombre comercial Durabis) que permite evitar los problemas anteriores brindándole mayor resistencia. En otras palabras, los BD durarán más; una característica muy fuerte a su favor.

Para entrar en lo concreto::

El BD inicialmente puede almacenar unas 25 Gb en una capa, llegando a las 50 Gb con doble capa. Se espera que en un futuro y gracias a la tecnología de láser azul, se pueda llegar a fabricar BD de hasta 8 capas consiguiendo una capacidad de 200 Gb. Estamos hablando de 25 Gb de datos -o de video de alta definición- en el mismo espacio que consume un DVD de 4.7 Gb. Parece grandioso.

El HD-DVD, a nivel tecnológico, está en clara desventaja respecto al Blu-Ray; además, proporciona menos capacidad de almacenamiento, de 15 a 30 GB -aunque últimamente se están consiguiendo ampliar hasta 45 Gb. Tienen menor velocidad de grabación, lo que requerirá de nuevas modificaciones tecnológicas en menos de 10 años.

A continuación, una tabla comparativa con las principales características:

Como podemos observar, ambas tecnologías son muy superiores al DVD actual. Entre las dos últimas hay diferencias importantes: la capacidad es mayor en el BD, posee mayor resistencia a rayaduras y suciedad, mayor tasa de transferencia de video/audio y más tiempo de reproducción.

Para lo último dejé la interactividad, que no es más que la interfaz para ver películas. En el BD todo se sustenta en una plataforma hecha en Java, de ahí la J. Esta plataforma, entre otras características, permite sacar los menús del sistema sin parar el filme, para, por ejemplo, poner el director explicando una parte de la cinta con ésta corriendo en el background. También podrás, a mitad de la película, descargar extras o subtítulos en otro idioma. Estoy pensando no escribir más sobre C#... a partir de ahora en BlackHat emigro a Java :-).

No pude encontrar mucho sobre iHD de HD-DVD; sólo que es una tecnología de Microsoft. Recuerdan que ésta era una de las empresas que apoyaban el proyecto... nada, que Billy Gates no hace nada de casualidad.

Conclusiones::

Como pudimos comprobar, ambos formatos de almacenamiento son similares en cuanto a la novedosa técnica que utilizan, el rayo láser azul. La principal diferencia que yo alcanzo a ver es la competencia de las empresas patrocinadoras. Pues pese a las desventajas técnicas antes citadas del HD-DVD, tiene una enorme fortaleza: el peso de sus aliados que, aunque pocos en número, "pesan" más. Para ser más atractivo y económico, Toshiba aportará las instalaciones de sus plantas en Japón y basaría su desarrollo en el DVD actual. De este modo el coste de fabricación de los nuevos discos apenas variaría en relación con los DVD.

En definitiva, el ganador de esta lucha no será aquel que ofrezca un producto de mayor calidad, sino el que cuente con un catálogo de títulos más amplio. Nos encontramos ante una lucha abierta que supuestamente elevará a uno de los dos formatos a las cumbres.

El apoyo de la industria del cine podría ser la clave para imponerse.

Pero esto no termina aquí, sino que varias empresas buscan expandir los límites de la capacidad de almacenamiento más allá de las especificaciones iniciales de los nuevos formatos. Así, Toshiba ha presentado un disco HD DVD con capacidad para nada menos que 51 Gb. Por otro lado, Sony tiene en desarrollo discos Blu-ray de 100 y hasta 200 Gb.

Para saber más...

Continuar leyendo

StarCraft II

Alex3D [ale_galguera@yahoo.com]

La Noticia::

Tiembla el Olympics Gymnastic Stadium de Seúl el 19 de Mayo pasado cuando la exclusiva de un gran anuncio mostrado en las pantallas del recinto deportivo, con Mike Morhaime -presidente y co-fundador de Blizzard Entertainment- proyectaba un trailer de StarCraft II.

Recientemente rompieron el silencio con el que venían conspirando desde hace 4 años cuando comenzaron a trabajar en el proyecto, luego de finalizar la expansión del Warcraft lll. Desde entonces, la gran compañía de juegos se encuentra inmersa en el desarrollo de la segunda parte de uno de los mejores títulos de la historia: StarCraft. En la página oficial en español de dicha compañía (http://www.blizzard.es/) ya dieron la noticia de ello e, incluso, ya se encuentra disponible la web oficial (http://eu.starcraft2.com/) con unas cuantas imágenes de arte conceptual, capturas de pantalla y alucinantes videos.

El juego::

¿Que hay que decir de StarCraft? En primer lugar que, en mi modesta opinión, está por encima de cualquier juego de estrategia que se haya realizado, pues ningún otro ha conseguido alcanzar el nivel de complejidad y posibilidades que este nos brinda. Además, y lo que es fundamental, tiene un balance exquisito entre sus tres razas: Protoss, Terran y Zerg. La velocidad es un factor digno de mérito: en una partida de 20 minutos en la versión beta, se puede ver el juego en todo su esplendor, con todo su abanico de unidades, mientras que en el resto de los juegos de estrategia, esto es simplemente inalcanzable. Nueve años después, StarCraft Broodwar todavía cuenta con una extensa comunidad mundial de seguidores, llegando casi al estatus de deporte nacional en Corea, con canales de televisión dedicados a transmitir partidas diariamente.

Nuestro país no se queda atrás, ya que tiene una buena banda de fanáticos. Incluso se hacen torneos de vez en cuando; pero generalmente los jugadores están bastante aislados, limitándose -la mayoría- a jugar entre dos PC por módem. El listado de los consagrados que dejaron alguna vez su teléfono en el dominio público lo anexamos a esta edición en la carpeta _tools. Esas personas generalmente -digo esto pues algunos ya no jugamos mucho- están dispuestas a "echar un play" en cualquier momento. Otra modalidad de juego es la on-line, donde participan más de dos jugadores simultáneamente. Para ello se necesita acceso a Internet donde conectarse al BattleNet, aunque en el caso de disponer de una red y de algún programa que haga de server de StarCraft, como el PVPGN, existe la posibilidad de montar un BattleNet propio.

StarCraft II::

En la nueva entrega del aclamado juego los jugadores serán testigos del retorno de los Protoss, Terran y Zerg. Aparentemente no existirá ninguna raza nueva, como decían los comentarios que recorrieron durante años la red. Dispone de una excelente variedad de unidades nuevas y trucos para las unidades clásicas, posee un motor gráfico 3D que permitirá apreciar increíbles efectos, enormes unidades y ejércitos masivos. También habrá mejoras en el juego on-line y en las competencias, gracias a mejoras en el BattleNet. Las campañas en modo historia también ofrecerán aspectos únicos y escenas cinemáticas con el nivel de calidad que caracteriza a la Blizzard.

StarCraft II se está desarrollando para PC y será totalmente compatible con Windows Vista y XP. Saldrá también una versión para Mac. El juego será compatible con DirectX 10, el motor gráfico será muy escalable para asegurar que pueda funcionar en una amplia gama de sistemas y ser capaz de mostrar unidades muy grandes, así como grandes cantidades de unidades. Se ha integrado Havok Physics a este motor para añadir realismo a la hora de usar la dinámica y las colisiones entre las unidades y el ambiente.

Lo nuevo::

Estos son algunos de los aspectos del Starcraft II analizados para los fans. Dicha información está recopilada a partir de los nuevos trailers del juego. Se debe recordar que el juego aún no está terminado, así que lo que veremos aquí será sólo una porción del resultado final.

Para los Protoss existen bastantes novedades: Los Zealots -unidad clásica del StarCraft- ahora cuentan con un ataque de carga, donde éstos se abalanzan rápidamente sobre sus enemigos a una corta distancia. Se introduce una nueva unidad llamada Immortal, que posee un escudo muy fuerte, activado solamente si la unidad está siendo atacado por armas potentes (ej: tanques de los Terran). Los Protoss cuentan con nuevos mecanismos que le permiten teletransportar unidades en el área de energía de los Pylons (construcción para aumentar la población). Otras nuevas unidades, en este caso aéreas, son los Phase Prism, capaces de proporcionar la misma energía que producen los Pylons, o sea, que también pueden usar la habilidad de la teletransportación de unidades. Surge un nuevo tipo de Dragoons llamados Stalkers, que consisten en unidades especiales que, a pesar de no ser muy fuertes, tienen la habilidad de teletransportarse a cortas distancias para acercarse o huir de sus enemigos. Existe otra unidad denominada Colossus: unidad robótica con largas patas que le permiten trepar los distintos niveles del terreno; además, cuenta con potentes láser que causan mucho daño a unidades pequeñas y medianas. Phoenix es otra unidad aérea totalmente nueva; tiene un ataque especial, "overload", que impacta al adversario aéreo una descarga muy potente. Siguen apareciendo unidades aéreas deslumbrantes como Warp Rays, que pueden atacar en conjunto usando un rayo sobre el mismo enemigo, así que ocasiona mucho daño al objetivo; además, pueden atacar a unidades no aéreas. Pero la más espectacular de las unidades es ésta: una potente Mothership (nave nodriza), la cual posee tres habilidades especiales increíbles, como el "timebomb", que puede congelar el tiempo y “planet cracker”, que descarga una serie de rayos devastadores a tierra. La Mothership cuenta también con la posibilidad de crear un agujero negro que se traga las naves enemigas de un solo golpe. Por supuesto, que usa gran cantidad de energía y el jugador sólo puede crear una de éstas naves a la vez.

Muchas de las tecnologías y unidades antiguas se mantienen, pero entran a jugar un buen papel otras nuevas unidades como los Rapers de los Terran, unidad que usa sus mochilas propulsadas para saltar entre niveles del terreno. Los Zergs disponen de la posibilidad de descargar tropas a través de una especie de gusano Nydus Worm que puede salir casi de cualquier parte del terreno. Además de esto, los Zerlings, pequeñas unidades de la raza Zerg, poseen la nueva habilidad de mutar en un tipo de unidad suicida-explosiva llamada Baneling, la cual es terriblemente peligrosa... y todo esto es solamente una demostración, ¿qué novedades nos aguardará la versión final?

El desarrollo del juego, aparentemente, se encuentra en una avanzada fase de desarrollo, aunque al parecer falta un poco para que salga al mercado. De hecho, es muy posible que no vea la luz hasta el venidero 2008, cuando se cumpliría la década del lanzamiento de la primera entrega.

Entonces sólo nos queda esperar esta excitante segunda parte del aclamado StarCraft y continuar apostando por la compañía de la que siempre nos quedamos complacidos, esperando que sigan entusiasmados y revelando nuevos proyectos para un público ansioso, conformado por los gamers de toda la vida.

Para saber más...

Continuar leyendo

init e Introducción a los Niveles de Ejecución en Linux

Orestes Leal R. [orestesleal13022@cha.jovenclub.cu]

Análisis del Stage ejecutado cuando el Núcleo "finaliza" ejecutando el proceso init::

El proceso de arranque del núcleo Linux tiene básicamente la misma distribución jerárquica en cuanto al proceso que se ejecuta después del arranque e inicialización del núcleo que los UNIX convencionales, lo que será descrito a continuación es una descripción de los entresijos que ocurren durante esa etapa de inicialización.

Desde su primera versión, y al ser un OS tipo UNIX, cuando el kernel "termina" su ejecución (realmente no lo hace, sólo cede el control a un proceso padre init), aunque continuará ejecutándose, planificando procesos, etc. Hace una búsqueda de un programa llamado init. Más adelante veremos qué es y para qué sirve, pero con el fin de ir dando un seguimiento correcto, mostremos a continuación lo que ejecuta el kernel para encontrar el ejecutable init:

// Definiciones en C para buscar / encontrar init
762 if (execute_command) {
763 run_init_process(execute_command);
764 printk(KERN_WARNING "Failed to execute %s. Attempting "
765 "defaults...\n", execute_command);
766 }
767 run_init_process("/sbin/init");
768 run_init_process("/etc/init");
769 run_init_process("/bin/init");
770 run_init_process("/bin/sh");
771
772 panic("No init found. Try passing init= option to kernel.");
773 }

Donde run_init_process se encuentra definida de esta manera en el mismo fichero:

727 static void run_init_process(char *init_filename)
728 {
729 argv_init[0] = init_filename;
730 kernel_execve(init_filename, argv_init, envp_init);
731 }

Donde argv_init se encuentra definida en el mismo fichero y donde se define que el argumento debe ser init:

184 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };

Estos segmentos de código están definidos en $KERNELSOURCE/init/main.c ($KERNELSOURCE es el árbol de las fuentes). Las líneas a analizar en cuestión son desde 767 -> 770, estando todo esto basado en el núcleo 2.6.21.1. Esas definiciones en C quieren decir, básicamente, que en este momento el núcleo está haciendo una búsqueda de los posibles lugares donde el proceso init se aloja haciendo llamadas a varias funciones. Si la búsqueda es efectiva, ejecuta el proceso con permisos de super usuario (UID=0); de lo contrario, si el kernel no puede encontrar a init, el mensaje posterior en la línea 772 es bastante claro en ese sentido. A diferencia de algunas variantes de UNIX o BSD UNIX, en Linux, init se encuentra siempre en /sbin/init, definido así por el LFH, un estándar de la distribución de ejecutables, directorios, etc., en un sistema Linux.

Stage Post INIT::

Una vez que init es encontrado, Linux le cede el control de inicialización de procesos -los cuales serán descritos más adelante. Se puede visualizar el momento en el que init ha sido iniciado por el kernel, ya que cuando ésto ocurre se muestra un mensaje tipo "Startting Init 2.86", por poner un ejemplo. Nótese que el comando dmesg no muestra los mensajes pre-init, sino los posteriores.

A partir de ese momento, init toma control de la inicialización de TODOS los procesos post-kernel; es por eso que init es considerado el padre de todos los procesos. Podemos caer en cuenta de esto ejecutando el comando pstree y observar desde dónde viene cada proceso desde el árbol jerárquico superior. Un fragmento de salida podría ser el siguiente:

init-+-abiword
|-4*[agetty]
|-bash---startx---xinit-+-X
|       `-fluxbox-+-gkrellm
|             `-konsole-+-bash---mplayer
|                   |-bash---vim
|                   |-bash
|                   |-bash---man---less
|                   `-bash---pstree

Claramente se puede observar desde dónde provienen cada uno de los procesos, y los procesos ejecutados a través de otros procesos; por ejemplo en este caso la siguiente línea:

|-bash---startx---xinit-+-X

Quiere decir que desde el shell actual (bash) se ha ejecutado el proceso startx que a su vez inicia a xinit y finaliza ejecutando el proceso X -que actualmente se encuentra en ejecución-, y donde bash es un proceso directo de init, como se pudo observar.

Habiendo visto esto vamos a entrar en detalles del por qué y cómo init funciona, dando paso a todos estos procesos. Init crea los procesos leyendo un fichero de configuración que se puede decir que es global, ya que siempre se encuentra en la misma ruta. El fichero /etc/inittab es leído e interpretado por init para la inicialización de los procesos en los denominados run-levels o niveles de ejecución. En inittab, entre otras cosas, se definen varias entradas que causan que init expanda gettys, getty y agetty (comúnmente usados en Linux para abrir un puerto tty, pidiendo login e invoca al ejecutable /bin/login en cada línea para que los usuarios puedan loguearse).

Runlevels o Niveles de Ejecución::

Un runlevel es una configuración del sistema que permite sólo a un grupo de procesos existir. Los procesos que han sido expandidos por init para cada runlevel son definidos en /etc/inittab. Init puede estar en uno de 8 runlevels: 0 al 6 y S, s. El runlevel puede ser cambiado corriendo como usuario privilegiado y corriendo el comando telinit, el cual envía señales apropiadas a init, indicándole a qué runlevel cambiar.

Los runlevels 0, 1 y 6 están reservados. El nivel de ejecución 0 es usado para detener el sistema, el 6 para reiniciarlo, y el 1 para el modo monousuario. El runlevel S no debe ser usado directamente, sólo para los scripts que son ejecutados cuando se está accediendo al runlevel 1.

Despues de que init es ejecutado como el último paso de la secuencia de arranque del kernel, se realiza una búsqueda del inittab en /etc para ver si encuentra una línea del tipo initdefault, la cual establece cuál es el runlevel por defecto o inicial del sistema. Si no existe la entrada o no se encuentra el inittab, un runlevel debe ser establecido en la consola del sistema.

En algunas líneas del inittab debemos tener en cuenta la siguiente sintaxis:

id:runlevels:accion:proceso

Por ejemplo:

1:2345:respawn:/sbin/agetty tty1 9600

En resumen, el ID aquí es 1, el 2345 quiere decir que se inicializará en cualquiera de esos runlevels (recordar que init siempre inicia por defecto en algún runlevel); la palabra respawn quiere decir que el proceso será reiniciado en el momento que sea terminado; /sbin/agetty, en este caso, es el proceso a ejecutar donde se le pasan 2 parámetros requeridos, el ttyX, donde X = número de tty, y la velocidad (en baudios).

Conociendo ya básicamente cómo funciona init, damos paso a la descripción del fichero inittab. Un fichero de ejemplo de este file es el siguiente:

id:3:initdefault:

si::sysinit:/etc/rc.d/init.d/rc sysinit
l0:0:wait:/etc/rc.d/init.d/rc 0
l1:S1:wait:/etc/rc.d/init.d/rc 1
l2:2:wait:/etc/rc.d/init.d/rc 2
l3:3:wait:/etc/rc.d/init.d/rc 3
l4:4:wait:/etc/rc.d/init.d/rc 4
l5:5:wait:/etc/rc.d/init.d/rc 5
l6:6:wait:/etc/rc.d/init.d/rc 6

ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

1:2345:respawn:/sbin/agetty tty1 9600
2:2345:respawn:/sbin/agetty tty2 9600
3:2345:respawn:/sbin/agetty tty3 9600
4:2345:respawn:/sbin/agetty tty4 9600
5:2345:respawn:/sbin/agetty tty5 9600
6:2345:respawn:/sbin/agetty tty6 9600
7:2345:respawn:/sbin/agetty tty7 9600
8:2345:respawn:/sbin/agetty tty8 9600
9:2345:respawn:/sbin/agetty tty9 9600

id:3:initdefault:

Como se mencionaba anteriormente, la entrada initdefault establece el runlevel por defecto que init va a leer posteriormente en el inicio del sistema o con el comando telinit RUNLEVEL, donde RUNLEVEL es un número de 0 a 6 (ej: telinit 3). En este caso, si estuviésemos en las X pasaríamos automáticamente al modo en línea de comandos, ya que normalmente las X se ejecutan en el runlevel 5.

si::sysinit:/etc/rc.d/init.d/rc sysinit

Esta línea es de suma importancia (y varía de una distribución a otra con toda seguridad), es parte del mecanismo que se encarga de inicializar los scripts de arranque (S) y de apagado (K). Por ejemplo, unas líneas del script shell podrán ser las siguientes:

for i in $( ls -v ${rc_base}/rc${runlevel}.d/S* 2> /dev/null)
do
  if [ "${previous}" != "N" ]; then
    suffix=${i#$rc_base/rc$runlevel.d/S[0-9][0-9]}
    stop=$rc_base/rc$runlevel.d/K[0-9][0-9]$suffix
    prev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffix
    [ -f ${prev_start} ] && [ ! -f ${stop} ] && continue
    fi

Entre otras cosas, dichas líneas se encargan de inicializar lo antes mencionado, scripts de inicio y apagado en sus coincidencias S[números de 0 a 9] o K[lo mismo].

Un detalle a tener en cuenta es el parámetro del final, sysinit, que causara que se ejecute antes que cualquiera de las definiciones boot o bootwait durante el arranque del sistema.

Estas definiciones albergan el mismo significado, sólo que wait quiere decir que el proceso será iniciado cuando el runlevel especificado sea iniciado e init esperara por su finalización.

l0:0:wait:/etc/rc.d/init.d/rc 0
l1:S1:wait:/etc/rc.d/init.d/rc 1
l2:2:wait:/etc/rc.d/init.d/rc 2
l3:3:wait:/etc/rc.d/init.d/rc 3
l4:4:wait:/etc/rc.d/init.d/rc 4
l5:5:wait:/etc/rc.d/init.d/rc 5
l6:6:wait:/etc/rc.d/init.d/rc 6

La siguiente definición quiere decir que se hará cuando se presione la combinación mas conocida del planeta: CTRL + ALT + DEL. Cabe decir que los runlevels 0 y 6 no se incluyen, como es obvio, pues ya estos runlevels de por sí son apagado y reinicio, respectivamente.

ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

Estas definiciones ya han sido explicadas, por lo cual no debe haber duda.

1:2345:respawn:/sbin/agetty tty1 9600
2:2345:respawn:/sbin/agetty tty2 9600
3:2345:respawn:/sbin/agetty tty3 9600
4:2345:respawn:/sbin/agetty tty4 9600
5:2345:respawn:/sbin/agetty tty5 9600
6:2345:respawn:/sbin/agetty tty6 9600
7:2345:respawn:/sbin/agetty tty7 9600
8:2345:respawn:/sbin/agetty tty8 9600
9:2345:respawn:/sbin/agetty tty9 9600

Normalmente, los inittab convencionales son algo elaborados, aunque un inittab podría ser lo siguiente y funcionar adecuadamente:

id:1:initdefault:
rc::bootwait:/etc/rc
1:1:respawn:/etc/getty 9600 tty1
2:1:respawn:/etc/getty 9600 tty2
3:1:respawn:/etc/getty 9600 tty3
4:1:respawn:/etc/getty 9600 tty4

Donde bootwait define que será ejecutado al arranque del sistema, mientras que init espera a que termine. El campo de los runlevels será ignorado.

En la parte final de toda esta ejecución, init lee las entradas de aggety o getty y es cuando se nos presenta el prompt de login que todos conocemos (en línea de comandos) algo así como:

========================================
Webdeveloper2 Linux2.6.21.1 tty1 i686
login:
========================================

Funcionamiento y distribución de los scripts de arranque::

Con las bases de todo lo mencionado en el tema anterior veamos cómo, por qué y cuándo serán ejecutados scripts de arranque más comúnmente llamados shells init o scripts de runlevels.

Para comenzar, hay que mencionar el directorio que contiene "casi todos" los scripts de inicio, los cuales serán iniciados en el runlevel al que pertenezcan. Es el dir /etc/init.d, comúnmente usado en distribuciones como Debian, no siendo así en Red Hat, que usa el estilo BSD (muy parecido al estilo del Debian, pero con otra ubicación en los ficheros shell y alguna que otra diferencia, aunque en el fondo se logra básicamente el mismo objetivo).

Se mencionaba "casi todos", pues hay scripts que son "fijos". Esos shells son los que se encargan de montar el sistema de ficheros, chequearlo, iniciar Udev, Limpiar el FS, establecer la consola de Linux, activar la swap, entre otras. Por ejemplo, en una distribución GNU/Linux con estilo de arranque System V al estilo BSD, el directorio /etc/init.d no existe propiamente en ese lugar, sino que se encuentra en /etc/rc.d/init, por lo que los scripts fijos de arranque se encuentran normalmente en el directorio /etc/rc.d/init.d/rcsysinit y los leídos por init antes que ningún otro. Es necesario explicar esto para que se comprenda en caso de confusión al tener contacto con alguna de las dos variantes.

Volviendo a los scripts de runlevel normales, éstos se alojan en /etc/rc.d/init.d o en /etc/init.d, habiendo enlaces simbólicos desde cada directorio, que es identificado por el número del runlevel. La estructura de los dir es la siguiente: /etc/rc.d/rcX.d, donde X es un número de 0 a 6. En el estilo que usa Debian es igual, sólo que se encuentran en /etc/rcX.d. Quedando así más o menos la siguiente estructura en los directorios /etc/ o /etc/rc.d:

- rc0.d
- rc1.d
- rc2.d
- rc3.d
- rc4.d
- rc5.d
- rc6.d

Como se había mencionado antes, los scripts se encuentran en init.d. Ejemplificado, vamos a ver un script real alojando en init.d:

/etc/rc.d/init.d/bind

Donde bind es un shell script de runlevel.

De por sí, bind alojado en init.d no será ejecutado por defecto, sino que tiene que ser enlazado a algún runlevel existente (rc0.d, rc1.d, etc.). Para enlazarlo es necesario conocer qué prioridades y acción tienen los enlaces simbólicos. Digamos que vamos a enlazar a bind al runlevel 3; para esto hacemos:

// ejemplo de enlazar un script a un runlevel para que sea iniciado en el arranque del sistema
cd /etc/rc.d/rc3.d
ln -sv ../init.d/bind S92bind

Esto quiere decir que estamos creando el enlace simbólico S92bind, que apunta al script shell ../init.d/bind.

La norma o sintaxis es muy fácil de comprender: los enlaces que comienzen con S (de start) serán iniciados dependiendo del número que prosiga a la letra, donde los números más bajos tienen mayor prioridad en la ejecución. Todo esto quiere decir que cuando init entre en el runlevel 3 (en el arranque del sistema o poco después) y ejecute todos los enlaces que comienzen con S, llegará el punto en que ejecutará el script del ejemplo anterior.

Como es lógico, los servicios que son iniciados también deben ser detenidos de manera automática cuando el sistema se vaya a reiniciar o apagar. Para ello, en este ejemplo vamos a enlazar a bind en los runlevels 0 y 6 para que se detenga en un reinicio o apagado:

// ejemplo de enlazar un script a un runlevel para que sea detenido
cd /etc/rc.d/rc6.d
ln -sv ../init.d/bind K12bind
cd /etc/rc.d/rc0.d
ln -sv ../init.d/bind K12bind

Aquí la norma es la misma, aunque con una diferencia: los que comiencen con K (de kill) serán detenidos de igual manera que lo antes explicado (la prioridad la tiene el número menor). Habiendo hecho esto aseguramos que si reiniciamos o apagamos se detenga el servicio que se había iniciado en el arranque del sistema.

A continuación un ejemplo del script bind. Algunos detalles sobre qué sucede cuando es S y K y qué tiene que ver con el script.

#!/bin/sh
# script bind.
# dns Bind9 {named}

case "$1" in
  start)
    echo "Iniciando Servidor DNS..."
    /usr/sbin/named -u named -t /srv/named -c /etc/named.conf
    ;;
  stop)
    echo "Deteniendo el Servidor DNS..."
    killall /usr/sbin/named
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  reload)
    echo "Recargando el servidor DNS..."
    /usr/sbin/rndc -c /etc/rndc.conf reload
    ;;
  *)
    echo "Uso: $0 {start|stop|restart|reload}"
    exit 1
    ;;
esac

Esta es la parte interesante. Cuando un enlace comienza con K, init sabe que tiene que matar ese proceso, por lo cual envía al script bind un parámetro de la siguiente manera:

/etc/rc.d/init.d/bind stop

Por el contrario, si comenzara con S sería así:

/etc/rc.d/init.d/bind start

Esto da la medida de cómo funcionan al nivel más básico los scripts de runlevels sin ser el presente documento un manual de programación shell.

La línea case "$1 in" es propia del intérprete de comandos (bash, sh, tcsh, ksh, etc). Lo que quiere decir es "en caso de darse el primer parámetro y que sea igual a los admitidos".

Los parámetros admitidos en este script son start, stop, restart, reload, (los parámetros start y stop son obligatorios). Si deseamos tener un script que sea un auténtico shell de runlevel, el parámetro start es enviado al script al arranque del sistema, así como el stop al apagado o reinicio. Los otros dos son muy usados para recargar la configuración del servicio y reiniciar el servicio, lo cual no se aplica en el inicio, apagado o reinicio por cuestiones lógicas.

Para saber más...

Continuar leyendo

Buffer Overflow: hackeando la pila (II)

EliuX [aorozco@infomed.sld.cu]

El primer ejemplo::

Luego de la introducción previa a los asuntos del Stack, veamos ahora nuestro primer ejemplo en C, porque como dice el dicho: “Vista hace fe”.

Nota: El compilador de C que utilizo es el C++ Builder 6.

Example1.c

void function (int a, int b, int c)
{
  char buffer1[5];
  char buffer2[10];
}

void main()
{
  function(1,2,3);
}


Ahora deberemos coger un desensamblador y tratar de estudiar el código. Es posible que no elijan todos un mismo desensamblador, por lo que decidí explicar los pedazos más importantes en código usando la opción del Builder para ver la CPU, en tiempo de ejecución: View » Debug Windows » CPU.

;las siguientes líneas son fragmentos del código ensamblador del compilado anteriormente en C
;éste se describirá según el orden de ejecución
;cuando se llama a function (1,2,3)
push 0x03 ;meto los parámetros en orden inverso
push 0x02
push 0x01
call function(int, int, int)

;Llamamos al procedimiento function y pushea a la pila el ret
add esp,0x0c ;corro la pila 12 Bytes(3 words) para reservar espacio para los 3 parámetros
;el código en asm de void function (int a, int b, int c) sería
push ebp ;guardo BP (más conocido como el FP guardado)
mv ebp,esp ;muevo el Stack Pointer(SP) hacia el BP, para hacerlo el nuevo FP
;en la siguiente instrucción disminuimos sp en 20, para que la pila crezca (12 decimal = 0x14 hexadecimal) ;así se reservará espacio para las cadenas char buffer1 y char buffer2.
add esp,-0x14

Debemos recordar que la memoria en los procesadores Intel sólo puede ser direccionada en múltiplos de WORD (4 BYTE), por lo que nuestro buffer de 5 (char buffer1[5];) en verdad ocupará 8 BYTE y el de 10 (char buffer2[10];) 12 BYTE. Este es el motivo por el que a SP se le resta 20 BYTE (8+12) cuando se pasan los parámetros a la pila. Veamos cómo quedaría la pila cuando se llama a function:

Un Buffer Overflow es el resultado de poner más datos dentro del buffer de los que se pueden manejar. Como estos bugs de la programación los podemos usar para crear un efecto colateral (BOF) beneficioso a nuestra causa, veamos otro ejemplo:

Example2.c

void function (char *c)
{
  char buffer1[16];
// exactamente 4 WORD, porque cada char es un BYTE
  strcpy(buffer1,c); // copio el contenido del parámetro en el buffer
}
void main()
{
  char large_str[256];
// una línea de 256 caracteres
  int i;
  for( i=0; i< 255; i++)
  large_str[i] = ‘A’;
// la empiezo a llenar
  function(large_str); // cuando llamo a la función, introduzco las 256 “A” en la cadena de 16
}

Para que observe bien lo que pasa, póngale un breakpoint a la línea que dice large_str[i] = 'A'. Luego abra la ventana de CPU (Ctrl + Alt + C) y veamos qué es lo que pasa: Vaya presionando la tecla F8 (Ejecución paso a paso) y observe el cuadro inferior derecho y vea cómo la memoria se va llenando de la letra “A”. Luego quite este breakpoint y cree uno en la declaración de la función void function (char *c) y presione F9 para ir al inicio de la función. Presione F8 una vez para ir a la instrucción strcpy(buffer1,c);. Entonces en la ventana de CPU busquemos en el cuadro inferior izquierdo el buffer large_str que de seguro aparecerá como una columna llena de “A”. Si ejecutamos la siguiente instrucción con un F8, el procesador escribirá 256 elementos (char) a partir de la dirección en memoria de la variable c mediante la instrucción strcpy, la variable c almacenará un carácter “A” según su capacidad y los otros 255 se colocarán a continuación sobrescribiendo registros cómo el FP guardado, los valores de los parámetros (1,2,3) y el RET que almacenaba el valor de retorno de la función. En este momento la memoria quedaría así:

Si presionamos F8 para ver qué se ejecutaría cuando se sale de la función, veremos que el CPU nos lleva a una zona de memoria que no pertenece a nuestro programa (puede estar vacía o no), por lo que el procesador se da cuenta que se está efectuando una violación de segmentación y lanza el mensaje de error siguiente:

Si lo anterior se ha realizado sin problemas, entonces ¡felicidades! Ya has creado tu primer Buffer Overflow.

¿Entonces quiere decir que puedo cambiar el flujo de ejecución del programa? Sí, eso y mucho más ¿No se te ocurre nada que se pudiera hacer con solamente sobrecargar la pila? Pues a mí, infinidades de cosas, partiendo de que se puede machacar un código que se vaya a ejecutar y colocar el nuestro. Por eso vamos a tornarnos más agresivos y modificar nuestro primer código para que sobrescriba la dirección de retorno, y demuestre cómo podemos hacerlo ejecutar un código arbitrario ¡Vamos a ver cómo se crea la magia!

Cojamos como punto de referencia el primer ejemplo. Antes de buffer1 [] está el SP guardado y antes de él la dirección de retorno (RET). Eso es 1 WORD (4 BYTE) pasando la dirección de buffer1 [] que ocupa 2 WORD (8 BYTE) por lo que son 12 BYTE de offset (desplazamiento).

Nuestra misión será modificar el RET para saltarnos el segmento de código x=1;. Para hacer esto agregaremos 8 BYTE a la dirección de retorno. El código a ejecutar es el siguiente:

Ejemplo3.c

void function(int a, int b, int c)
{
  char buffer1[5];
  char buffer2[10];
  int *ret;
// variable apuntadora
  ret= buffer1 + 12;// RET ahora apunta al RET en la pila la dirección de buffer1 offset 12
  (*ret)+=8; // en la aritmética de apuntadores los # que se suman son BYTES, por lo
} // que se le aumenta la dirección a la que apunta RET en 8 BYTE
void main (){
  int x;
  x=’A’;
  function (1,2,3);
  x=’B’;
  printf(“%c\n”,x);
}

Veámoslo en la ventana del CPU ahora, por orden de ejecución, y las partes que se agregaron diferentes al ejemplo 1:

;cuando se ejecuta el código void main{
;main es la función que da inicio a nuestro programa y, como toda función, se realizan
;los mismos pasos iniciales
push ebp ;guardo el fp anterior (recuerda que se guarda en BP)
mov ebp,esp ;corro el bp hacia adelante donde esta el SP
push ecx ;guardo cx el registro contador (irrelevante)
;la instrucción x=0 se codifica
move byte ptr [ebp-0x01],0x00
;fíjense cómo usa el ebp como puntero pase y luego accede a la variable x mediante el offset 0x01
;el signo negativo significa que la variable se encuentra después de ebp, o sea, una una zona de memoria inferior (recuerda que la pila crece hacia zonas inferiores de memoria)
;luego llama a function(1,2,3) y se ejecuta
push ebp ;lo mismo que en todas las funciones
mov ebp,esp ;creo un nuevo FP para apuntar a los variables
add esp,-0x18 ;1word del puntero RET, 2 word de buffer1 y 3 word de buffer2
;la instrucción ret= buffer1 + 12 se codifica
lea eax,[ebp+0x04]
; pongo buffer1 +12 en ax= +0x04 de offset del BP (apunta al RET de function); se hace así porque el CPU interpreta buffer1 como ebp+-0x08 y si le sumamos 12 sería ebp+0x04
mov [ebp-0x18],eax ;muevo el contenido la dirección de buffer1+12 a *ret (el apuntador)
mov edx,[ebp-0x18] ;copio lo que está en *ret a dx (registro usado para direccionar como BP)
add dword ptr [edx],0x08 ;le sumo 8 al contenido que está en la dirección que apunta *ret en dx
mov esp,ebp ;corrijo el SP
pop ebp ;rescato el ebp anterior (FP guardado)
ret ;salgo de la función

;cuando regresa de la función se salta la siguiente instrucción
add esp,0x0c
;para corregir el offset de SP con respecto a los parámetros de la función, pero como no se ejecuta, abra ;después un error de segmentación de pila.
;La instrucción x+=1 se codifica
inc dword ptr [ebp-0x04];el offset de x es el primero (-0x04 de esta función)
;pero como las dos anteriores se saltan se ejecuta la siguiente
printf(“%c\n”,x);
El resultado que se obtendría al final del programa sería la salida en pantalla del 0, puesto que no se ejecutó la línea x=1 y se mantuvo su último valor asignado, que fue el impreso.
¿Ahora sí se les ocurren más cosas para hacer, no? Pues esto no es todo... ¡todavía hay más!

Para saber más...

Continuar leyendo

¡ Infomed !

Alien [blackhat4all@gmail.com]

Antes que nada quisiera pedir disculpas si ven algo de informalidad en este artículo, pero fue escrito en una de esas madrugadas en que mi cuerpo y mi mente, más que a mí, pertenecían a la nicotina y al café.

Sucede que estando yo en lo que considero “red de redes” de Cuba, se me ocurrió entrar a una página a la cual, por supuesto, no debería haber entrado. Era una página de esas de las que requiere una contraseña para poder tener acceso a la misma. Sin otra cosa que hacer que perder el tiempo, me dediqué a estudiar ese tipo de páginas, ver como era su funcionamiento por dentro, su estructura, etc. Desde ese momento me conecté a la página de Infomed que permite ver los correos que nos han enviado, ya que de ese servicio yo sí tengo autenticación y me sería más fácil hacer comparaciones. Una vez que estuve con los típicos letreros de Usuario y Contraseña delante, lo primero que hice fue guardar la página en mi Escritorio (donde pongo las cosas que borraré en menos de tres días) y luego procedí a editarla.

Gran parte del código estaba compuesto por simbologías propias de lenguajes script, pero, aun así, fui capaz de entender algunos fragmentos. Para sorpresa mía no había en ningún trozo de código (de los que logré descifrar), algo que hablara algo sobre password, o contraseña, o alguna palabra clave de esa de la que sabemos se usan. La única instrucción clave que logré entender fue una que decía algo como:

submit_login()

De esta frase, se puede concluir por los paréntesis que es una función, y después de buscar un poco más con los ojos, y menos con los buscadores que traen implementados los editores de texto, encontré dicha función:

function submit_login()
{
  if (document.implogin.imapuser.value == "")
  {
    alert('Provea su nombre de usuario y contraseña');
    document.implogin.imapuser.focus();
    return false;
  }
  else if (document.implogin.pass.value == "")
  {
    alert('Provea su nombre de usuario y contraseña');
    document.implogin.pass.focus();
    return false;
  }
  else
    {return true;}
  }
}

Repito que mi fuerte no son los lenguajes script, pero claramente se ve que lo único que se hace con ella, es retornar false en caso de que los campos de usuario o de contraseña estén vacíos y mostrar un mensaje.

El resto del código era para mí igual de desechable, así que toda la búsqueda había sido en vano. Sin embargo, no se por qué me dio en ese momento por revisar mi correo (siempre hay locos que me escriben de madrugada) y, como casualmente en ese momento estaba conectado, me limité a hacer doble clic en la página que había descargado, con la idea de luego, presionando sobre el botón que valida mis datos, obtener la lista de todos mis mensajes. Sorpresa fue la mía al ver que abriendo dicha página, había perdido todos los colores, el formato, y las palabras Usuario y Contraseña... difícilmente eran legibles para quien nunca había entrado a esta sección.

¿Qué sucedió?
¿Por qué veo las cosas de esta manera?

Fueron las primeras preguntas que me hice. Pude pensar que había modificado algo del código, pero realmente estaba seguro de que lo único que hice fue leer, ya que al cerrarla no me pidió ni siquiera si quería guardar los cambios.

¿Qué podría haber pasado?

En estos líos de edición de la revista he aprendido con ZorphDark algo sobre programación script y cosas por el estilo. Él es una persona realmente "obsesiva" con la limpieza del código y las facilidades que nos brindan las hojas de estilo CSS, así que de forma casi obligatoria he tenido que aprender algo sobre ellas.

El problema de las hojas de estilo, es que para que la página se pueda visualizar correctamente, debe tener a la hoja CSS en su misma dirección o, de lo contrario, especificar desde dónde va a ser cargarda (casi todo el mundo la pone en la misma dirección de la página). Quizás el problema de la pérdida de belleza radicaba en ese aspecto, que el código hacía referencia a una hoja de estilo que estaba en el servidor y a la cual yo, desde mi condición de cliente, no tenía acceso.

¿Cómo hacer referencia a la hoja de estilo?

Al utilizar Firefox como navegador, éste me permite (no sé si Internet Explorer también), entre otras opciones, ver una información bastante detallada de la página en cuestión. Usando esta función pude tener acceso a la dirección en el servidor donde se guarda la hoja de estilo, a la dirección donde es enviado el nombre de usuario y la contraseña que se introduce, el puerto y dominio utilizado, etc. (¡y pensar que todavía hay quienes trabajan con Internet Explorer!). Una vez que tengo los datos necesarios, solo tengo que ir reemplazando por todo el documento las direcciones, y donde dice algo similar a:

<link href="/css.php?app=imp" rel="stylesheet" type="text/css">

Poner:
<link href="http://webmail.sld.cu/css.php?app=imp" rel="stylesheet" type="text/css">

Además de eso yo decidí completar de paso todas aquellas direcciones que iba encontrando entre el código.

Hasta aquí las cosas estaban bien, pero como ya era tan tarde -que podía confundirse con súper temprano- se me antojó seguir... quizás tenía la musa inspirada, y eso no se da todos los días. Quise seguir buscando por todo el código para ver en qué parte podría encontrar lo de la contraseña, pero esta vez busqué con más énfasis, y encontré algo como:

<tr>
  <td class="light" align="right"><b>Usuario</b></td>

  <!-- nótese que no se revela el campo que almacena el nombre del usuario -->
  <td align="left"><input tabindex="1" name="imapuser" value="USUARIO" type="text"></td>
</tr>
<tr>
  <td class="light" align="right"><b>Contraseña</b></td>
  <td align="left"><input tabindex="2" name="pass" type="password"></td>
</tr>

En estas líneas se puede apreciar fácilmente que, según el estilo que tiene la página del correo de Infomed, tiene dos cuadros de texto. Al primero se le pasa el nombre de usuario, y del segundo la única información que se nos da es el tabindex, el name y el type, pero en ningún momento se revela la contraseña (por supuesto), esto es algo que está almacenado en el servidor, pero sólo con reemplazar la línea:

<td align="left"><input tabindex="2" name="pass" type="password"></td>

Con:
<td align="left"><input tabindex="2" name="pass" value=”CONTRASEÑA” type="password"></td>

...al abrir la página sólo tendríamos que hacerle un clic al botón Enviar.

Nota: Ya este archivo no está en el escritorio, desde que vi esto lo pasé inmediatamente para mi otra partición.

Repito, yo no conozco mucho sobre lenguajes script, digamos que no es mi fuerte, pero me pregunto: ¿qué pasaría si una persona con algún diccionario amplio de palabras fuese capaz de generar de forma automática una página con todas estas condiciones y decirle que desde que se cargue envíe la información al servidor? Por supuesto, debería tener además una función que se encargue de verificar si la respuesta es verdadera y, en caso contrario, que cierre página y genere otra seleccionando una palabra distinta entre los posibles passwords. No se asegura que se pueda entrar a todas las cuentas, puesto que hay muchas personas que saben de estos aspectos de seguridad y tienen contraseñas combinadas con números, pero también los hay que siguen poniendo como password “qwerty” (por sólo citar un ejemplo).

Antes de terminar, quisiera dejar bien claro que “NO SÉ DE PROGRAMACIÓN SCRIPT”, lo que hace de este artículo un texto completamente inofensivo. Si existen otras mentes perversas que con los conocimientos adecuados son capaces de hacer cosas detestables luego de leerse esto, ése es su problema.

Para saber más...

Continuar leyendo

Espacio de intercambio

charlie_mtp

En informática, el espacio de intercambio es una zona del disco (un fichero o partición) que se usa para guardar las imágenes de los procesos que no han de mantenerse en memoria física. A este espacio se le suele llamar swap, del inglés "intercambiar".

Descripción::

La mayoría de los sistemas operativos modernos poseen un mecanismo llamado memoria virtual, que permite hacer creer a los programas que tienen más memoria que la disponible realmente (por ejemplo, 4 Gb en un ordenador de 32 bits). Como en realidad no se tiene físicamente toda esa memoria, algunos procesos no podrán ser ubicados en la memoria RAM.

En este caso es cuando es útil el espacio de intercambio: el sistema operativo puede buscar un proceso poco activo, y moverlo al área de intercambio (el disco duro) y de esa forma liberar la memoria principal para cargar otros procesos. Mientras no haga falta, el proceso extraído de memoria puede quedarse en el disco, ya que ahí no gasta memoria física. Cuando sea necesario, el sistema vuelve a hacer un intercambio, pasándolo del disco a memoria RAM. Es un proceso lento (comparado con usar sólo la memoria RAM), pero permite dar la impresión de que hay más memoria disponible.

Implementación::

En realidad, puede ser que no toda la imagen del proceso se lleve al disco. De esta forma, se mantienen algunas partes en memoria principal, mientras que otras permanecen en el almacenamiento secundario.

Si los algoritmos utilizados en el intercambio de páginas están mal diseñados o hay poca memoria disponible, se puede dar un problema conocido como "hiperpaginación" o, en inglés, thrashing. Los síntomas son un atasco y sobrecarga en el sistema; esto se debe a que los procesos continuamente están siendo pasados de memoria física a área de intercambio (porque hace falta memoria para correr otro proceso) y luego otra vez a memoria (porque han de ejecutarse). Aquí vamos a hacer un alto y añadir una observación donde espero que los seguidores de Microsoft no se molesten. Tenemos que dejar claro que en Windows esto no está todo lo bien implementado que pudiera, y el resultado de ésto lo podemos ver cuando en ocasiones estamos sin hacer nada en el ordenador y vemos el bombillo del disco duro encendido (o sea, que está trabajando) y pensamos que está loco o nos preguntamos que estará haciendo. Pues bien, el problema está que Windows es algo nervioso (hiperactivo) y pagina en ocasiones sin necesitarlo. La razón es que cuando el sistema tiene menos de 200 Mb de memoria física libre necesita paginar, y he aquí la explicación de por qué pagina tan seguido.

Posibles ubicaciones::

En los sistemas operativos se puede usar como área de intercambio un fichero o una partición (los dos son en realidad parte de un disco duro o almacenamiento secundario).

Fichero de intercambio:
Un fichero en blanco puede prepararse para ser usado como área de intercambio. Esto tiene una gran ventaja: es fácil de crear, borrar, ampliar o reducir, según se crea necesario (a diferencia de una partición). Pero tiene una desventaja: le afecta la fragmentación, ya que se encuentra dentro de un sistema de ficheros. El problema de la fragmentación no es grave, ya que el espacio de intercambio no siempre es accedido de forma secuencial, sino directa (en oposición a la secuencial).

Partición de intercambio:
También se puede dedicar una partición entera del disco duro (o el disco completo) como área de intercambio. Ventajas: se puede conseguir mejor rendimiento si se coloca la partición en la zona más rápida del disco, que es al principio (los cilindros exteriores del disco, por donde pasan más datos a cada vuelta). No hay problemas de fragmentación y no hay que usar ningún sistema de ficheros en concreto.
Tiene pocas desventajas: crear una partición es un proceso algo difícil; de todas formas, si se elige bien el tamaño de la partición, no hará falta ningún cambio en el futuro la partición siempre ocupará el mismo espacio, aunque no se esté usando al 100%.

Otros dispositivos::

Las tarjetas de video incluyen una memoria, que en los modelos actuales puede llegar a cientos de megabytes; además, son muy rápidas, y no se están usando siempre. Por eso no es extraño que ya se haya intentado usar esta memoria como dispositivo de intercambio (y como almacenamiento genérico). En Linux se puede hacer esto mediante MTD. También ésto se ha hecho con la memoria de una tarjeta de sonido, usando un controlador específico que la convierte en un dispositivo de bloque.

Uso en sistemas operativos::

Cada sistema operativo gestiona la memoria virtual de forma distinta, por tanto, el intercambio depende de la implementación de los algoritmos de intercambio.

En Windows:
Microsoft Windows usa un fichero de intercambio desde su versión 3.1 (1992), la primera en usar memoria virtual. Lo implementa mediante un fichero situado en el directorio raíz (C:\) o en el de sistema ( C:\WINDOWS\), y tiene por nombre: 386SPART.PAR en Windows 3.1; WIN386.SWP en Windows 3.11, 95 y 98; pagefile.sys en Windows NT y sucesores. Este fichero tiene un tamaño variable (depende de la configuración) y no debe ser movido o borrado. Aquí haremos otro alto para añadir que si quiere ver cómo aumenta este archivo, sólo obsérvelo recién iniciada la máquina y más adelante, después de tener varios procesos pesados abiertos. Entonces verá cómo su tamaño aumenta.

Hay una opción para establecer un tamaño fijo para el fichero, pero no es recomendable, porque a veces (cuando se acaba la memoria física y un programa necesita más) hace falta aumentar el tamaño del fichero de intercambio, y si no se puede, no habrá memoria extra para los programas. Si los programas (o el propio Windows) no pueden conseguir la memoria que necesitan, probablemente den fallos extraños. Se puede controlar el tamaño mínimo y el máximo para el fichero. Mientras que aumentar mucho el máximo no hará que funcione mejor, aumentar el mínimo sí que puede ayudar en sistemas que tengan poca memoria RAM.

En Linux:
Linux se suele usar con una partición de intercambio, aunque también permite usar ficheros de intercambio.
Se pueden asignar varios dispositivos de intercambio, incluso de diferentes tipos, y asignar a cada uno una prioridad. Si la prioridad es la misma en varios, las páginas de memoria se distribuirán como en un RAID de nivel 0. Esto permite que los dispositivos de swap se usen en paralelo, cosa que puede aumentar la eficacia, sobre todo si están en discos independientes.

Para crear un área de intercambio en Linux se usa la orden mkswap nombre, donde nombre puede ser un fichero o la ruta a un dispositivo de disco (por ejemplo /dev/hda1). Esto prepara el dispositivo y le pone la cabecera apropiada. Si lo que se está usando es un fichero swap, el contenido puede ser cualquiera (se destruirá), y lo que importa es el tamaño. Pero además, mkswap tiene un requisito especial: el fichero no ha de tener agujeros. Quiere decir que los bytes del fichero han de estar realmente en el disco. Esto no pasa siempre: si se usa cp /dev/zero nuevo, el sistema de ficheros probablemente vea que se trata de un fichero disperso (tiene regiones muy grandes todas con nulos), y no lo grabará realmente en el disco. Al usar algo como dd if=/dev/zero of=nuevo bs=1024 count=65536 se le fuerza a que escriba todos los bloques, sin agujeros. El dispositivo de intercambio se activa con la orden swapon nombre y se desactiva con swapoff nombre. En el fichero /proc/swaps se muestra una lista de los dispositivos de intercambio activos, y en /etc/fstab se suelen añadir las particiones swap que se activan al inicio del sistema. Con el programa free se puede ver, además de cuánta RAM queda libre, el tamaño total de las áreas de intercambio, cuán de llenas están, y cuánta memoria (RAM) se está usando como caché.

¿Hace falta swap?

La memoria de intercambio sirve como RAM adicional. Entonces, en un ordenador que ya tenga mucha memoria RAM, ¿hace falta swap?

Aunque puede funcionar bien sin tener ningún área de intercambio, es muy recomendable crearla. La razón es que siempre es bueno quitar de la memoria los procesos poco usados, ya que eso permite usar la RAM para otras tareas, como por ejemplo, la memoria caché de las operaciones de entrada/salida o el acceso al disco.

Un ejemplo: supongamos que un usuario abre en un programa una imagen muy grande, que le consume el 80% de la memoria RAM, y después, sin cerrarla, se pone a hacer varias búsquedas de ficheros por su disco duro. Si no se puede llevar a disco ese proceso grande, quiere decir que ha de mantenerse en memoria física; por tanto, las búsquedas sólo tendrán menos del 20% de la memoria RAM para hacer de caché, y por eso serán poco eficientes. Con swap, se podría llevar a disco el proceso grande (o al menos una parte), hacer esas búsquedas usando toda la RAM como caché, y luego restaurar el proceso, si hace falta.
Hay algunos procesos que, debido a la función que realizan, están poco activos, y puede ser recomendable que estén en el área de intercambio para liberar un poco la memoria RAM. Por ejemplo, un servidor SSH (mecanismo de control remoto del ordenador) tiene que estar siempre activo para atender las posibles peticiones, pero sólo empezará a trabajar de verdad cuando un usuario se conecte.

Tamaño del espacio de intercambio::

Ésta es una discusión típica entre los administradores de sistemas, y una duda común que aparece durante la instalación de un sistema Linux (o cualquier UNIX). Hay una regla muy conocida que dice que "la swap ha de ser el doble de la memoria RAM instalada", pero esto ya no es válido hoy en día. Esta regla funcionaba bien antes, cuando siempre se compraba menos RAM de la que realmente se necesitaba, porque era muy cara. Tener tres veces más memoria que la física iba bien para la mayoría de usuarios. Pero en un ordenador nuevo que tenga 1 Gb de RAM, no será necesario gastar 2 Gb en una partición de swap, porque probablemente no se usará.

La regla habitual usada para decidir el tamaño del área de intercambio es "pensar en cuánto querrías tener y en cuánto tienes, y poner como swap la diferencia". Por ejemplo, si un usuario necesita abrir ficheros de hasta 700 Mb, pero sólo tiene 256 Mb de RAM, entonces lo que le falta (aproximadamente 500 Mb) se ha de poner como swap, como mínimo. Más swap puede ir bien, pero no será muy usada. Si el ordenador ha de soportar mucha carga, la partición ha de ser mínimamente grande; se recomienda algo más de 128 Mb.

Seguridad::

El espacio de intercambio sirve para guardar, aproximadamente, las mismas cosas que la memoria RAM. Esto incluye información privada, contraseñas, documentos abiertos (aunque no se hayan grabado), etc. Pero con una diferencia: la memoria RAM se pierde al apagar el ordenador; en cambio, la swap no (porque está dentro del disco duro).

Esto hace que sea necesaria una política de borrado de swaps en algunos sistemas donde la privacidad sea importante. Borrar una partición de swap en Linux es muy fácil (sólo hay que escribirla con ceros mediante dd), pero hacerlo manualmente puede ser tedioso, sobre todo porque antes hay que desmontarla y luego volverla a montar.

Otra opción es escribir un código que se ejecute al apagar el ordenador para que haga esto cada vez, cosa que puede ser algo lenta. Existen programas que automatizan estas tareas en varios sistemas operativos.

De todas formas, borrar la swap al apagar no asegura los datos mientras el ordenador está encendido, ya que en el disco habrá información que supuestamente sólo debía estar en memoria RAM. Por eso, en algunos casos se usa un dispositivo de intercambio cifrado, que ofrece más protección, pero, como contrapartida, es mucho más lento. Eso afecta al rendimiento general del sistema, y hace que esta solución sea prohibitiva en el caso general. Naturalmente, también es necesario controlar los permisos de los dispositivos de intercambio, para evitar que usuarios no autorizados puedan leer un fichero de swap, y por tanto la memoria.

Para saber más...

Continuar leyendo

¿Está protegida mi PC?

ZorphDark [blackhat4all@gmail.com]

Actualizaciones semanales -e incluso diarias- del programa antivirus instalado en el sistema, la efectiva configuración de un potente cortafuegos (firewall) que bloquea la entrada y salida de datos por puertos no seguros, la adopción de largas y complejas contraseñas alfanuméricas para el aseguramiento de recursos, la encriptación PGP, el manejo de diversas políticas de seguridad y cualquier otra eficaz medida de control a nivel de software, por más novedosa que sea, no constituye el punto final para lograr la invulnerabilidad de un sistema de cómputo.

Por lo general, al referirse a la seguridad informática, siempre se lleva a un segundo plano las reglas de protección física. Dejando a un lado el hecho de que casi siempre el hardware suele ser más costoso que la información almacenada en su parte lógica, se debe mencionar que el desgaste, la rotura o el robo de cualquier dispositivo central o periférico de una computadora puede arruinar fácilmente cualquier norma de seguridad de datos basada en softwares de protección digital.

Por esa razón, es necesario incluir la custodia y la protección física dentro de los planes de seguridad informática, tanto a nivel institucional o empresarial como en un simple hogar.

Protegiendo el hardware::

La mejor forma de proteger un sistema informático es mediante la prevención. Si se toma en cuenta una serie de medidas que eviten el deterioro, el daño intencional o el hurto de algún dispositivo del hardware instalado, obviamente el nivel de riesgos disminuirá de forma considerable.

Todo informático, administrador de red o persona que esté a cargo de la integridad de una o varias computadoras, debe realizar un estudio general acerca de los peligros físicos existentes relacionados con la geografía y las condiciones del local donde estén instaladas. Las determinaciones que se hayan tomado deben incluirse en el plan de seguridad informática y, consiguientemente, deben ser transmitidas a todas las personas que utilicen esos equipos. Al igual que el hardware, los demás componentes electrónicos que intervienen en el correcto funcionamiento de las computadoras, como los suministros de potencia (UPS), los aires acondicionados y los dispositivos de transmisión de datos (routers, switchs, gateways), deben ser protegidos con cautela.

Peligros y amenazas::

Existen miles de factores que pueden atentar físicamente contra un sistema de equipos de cómputo. Para contribuir a la formación de un riguroso plan de seguridad y control, es necesario destacar un conjunto de propuestas mínimas para la prevención y detección de las amenazas más comunes.

Catástrofes naturales:
El número de medidas que se deben tomar frente a catástrofes de este tipo deben de estar acordes con el nivel de frecuencia y probabilidad de que estas ocurran. En nuestro país los huracanes y ciclones tropicales representan la mayor amenaza, ya que traen consigo poderosas ráfagas de vientos y grandes inundaciones que pueden afectar la integridad del local donde se encuentren ubicados componentes electrónicos e informáticos. Para evitar graves perjuicios, se deben colocar los equipos a una determinada altura. En caso de alerta ciclónica las medidas deben extremarse, alejándolos de ventanas y puertas y, dentro de las posibilidades, ubicándolos en pisos superiores o alejándolos de zonas peligrosas, como presas, ríos, playas, con el objetivo de evitar el riesgo de contacto con el agua por una inundación.

Tormentas eléctricas:
Si el campo electromagnético de un sistema de cómputo se ve afectado por las colosales descargas de este fenómeno, los daños del hardware podrían ocasionar una rotura parcial o total. Aunque los pararrayos pueden evitar la caída de un rayo sobre la estructura metálica del edificio donde se encuentren instalados equipos electrónicos e informáticos, los responsables de su integridad deben apagarlos y desconectarlos de la corriente eléctrica para prevenir cualquier situación irremediable. Uno de los dispositivos más afectados es el módem, por lo que se recomienda desconectarlo de la línea telefónica cuando se termine de utilizar y no transferir información cuando hayan descargas eléctricas.

Incendios:
Todo laboratorio de computación debe contar con un sistema de detección y extinción de incendios, para evitar que algún desastre de este tipo pueda ocasionar más daños. Es necesario que se pongan en práctica medidas que impidan que ocurra un accidente que conlleve a un incendio, como prohibir el fumar, la correcta instalación y la revisión sistemática de la red eléctrica del local.

Fallos eléctricos:
Las afectaciones provocadas por las caídas de tensión, los picos, cortes, entre otros fallos eléctricos, pueden ser evitadas por el uso de sistemas de alimentación eléctrica ininterrumpida (UPS). Además de que el usuario tiene la posibilidad de guardar los documentos abiertos y apagar la computadora correctamente ante cualquier fallo de suministro eléctrico, el hardware queda bien protegido con la ayuda de esos equipos. Una alternativa son los protectores de equipos electrónicos fabricados por GEDEME Electrónica, que se comercializan a costos mucho menores que un back-up en las tiendas del país.

Temperaturas extremas:
El calor excesivo, el aumento de la humedad relativa o el frío intenso pueden dañar con el tiempo los componentes físicos de un equipo informático. Para evitarlo, se deben instalar reguladores y detectores climáticos en los laboratorios de computación. El uso de aires acondicionados es una excelente opción para mantener la temperatura ideal en estos locales, pero un buen ventilador refrescando el monitor y la torre puede utilizarse también para dicha tarea.

Hurtos y atentados:
Un factor que se debe tener muy en cuenta por su alto nivel de riesgo es el aseguramiento del sistema de protección contra robos y otras acciones ilícitas. El cuidado de las computadoras portátiles, de bolsillo y los dispositivos de hardware más pequeños, representan el mayor problema debido a su alto nivel de portabilidad. Para prevenir este tipo de amenaza existen diversos métodos que, con un mayor o menor costo económico, por lo general evitan tener que sufrir pérdidas superiores. Con el objetivo de limitar el acceso a personas no autorizadas al área donde se encuentren instalados los equipos informáticos, es recomendable disponer de un sistema de control. La instalación de un circuito de cámaras y la restricción mediante permisos, llaves o técnicas biométricas (identificación de características físicas o sensoriales de un individuo) son varios ejemplos que se pueden aplicar.

PROTECCIÓN DE LA INFORMACIÓN::

Velar por el mantenimiento en buen estado de los soportes de almacenamiento de información digital es una necesidad y a la vez una obligación de cualquier persona que trabaje con computadoras. A diferencia de los medios tradicionales como el papel, las cintas de audio y de video, los datos acumulados en dispositivos informáticos no pueden ser recuperados cuando hay graves daños físicos en su estructura. Aunque existen eficaces métodos de recuperación de la información ubicada en sectores defectuosos de discos rígidos y extraíbles, cuando ocurre un fallo eléctrico, desgaste o un grave incidente sobre su superficie magnética, es casi seguro que se afecte su integridad, reflejándose en la pérdida total del sistema de archivos.

Puede darse la situación de que las líneas de comunicación que utilicemos para transferir datos sean interferidas por algún motivo. En caso de no poder enfrentarse a tal amenaza a nuestra privacidad, es necesario instalar algún sistema de encriptación de información, ya sea binario (los más seguros) o en modo texto (como el ROT-13).

Por último, es necesario enfatizar que todo individuo que se responsabilice por una o varias computadoras, debe poner a prueba su sistema de seguridad informática, simulando, en la medida de las posibilidades, cualquiera de las situaciones antes expuestas. Una de las vías para estar seguro de uno mismo es siendo capaces de defendernos de ataques provocados por nuestra voluntad. Es preferible ganar una batalla anticipada contra uno mismo que perderla contra quien quiera atacarnos por sorpresa...

Para saber más...

Continuar leyendo