miércoles, 31 de mayo de 2017

Branchs para andar a los saltos

Quien aprende a programar en alto nivel puede que sienta que su vida se complica cuando halla que en los bajos fondos del assembler no hay if, case/switch, for, while... la carencia de estructuras de control que formaron parte desde un mismo comienzo de su aprendizaje de la programación. Ahora bien, que no existan las mencionadas estructuras no significa que no las podamos imitar. La verdad es que a base de saltos o bifurcaciones nos las podemos arreglar para extrañar menos a if y sus amigas. Veamos cómo emplear la familia de instrucciones branch y conozcamos mejor a cada integrante del clan. 
No voy a entrar en detalles sobre el cálculo de los saltos, dado que en la nota Direccionamiento (continuacion). Todo es relativo... bah, no siempre. está cubierto. Sugiero leer primero la serie de dos partes sobre Direccionamiento antes de abordar el presente tema. Adicionalmente hallará más información sobre aplicación de saltos a comparaciones rutinarias en la serie de cuatro partes ¿Ser o no ser?
Conozcamos a la familia
Toda las instrucciones de bifurcación/salto condicional las encontraremos agrupadas en el set de instrucciones en la "B", y salvo un par de excepciones podríamos decir que si empieza con B es Branch. (Lamento(?) si la mención de la segunda letra del abecedario trae algún recuerdo doloroso para simpatizantes de algún club de fútbol. El uso de los colores rojo y blanco en los gráficos es totalmente casual.). 
Observaremos que todos los branchs en su columna "Descripción" tienen un signo de interrogación y la condición que evalúan para determinar si se ejecuta el salto o no. A excepción de BRCLR y BRSET, a las que abordaremos en forma particular, todos los saltos dependen del resultado algebraico booleano obtenido al operar con banderas de la palabra de estado.

El signo de interrogación es otra forma de indicar que el salto se produce solo si la respuesta a la pregunta es afirmativa. Siempre se trata de condiciones booleanas, por tanto la suma es en realidad una operación OR booleana (basta con que uno de los términos sea verdad para que la proposición sea verdad), el producto es AND booleano (ambos términos han de ser verdad para que la proposición también los sea) y el más dentro de un círculo es XOR (uno y solo uno de los dos términos debe ser verdad para que la proposición lo sea). Incluso en BRSET se usa un negador sobre M, que nuevamente debemos interpretar como NOT booleano.

Entendiendo a cada integrante, del derecho y del revés
Hay más de una manera de escoger el miembro de la familia Branch correcto para nuestro algoritmo. Por ejemplo, podemos interpretar fácilmente cuál es la condición que evalúa BCC y BCS. Si al elaborar el algoritmo requerimos de un salto por el estado del flag de Carry, es más sencillo que nuestra mente nos lleve a usar BCC (salte si carry está en cero, branch if carry clear) o BCS (salte si carry está en uno, branch if carry set).
Si por el contrario estamos verificando la condición de cero nos quedaremos con BEQ y BNE, que saltan cuando Z (cero) es 1 o no. Lo mismo podríamos aplicar a BPL y BMI, que operan sobre el flag N (negativo).
El problema radica en entender ¿por qué me tengo que fijar en los flags (N,Z,V,C)? El significado de los flags para cada operación se desarrolla en un post aparte, pero veamos algunas particularidades.

