Cabecera blog ciberseguridad

Soporte para plugins en PLCTool

El nuevo soporte para plugins de PLCTool permite la implementación de nuevas funciones

El nuevo soporte para plugins de PLCTool permite la implementación de nuevas funciones sin necesidad de modificar el código base

En este artículo se presenta el soporte para plugins de la herramienta PLCTool y se proporciona una guía de implementación de nuevos plugins, para añadir funcionalidades a la herramienta y adaptarla a nuevas necesidades.

En el artículo anterior se describió la herramienta PLCTool, para la inspección de redes PRIME con las que se comunican los contadores inteligentes de la luz instalados en muchos hogares. Esta herramienta cuenta con funciones básicas para las redes de contadores que permitían encender y apagar un contador del que se conociese la contraseña de acceso, que, en muchos casos, viaja en claro por la red.

En la última actualización de PLCTool se ha añadido soporte para plugins independientes de la herramienta y en este artículo se explican los pasos para implementar nuevas funciones.

1. Gestión de plugins

En la versión 1.1.0 de PLCTool se ha añadido soporte de plugins para implementar nuevas funcionalidades, de manera que, para ello, no es necesario modificar ni recompilar PLCTool, haciendo más versátil el desarrollo y la investigación sobre los protocolos PRIME y DLMS.

Se ha añadido PLCTool al repositorio AUR de Archlinux para facilitar la instalación y poder comenzar a desarrollar plugins rápidamente.

2. Un plugin de ejemplo, BlinkAttack

Puedes encontrar el código de este plugin en el repositorio de Tarlogic.

Este plugin utiliza los datos asociados a un contador, que se pueden obtener mediante la captura de paquetes PRIME con PLCTool, para establecer una conexión y enviar mensajes que fuerzan a que el contador se encienda y apague continuamente.

Antes de compilar el plugin, es necesario tener instalado PLCTool en el sistema. Para compilarlo, pueden seguirse los pasos descritos en este artículo. Luego, debe instalarse con el mandato:

% sudo make install

Si se utiliza la distribución Arch Linux, también puede utilizarse el paquete publicado en el repositorio AUR.

El archivo de proyecto del plugin, PLCTool-Plugin.pro, se encuentra en la carpeta raíz y puede abrirse con Qt Creator o compilarlo manualmente con los siguientes comandos.

% cd PLCTool-Plugin
% mkdir build
% cd build
% qmake PREFIX=/usr ..
% make
% sudo make install

En este ejemplo se incluye el uso de la variable de prefijo que especifica dónde el usuario quiere instalar el programa en el sistema. También se ejemplifica el uso del install target del Makefile que instalará el plugin en el lugar especificado.

A diferencia del proyecto PLCTool, en esta ocasión la compilación no resultará en un ejecutable sino en una biblioteca dinámica. En la carpeta del proyecto ahora contaremos con un archivo libBlinkAttack.so que podremos cargar en PLCTool para poder ejecutar la función implementada.

PLCTool cuenta con una serie de rutas en las que buscará plugins y los cargará automáticamente durante el arranque. Estas rutas, por orden de preferencia, son:

  • ~/.plctool
  • ~/.local/lib/plctool
  • /usr/local/lib/plctool
  • /usr/lib/plctool
  • /lib/plctool
  • El directorio de ejecución actual

Para usar el nuevo plugin simplemente se abre la herramienta PLCTool y esta cargará la biblioteca durante el arranque. PLCTool se encargará de buscar la función entry dentro de la biblioteca para verificar que lo que se ha cargado es un plugin válido y, si todo ha ido bien, añadirá a la interfaz un nuevo icono para lanzarlo.

PLCTool con el plugin Blink Attack cargado

PLCTool con el plugin Blink Attack cargado

3. Cómo desarrollar un nuevo plugin

Es necesario Qt (5.9 o superior) para la compilación y desarrollo de los plugins.

3.1. Archivo de proyecto de Qt

El fichero de proyecto de Qt, el archivo .pro, para el desarrollo de un nuevo plugin sigue las reglas básicas de qmake, que pueden encontrarse en el manual oficial. Sin embargo, hay que tener en cuenta las siguientes indicaciones.

