Wireshark: Captura remota via UART

Wireshark: Captura remota via UART

DR:Como canalizar corretamente pelo UART a saída de um controle remoto tcpdumppara um local wireshark?

Tento capturar pacotes que fluem através de um dispositivo incorporado no qual não consigo instalar nada. Felizmente, há um getty aberto na interface serial e o tcpdump instalado. Infelizmente, sem SSH, sem dumpcap, sem tshark.

Tubo direto

Primeiro tentei configurar o tty e passar os dados para o wireshark através de pipes.

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 reclama que a entrada não é um formato libpcap válido, certamente porque o comando foi repetido e não consegui me livrar dele.

Usando PySerial bruto

Então decidi criar um script python para controlar como funcionaria a tubulação:

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))

Deixando de lado alguns problemas sobre como o script deveria terminar corretamente, isso não funcionou tão bem quanto eu imaginava. O Wireshark fica feliz por algum tempo, mas logo a entrada fica corrompida e a gravação é interrompida. Acho que isso ocorre porque o tty no host ainda converte alguns caracteres especiais, provavelmente o avanço de linha ou o retorno de carro.

Ficando estúpido: hexdump sobre PySerial

Então eu sei que isso é ridículo, mas como não tive outras ideias, foi isso que pensei:

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))

Infelizmente, embora funcione um pouco mais que a versão anterior, quando os frames são um pouco grandes demais, o wireshark apresenta um problema dizendo que o frame é muito grande, com um comprimento que é realmente ridículo (como -1562980309832), e novamente a gravação para.

Por favor ajude! :)

Você pode notar que tentei brincar com a -sopção tcpdump, mas não funcionou, mesmo com valores baixos.

Também tentei tubulação do picocom, sem sucesso.

Então, se você tiver alguma ideia, qualquer software de tunelamento UART que funcione, qualquer comentário sobre meu uso (incompetente) de stty ou qualquer melhoria em meus scripts python, eu ficaria muito feliz!

Wireshark é 2.2.5, tcpdump é 4.5.0 com libpcap 1.5.0.

Responder1

Finalmente, consegui realmente funcionar. Esta não é a configuração perfeita, mas pelo menos funciona, então talvez possa ajudar alguém no futuro.

Eu usei um script Python em cima dePySerialpara iniciar o tcpdump pelo UART e usar o hexdump para que os dados binários possam atravessar o link sem serem modificados pelas regras de transcrição tty. Em seguida, o script Python converte novamente os dados e os canaliza para o wireshark. O script abaixo é o resultado, comparado ao da pergunta, adicionei a -vopção hexdump para que não tente compactar linhas iguais.

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))

informação relacionada