Compare por ejemplo estos dos pares de instrucciones:  BCS, BCC y BLO, BHS. 
Estas cuatro instrucciones -que realmente son dos y sus alter ego- son un claro ejemplo de las dos formas de entender cada una.
El asunto es ¿qué significa que carry esté en cero o uno, en verdadero o falso? Dependerá de la operación previa, si antes del branch ejecutamos una suma entonces el significado de Carry será el acarreo de dicha operación. ¿Y si ejecutamos una resta o una comparación? Recordemos que una comparación no es otra cosa que una resta de la que no nos interesa el resultado. ¿Qué significado tiene Carry en estos casos?
Remontémonos por un momento a los años felices en que comenzábamos a descubrir el mundo de las matemáticas. Lejos de integrales, límites, diferenciales y tantas cosas que luego quemaron nuestros cerebros, descubríamos inocentes una operación que sigue acompañándonos a diario (especialmente luego de cobrar el sueldo): la resta. ¿Qué ocurría cuando teníamos que restar y no nos alcanzaba? Por ejemplo, si la resta era:
12
- 9
No podíamos restar 9 de 2... así que le "pedíamos al compañero". Ese pedido/préstamo (en inglés borrow) nos permitía resolver la resta. Lo mismo aplicaba a restar a un número otro mayor, por ejemplo restarle 15 a 9 nos generaba el mismo borrow, solo que aquí se lo aplicamos al signo del número haciendo que el resultado sea negativo.
Por lo tanto, si luego de una comparación de números sin signo deseamos saber cuál de los dos es mayor... ¿qué flag podemos evaluar? (por favor observe que esto es válido para números sin signo!, luego desarrollaremos los signados) En este momento puede que revise la composición de la palabra de estado y no encuentre ninguna "B" (alivio para un club afecto al maíz)... ¿entonces? Resulta que el mismo flag que se usa para Carry es el que se emplea para Borrow. De hecho en los manuales del HC11 aparece como Carry/Borrow en más de una ocasión.
La respuesta es: Carry. Si el segundo número de la comparación es mayor, entonces Carry/Borrow será 1 porque "no le alcanzó" al primero para la resta. Recordemos que la comparación es una resta que no se resuelve sino solo para los flags.
Del mismo modo, si tenemos dos números -signados o no signados, es lo mismo- y queremos saber si son iguales... ¿cómo lo podemos determinar? Si se restan dos números iguales el resultado es cero. En cualquier otro caso el resultado es distinto de cero. Eso significa que podemos usar el flag Z (cero) y los saltos asociados BEQ y BNE.
En otro post desarrollaré con más detalle cómo tomar decisiones con números signados. Veamos el segundo método para escoger saltos.

Menos filosofía y cuentitas y más programación.
Una manera más pragmática de determinar el branch a emplear es recordando que el HC11 solo permite comparaciones entre registros o entre registro y memoria. Por ejemplo, si queremos comparar dos direcciones de memoria (digamos $0010 y $0011) podríamos hacer:

LDAA $0010
CMPA $0011 ; obviamente comparo el contenido de las direcciones

otra alternativa sería
LDAA $0010
LDAB $0011
CBA        ; algo menos eficiente, usé una instrucción adicional

Observe en el set de instrucciones la columna "Description" de las instrucciones de comparación (hice un collage para que esten todas juntas):
¿Qué puede ver en común en todas ellas? Siempre son restas y nunca se asignan los resultados (o sea el resultado se descarta, no se puede obtener con ellas). También note que (salvo CBA) todas comparan un registro (A, B, D, IX, IY) contra memoria. En la resta siempre va primero el registro y segunda la memoria. En el caso de CBA la operación es A-B, para lo que vamos a definir ahora "B" hace las veces de memoria. (Parece a propósito que saco a colación la "B" y la memoria, pero no, para nada). Recordando el orden de la comparación (registro respecto a memoria) veamos ahora esta tabla:
BHS
Branch if Higher or Same
r >= M
No signado
BLO
Branch if Lower
r < M
No signado
BHI
Branch if Higher
r > M
No signado
BLS
Branch if Lower or Same
r <= M
No signado
BLE
Branch if Less or Equal
r <= M
Signado
BGT
Branch if Greater Than
r > M
Signado
BGE
Branch if Greater or Equal
r >= M
Signado
BLT
Branch if Less Than
r < M
Signado

Supongo que el poco de inglés que se necesita a este punto ya lo comprenderá. Observe la correlación entre el mnemónico (expandido en la segunda columna) y el signo de desigualdad de la tercera.

A este punto debiera ser más clara la decisión. Si estamos comparando dos valores y deseamos que se cambie el flujo de programa (o sea se produzca un salto o bifurcación, branch) la condición por la que deseamos saltar será la que se lea en "inglés natural" si recordamos que estamos comparando registro contra memoria (en ese orden).

El único truco adicional es saber qué salto utilizar si estamos tratando con números signados o no, y para eso va el comentario de la cuarta columna.

Habrá segunda parte para que conozcamos sobre BRSET y BRCLR, BRA y BRN y para que tratemos de asimilar la forma de decidir saltos pensando en bajo nivel.

Me despido con un clásico del Borrow...



jueves, 18 de mayo de 2017

[Redes] Blanquear password enable en un router Cisco

¿A quién no se le perdió la contraseña enable de un router Cisco? Pasa en las mejores familias. Veamos cómo sobreescribir la password enable sin perder la configuración del equipo.
Para quien no lo sepa: la contraseña enable es la que permite acceso al modo privilegiado de configuración del equipo.

