Skip to content

UnicodeDecodeError with a non-UTF-8 Decryption Secrets Block #3936

@evverx

Description

@evverx

Brief description

scapy writes key logs to temporary files as bytes

scapy/scapy/utils.py

Lines 1699 to 1703 in 378be02

with open(filename, "wb") as fd:
fd.write(secrets_data)
fd.close()
keys = load_nss_keys(filename)

and then load_nss_keys opens them using the default UTF-8 encoding:
with open(filename) as fd:

and it leads to UnicodeDecodeError when the decoder fails.

Scapy version

81b51d0

Python version

3.11.2

Operating system

Linux version 6.1.14-200.fc37

Additional environment information

No response

How to reproduce

diff --git a/test/tls.uts b/test/tls.uts
index 474db2b3..42879d3e 100644
--- a/test/tls.uts
+++ b/test/tls.uts
@@ -1590,3 +1590,36 @@ if shutil.which("editcap"):
     assert b"GET /secret.txt HTTP/1.0\n" in packets[11].msg[0].data
     assert b"z2|gxarIKOxt,G1d>.Q2MzGY[k@" in packets[13].msg[0].data
     conf = bck_conf
+
+= pcapng file with a non-UTF-8 Decryption Secrets Block
+
+hdump = """
+00000000  0a 0d 0d 0a c4 00 00 00  4d 3c 2b 1a 01 00 00 00  |........M<+.....|
+00000010  ff ff ff ff ff ff ff ff  02 00 37 00 49 6e 74 65  |..........7.Inte|
+00000020  6c 28 52 29 20 43 6f 72  65 28 54 4d 29 20 69 37  |l(R) Core(TM) i7|
+00000030  2d 36 37 30 30 48 51 20  43 50 55 20 40 20 32 2e  |-6700HQ CPU @ 2.|
+00000040  36 30 47 48 7a 20 28 77  69 74 68 20 53 53 45 34  |60GHz (with SSE4|
+00000050  2e 32 29 00 03 00 2a 00  4c 69 6e 75 78 20 34 2e  |.2)...*.Linux 4.|
+00000060  32 30 2e 31 32 2d 67 65  6e 74 6f 6f 2d 61 6e 64  |20.12-gentoo-and|
+00000070  72 6f 6d 65 64 61 2d 32  30 31 39 30 33 30 35 2d  |romeda-20190305-|
+00000080  76 31 00 00 04 00 33 00  44 75 6d 70 63 61 70 20  |v1....3.Dumpcap |
+00000090  28 57 69 72 65 73 68 61  72 6b 29 20 33 2e 31 2e  |(Wireshark) 3.1.|
+000000a0  30 20 28 76 33 2e 31 2e  30 72 63 30 2d 34 36 38  |0 (v3.1.0rc0-468|
+000000b0  2d 67 65 33 65 34 32 32  32 62 29 00 00 00 00 00  |-ge3e4222b).....|
+000000c0  c4 00 00 00 0a 00 00 00  c4 00 00 00 4b 53 4c 54  |............KSLT|
+000000d0  b0 00 00 00 43 4c 49 45  4e 54 5f 52 41 4e 44 4f  |....CLIENT_RANDO|
+000000e0  4d 20 41 36 39 39 35 43  37 44 35 41 35 31 35 42  |M A6995C7D5A515B|
+000000f0  30 44 34 39 41 31 42 38  31 33 33 39 33 34 32 37  |0D49A1B813393427|
+00000100  43 43 35 43 39 44 42 37  36 36 37 38 45 34 38 44  |CC5C9DB76678E48D|
+00000110  31 41 43 35 39 31 44 37  44 37 44 35 42 38 30 31  |1AC591D7D7D5B801|
+00000120  44 43 20 34 30 33 37 35  37 34 30 31 42 30 30 37  |DC 403757401B007|
+00000130  34 35 33 38 33 41 46 36  41 36 30 38 31 39 42 43  |45383AF6A60819BC|
+00000140  37 46 38 42 36 33 39 33  42 37 32 45 44 45 39 46  |7F8B6393B72EDE9F|
+00000150  45 42 32 30 44 33 31 33  46 38 31 42 39 c0 bd bb  |EB20D313F81B9...|
+00000160  c6 36 46 36 41 43 37 34  32 46 46 46 35 45 43 31  |.6F6AC742FFF5EC1|
+00000170  44 31 41 32 44 39 39 41  46 34 39 35 33 45 31 33  |D1A2D99AF4953E13|
+00000180  33 34 41 0a c4 00 00 00                           |34A.....|
+00000188
+""".strip()
+
+rdpcap(io.BytesIO(import_hexcap(hdump)))

Actual result

>>> rdpcap(io.BytesIO(import_hexcap(hdump)))
Traceback (most recent call last):
  File "<input>", line 2, in <module>
  File "/home/vagrant/scapy-2/scapy/utils.py", line 1142, in rdpcap
    return fdesc.read_all(count=count)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vagrant/scapy-2/scapy/utils.py", line 1414, in read_all
    res = self._read_all(count)
          ^^^^^^^^^^^^^^^^^^^^^
  File "/home/vagrant/scapy-2/scapy/utils.py", line 1324, in _read_all
    p = self.read_packet()  # type: Packet
        ^^^^^^^^^^^^^^^^^^
  File "/home/vagrant/scapy-2/scapy/utils.py", line 1729, in read_packet
    rp = super(PcapNgReader, self)._read_packet(size=size)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vagrant/scapy-2/scapy/utils.py", line 1527, in _read_packet
    res = self._read_block()
          ^^^^^^^^^^^^^^^^^^
  File "/home/vagrant/scapy-2/scapy/utils.py", line 1481, in _read_block
    return self.blocktypes.get(
           ^^^^^^^^^^^^^^^^^^^^
  File "/home/vagrant/scapy-2/scapy/utils.py", line 1703, in _read_block_dsb
    keys = load_nss_keys(filename)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vagrant/scapy-2/scapy/layers/tls/session.py", line 47, in load_nss_keys
    for line in fd:
  File "<frozen codecs>", line 322, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc0 in position 137: invalid start byte

Expected result

I think decryption secrets blocks like that should probably be just ignored.

On a somewhat related note I'm not sure scapy should fully log those secrets when the parser fails because it's relatively easy to screw something up with, say, editcap --inject-secrets and inject actual secrets that can be rejected by the parser anyway. For example wireshark doesn't even complain about that by default. When the debug log level is on it just prints something like pcapng_read_block(): wtap_read_bytes_or_eof() failed without being specific.

Related resources

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions