Curriculum Lattes ORCID SciProfiles Scopus Web of Science substationworm LFFreitasGutierres

📝 Tasks

  • 1️⃣ After starting OTLab 04, access the otlab-student workstation via VNC at 10.1.0.40:5901 using the password 123456. Hint: if you are running OTLab 04 on a Linux system, it is recommended to use Remmina to access the graphical interface of the otlab-student workstation. If you are using Windows with WSL, the graphical interface may be accessed through localhost:5901, provided that WSL is running in WSL2 mode and no firewall restrictions are present.
  • 2️⃣ Within the graphical interface of the otlab-student workstation accessed through VNC, add a Modbus slave in ModbusPal, a Java-based Modbus simulator: slave ID: 1, slave name: Slave.
  • 3️⃣ Edit the newly created Modbus slave by adding five holding registers with addresses 1 to 5 and assigning the corresponding values 10, 20, 30, 40, and 50.
  • 4️⃣ After completing these configurations, click Run in ModbusPal and open a terminal on the otlab-student workstation (./OTLab04.sh -run).
  • 5️⃣ Verify the IP address of the otlab-student workstation.
  • 6️⃣ Determine the subnet range of the network where the otlab-student workstation is deployed.
  • 7️⃣ Discover the IP address, MAC address, and vendor information of the otlab-student workstation.
  • 8️⃣ Use favalex/modbus-cli to read the holding registers of the slave configured in ModbusPal. Hint: modbus -s <Slave_ID> <IPAddress> 0 1 2 3 4 (where addresses 0 to 4 correspond to the first five holding registers).

🛠️ Tools

The following tools are available on the otlab-student workstation to complete OTLab 04: ifconfig, masscan, netdiscover, nmap, and modbus.

🔖 Nomenclature

  • ID: identifier.
  • IP: Internet Protocol.
  • MAC: Media Access Control.
  • TCP: Transmission Control Protocol.
  • UDP: User Datagram Protocol.
  • VNC: Virtual Network Computing.
  • WSL: Windows Subsystem for Linux.
📝 RESOLUTION (view content)

      
#!/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
      

    
📝 RESOLUTION OFFLINE (view content)

      
#!/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