Vayamos paso a paso:
1. Necesitaremos conexión a consola. Esto no se puede hacer por telnet/SSH por la sencilla razón de que vamos a modificar un parámetro del boot loader, antes de que inicie el sistema operativo del equipo. Si no se ha cargado el sistema operativo, no hay quien escuche conexiones telnet, ssh o de ningún tipo. Conectamos entonces el cable consola (celeste) al puerto serie de la computadora, con la configuración usual (9600 baudios, sin paridad, 8 bits de datos, 1 bit de stop, sin control de flujo). Abrimos la sesión de consola.

2. Si el caso es que podemos ingresar al equipo con credenciales con privilegios suficientes, el comando
> show version
nos indicará ciertos parámetros de configuración que haríamos bien en documentar (puede que no tengamos acceso enable pero igualmente podamos ejecutar este comando). En particular nos interesa la línea
Configuration register is 0x2102
que suele encontrarse al final.
El registro de configuración afecta el comportamiento del boot loader. Es un registro de 16 bits, donde uno de ellos es el que regula si se debe cargar la configuración presente en NVRAM, o sea el archivo startup-config. Al modificar el valor del registro de configuración le indicaremos al equipo que no procese el startup-config.
Si no tenemos acceso para tomar el valor previo, haríamos bien en averiguar en internet el valor default de este registro para el modelo de equipo que estamos trabajando.

3. Apagamos el equipo Cisco y lo encendemos de nuevo

4 a. Cuando vemos el mensaje
program load complete, entry point: 0x80008000, size:0x6fdb4c
o algo así, debemos interrumpir la carga del Cisco IOS que hará el boot loader. Para esto usaremos la tecla Break (Inter), o segun el programa que estemos usando para la conexión de consola puede ser:
En Hyperterminal: Ctrl+Break;
En TeraTerm Break, Ctrl+Break, o Alt+b;
En PuTTY: Ctrl+Break
Si no hay forma de interrumpir la carga del IOS y quedar en modo ROMMON, se puede hacer esto:
  1. Quitar la memoria flash
  2. Reiniciar el equipo, quedará en modo ROMMON
  3. Insertar la flash

5. Ahora vamos a reconfigurar el registro, por ejemplo para un router 1941 el comando sería:
rommon 1> confreg 0x2142 

6. Lo que sigue es reiniciar el equipo así:
rommon 1> reset

7. El equipo va iniciar ignorando la configuración cargada. Mucha atención! Cuando inicie va a preguntar si deseamos usar el asistente de configuración, le decimos que NO o presionamos Ctrl+C.

8. Entramos al modo privilegiado con el comando

Router> enable

deberíamos ver el prompt cambiado:

Router#

9. Aunque todo el procedimiento es delicado, ahora hay que prestar 25% más de atención, lo que sigue es aplicar la configuración manualmente con un comando parecido al que usaríamos para guardar cambios... pero no es igual!

Router# copy startup-config running-config

Notar que el orden de copia es al revés!!! Cuando hagamos esto se aplicará toda la configuración del equipo, dejándolo operativo nuevamente.

10. Ejecutamos

show running-config

y tomamos nota de las contraseñas no encriptadas que pudiera haber.
Acto seguido podemos crear la contraseña enable:

# configure terminal
(config)# enable secret <nueva clave>

Si fuera necesario podemos también aprovechar a sobreescribir otras contraseñas necesarias. 

11. Revisemos con:

# show ip interface brief

si hay alguna interfaz que requera activarse (no shutdown), por las dudas.

12. Finalmente volveremos a poner en el registro de configuración el valor que tenía antes para que al reiniciar procese el archivo de configuración. Si pudimos tomar nota en el paso 2, excelente! usamos ese. Si no lo pudimos hacer, verificamos lo que hayamos verificado en internet. Por ejemplo para el router 1811, 1941 (y el 2911) sería -obviamente desde modo de configuración-:

(config)#config-register 0x2102

Si el valor original no era 2102, habrá que indicar el correcto.

13. Salimos del modo de configuración y guardamos los cambios:

copy running-config startup-config

14. Voilà. Tenemos acceso enable al equipo sin perder la configuración!

En otro post veremos el procedimiento con switchs, que conceptualmente es igual pero tiene otras particularidades.



[Redes] Configurar un switch para usar sniffers Switch Port Analyzer

Este post lo hago con base en un paper mío del 27 de septiembre de 2013.

