Search code examples
pythontelnetscapy

Recognize telnet protocol with Scapy python


I am reading a Pcap file with Scapy. How can I recognize if, in this pcap file, there is a packet that uses the Telnet protocol?

I see that Scapy can write 'telnet' into dport/sport only if 1 of those ports is 23, but if I am using another port for Telnet, how do I recognize this with Scapy?


Solution

  • @TimRoberts stated in the comments that "Telnet is indistinguishable from other TCP protocols." This is true to some extent, because all TCP packets use the same structure, which is outlined in multiple Internet Engineering Task Force (IETF) Request for Comments (RFC) documents:

    Here is the structure of a TCP packet.

    enter image description here

    Common application protocols such as Hypertext Transfer Protocol (HTTP), File Transfer Protocol (FTP) and Telnet all use this structure.

    Concerning the application protocol Telnet. As you already know the official port assignment for the telnet protocol is port 23. Most vendors adhere to this port standard, which is why "Scapy can write 'telnet' into dport/sport only if 1 of those ports is 23."

    This is the TCP layer from a Telnet session using port 23:

    Layer TCP:
        Source Port: 1254
        Destination Port: 23
        Stream index: 0
        TCP Segment Len: 0
        Sequence number: 0    (relative sequence number)
        Sequence number (raw): 72603759
        Next sequence number: 1    (relative sequence number)
        Acknowledgment number: 0
        Acknowledgment number (raw): 0
        1010 .... = Header Length: 40 bytes (10)
        Flags: 0x002 (SYN)
        000. .... .... = Reserved: Not set
        ...0 .... .... = Nonce: Not set
        .... 0... .... = Congestion Window Reduced (CWR): Not set
        .... .0.. .... = ECN-Echo: Not set
        .... ..0. .... = Urgent: Not set
        .... ...0 .... = Acknowledgment: Not set
        .... .... 0... = Push: Not set
        .... .... .0.. = Reset: Not set
        .... .... ..1. = Syn: Set
        Expert Info (Chat/Sequence): Connection establish request (SYN): server port 23
        Connection establish request (SYN): server port 23
        Severity level: Chat
        Group: Sequence
        .... .... ...0 = Fin: Not set
        TCP Flags: \xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7S\xc2\xb7
        Window size value: 32120
        Calculated window size: 32120
        Checksum: 0x5d40 [unverified]
        Checksum Status: Unverified
        Urgent pointer: 0
        Options: (20 bytes), Maximum segment size, SACK permitted, Timestamps, No-Operation (NOP), Window scale
        TCP Option - Maximum segment size: 1460 bytes
        Kind: Maximum Segment Size (2)
        Length: 4
        MSS Value: 1460
        TCP Option - SACK permitted
        TCP Option - Timestamps: TSval 1444389, TSecr 0
        Timestamp value: 1444389
        Timestamp echo reply: 0
        TCP Option - No-Operation (NOP)
        TCP Option - Window scale: 0 (multiply by 1)
        Shift count: 0
        Multiplier: 1
        Timestamps
        Time since first frame in this TCP stream: 0.000000000 seconds
        Time since previous frame in this TCP stream: 0.000000000 seconds
        Kind: SACK Permitted (4)
        Kind: Time Stamp Option (8)
        Kind: No-Operation (1)
        Kind: Window Scale (3)
        Length: 2
        Length: 10
        Length: 3
    

    This is the TCP layer from a Telnet session using port 3005:

    Layer TCP:
        Source Port: 52187
        Destination Port: 3005
        Stream index: 0
        TCP Segment Len: 0
        Sequence number: 0    (relative sequence number)
        Sequence number (raw): 1355255000
        Next sequence number: 1    (relative sequence number)
        Acknowledgment number: 0
        Acknowledgment number (raw): 0
        1011 .... = Header Length: 44 bytes (11)
        Flags: 0x002 (SYN)
        000. .... .... = Reserved: Not set
        ...0 .... .... = Nonce: Not set
        .... 0... .... = Congestion Window Reduced (CWR): Not set
        .... .0.. .... = ECN-Echo: Not set
        .... ..0. .... = Urgent: Not set
        .... ...0 .... = Acknowledgment: Not set
        .... .... 0... = Push: Not set
        .... .... .0.. = Reset: Not set
        .... .... ..1. = Syn: Set
        Expert Info (Chat/Sequence): Connection establish request (SYN): server port 3005
        Connection establish request (SYN): server port 3005
        Severity level: Chat
        Group: Sequence
        .... .... ...0 = Fin: Not set
        TCP Flags: \xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7S\xc2\xb7
        Window size value: 65535
        Calculated window size: 65535
        Checksum: 0x0afb [unverified]
        Checksum Status: Unverified
        Urgent pointer: 0
        Options: (24 bytes), Maximum segment size, No-Operation (NOP), Window scale, No-Operation (NOP), No-Operation (NOP), Timestamps, SACK permitted, End of Option List (EOL)
        TCP Option - Maximum segment size: 1460 bytes
        Kind: Maximum Segment Size (2)
        Length: 4
        MSS Value: 1460
        TCP Option - No-Operation (NOP)
        TCP Option - Window scale: 6 (multiply by 64)
        Shift count: 6
        Multiplier: 64
        TCP Option - Timestamps: TSval 3609205717, TSecr 0
        Timestamp value: 3609205717
        Timestamp echo reply: 0
        TCP Option - SACK permitted
        TCP Option - End of Option List (EOL)
        Timestamps
        Time since first frame in this TCP stream: 0.000000000 seconds
        Time since previous frame in this TCP stream: 0.000000000 seconds
        Kind: No-Operation (1)
        Kind: Window Scale (3)
        Kind: No-Operation (1)
        Kind: No-Operation (1)
        Kind: Time Stamp Option (8)
        Kind: SACK Permitted (4)
        Kind: End of Option List (0)
        Length: 3
        Length: 10
        Length: 2
        TCP Option - No-Operation (NOP)
        TCP Option - No-Operation (NOP)
    

    This is the TCP layer from a FTP session using port 21:

    Layer TCP:
        Source Port: 35974
        Destination Port: 21
        Stream index: 0
        TCP Segment Len: 0
        Sequence number: 0    (relative sequence number)
        Sequence number (raw): 29473206
        Next sequence number: 1    (relative sequence number)
        Acknowledgment number: 0
        Acknowledgment number (raw): 0
        1010 .... = Header Length: 40 bytes (10)
        Flags: 0x002 (SYN)
        000. .... .... = Reserved: Not set
        ...0 .... .... = Nonce: Not set
        .... 0... .... = Congestion Window Reduced (CWR): Not set
        .... .0.. .... = ECN-Echo: Not set
        .... ..0. .... = Urgent: Not set
        .... ...0 .... = Acknowledgment: Not set
        .... .... 0... = Push: Not set
        .... .... .0.. = Reset: Not set
        .... .... ..1. = Syn: Set
        Expert Info (Chat/Sequence): Connection establish request (SYN): server port 21
        Connection establish request (SYN): server port 21
        Severity level: Chat
        Group: Sequence
        .... .... ...0 = Fin: Not set
        TCP Flags: \xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7S\xc2\xb7
        Window size value: 32648
        Calculated window size: 32648
        Checksum: 0x8fda [unverified]
        Checksum Status: Unverified
        Urgent pointer: 0
        Options: (20 bytes), Maximum segment size, No-Operation (NOP), Window scale, No-Operation (NOP), No-Operation (NOP), Timestamps
        TCP Option - Maximum segment size: 1380 bytes
        Kind: Maximum Segment Size (2)
        Length: 4
        MSS Value: 1380
        TCP Option - No-Operation (NOP)
        TCP Option - Window scale: 0 (multiply by 1)
        Shift count: 0
        Multiplier: 1
        TCP Option - Timestamps: TSval 1657560000, TSecr 0
        Timestamp value: 1657560000
        Timestamp echo reply: 0
        Timestamps
        Time since first frame in this TCP stream: 0.000000000 seconds
        Time since previous frame in this TCP stream: 0.000000000 seconds
        Kind: No-Operation (1)
        Kind: Window Scale (3)
        Kind: No-Operation (1)
        Kind: No-Operation (1)
        Kind: Time Stamp Option (8)
        Length: 3
        Length: 10
        TCP Option - No-Operation (NOP)
        TCP Option - No-Operation (NOP)
    

    This is the TCP layer from a SSH session using port 22:

    Layer TCP:
        Source Port: 57732
        Destination Port: 22
        Stream index: 0
        TCP Segment Len: 0
        Sequence number: 0    (relative sequence number)
        Sequence number (raw): 71043058
        Next sequence number: 1    (relative sequence number)
        Acknowledgment number: 0
        Acknowledgment number (raw): 0
        1011 .... = Header Length: 44 bytes (11)
        Flags: 0x002 (SYN)
        000. .... .... = Reserved: Not set
        ...0 .... .... = Nonce: Not set
        .... 0... .... = Congestion Window Reduced (CWR): Not set
        .... .0.. .... = ECN-Echo: Not set
        .... ..0. .... = Urgent: Not set
        .... ...0 .... = Acknowledgment: Not set
        .... .... 0... = Push: Not set
        .... .... .0.. = Reset: Not set
        .... .... ..1. = Syn: Set
        Expert Info (Chat/Sequence): Connection establish request (SYN): server port 22
        Connection establish request (SYN): server port 22
        Severity level: Chat
        Group: Sequence
        .... .... ...0 = Fin: Not set
        TCP Flags: \xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7\xc2\xb7S\xc2\xb7
        Window size value: 65535
        Calculated window size: 65535
        Checksum: 0xd079 [unverified]
        Checksum Status: Unverified
        Urgent pointer: 0
        Options: (24 bytes), Maximum segment size, No-Operation (NOP), Window scale, No-Operation (NOP), No-Operation (NOP), Timestamps, SACK permitted, End of Option List (EOL)
        TCP Option - Maximum segment size: 1460 bytes
        Kind: Maximum Segment Size (2)
        Length: 4
        MSS Value: 1460
        TCP Option - No-Operation (NOP)
        TCP Option - Window scale: 6 (multiply by 64)
        Shift count: 6
        Multiplier: 64
        TCP Option - Timestamps: TSval 1452973307, TSecr 0
        Timestamp value: 1452973307
        Timestamp echo reply: 0
        TCP Option - SACK permitted
        TCP Option - End of Option List (EOL)
        Timestamps
        Time since first frame in this TCP stream: 0.000000000 seconds
        Time since previous frame in this TCP stream: 0.000000000 seconds
        Kind: No-Operation (1)
        Kind: Window Scale (3)
        Kind: No-Operation (1)
        Kind: No-Operation (1)
        Kind: Time Stamp Option (8)
        Kind: SACK Permitted (4)
        Kind: End of Option List (0)
        Length: 3
        Length: 10
        Length: 2
        TCP Option - No-Operation (NOP)
        TCP Option - No-Operation (NOP)
    

    As previously stated these TCP layers are almost indistinguishable. So trying to use the TCP layer alone would be hard to determine a Telnet session over a port other than port 23. So trying to use Scapy to identify these sessions without doing a more in-depth packet analysis would be extremely hard.

    You could potential analyze the data layer of a TCP packet to determine if a connection is or isn't a Telnet session. This again requires substantial effort unless you have done some level of traffic analysis.

    Using the Python module pyshark you extract content from the Data layer.

    Telnet session over port 23:

    import pyshark
    
    # the pcap is a Telnet session over port 23
    capture = pyshark.FileCapture('telnet-raw.pcap')
    for packet in capture:
        if hasattr(packet, 'tcp'):
            layers = packet.layers
            #      0            1           2             3
            # [<ETH Layer>, <IP Layer>, <TCP Layer>, <DATA Layer>]
            if len(layers) > 3:
                payload = packet.tcp.payload
    

    The payload output is in hex

    truncated...
    ff:fb:01:ff:fa:21:02:ff:f0:ff:fc:01
    
    ff:fd:01:ff:fe:01
    
    ff:fa:22:03:05:80:00:11:80:00:12:80:00:ff:f0
    
    0d:0a:4f:70:65:6e:42:53:44:2f:69:33:38:36:20:28:6f:6f:66:29:20:28:74:74:79:70:31:29:0d:0a:0d:0a
    
    6c:6f:67:69:6e:3a:20
    
    ff:fc:22:ff:fd:01
    truncated...
    

    The 4th and 5th hex strings in the output are an important piece to deciphering what type of TCP connection might be occurring.

    import binascii
    
    hex_data = '0d:0a:4f:70:65:6e:42:53:44:2f:69:33:38:36:20:28:6f:6f:66:29:20:28:74:74:79:70:31:29:0d:0a:0d:0a6c:6f:67:69:6e:3a:20 '
    hex_string = ' '.join(hex_data.split('0d:0a')).replace(':', '')
    hex_list = hex_string.split()
    for item in hex_list:
        decoded_string = binascii.unhexlify(item)
        print(decoded_string)
        # output 
        b'OpenBSD/i386 (oof) (ttyp1)'
        b'login: '
    

    After decoding the hex we can see that authentication is occurring over port 23.

    Telnet session over port 3005:

    import pyshark
    
    # the pcap is a Telnet session over port 3005
    capture = pyshark.FileCapture('telnet-pcap-1.pcapng')
    for packet in capture:
        if hasattr(packet, 'tcp'):
            layers = packet.layers
            #      0            1           2             3
            # [<ETH Layer>, <IP Layer>, <TCP Layer>, <DATA Layer>]
            if len(layers) > 3:
                payload = packet.tcp.payload
    

    The payload output is in hex

    ff:fb:01:ff:fb:03:ff:fd:18:ff:fd:1f
    
    ff:fd:01:ff:fd:03:ff:fb:18:ff:fb:1f:ff:fa:1f:00:97:00:2f:ff:f0
    
    0d:0a:55:73:65:72:20:41:63:63:65:73:73:20:56:65:72:69:66:69:63:61:74:69:6f:6e:0d:0a:0d:0a:55:73:65:72:6e:61:6d:65:3a:20
    
    ff:fa:18:01:ff:f0
    
    ff:fa:18:00:58:54:45:52:4d:2d:32:35:36:43:4f:4c:4f:52:ff:f0
    truncated...
    

    The 3rd hex string in the output is an important piece to deciphering what type of TCP connection might be occurring.

    import binascii
    
    hex_data = '0d:0a:55:73:65:72:20:41:63:63:65:73:73:20:56:65:72:69:66:69:63:61:74:69:6f:6e:0d:0a:0d:0a:55:73:65:72:6e:61:6d:65:3a:20'
    
    # removing line breaks from the hex string
    hex_string = ' '.join(hex_data.split('0d:0a')).replace(':', '')
    hex_list = hex_string.split()
    for item in hex_list:
        decoded_string = binascii.unhexlify(item)
        print(decoded_string)
        # output 
        b'User Access Verification'
        b'Username: '
    
    

    After decoding the hex we can see that some type of authentication is occurring over port 3005. Additional analysis would be required to determine if this session is a Telnet session or some other session.