Deben incluirse los ficheros de cabecera de PLCTool, donde se describen las clases que se utilizarán como base para el plugin. Para ello, los ficheros de cabecera deberán encontrarse instalados en el sistema o el usuario deberá añadirlos manualmente modificando el archivo .pro mediante la siguiente línea:

INCLUDEPATH += /Ruta/a/PLCTool/include/

El otro elemento relevante es el directorio de instalación de la nueva biblioteca, que debería ser una de las rutas de búsqueda de PLCTool, indicadas anteriormente. Esto se consigue con las siguientes líneas.

TARGET = BlinkAttackPlugin
TEMPLATE = lib

isEmpty(PREFIX) {
  PREFIX=/usr/local
}

target.path=$PREFIX/lib/plctool

En primer lugar, se define el nombre y tipo del proyecto (biblioteca dinámica) y se indica el prefijo de instalación, PREFIX, que podrá ser modificado durante la compilación.

Para comenzar, se recomienda reutilizar el archivo .pro de los plugins de ejemplo como base o crear un nuevo proyecto de biblioteca dinámica de Qt Creator.

3.2. Proceso de ejecución

Antes de describir con más detalle el desarrollo de un plugin, es necesario tener una visión general de la arquitectura.

Cuando se selecciona un plugin desde PLCTool, se crea una instancia de la clase AttackController, y esta solicita a AttackFactoryLibrary los parámetros necesarios para la ejecución a través del AttackManager. AttackFactoryLibrary consulta a la AttackFactory correspondiente y devuelve una lista con los nombres de los parámetros. Con estos, el AttackController muestra una ventana donde introducir los valores necesarios:

Interfaz gráfica

Interfaz gráfica

Al iniciar la ejecución mediante el botón Start, el AttackController notifica al AttackManager para que cree un objeto del tipo Attack y lo inicia.

El objeto se inicializa con una instancia de la clase PrimeAdapter, que gestiona las comunicaciones con el adaptador hacia la red PRIME (kit ATPL360-EK), conectado al host mediante un puerto serie, como se indica en el artículo PLCTool, la navaja suiza de los contadores inteligentes. De este modo se pueden enviar y recibir datos a la red PRIME.

Para más detalles, se recomienda consultar los plugins que se incluyen con PLCTool en el siguiente repositorio.

3.3. Implementación de las clases de un nuevo plugin

En la explicación anterior pueden apreciarse dos clases fundamentales para la implementación de un nuevo plugin: AttackFactory y Attack. La primera implementa el constructor de nuevas clases Attack (patrón factory) e informa al resto de la aplicación de los parámetros necesarios, mientras que la segunda especifica el comportamiento. También hablaremos de la clase AttackFactoryLibrary, que contiene referencias a las clases AttackFactory de registradas, y de la función entry, que sirve de punto de entrada para la carga del plugin.

3.3.1. Clase AttackFactory

Para especificar los parámetros requeridos, que son diferentes en cada caso, e implementar la creación de una forma estandarizada, se ha empleado un patrón factory, en el que la clase AttackFactory provee de tres métodos que deben reimplementarse en una subclase, como BlinkAttackFactory:

  • QString getAttackName(void): devuelve el nombre de la función. Este será el nombre utilizado en la ventana de la interfaz gráfica y también se utiliza como referencia al solicitar la creación de un nuevo objeto Attack.
  • PLCTool::Attack *getAttack(…): devuelve un nuevo objeto Attack llamando a su constructor específico, y le envía los parámetros recibidos de la interfaz gráfica en forma de objeto StringParams. Además de los parámetros, le proporciona al objeto una referencia a PrimeAdapter, que permite la comunicación con el adaptador PRIME (kit ATPL360-EK).
  • QList<QString> getAttackParamList(void): debe devolver una lista con los nombres de los parámetros, que se utilizará en la creación de la interfaz gráfica.

3.3.2. Clase Attack

Las funciones deben implementarse como subclases de la clase Attack. Puede tomarse BlinkAttack como ejemplo:

