Capítulo 9 — Infraestructura crítica y seguridad sectorial: herramientas y métodos
Mapa de la lección
Lección 09 publicada. Mapa, ejemplo, EX033.
flowchart TD
N0["Resultados de aprendizaje y conexión"]
N1["9.1 Elegir un método"]
N2["9.2 DNP3 en la capa de enlace"]
N3["9.3 Valide primero la herramienta"]
N4["9.6 Actividad práctica"]
N5["Síntesis del capítulo"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Ejemplo resuelto"]
EX --> Q["Ejercicio EX033"]
Dibujo lógico
flowchart LR
N0["Resultados de aprendizaje y conexión"]
N1["9.1 Elegir un método"]
N2["9.2 DNP3 en la capa de enlace"]
N3["9.3 Valide primero la herramienta"]
N4["9.6 Actividad práctica"]
N5["Síntesis del capítulo"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX033"]
[Resultados de aprendizaje y conexión]
|
v
[9.1 Elegir un método]
|
v
[9.2 DNP3 en la capa de enlace]
|
v
[9.3 Valide primero la herramienta]
|
v
[9.6 Actividad práctica]
|
v
[Síntesis del capítulo]
|
v
[Ejemplo resuelto] --> [Ejercicio EX033]
Resultados de aprendizaje y conexión
Al terminar este capítulo debería ser capaz de:
- elegir la herramienta técnica adecuada para una pregunta en un entorno de control: exportación de configuración, captura pasiva, decodificador de protocolos, consulta de registros, herramienta de ingeniería del fabricante o prueba activa;
- implementar y verificar una comprobación de integridad a partir de sus parámetros publicados, con el CRC de la capa de enlace de DNP3 como ejemplo;
- explicar la diferencia entre un código de detección de errores y la autenticación, y por qué un CRC válido no demuestra nada sobre quién envió una trama;
- validar una herramienta antes de confiar en ella: pruebas de respuesta conocida, pruebas negativas y versiones documentadas.
Los capítulos 7 y 8 usaron la telemetría. Este capítulo trata de los propios instrumentos: cómo elegirlos, cómo construir bien los pequeños y cómo saber cuándo mienten.
9.1 Elegir un método
| Pregunta | Preferir | Evitar salvo con alcance definido |
|---|---|---|
| ¿Qué está configurado? | Exportación de configuración, vista de solo lectura de la herramienta del fabricante | Sondear puertos para deducir la configuración |
| ¿Quién habla con quién? | Registros de flujos, captura pasiva en un puerto SPAN o un derivador (tap) | Escaneo activo |
| ¿Qué ejecuta un dispositivo? | Registros de activos, inventario de la herramienta de ingeniería durante una sesión aprobada | Identificación de huellas mediante sondeo |
| ¿Funciona una regla de denegación? | Registros del cortafuegos más una prueba de conexión delimitada | Escaneos amplios |
| ¿Está bien formada una trama? | Decodificador con comprobaciones del protocolo (capítulo 2, este capítulo) | Mirar el hexadecimal a ojo |
La guía de seguridad de TO NIST SP 800-82 Rev. 3 trata la supervisión pasiva y los riesgos de las técnicas activas (SP 800-82 Rev. 3). Los analizadores de paquetes como Wireshark incluyen disectores para Modbus y DNP3; sus propios scripts sirven para las comprobaciones que esas herramientas no hacen por usted y para una automatización repetible y revisable.
9.2 DNP3 en la capa de enlace
DNP3 se usa ampliamente en el telecontrol eléctrico y del agua. Cada trama de la capa de enlace empieza con una cabecera de 10 bytes: los bytes de inicio 05 64, un byte de longitud, un byte de control, una dirección de destino de 2 bytes y una de origen de 2 bytes (little-endian), y un CRC de 2 bytes. Los datos de usuario siguen en bloques de hasta 16 bytes, cada uno con su propio CRC. En el byte de control, el bit 7 (DIR) está activado en las tramas que envía la maestra, el bit 6 (PRM) en las tramas primarias (iniciadoras), y los cuatro bits bajos son el código de función del enlace; por ejemplo, primaria 0 «reiniciar los estados del enlace», primaria 4 «datos de usuario no confirmados», secundaria 11 «estado del enlace». El DNP Users Group publica una visión general; la norma completa es IEEE 1815 (DNP3 overview).
El CRC es CRC-16/DNP: polinomio 0x3D65, valor inicial 0, entrada y salida reflejadas, XOR final 0xFFFF, con el valor de comprobación del catálogo 0xEA82 para la cadena ASCII 123456789 (CRC catalogue). Reflejado, el polinomio es 0xA6BC, que es la constante que se usa en una implementación bit a bit.
9.3 Valide primero la herramienta
Una rutina de CRC sutilmente errónea sigue produciendo números. Antes de usarla, ejecute una prueba de respuesta conocida: calcule el CRC de 123456789 y compárelo con 0xEA82. Después, una prueba negativa: cambie un bit de una trama válida y confirme que la comprobación falla. El Lab 9 hace ambas (la línea assert es la prueba de respuesta conocida), y anote la versión de Python, porque el resultado de cualquier herramienta solo es evidencia si la herramienta está identificada. Mantenga en el script el assert que comprueba el valor del catálogo y haga fallar la tarea si deja de cumplirse tras un cambio en la función de CRC. Anote la versión de Python junto a cada resultado que vaya a usarse como evidencia. Ejecute la prueba negativa sobre una trama que haya corrompido usted mismo, para saber que el comprobador rechaza los CRC erróneos antes de confiar en él sobre una captura.
9.4 Detectar errores no es autenticar
Un CRC se calcula a partir de parámetros públicos; cualquiera que pueda enviar una trama puede calcular un CRC válido. Detecta la corrupción accidental, no la falsificación. El Lab 9 lo muestra directamente: una trama de una dirección de origen desconocida (77) tiene un CRC válido. Distinguir lo auténtico de lo falsificado exige autenticación criptográfica (DNP3 Secure Authentication o un túnel protegido) o contexto: direcciones de origen conocidas, rutas conocidas, tiempos esperados. Compárelo con el capítulo 15 del libro de tecnólogo, que usa HMAC (RFC 2104) para la autenticidad (RFC 2104).
9.5 Ejemplo resuelto: comprobación de las cabeceras de SS-3 (sintético)
La maestra de Kestrel Grid (dirección DNP3 1) sondea la estación remota de la subestación SS-3 (dirección 10) a través de fep-01. Un técnico capturó seis cabeceras de enlace. Lab 9 (guárdelo como lab09.py y ejecútelo con python3 lab09.py):
# Lab 9 - check DNP3 link-layer headers and their CRC (offline, standard library only)
# CRC-16/DNP: poly 0x3D65 (reflected 0xA6BC), init 0x0000, reflected in/out, xorout 0xFFFF.
# Synthetic frames between the Kestrel Grid master (address 1) and substation SS-3 outstation (address 10).
import struct
def crc_dnp(data: bytes) -> int:
crc = 0
for byte in data:
crc ^= byte
for _ in range(8):
crc = (crc >> 1) ^ 0xA6BC if crc & 1 else crc >> 1
return crc ^ 0xFFFF
assert crc_dnp(b"123456789") == 0xEA82 # catalogue check value
def header(length, ctrl, dest, src):
h = bytes([0x05, 0x64, length, ctrl]) + struct.pack("<HH", dest, src)
return h + struct.pack("<H", crc_dnp(h))
capture = [
("master->SS-3", header(0x05, 0xC0, 10, 1).hex()), # primary function 0: reset link states
("SS-3->master", header(0x05, 0x0B, 1, 10).hex()), # secondary function 11: link status
("master->SS-3", header(0x11, 0xC4, 10, 1).hex()), # primary function 4: unconfirmed user data
("master->SS-3", "056411c40a000100" + "ffff"), # wrong CRC
("unknown->SS-3", header(0x11, 0xC4, 10, 77).hex()), # source not in station table
("master->SS-3", "0565" + header(0x05, 0xC0, 10, 1).hex()[4:]), # bad start bytes
]
KNOWN_SOURCES = {1}
for label, hx in capture:
b = bytes.fromhex(hx)
if b[:2] != b"\x05\x64": print(f"{label:<14} {hx} REJECT start bytes {b[:2].hex()}"); continue
got = struct.unpack("<H", b[8:10])[0]; want = crc_dnp(b[:8])
length, ctrl, dest, src = b[2], b[3], *struct.unpack("<HH", b[4:8])
if got != want: print(f"{label:<14} {hx} REJECT crc {got:04x} != {want:04x}"); continue
direction = "from master" if ctrl & 0x80 else "from outstation"
note = "" if src in KNOWN_SOURCES or src == 10 else " ALERT unknown source address"
print(f"{label:<14} {hx} ok len={length} ctrl=0x{ctrl:02x} ({direction}, fc={ctrl & 0x0F}) dest={dest} src={src}{note}")
Salida esperada (Python 3.13.5):
master->SS-3 056405c00a000100b1ac ok len=5 ctrl=0xc0 (from master, fc=0) dest=10 src=1
SS-3->master 0564050b01000a006ded ok len=5 ctrl=0x0b (from outstation, fc=11) dest=1 src=10
master->SS-3 056411c40a0001000615 ok len=17 ctrl=0xc4 (from master, fc=4) dest=10 src=1
master->SS-3 056411c40a000100ffff REJECT crc ffff != 1506
unknown->SS-3 056411c40a004d0073e6 ok len=17 ctrl=0xc4 (from master, fc=4) dest=10 src=77 ALERT unknown source address
master->SS-3 056505c00a000100b1ac REJECT start bytes 0565
Tres tramas son válidas y esperadas. Una tiene el CRC ffff donde se esperaba 1506: corrupción o una trama fabricada; en un enlace ruidoso, una racha de fallos de CRC es un hallazgo de calidad del enlace para el proveedor de telecomunicaciones. Otra tiene bytes de inicio erróneos y se rechaza antes de leer nada más. La línea más importante es la que supera el CRC: la dirección de origen 77 no está en la tabla de estaciones. El CRC dice que los bytes llegaron intactos; solo la comprobación de la dirección dice que procedían de un lugar inesperado.
9.6 Actividad práctica
Amplíe el Lab 9 para verificar el CRC de cada bloque de datos de usuario de 16 bytes que sigue a la cabecera. Construya una trama con 17 bytes de datos de usuario (un bloque completo y un bloque de 1 byte), calcule los CRC de ambos bloques y corrompa un byte del segundo bloque para mostrar que la comprobación lo detecta. Corrompa un byte del segundo bloque y confirme que solo falla la comprobación de ese bloque. Guarde los pasos de construcción en las notas del laboratorio para que un revisor pueda reconstruir la misma trama, y anote qué byte corrompió y el CRC esperado y el calculado de ese bloque.
9.7 Errores comunes y límites
- Confiar en un comprobador casero sin una prueba de respuesta conocida.
- Equivocarse con el orden de los bytes: las direcciones y el CRC de DNP3 son little-endian; los campos de Modbus son big-endian.
- Tratar «CRC válido» como «auténtico».
- Sondear activamente cuando una fuente pasiva responde a la pregunta.
- El Lab 9 solo comprueba las cabeceras; las capas de transporte y de aplicación llevan las órdenes y necesitan su propia decodificación.
-
Decodificar una captura sin anotar la versión de la herramienta ni los ajustes de orden de bytes usados, de modo que nadie puede reproducir el resultado.
-
Leer la ALERT del Lab 9 para la dirección de origen 77 como prueba de un ataque; solo muestra una dirección que falta en la lista de la maestra.
Ejercicios — capítulo 9
EX033 — Prueba de respuesta conocida. Objetivo: validar una herramienta. Entradas: la función crc_dnp del Lab 9. Pasos: (1) sustituya 0xA6BC por 0x3D65 y ejecute; (2) explique el resultado. Evidencia esperada: salida y explicación. Rúbrica: 3 = el assert falla porque un algoritmo con desplazamiento a la derecha (reflejado) necesita el polinomio reflejado; la prueba de respuesta conocida detectó un error verosímil antes de juzgar ninguna trama; 2 = observa el fallo sin explicarlo; 1 = intentado; 0 = nada.
EX034 — Decodifique el byte de control. Objetivo: leer los campos de enlace de DNP3. Entradas: los bytes de control 0xC9, 0x44 y 0x0B. Pasos: dé DIR, PRM y el código de función de cada uno y nombre la función. Evidencia esperada: tres filas. Rúbrica: 3 = 0xC9: DIR 1, PRM 1, fc 9 solicitar el estado del enlace; 0x44: DIR 0, PRM 1, fc 4 datos de usuario no confirmados desde una estación remota (por ejemplo, una respuesta no solicitada); 0x0B: DIR 0, PRM 0, fc 11 estado del enlace; 2 = uno erróneo; 1 = solo los bits; 0 = nada.
EX035 — Experimento mental de falsificación. Objetivo: separar integridad y autenticidad. Entradas: una trama con CRC válido, dirección de origen 1 y destino 10, que llega a la estación remota desde una dirección de la red MPLS que no es fep-01. Pasos: explique lo que muestra el CRC, lo que muestra la dirección y lo que establecería realmente la autenticidad. Evidencia esperada: explicación breve. Rúbrica: 3 = el CRC muestra que no hubo corrupción accidental; la dirección DNP3 1 la declara el propio emisor; la autenticidad requiere Secure Authentication o un túnel criptográfico que termine en extremos conocidos, más la aplicación de la ruta en la red; 2 = parcial; 1 = «CRC válido, luego auténtica»; 0 = nada.
EX036 — Selección del método. Objetivo: elegir el método menos intrusivo. Entradas: preguntas: (a) qué direcciones de maestra DNP3 ha visto SS-3 este mes; (b) si el cortafuegos de fep-01 solo permite la estación remota; (c) la versión de firmware de la estación remota. Pasos: elija un método para cada una y justifíquelo. Evidencia esperada: tres elecciones. Rúbrica: 3 = (a) captura pasiva o registros de fep-01 analizados con un decodificador; (b) exportación de configuración más registros y, después, una prueba delimitada si hace falta; (c) registro de activos o herramienta del fabricante durante una sesión aprobada con el acuerdo del ingeniero de protecciones; 2 = una elección intrusiva; 1 = escaneo; 0 = nada.
Síntesis del capítulo
Elija el método menos intrusivo que responda a la pregunta y valide toda herramienta antes de confiar en ella: pruebas de respuesta conocida, pruebas negativas, versiones registradas. El CRC de la capa de enlace de DNP3 muestra esta disciplina en miniatura (implementarlo a partir de los parámetros publicados, comprobarlo con el valor del catálogo) y también su límite: la detección de errores demuestra que los bytes llegaron intactos, nunca quién los envió.
Siga estudiando — capítulo 09 de 18
← Capítulo 08 · Índice de capítulos del curso · Capítulo 10 →
Continúe con la siguiente lección escrita.