ASA-2019-00011 – systemd: Out-of-bounds read when parsing a crafted syslog message


Allele Security Alert

ASA-2019-00011

Identifier(s)

ASA-2019-00011, CVE-2018-16866

Title

Out-of-bounds read when parsing a crafted syslog message

Vendor(s)

The systemd project

Product(s)

systemd

Affected version(s)

systemd v221 up to v240

Fixed version(s)

systemd released with the following commits:

journal: fix syslog_parse_identifier()
https://github.com/systemd/systemd/commit/a6aadf4ae0bae185dc4c414d492a4a781c80ffe5

journal: do not remove multiple spaces after identifier in syslog message
https://github.com/systemd/systemd/commit/8595102d3ddde6d25c282f965573a6de34ab4421

Proof of concept

Yes

Description

An out-of-bounds read was discovered in systemd-journald in the way it parses log messages that terminate with a colon ‘:’. A local attacker can use this flaw to disclose process memory data.

Technical details

It was discovered an out-of-bounds read in journald that can be transformed into an information leak:

File: v238/src/journal/journald-syslog.c
---
31 #define WHITESPACE " \t\n\r"
...
194 size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid) {
195 const char *p;
...
197 size_t l, e;
...
203 p = *buf;
204
205 p += strspn(p, WHITESPACE);
206 l = strcspn(p, WHITESPACE);
207
208 if (l <= 0 ||
209 p[l-1] != ':')
210 return 0;
211
212 e = l;
...
240 if (strchr(WHITESPACE, p[e]))
241 e++;
242 *buf = p + e;
243 return e;
244 }
---

If we send a syslog message to journald (in *buf), and if the last character of this message is a ‘:’ (before the ‘\0’ terminator), then:

– at line 240, p[e] is the ‘\0’ terminator of our message;

– at line 240, strchr(WHITESPACE, p[e]) returns a pointer to the ‘\0’ terminator of the WHITESPACE string (as mentioned in man strchr: “The terminating null byte is considered part of the string, so that if c is specified as ‘\0’, these functions return a pointer to the terminator.”);

– at line 241, e is incremented;

– at line 242, *buf points out-of-bounds, to the first character after the ‘\0’ terminator of our message;

– later, the out-of-bounds string at *buf (supposedly the body of our syslog message) is written (leaked) to the journal.

Consequently, we can read this out-of-bounds string:

– either directly from the journal (if journald’s “Storage” is “persistent”, or “auto” and /var/log/journal/ exists), because journald supports extended file ACLs (Access Control Lists):

$ id
uid=1000(john) gid=1000(john) groups=1000(john) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

$ ls -l /var/log/journal/*/user-$UID.journal
-rw-r-----+ 1 root systemd-journal 8388608 Nov 20 09:35 
/var/log/journal/2562d1eced654f44a3d3a217d66b9ff3/user-1000.journal

$ getfacl /var/log/journal/*/user-$UID.journal
...
user:john:r--

$ ./infoleak

$ journalctl --all --user --lines=1 --identifier=infoleak | hexdump -C
...
00000050 2e 20 2d 2d 0a 4e 6f 76 20 32 30 20 31 36 3a 30 |. --.Nov 20 16:0|
00000060 30 3a 33 36 20 6c 6f 63 61 6c 68 6f 73 74 2e 6c |0:36 localhost.l|
00000070 6f 63 61 6c 64 6f 6d 61 69 6e 20 69 6e 66 6f 6c |ocaldomain infol|
00000080 65 61 6b 5b 33 35 34 38 5d 3a 20 78 fb 1e 78 54 |eak[3548]: x..xT|
00000090 7f 0a |..|

– or (if journald’s “Storage” is “volatile”, or “auto” and /var/log/journal/ does not exist) from a tty that we recorded to /var/run/utmp, because journald writes (“walls”) emergency messages (LOG_EMERG) to the tty of every logged-in user; our exploit records a tty to /var/run/utmp via an ssh connection to localhost, but other methods exist (for example, utempter and gnome-pty-helper):

$ ./infoleak
...
00003510 0a 07 0d 0d 0a 42 72 6f 61 64 63 61 73 74 20 6d |.....Broadcast m|
00003520 65 73 73 61 67 65 20 66 72 6f 6d 20 73 79 73 74 |essage from syst|
00003530 65 6d 64 2d 6a 6f 75 72 6e 61 6c 64 40 6c 6f 63 |emd-journald@loc|
00003540 61 6c 68 6f 73 74 2e 6c 6f 63 61 6c 64 6f 6d 61 |alhost.localdoma|
00003550 69 6e 20 28 54 75 65 20 32 30 31 38 2d 31 31 2d |in (Tue 2018-11-|
00003560 32 30 20 31 36 3a 32 35 3a 34 36 20 43 53 54 29 |20 16:25:46 CST)|
00003570 3a 0d 0d 0a 0d 0d 0a 69 6e 66 6f 6c 65 61 6b 5b |:......infoleak[|
00003580 33 38 37 32 5d 3a 20 78 6b a2 e1 2f 7f 0d 0d 0a |3872]: xk../....|

This vulnerability was introduced in systemd v221:

commit ec5ff4445cca6a1d786b8da36cf6fe0acc0b94c8
Date: Wed Jun 10 22:33:44 2015 -0700
...
- e += strspn(p + e, WHITESPACE);
+ if (strchr(WHITESPACE, p[e]))
+ e++;

and was inadvertently fixed in August 2018:

commit a6aadf4ae0bae185dc4c414d492a4a781c80ffe5
Date: Wed Aug 8 15:06:36 2018 +0900
...
- if (strchr(WHITESPACE, p[e]))
- e++;
+ e += strspn(p + e, WHITESPACE);
commit 8595102d3ddde6d25c282f965573a6de34ab4421
Date: Fri Aug 10 11:07:54 2018 +0900
...
- e += strspn(p + e, WHITESPACE);
+ /* Single space is used as separator */
+ if (p[e] != '\0' && strchr(WHITESPACE, p[e]))
+ e++;

Credits

Qualys Research Labs

Reference(s)

System Down: A systemd-journald exploit
https://seclists.org/oss-sec/2019/q1/54

journal: fix syslog_parse_identifier()
https://github.com/systemd/systemd/commit/a6aadf4ae0bae185dc4c414d492a4a781c80ffe5

journal: do not remove multiple spaces after identifier in syslog message
https://github.com/systemd/systemd/commit/8595102d3ddde6d25c282f965573a6de34ab4421

system-down.tar.gz
https://www.qualys.com/2019/05/09/system-down/system-down.tar.gz

CVE-2018-16866
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-16866

CVE-2018-16866
https://nvd.nist.gov/vuln/detail/CVE-2018-16866

If there is any error in this alert or you wish a comprehensive analysis, let us know.

Last modified: September 3, 2019

We are not responsible for any data loss, device corruption or any other type of issue due to the use of any information mentioned in our security alerts.