Wireshark: captura remota sobre UART

Wireshark: captura remota sobre UART

TL;DR:¿Cómo canalizar correctamente a través de UART la salida de un control remoto tcpdumpa un local wireshark?

Intento capturar paquetes que fluyen a través de un dispositivo integrado en el que no tengo la capacidad de instalar nada. Afortunadamente, hay un getty abierto en la interfaz serie y tcpdump instalado. Lamentablemente, no hay SSH, ni dumpcap, ni tshark.

Tubería directa

Primero intenté configurar el tty y pasar los datos a Wirehark a través de tuberías.

stty -F /dev/ttyUSB0 raw
stty -F /dev/ttyUSB0 -echo -echoe -echok
cat /dev/ttyUSB0 | wireshark -k -i -
# On another terminal:
echo "tcpdump -U -s0 -i eth0 -w - 2>/dev/null" > /dev/ttyUSB0

Wireshark se queja de que la entrada no tiene un formato libpcap válido, ciertamente porque el comando se repite y no logré deshacerme de eso.

Usando PySerial sin formato

Así que decidí crear un script en Python para controlar cómo funcionaría la tubería:

import serial
import sys
import subprocess
import fcntl

def main(args):
    with serial.Serial('/dev/ttyUSB0', 115200, timeout=0) as ser:
        length = ser.write(b"tcpdump -U -s0 -i eth0 -w - 2> /dev/null\n") + 1
        # Discard the echoed command line
        while length > 0:
            discard = ser.read(length)
            length -= len(discard)
        # Spawn wireshark
        wireshark = subprocess.Popen(
            ["wireshark", "-k", "-i", "-"], stdin=subprocess.PIPE
        )
        # Pipe data from serial to wireshark's input
        while True:
            data = ser.read(256)
            wireshark.stdin.write(data)
            try:
                wireshark.stdin.flush()
            except BrokenPipeError as e:
                break
            if len(data) > 0: print(data)
        # Send "Ctrl+C" to tcpdump
        ser.write(b"\x03")
        wireshark.wait()
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

Dejando de lado algunos problemas sobre cómo debería terminar correctamente el guión, esto no funcionó tan bien como imaginaba. Wireshark está contento por un tiempo, pero muy pronto la entrada se corrompe y la grabación se detiene. Creo que esto se debe a que el tty del host todavía convierte algunos caracteres especiales, probablemente el avance de línea o el retorno de carro.

Volviéndose estúpido: volcado hexadecimal sobre PySerial

Sé que esto es poco convincente, pero como no tenía otras ideas, esto es lo que se me ocurrió:

import serial
import sys
import subprocess
import binascii

def main(args):
    with serial.Serial('/dev/ttyUSB0', 115200, timeout=5) as ser:
        # Spawn tcpdump on the host and convert the raw output to stupid hex format
        # We need hexdump -C because that's the only format that doesn't mess up with the endianess
        length = ser.write(b"tcpdump -U -s256 -i eth0 -w - 2> /dev/null | hexdump -C\n")
        # Discard command line that is echoed
        discard = ser.readline()
        # Spawn wireshark
        wireshark = subprocess.Popen(
            ["wireshark", "-k", "-i", "-"], stdin=subprocess.PIPE
        )
        while True:
            # Process each line separately
            data = ser.readline().decode('ascii')
            elements = data.split()
            # Remove the address and ascii convertion of hexdump and spaces
            hexa = "".join(elements[1:17])
            # Convert back hex to binary
            real_data = binascii.unhexlify(hexa)
            # Feed to the shark
            wireshark.stdin.write(real_data)
            try:
                wireshark.stdin.flush()
            except BrokenPipeError as e:
                break
        # Stop tcpdump
        ser.write(b"\x03")
        wireshark.wait()
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

Por desgracia, aunque funciona un poco más que la versión anterior, cuando los marcos son demasiado grandes, Wireshark presenta un problema diciendo que el marco es demasiado grande, con una longitud que es realmente ridícula (como -1562980309832), y nuevamente la grabación se detiene.

¡Por favor ayuda! :)

Puedes notar que intenté jugar con la -sopción de tcpdump, pero no funcionó, incluso con cantidades bajas.

También intenté conectar desde picocom, sin éxito.

Entonces, si tiene alguna idea, algún software de túnel UART que funcione, algún comentario sobre mi (incompetente) uso de stty o alguna mejora en mis scripts de Python, ¡estaría muy feliz!

Wireshark es 2.2.5, tcpdump es 4.5.0 con libpcap 1.5.0.

Respuesta1

Finalmente, lo hice realmente funcionar. Esta no es la configuración perfecta, pero al menos funciona, así que tal vez pueda ayudar a alguien en el futuro.

Utilicé un script de Python encimaPySerialpara iniciar tcpdump sobre UART y usar hexdump para que los datos binarios puedan atravesar el enlace sin ser modificados por las reglas de transcripción tty. Luego, el script de Python vuelve a convertir los datos y los canaliza a Wirehark. El siguiente script es el resultado, en comparación con el de la pregunta, agregué la -vopción de volcado hexadecimal para que no intente comprimir líneas iguales.

import serial
import sys
import subprocess
import binascii

def main(args):
    with serial.Serial('/dev/ttyUSB0', 115200, timeout=5) as ser:
        # Spawn tcpdump on the host and convert the raw output to stupid hex format
        # We need hexdump -C because that's the only format that doesn't mess up with the endianess
        length = ser.write(b"tcpdump -U -s256 -i eth0 -w - 2> /dev/null | hexdump -Cv\n")
        # Discard command line that is echoed
        discard = ser.readline()
        # Spawn wireshark
        wireshark = subprocess.Popen(
            ["wireshark", "-k", "-i", "-"], stdin=subprocess.PIPE
        )
        while True:
            # Process each line separately
            data = ser.readline().decode('ascii')
            elements = data.split()
            # Remove the address and ascii convertion of hexdump and spaces
            hexa = "".join(elements[1:17])
            # Convert back hex to binary
            real_data = binascii.unhexlify(hexa)
            # Feed to the shark
            wireshark.stdin.write(real_data)
            try:
                wireshark.stdin.flush()
            except BrokenPipeError as e:
                break
        # Stop tcpdump
        ser.write(b"\x03")
        wireshark.wait()
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

información relacionada