class BlinkAttack : public PLCTool::Attack
  {…}

Nótese que la clase Attack se encuentra definida dentro del namespace PLCTool, que se utiliza para todas las clases de la herramienta. La clase Attack define tres métodos virtuales, que actúan como slots de Qt, y que deben ser redefinidos por la nueva clase:

  • void onStart(void): se ejecuta al pulsar el botón Start de la interfaz gráfica.
  • void onCancel(void): se ejecuta al pulsar el botón Cancel de la interfaz gráfica.
  • void onEnd(void): se ejecuta antes de terminar la ejecución y desconectar al objeto de la interfaz gráfica.

En caso de que no se defina alguno de los métodos, la clase base Attack define un comportamiento básico que simplemente envía una señal correspondiente de vuelta hacia el AttackController.

Además de los métodos anteriores, Attack define un conjunto de señales con las que se pueden enviar mensajes hacia el controlador:

  • void attackStarted(void): indica que se han completado las tareas de inicialización y se ha iniciado la ejecución.
  • void attackProgress(float progress): indica a la interfaz el porcentaje de la ejecución para actualizar la barra de progreso de la ventana.
  • void attackStatus(QString status): muestra un mensaje de estado en la interfaz gráfica.
  • void attackCompleted(void): indica que la ejecución ha sido completada con éxito.
  • void attackFailed(QString message): indica que la ejecución ha fallado.
  • void attackCancelled(void): indica que se ha recibido una señal de cancelación y ha terminado la ejecución.
  • void attackTimeout(void): indica que la ejecución ha terminado sin éxito por el cumplimiento de un timeout.
  • void attackEnded(void): indica que el objeto Attack está listo para ser destruido.

Además, se define otra señal especial: void attackCreated(PLCTool::Attack *attack). Esta señal indica al controlador que se ha completado la creación de un nuevo objeto Attack, la envía el AttackManager y no debe ser utilizada durante la ejecución.

Con el nuevo soporte para plugins de PLCTool no hay necesidad de modificar el código base

3.3.3. Punto de entrada y AttackFactoryLibrary

Durante la carga de un plugin, PLCTool busca en las rutas predeterminadas archivos de bibliotecas dinámicas e intenta cargar la función entry definida en ellas. Si se encuentra la función, se ejecuta pasándole como argumento el objeto AttackFactoryLibrary de la ejecución actual. Este objeto mantiene referencias a objetos AttackFactory que serán utilizados para la creación de objetos Attack.

Es, por tanto, la tarea de la función entry registrar la AttackFactory del nuevo plugin llamando al método AttackFactoryLibrary::registerAttackFactory(…). A continuación, se muestra un ejemplo de cómo hacerlo en el caso de BlinkAttackPlugin:

extern "C" {
void entry(PLCTool::AttackFactoryLibrary *);
}

