~21 min de lectura
Lab 04 - Emulación Modbus/TCP y acceso a registros
Configuración de un simulador Modbus/TCP e interacción con registros holding mediante descubrimiento de red y acceso a registros Modbus.

📝 Tareas
- 1️⃣ Después de iniciar OTLab 04, accede a la estación
otlab-studentmediante VNC en10.1.0.40:5901con la contraseña123456. Pista: si ejecutas OTLab 04 en Linux, se recomienda usar Remmina para acceder a la interfaz gráfica de la estaciónotlab-student. Si estás en Windows y usando WSL, la interfaz puede accederse mediantelocalhost:5901, siempre que WSL esté en modo WSL2 y no existan restricciones de firewall. - 2️⃣ Dentro de la interfaz gráfica de
otlab-studentaccedida por VNC, añade un esclavo Modbus en ModbusPal, un simulador Modbus basado en Java: añadir esclavo: 1, nombre del esclavo: Slave. - 3️⃣ Edita el esclavo Modbus recién creado añadiendo cinco registros holding con las direcciones 1 a 5, asignando los valores 10, 20, 30, 40 y 50, respectivamente.
- 4️⃣ Tras completar esta configuración, haz clic en Run en ModbusPal y abre un terminal en la estación
otlab-student(./OOTab04.sh -run). - 5️⃣ Verifica la dirección IP de la estación
otlab-student. - 6️⃣ Determina el rango de subred de la red donde está desplegada la estación
otlab-student. - 7️⃣ Descubre la dirección IP, la dirección MAC y la información del fabricante de la estación
otlab-student. - 8️⃣ Usa
favalex/modbus-clipara leer los registros holding del esclavo configurado en ModbusPal. Pista:modbus -s <Slave_ID> <IPPAddress> 0 1 2 3 4(donde las direcciones 0 a 4 corresponden a los primeros cinco registros).
🛠️ Herramientas
Estas son las herramientas disponibles en la estación otlab-student para completar OTLab 04:
ifconfig, masscan, netdiscover, nmap y modbus.
🔖 Nomenclatura
- ID: identificador.
- IP: protocolo de Internet.
- MAC: control de acceso al medio.
- TCP: protocolo de control de transmisión.
- UDP: protocolo de datagramas de usuario.
- VNC: computación en red virtual.
- WSL: subsistema de Windows para Linux.
📝 RESOLUCIÓN (ver contenido) ▼
#!/bin/bash
lab_name="OTLab04"
compose_file="${lab_name}.yml"
ews_container_name="otlab-student"
kali_image="kalilinux/kali-rolling"
ubuntu_image="ubuntu:22.04"
lab_net="otlab-net"
# ----------------------------------------
# Function to display the banner
show_banner() {
printf "\033[1;33m" # Yellow and bold
echo " _____ _____ __ _ "
echo "| |_ _| | ___| |_ "
echo "| | | | | | |__| .'| . |"
echo "|_____| |_| |_____|__,|___|"
printf "\033[1;37m" # White and bold
printf "Exercise: 04-Modbus/TCP Emulation and Register Access\n"
printf "Version: 1.1\n"
printf "Author: substationworm\n"
printf "Contact: in/lffreitas-gutierres\n"
printf "\033[0m" # Reset all styles
echo ""
}
# ----------------------------------------
# Function to generate Docker Compose file
generate_compose_file() {
local ews_image="$1"
cat > "$compose_file" <<EOF
services:
$ews_container_name:
image: $ews_image
container_name: $ews_container_name
hostname: $ews_container_name
environment:
- DEBIAN_FRONTEND=noninteractive
command: >
bash -c '
vncserver -kill :1 || true &&
rm -rf /tmp/.X1-lock /tmp/.X11-unix/X1 /root/.vnc/*:1.log /root/.vnc/*:1.pid &&
apt update &&
if grep -qi "kali" /etc/os-release; then
apt install -y openjdk-11-jre wget tightvncserver xfce4 xfce4-terminal fluxbox iputils-ping nmap masscan net-tools netdiscover snmp pipx &&
pipx install modbus-cli &&
pipx ensurepath &&
export PATH="$PATH:/root/.local/bin";
else
apt install -y openjdk-11-jre wget tightvncserver xfce4 xfce4-terminal fluxbox iputils-ping nmap masscan net-tools netdiscover snmp pip &&
pip install modbus-cli;
fi &&
mkdir -p /opt/modbuspal &&
[ -f /opt/modbuspal/ModbusPal.jar ] || \
wget -O /opt/modbuspal/ModbusPal.jar https://sourceforge.net/projects/modbuspal/files/latest/download &&
mkdir -p /root/.vnc &&
echo "123456" | vncpasswd -f > /root/.vnc/passwd &&
chmod 600 /root/.vnc/passwd &&
echo -e "#!/bin/bash\nxrdb \$HOME/.Xresources\nstartxfce4 &\nfluxbox &\njava -jar /opt/modbuspal/ModbusPal.jar &" > /root/.vnc/xstartup &&
chmod +x /root/.vnc/xstartup &&
export USER=root &&
vncserver :1 -geometry 1024x768 -depth 24 &&
tail -f /root/.vnc/*.log'
ports:
- "5901:5901"
networks:
$lab_net:
ipv4_address: 10.1.0.40
privileged: true
networks:
$lab_net:
name: $lab_net
driver: bridge
ipam:
config:
- subnet: 10.1.0.0/24
EOF
}
# ----------------------------------------
# System requirements check
check_requirements() {
error_flag=0
if ! command -v docker >/dev/null 2>&1; then
printf "\033[31m[Error]\033[0m Docker is not installed on this system.\n"
error_flag=1
elif ! docker info >/dev/null 2>&1; then
printf "\033[31m[Error]\033[0m Docker is installed, but not accessible.\n"
error_flag=1
fi
if command -v docker-compose >/dev/null 2>&1; then
DOCKER_COMPOSE_CMD="docker-compose"
elif docker compose version >/dev/null 2>&1; then
DOCKER_COMPOSE_CMD="docker compose"
else
printf "\033[31m[Error]\033[0m Docker Compose is not installed.\n"
error_flag=1
fi
if [ "$error_flag" -eq 1 ]; then
printf "\033[31m✘ The $lab_name system requirements check failed.\033[0m\n"
exit 1
fi
}
# ----------------------------------------
# Function to check if a container exists
container_exists() {
docker ps -a --format '{{.Names}}' | grep -q "$1"
}
# ----------------------------------------
# Command handling
case "$1" in
-start)
show_banner
distro="${2:-ubuntu}"
if [[ "$distro" == "kali" ]]; then
selected_image="$kali_image"
elif [[ "$distro" == "ubuntu" ]]; then
selected_image="$ubuntu_image"
else
printf "\033[31m[Error]\033[0m Invalid distro. Please use 'kali' or 'ubuntu'.\n"
exit 1
fi
check_requirements
printf "\033[1;33m[Working]\033[0m Starting $lab_name. . .\n"
generate_compose_file "$selected_image"
$DOCKER_COMPOSE_CMD -f "$compose_file" up -d
if [ $? -eq 0 ]; then
printf "\033[32m✔ $lab_name started.\033[0m\n"
else
printf "\033[31m✘ $lab_name failed to start.\033[0m\n"
exit 1
fi
;;
-stop)
show_banner
if container_exists "$ot_container_name" || container_exists "$ews_container_name"; then
check_requirements
printf "\033[1;33m[Working]\033[0m Stopping $lab_name. . .\n"
$DOCKER_COMPOSE_CMD -f "$compose_file" stop
printf "\033[32m✔ $lab_name stopped.\033[0m\n"
else
printf "\033[34m[Information]\033[0m No containers to stop.\n"
exit 1
fi
;;
-clean)
show_banner
if container_exists "$ot_container_name" || container_exists "$ews_container_name"; then
check_requirements
printf "\033[1;33m[Working]\033[0m Cleaning up all $lab_name resources. . .\n"
$DOCKER_COMPOSE_CMD -f "$compose_file" down -v
docker network rm "$lab_net" 2>/dev/null
rm -f "$compose_file"
printf "\033[32m✔ All $lab_name resources removed.\033[0m\n"
else
printf "\033[34m[Information]\033[0m No containers found to clean.\n"
exit 1
fi
;;
-run)
show_banner
if container_exists "$ews_container_name"; then
check_requirements
printf "\033[1;33m[Working]\033[0m Accessing $ews_container_name terminal. . .\n"
docker exec -it "$ews_container_name" bash
else
printf "\033[31m[Error]\033[0m Container $ews_container_name not found.\n"
exit 1
fi
;;
-restart)
show_banner
check_requirements
if [ ! -f "$compose_file" ]; then
printf "\033[31m[Error]\033[0m Cannot restart: $compose_file not found.\n"
exit 1
fi
printf "\033[1;33m[Working]\033[0m Restarting $lab_name. . .\n"
$DOCKER_COMPOSE_CMD -f "$compose_file" up -d
if [ $? -eq 0 ]; then
printf "\033[32m✔ $lab_name restarted.\033[0m\n"
else
printf "\033[31m✘ $lab_name failed to restart.\033[0m\n"
exit 1
fi
;;
-status)
show_banner
check_requirements
$DOCKER_COMPOSE_CMD -f "$compose_file" ps
;;
*)
show_banner
echo "Usage: $0 -start [kali|ubuntu] | -stop | -clean | -run | -restart | -status"
echo ""
echo " -start Start the $lab_name environment using the specified distro (default: ubuntu)"
echo " Valid options: kali (rolling) or ubuntu (22.04)"
echo " -run Open a terminal inside the $ews_container_name container"
echo " -clean Remove containers, volumes, and network"
echo " -stop Stop all containers"
echo " -restart Restart previously stopped containers"
echo " -status Show current containers status"
exit 1
;;
esac
📝 RESOLUCIÓN OFFLINE (ver contenido) ▼
#!/bin/bash
lab_name="OTLab04"
compose_file="${lab_name}.yml"
ews_container_name="otlab-student"
kali_image="ews-image-kali02"
ubuntu_image="ews-image-ubuntu02"
lab_net="otlab-net"
# ----------------------------------------
# Function to display the banner
show_banner() {
printf "\033[1;33m" # Yellow and bold
echo " _____ _____ __ _ "
echo "| |_ _| | ___| |_ "
echo "| | | | | | |__| .'| . |"
echo "|_____| |_| |_____|__,|___|"
printf "\033[1;37m" # White and bold
printf "Exercise: 04-Modbus/TCP Emulation and Register Access\n"
printf "Version: 1.1-Offline\n"
printf "Author: substationworm\n"
printf "Contact: in/lffreitas-gutierres\n"
printf "\033[0m" # Reset all styles
echo ""
}
# ----------------------------------------
# Function to generate Docker Compose file
generate_compose_file() {
local ews_image="$1"
cat > "$compose_file" <<EOF
services:
$ews_container_name:
image: $ews_image
container_name: $ews_container_name
hostname: $ews_container_name
ports:
- "5901:5901"
networks:
$lab_net:
ipv4_address: 10.1.0.40
privileged: true
networks:
$lab_net:
name: $lab_net
driver: bridge
ipam:
config:
- subnet: 10.1.0.0/24
EOF
}
# ----------------------------------------
# System requirements check
check_requirements() {
error_flag=0
if ! command -v docker >/dev/null 2>&1; then
printf "\033[31m[Error]\033[0m Docker is not installed on this system.\n"
error_flag=1
elif ! docker info >/dev/null 2>&1; then
printf "\033[31m[Error]\033[0m Docker is installed, but not accessible.\n"
error_flag=1
fi
if command -v docker-compose >/dev/null 2>&1; then
DOCKER_COMPOSE_CMD="docker-compose"
elif docker compose version >/dev/null 2>&1; then
DOCKER_COMPOSE_CMD="docker compose"
else
printf "\033[31m[Error]\033[0m Docker Compose is not installed.\n"
error_flag=1
fi
if [ "$error_flag" -eq 1 ]; then
printf "\033[31m✘ The $lab_name system requirements check failed.\033[0m\n"
exit 1
fi
}
# ----------------------------------------
# Function to check if a container exists
container_exists() {
docker ps -a --format '{{.Names}}' | grep -q "$1"
}
# ----------------------------------------
# Command handling
case "$1" in
-start)
show_banner
distro="${2:-ubuntu}"
if [[ "$distro" == "kali" ]]; then
selected_image="$kali_image"
elif [[ "$distro" == "ubuntu" ]]; then
selected_image="$ubuntu_image"
else
printf "\033[31m[Error]\033[0m Invalid distro. Please use 'kali' or 'ubuntu'.\n"
exit 1
fi
check_requirements
printf "\033[1;33m[Working]\033[0m Starting $lab_name. . .\n"
generate_compose_file "$selected_image"
$DOCKER_COMPOSE_CMD -f "$compose_file" up -d
if [ $? -eq 0 ]; then
printf "\033[32m✔ $lab_name started.\033[0m\n"
else
printf "\033[31m✘ $lab_name failed to start.\033[0m\n"
exit 1
fi
;;
-stop)
show_banner
if container_exists "$ot_container_name" || container_exists "$ews_container_name"; then
check_requirements
printf "\033[1;33m[Working]\033[0m Stopping $lab_name. . .\n"
$DOCKER_COMPOSE_CMD -f "$compose_file" stop
printf "\033[32m✔ $lab_name stopped.\033[0m\n"
else
printf "\033[34m[Information]\033[0m No containers to stop.\n"
exit 1
fi
;;
-clean)
show_banner
if container_exists "$ot_container_name" || container_exists "$ews_container_name"; then
check_requirements
printf "\033[1;33m[Working]\033[0m Cleaning up all $lab_name resources. . .\n"
$DOCKER_COMPOSE_CMD -f "$compose_file" down -v
docker network rm "$lab_net" 2>/dev/null
rm -f "$compose_file"
printf "\033[32m✔ All $lab_name resources removed.\033[0m\n"
else
printf "\033[34m[Information]\033[0m No containers found to clean.\n"
exit 1
fi
;;
-run)
show_banner
if container_exists "$ews_container_name"; then
check_requirements
printf "\033[1;33m[Working]\033[0m Accessing $ews_container_name terminal. . .\n"
docker exec -it "$ews_container_name" bash
else
printf "\033[31m[Error]\033[0m Container $ews_container_name not found.\n"
exit 1
fi
;;
-restart)
show_banner
check_requirements
if [ ! -f "$compose_file" ]; then
printf "\033[31m[Error]\033[0m Cannot restart: $compose_file not found.\n"
exit 1
fi
printf "\033[1;33m[Working]\033[0m Restarting $lab_name. . .\n"
$DOCKER_COMPOSE_CMD -f "$compose_file" up -d
if [ $? -eq 0 ]; then
printf "\033[32m✔ $lab_name restarted.\033[0m\n"
else
printf "\033[31m✘ $lab_name failed to restart.\033[0m\n"
exit 1
fi
;;
-status)
show_banner
check_requirements
$DOCKER_COMPOSE_CMD -f "$compose_file" ps
;;
*)
show_banner
echo "Usage: $0 -start [kali|ubuntu] | -stop | -clean | -run | -restart | -status"
echo ""
echo " -start Start the $lab_name environment using the specified distro (default: ubuntu)"
echo " Valid options: kali (rolling) or ubuntu (22.04)"
echo " -run Open a terminal inside the $ews_container_name container"
echo " -clean Remove containers, volumes, and network"
echo " -stop Stop all containers"
echo " -restart Restart previously stopped containers"
echo " -status Show current containers status"
echo ""
echo "[i] Local images required: ews-image-kali02 and ews-image-ubuntu02"
exit 1
;;
esac
Tags:
OT
ICS
Modbus/TCP
ModbusPal
Holding Registers
Modbus CLI
Network Discovery
Nmap
Masscan
Netdiscover