En un hub el tráfico recibido en cada puerto se copia en todos los restantes. Por ello es sencillo
utilizar un sniffer para ver todo el tráfico, tal como se ve en la figura:
En un switch el comportamiento es distinto. Una vez que aprendió en qué puerto se encuentra la dirección MAC de destino, el tráfico solo se reenviará en ese puerto. Dada esta situación, un sniffer conectado en otro puerto no puede ver el tráfico. Esto es bueno para la performance y seguridad, pero cuando el caso es que queremos examinar el tráfico de alguien más, representa una limitación.

El único tráfico que podría capturar es el que inunda todos los puertos, a saber:
• Tráfico de broadcast
• Tráfico multicast con CGMP o IGMP (Internet Group Management Protocol)
• Tráfico unicast desconocido
La inundación (flooding) unicast ocurre cuando el switch no tiene la MAC en su tabla en memoria direccionable por contenido (CAM). Al no saber a dónde enviar el tráfico, lo reenvía a todos los puertos en la VLAN destino. Se necesita una característica adicional para copiar artificialmente al sniffer todos los paquetes unicast que un host envía.
En este diagrama el switch ha sido configurado para enviar copia del tráfico que envía el host A al puerto del sniffer. Este puerto se denomina puerto SPAN:
Al configurar la funcionalidad SPAN se puede escoger entre copiar el tráfico de entrada, de salida o ambos. También puede utilizarse un mismo puerto para monitorear tráfico de varias VLAN.

Veamos un ejemplo de configuración para un switch Cisco 2960.
Se define que el puerto FastEthernet 0/3 reciba copia de todo el tráfico (entrante y saliente) que pasa por el puerto FastEthernet 0/2.

C2960#configure terminal
C2960(config)#monitor session 1 source interface fa 0/2
C2960(config)#monitor session 1 destination interface fa 0/3



Con el comando show monitor podemos ver la configuración creada:


C2960#show monitor session 1
Session 1
---------
Source Ports:
RX Only: None
TX Only: None
Both: Fa0/2
Destination Ports: Fa0/3

¿Cómo podemos aprovechar esto? Además de la monitorización de actividad de un host o servidor en particular, aplicando esta config en un enlace a otras redes (por ejemplo el puerto donde se conecta el default gateway) puede estudiarse con detenimiento todo el tráfico que va hacia y desde internet. Podemos examinar el tráfico desde/hacia un servidor con minuciosidad. Entre las herramientas de software que podemos emplear destacamos Wireshark
Por supuesto, el equipo que conectemos en el puerto FastEthernet0/3 no tendrá conectividad a la red mediante este puerto, ya que el tráfico es "ajeno". Si pretendemos estar conectados a la red y en forma paralela examinar el tráfico, deberíamos disponer de dos interfaces de red.

Fuente: Cisco

sábado, 13 de mayo de 2017

DNS protegido (y gratis!)

Recientemente asistí al evento Cisco Route 2017, donde se trató una y otra vez la "transformación digital" hacia la que inexorablemente vamos todos. En estos días se produjo el ataque de un ransomware llamado WannaCry, que afectó a más de 50 mil empresas en 99 países. Es realmente pasmoso pensar cómo la "transformación digital" (algo totalmente positivo) nos deja tan vulnerables si no tomamos las medidas precautorias del caso (hay desde hospitales paralizados hasta plantas automotrices con la producción suspendida).

En una de las charlas del Cisco Route mi amigo Juan Carlos Marino compartió una de esas cosas que rara vez se ven: algo gratis (bueno, bonito y barato, las tres B!). Cisco adquirió una empresa que provee DNS: OpenDNS, y ahora su servicio OpenDNS Umbrella se llama Cisco Umbrella

El asunto aquí (iré al grano) es que muchos de los ataques de phishing -y otros- comienzan cuando el usuario accede a un dominio que hostea contenido malicioso. Entonces una manera eficaz de protegerse es contando con un servicio de DNS que filtre las respuestas. O sea, si desde una computadora se hace una petición DNS de un dominio malicioso, si el servidor DNS es capaz de detectarlo, nos puede "denegar" la petición, lo que estaría salvándonos de ser atacados.

Para usar el servicio Umbrella hay que configurar los DNS en estos valores:
208.67.222.222
208.67.220.220
reemplazando los del proveedor de servicio. Si usamos un servidor a manera de forwarder o de DNS local, entonces ahí es donde debiéramos configurarlo. 

Obviamente esto no nos exime de tomar otras medidas precautorias, pero es un aporte más a la tranquilidad del administrador de la red.