void
entry(PLCTool::AttackFactoryLibrary *attackFactoryLibrary)
{
  attackFactoryLibrary->registerAttackFactory(
      new BlinkAttackFactory(attackFactoryLibrary));

Este código puede encontrarse en BlinkAttackPluginEntryPoint.cpp y puede utilizarse como base en la creación de nuevos plugins. Es importante declarar entry dentro de un bloque extern “C”, para evitar que el compilador C++ cambie el nombre de la función.

Con estas clases es suficiente para implementar y cargar un plugin básico, pero, para interactuar con la red PRIME, la siguiente sección describe brevemente algunas clases útiles.

 

4. Otras clases

En esta sección se describen las clases que PLCTool utiliza para componer y enviar mensajes PRIME y DLMS hacia la red PLC, así como para interactuar con el adaptador.

4.1. PrimeAdapter

La clase PrimeAdapter permite la recepción y envío de mensajes en la red PRIME, interactuando con el adaptador conectado al host mediante puerto serie, en nuestro caso, el kit de evaluación ATPL360-EK. En su creación, un nuevo objeto Attack recibe una referencia al objeto PrimeAdapter del proceso actual de PLCTool, de manera que puede utilizarlo para la comunicación con la red PLC.

Para la lectura de datos desde la red, la clase implementa las siguientes señales de Qt:

  • void subnetAnnounce(…): se emite al encontrar un nuevo beacon en la red anunciando la existencia de un concentrador.
  • void meterFound(…): se emite al encontrar mensajes de un nuevo contador en la red.
  • void frameReceived(…): se emite al leer un frame de PRIME, contenga o no datos DLMS, de la red.
  • void dataReceived(…): se emite al leer datos DLMS en un frame de PRIME.
  • void closed(void): se emite al cerrar la conexión con el adaptador.

Conectando estas señales a slots del objeto Attack, o de cualquier otra clase, es posible recibir los eventos de la red.

Asimismo, PrimeAdapter cuenta con los métodos writeFrame(…), para escribir datos en el medio PLC, setLcd(…), para enviar datos al LCD del adaptador, y setLeds(…), para establecer el estado de los leds del adaptador.

Este plugin utiliza los datos asociados a un contador para establecer una conexión y enviar mensajes que fuerzan a que el contador se encienda y apague continuamente

4.2. Prime

Los datos escritos por writeFrame(…) se envían sobre la capa física de PRIME, por lo que, para enviar datos relevantes para la capa MAC, se utilizan los tipos definidos en PrimeFrame.h. La clase PrimeFrame definida en esta cabecera permite establecer los campos y tipos de mensajes, y provee de métodos para transformar el mensaje en un vector de bytes que puede enviarse a través de PrimeAdapter.

Para un ejemplo práctico de uso, pueden consultarse los métodos compose del plugin de ejemplo BlinkAttack.

Para más información sobre el estándar PRIME 1.3, puede consultarse en la web oficial.

4.3. DLMS

Para definir un mensaje DLMS contenido en un frame de PRIME (en el campo DATA). Se han diseñado un conjunto de clases disponibles en los directorios Types/ber y Types/dlms de los archivos de cabecera de PLCTool.

Los mensajes DLMS se encuentran definidos como tipos ASN.1, por lo que conviene conocer la notación para el estudio y la implementación de mensajes DLMS.

En concreto, DLMS define mensajes utilizando la codificación BER, propia de ASN.1, o la codificación A-XDR, que, a pesar de su nombre, tiene poco que ver con la codificación XDR. A-XDR es, en realidad, una codificación derivada de BER en la que se asume el valor de ciertos campos del mensaje.

Para una comprensión más profunda de la codificación BER y la notación ASN.1 se recomienda la lectura de la nota técnica escrita por los laboratorios RSA al respecto.

En las clases provistas por PLCTool se encuentran implementados los mensajes necesarios para la ejecución de las funciones actuales. Se puede encontrar un ejemplo práctico de su uso en los métodos compose del plugin BlinkAttack.

Para más información sobre los mensajes DLMS, se recomienda consultar el BlueBook del estándar DLMS, así como el uso del traductor incorporado en PLCTool, que traduce mensajes DLMS a XML gracias a la biblioteca gurux.

Gracias al nuevo soporte para plugins de PLCTool, la navaja suiza para redes PRIME puede ahora implementar nuevas funciones y adaptarse a las necesidades del usuario, permitiendo la personalización y automatización de tareas de auditoría en redes de contadores.

El plugin BlinkAttack es un ejemplo de las capacidades que la herramienta puede implementar y de las posibilidades que ofrece la investigación de estas redes. Ayúdanos en nuestra investigación creando nuevas funciones y mejorando su utilidad.

Mantente al tanto de las novedades en Tarlogic con nuestro blog.

Más artículos de la serie Contadores Inteligentes

Este artículo forma parte de una serie de articulos sobre Contadores Inteligentes

  1. Contadores Inteligentes – El escenario español y el sistema de Telegestión.
  2. Contadores Inteligentes – Amenazas a los contadores y ataques PRIME
  3. Contadores Inteligentes – Una prueba de concepto: secuestrando un contador
  4. Contadores Inteligentes – Evaluando el riesgo del concentrador
  5. Seguridad en las redes PRIME – Estado actual
  6. PLCTool, la navaja suiza de los contadores inteligentes
  7. Soporte para plugins en PLCTool