Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
ate shit on live tv
Feb 15, 2004

by Azathoth

That's pretty cool.

Adbot
ADBOT LOVES YOU

CmdrRiker
Apr 8, 2016

You dismally untalented little creep!

apseudonym posted:

The bag of certs in a TLS connection is unordered (except that the first one is the server cert), so if you have something like:

Server -> Intermediate -> Root where Root is also Cross signed by Old the bag of certs might be Server, Intermediate, Root_crosssigned

For devices that have Root in their trust store they will build Server -> Intermediate -> Root (Root_crosssigned is ignored) and on old devices you'd build Server -> Intermediate -> Root_crossigned -> Old, you might do this for multiple levels if you have a CA that is itself cross signed by something newish, correct clients prefer trust anchors in path building so it works nicely.

However, the server is just returning the leaf and not any other certificates and that's the actual issue. The certificate paths you're seeing in SSLlabs are just possible paths given their set of known certificates so yeah with cross signing you can see a bunch of weird ones but that doesnt mean that's what is actually used and its just SSLLabs trying to find valid paths by following every possible bridge it knows about.

Thanks for taking the time to explain more. It helped.



This twitter play by play of the talks isn't something I've encountered before. It's neat but since I don't know enough about messaging security I have to resort to the paper.

apseudonym
Feb 25, 2011

CmdrRiker posted:

Thanks for taking the time to explain more. It helped.
I have implemented enough trust management that I like to post about it.


If you want to know why most attempts to do certificate pinning using Java's standard Trust Management APIs is wrong I can talk about that too

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

apseudonym posted:

I have implemented enough trust management that I like to post about it.


If you want to know why most attempts to do certificate pinning using Java's standard Trust Management APIs is wrong I can talk about that too

:justpost:

Qtotonibudinibudet
Nov 7, 2011



Omich poluyobok, skazhi ty narkoman? ya prosto tozhe gde to tam zhivu, mogli by vmeste uyobyvat' narkotiki
on the subject of dumb cert chain poo poo, gently caress s_client

the s_client manpage helpfully includes these two options right next to each other

quote:

-verify depth

The verify depth to use. This specifies the maximum length of the server certificate chain and turns on server certificate verification. Currently the verify operation continues after errors so all the problems with a certificate chain can be seen. As a side effect the connection will never fail due to a server certificate verify failure.

-verify_return_error

Return verification errors instead of continuing. This will typically abort the handshake with a fatal error.

it's not immediately clear why there are separate options for "set the max chain depth" and "actually fail if you exceed it", but whatever. however, setting both of these and using a chain that's longer than the argument passed to verify does nothing. no fatal error, same output.

there is, however, a second block of options, which is just poo poo copied verbatim from openssl verify:

quote:

-attime, -check_ss_sig, -crl_check, -crl_check_all, -explicit_policy, -extended_crl, -ignore_critical, -inhibit_any, -inhibit_map, -no_alt_chains, -no_check_time, -partial_chain, -policy, -policy_check, -policy_print, -purpose, -suiteB_128, -suiteB_128_only, -suiteB_192, -trusted_first, -use_deltas, -auth_level, -verify_depth, -verify_email, -verify_hostname, -verify_ip, -verify_name, -x509_strict

Set various certificate chain validation options. See the verify(1) manual page for details.

setting verify_depth too short will cause s_client to error out, regardless of whether verify_return_error is present.

for extra fun, the depth reported in the output uses a different counter than what's used to determine whether poo poo will fail. output is zero-indexed and includes all certs in the chain:

code:
$ openssl s_client -connect login.microsoftonline.com:443 -verify 1 -verify_return_error -verify_depth 1 < /dev/null > /dev/null 
verify depth is 1
depth=2 C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root
verify return:1
depth=1 C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, OU = Microsoft IT, CN = Microsoft IT TLS CA 4
verify return:1
depth=0 CN = stamp2.login.microsoftonline.com
verify return:1
DONE
the verify limiter apparently only counts the intermediates:

code:
$ openssl s_client -connect login.microsoftonline.com:443 -verify 1 -verify_return_error -verify_depth 0 < /dev/null > /dev/null 
verify depth is 1
depth=1 C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, OU = Microsoft IT, CN = Microsoft IT TLS CA 4
verify error:num=22:certificate chain too long
140273999987200:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1925:
in somewhat unrelated news, i couldn't find a good example long chain to use.

BangersInMyKnickers
Nov 3, 2004

I have a thing for courageous dongles

openssl has too many easily-configured silent error modes and belongs in the trash heap of history since they clearly have zero interest in actually making a usable and secure product for the world but instead are just throwing a loose bag of parts at you with limited constraints or guidance

CRIP EATIN BREAD
Jun 24, 2002

Hey stop worrying bout my acting bitch, and worry about your WACK ass music. In the mean time... Eat a hot bowl of Dicks! Ice T



Soiled Meat

BangersInMyKnickers posted:

I 100% assure you the actual mil systems are pushing all their hosed up root and intermediate certs through GPOs to override the numerous PKI validation errors

hahahaha Alexion is a Symantec-issued cert mischief managed

this is true. i have to connect to a lot of sites that follow a chain to root certs that aren't provided by default by any browser or OS. for whatever reason they like their own.

also:

Mr. Nice!
Oct 13, 2005

c-spam cannot afford



i remember back in 2013 when i was still in the navy that you'd have to install a bunch of root certs to make most dod/navy websites functional. it was just a downloadable installer available on a .mil page, iirc. but yeah, without it most mil pages throw up errors and aren't really functional.

Cybernetic Vermin
Apr 18, 2005

BangersInMyKnickers posted:

openssl has too many easily-configured silent error modes and belongs in the trash heap of history since they clearly have zero interest in actually making a usable and secure product for the world but instead are just throwing a loose bag of parts at you with limited constraints or guidance

:yeah:

Shaggar
Apr 26, 2006

BangersInMyKnickers posted:

throwing a loose bag of parts at you with limited constraints or guidance

that's litterrally the unix philosophy

duz
Jul 11, 2005

Come on Ilhan, lets go bag us a shitpost


always pay your it staff very well if running a huge drug empire

quote:

Mexican drug lord El Chapo was only caught because his systems administrator flipped and started working for the feds, backdooring El Chapo's comms infrastructure and providing the cops with the decryption keys needed to eavesdrop on El Chapo's operations.

Former narcomorlock Jorge Cifuentes never really seemed to have his heart in the job: at one point, he failed to renew a license for some critical piece of secure communications software (I'm betting it's some kind of SIPP/VoIP server), forcing the narcos to use cleartext, unsecured voice channels (we know this because the feds made recordings of El Chapo screaming furious, terrifying abuse at Cifuentes over one of those insecure channels).
https://news.vice.com/en_us/article/439pv3/el-chapo-got-wiretapped-because-the-cartels-it-guy-screwed-up
https://gizmodo.com/the-feds-cracked-el-chapos-encrypted-communications-net-1831595734

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

Mr. Nice! posted:

i remember back in 2013 when i was still in the navy that you'd have to install a bunch of root certs to make most dod/navy websites functional. it was just a downloadable installer available on a .mil page, iirc. but yeah, without it most mil pages throw up errors and aren't really functional.

and even worse, if you install it, most .mil pages don't throw up errors but aren't really functional anyways

CRIP EATIN BREAD
Jun 24, 2002

Hey stop worrying bout my acting bitch, and worry about your WACK ass music. In the mean time... Eat a hot bowl of Dicks! Ice T



Soiled Meat
yeah its cool because so many pages have mixed content where some use certs signed by a root cert that is provided by default but then has embedded assets from pages served with DOD only certs.

Chris Knight
Jun 5, 2002

me @ ur posts


Fun Shoe
heh

Vesi
Jan 12, 2005

pikachu looking at?

apseudonym posted:

If you want to know why most attempts to do certificate pinning using Java's standard Trust Management APIs is wrong I can talk about that too

I'd like to know about this

cinci zoo sniper
Mar 15, 2013




this online jewellry store i had to buy a family gift from, a decently priced one for the country its located in, not only sent me my initial password, on registration, in plain text, but also the one i changed it to

Jewel
May 2, 2009

UK gov.org revenue and taxes registration page :gonk:

Shame Boy
Mar 2, 2010

Jewel posted:

UK gov.org revenue and taxes registration page :gonk:



too many characters make it loop back around to not strong

Grace Baiting
Jul 20, 2012

Audi famam illius;
Cucurrit quaeque
Tetigit destruens.



Shame Boy posted:

too many characters make it loop back around to not strong

UNSIGNED_ENTROPY_MAX is a helluva const

Farmer Crack-Ass
Jan 2, 2001

this is me posting irl
https://www.qualys.com/2019/01/09/system-down/system-down.txt

quote:

Qualys Security Advisory

System Down: A systemd-journald exploit


========================================================================
Contents
========================================================================

Summary
CVE-2018-16864
- Analysis
- Exploitation
CVE-2018-16865
- Analysis
- Exploitation
CVE-2018-16866
- Analysis
- Exploitation
Combined Exploitation of CVE-2018-16865 and CVE-2018-16866
- amd64 Exploitation
- i386 Exploitation
Acknowledgments
Timeline

Conversion, software version 7.0
-- System of a Down, "Toxicity"


========================================================================
Summary
========================================================================

We discovered three vulnerabilities in systemd-journald
(https://en.wikipedia.org/wiki/Systemd):

- CVE-2018-16864 and CVE-2018-16865, two memory corruptions
(attacker-controlled alloca()s);

- CVE-2018-16866, an information leak (an out-of-bounds read).

CVE-2018-16864 was introduced in April 2013 (systemd v203) and became
exploitable in February 2016 (systemd v230). We developed a proof of
concept for CVE-2018-16864 that gains eip control on i386.

CVE-2018-16865 was introduced in December 2011 (systemd v38) and became
exploitable in April 2013 (systemd v201). CVE-2018-16866 was introduced
in June 2015 (systemd v221) and was inadvertently fixed in August 2018.

We developed an exploit for CVE-2018-16865 and CVE-2018-16866 that
obtains a local root shell in 10 minutes on i386 and 70 minutes on
amd64, on average. We will publish our exploit in the near future.

To the best of our knowledge, all systemd-based Linux distributions are
vulnerable, but SUSE Linux Enterprise 15, openSUSE Leap 15.0, and Fedora
28 and 29 are not exploitable because their user space is compiled with
GCC's -fstack-clash-protection.

This confirms https://grsecurity.net/an_ancient_kernel_hole_is_not_closed.php:
"It should be clear that kernel-only attempts to solve [the Stack Clash]
will necessarily always be incomplete, as the real issue lies in the
lack of stack probing."


========================================================================
CVE-2018-16864
========================================================================

------------------------------------------------------------------------
Analysis
------------------------------------------------------------------------

The waves all keep on crashing by
-- System of a Down, "Suggestions"

We accidentally discovered CVE-2018-16864 while working on the exploit
for Mutagen Astronomy (CVE-2018-14634); if we pass several megabytes of
command-line arguments to a program that calls syslog(), then journald
crashes:

systemd-journal[472]: segfault at 7ffe9a077420 ip 00007f45f6174877 sp 00007ffe9a0773f0 error 6 in systemd-journald[7f45f6169000+3f000]

(gdb) disassemble 0x7f45f6174877 - 0x7f45f6169000
Dump of assembler code for function dispatch_message_real.4064:
...
0x000000000000b82c <+988>: callq 0x2bd10 <get_process_cmdline.constprop.96>
0x000000000000b831 <+993>: test %eax,%eax
0x000000000000b833 <+995>: js 0xb8ea <dispatch_message_real.4064+1178>
0x000000000000b839 <+1001>: mov -0x218(%rbp),%rbx
0x000000000000b840 <+1008>: test %rbx,%rbx
0x000000000000b843 <+1011>: je 0xd31b <dispatch_message_real.4064+7883>
0x000000000000b849 <+1017>: mov %rbx,%rdi
0x000000000000b84c <+1020>: callq 0x5360 <strlen@plt>
0x000000000000b851 <+1025>: add $0xa,%eax
0x000000000000b854 <+1028>: cltq
0x000000000000b856 <+1030>: add $0x1e,%rax
0x000000000000b85a <+1034>: and $0xfffffffffffffff0,%rax
0x000000000000b85e <+1038>: sub %rax,%rsp
0x000000000000b861 <+1041>: movabs $0x454e494c444d435f,%rax
0x000000000000b86b <+1051>: lea 0x37(%rsp),%r15
0x000000000000b870 <+1056>: and $0xfffffffffffffff0,%r15
0x000000000000b874 <+1060>: test %rbx,%rbx
0x000000000000b877 <+1063>: mov %rax,(%r15)
0x000000000000b87a <+1066>: mov $0x3d,%eax
0x000000000000b87f <+1071>: mov %ax,0x8(%r15)
0x000000000000b884 <+1076>: lea 0x9(%r15),%rax
0x000000000000b888 <+1080>: je 0xb895 <dispatch_message_real.4064+1093>
0x000000000000b88a <+1082>: mov %rbx,%rsi
0x000000000000b88d <+1085>: mov %rax,%rdi
0x000000000000b890 <+1088>: callq 0x5370 <stpcpy@plt>

538 static void dispatch_message_real(
...
604 r = get_process_cmdline(ucred->pid, 0, false, &t);
605 if (r >= 0) {
606 x = strjoina("_CMDLINE=", t);

919 #define strjoina(a, ...) \
920 ({ \
921 const char *_appendees_[] = { a, __VA_ARGS__ }; \
922 char *_d_, *_p_; \
923 int _len_ = 0; \
924 unsigned _i_; \
925 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
926 _len_ += strlen(_appendees_[_i_]); \
927 _p_ = _d_ = alloca(_len_ + 1); \
928 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
929 _p_ = stpcpy(_p_, _appendees_[_i_]); \
930 *_p_ = 0; \
931 _d_; \
932 })

This vulnerability, an attacker-controlled alloca()
(https://wiki.sei.cmu.edu/confluence/display/c/MEM05-C.+Avoid+large+stack+allocations)
at instruction 0xb85e and line 927, was introduced in systemd v203:

commit ae018d9bc900d6355dea4af05119b49c67945184
Date: Mon Apr 22 23:10:13 2013 -0300
...
r = get_process_cmdline(ucred->pid, 0, false, &t);
if (r >= 0) {
- cmdline = strappend("_CMDLINE=", t);
+ cmdline = strappenda("_CMDLINE=", t);

(strappenda() was renamed strjoina() in systemd v219) and became
exploitable in systemd v230:

commit ac2e41f5103ce2c679089c4f8fb6be61d7caec07
Date: Fri Feb 12 04:59:57 2016 -0800
...
This adds a wait flag to journal_file_set_offline(), when false the offline is
performed asynchronously in a separate thread.

------------------------------------------------------------------------
Exploitation
------------------------------------------------------------------------

... it's the race
Can you break out?
-- System of a Down, "36"

CVE-2018-16864 is similar to a Stack Clash vulnerability
(https://www.qualys.com/2017/06/19/stack-clash/stack-clash.txt), but:

- Steps 1 (Clash the stack with another memory region) and 2 (Run the
stack pointer to the start of the stack) are not needed, because the
attacker-controlled alloca() can be very large (several megabytes of
command-line arguments); only Steps 3 (Jump over the stack guard page,
into another memory region) and 4 (Smash the stack, or another memory
region) are needed.

- In Step 4 (Smash), the alloca() is fully written to (the vulnerability
is essentially a stpcpy(alloca(strlen(cmdline) + 1), cmdline)), and
the stpcpy() (a "wild copy") will therefore always crash into a
read-only or unmapped memory region:

https://googleprojectzero.blogspot.com/2015/03/taming-wild-copy-parallel-thread.html
https://cansecwest.com/slides/2015/Taming%20wild%20copies%20-%20Chris%20evans.pdf

We tried to asynchronously interrupt this stpcpy() before it crashes,
with a signal or a timer, but we failed because journald uses signalfd()
and timerfd_create() to handle these events synchronously.

We eventually gained control of eip (i386's instruction pointer) by
jumping into and smashing the stack of a concurrent thread (a "Parallel
Thread Corruption"):

- First, we send a large, high-priority message (LOG_CRIT or higher) to
journald, from a process whose cmdline is small; this message forces a
large write() (between 1MB and 2MB) to /var/log/journal/ and forces
the creation of a short-lived thread that fsync()s the journal (the
stack of this thread is allocated in the mmap region).

- Next, we create several processes (between 32 and 64) that write() and
fsync() large files (between 1MB and 8MB) to /var/tmp/ (for example);
these processes stall journald's fsync() thread and will allow us to
win a tight race: exploit the "wild copy" before it crashes.

- Last, we send a small, low-priority message to journald, from a
process whose cmdline is very large (roughly 128MB, the distance
between the main stack and the mmap region); this message forces a
very large alloca() that jumps from journald's main stack into the
stack of the fsync() thread, and smashes a saved eip before fsync()
returns from kernel space.

On a Debian stable (9.5), our proof of concept wins this race and gains
eip control after a dozen tries (systemd automatically restarts journald
after each crash):

systemd-journal[2195]: segfault at 41414141 ip 41414141 sp b5f3d22c error 14

Despite this initial success, we abandoned the exploitation of
CVE-2018-16864: while working on our proof of concept, we discovered two
different vulnerabilities (CVE-2018-16865, another attacker-controlled
alloca(), and CVE-2018-16866, an information leak) that are reliably
exploitable on both i386 and amd64.


========================================================================
CVE-2018-16865
========================================================================

------------------------------------------------------------------------
Analysis
------------------------------------------------------------------------

Can you feel their haunting presence?
-- System of a Down, "Holy Mountains"

Surprised by the heavy usage of alloca() in journald, we searched for
another attacker-controlled alloca() and found CVE-2018-16865:

1963 int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, uint64_t *seqnum, Object **ret, uint64_t *offset) {
....
1986 items = alloca(sizeof(EntryItem) * MAX(1u, n_iovec));
1987
1988 for (i = 0; i < n_iovec; i++) {
1989 uint64_t p;
1990 Object *o;
1991
1992 r = journal_file_append_data(f, iovec[i].iov_base, iovec[i].iov_len, &o, &p);
1993 if (r < 0)
1994 return r;
1995
1996 xor_hash ^= le64toh(o->data.hash);
1997 items[i].object_offset = htole64(p);
1998 items[i].hash = o->data.hash;
1999 }

This vulnerability was introduced in systemd v38:

commit cf244689e9d1ab50082c9ddd0f3c4d1eb982badc
Date: Thu Dec 29 15:00:57 2011 +0100
...
- items = new(EntryItem, n_iovec);
- if (!items)
- return -ENOMEM;
+ items = alloca(sizeof(EntryItem) * n_iovec);

and became exploitable in systemd v201:

commit c4aa09b06f835c91cea9e021df4c3605cff2318d
Date: Mon Apr 8 20:32:03 2013 +0200
...
-#define ENTRY_SIZE_MAX (1024*1024*64)
-#define DATA_SIZE_MAX (1024*1024*64)
...
+#define ENTRY_SIZE_MAX (1024*1024*768)
+#define DATA_SIZE_MAX (1024*1024*768)

If we send a large "native" message to /run/systemd/journal/socket:
since the maximum size of a "native" entry is 768MB, and the minimum
length of a "native" item is 3 ("A=\n"), and the size of an EntryItem
structure is 16 (a 64-bit offset and a 64-bit hash), the maximum size of
the attacker-controlled alloca() in journal_file_append_entry() is 768MB
/ 3 * 16 = 4GB, large enough to jump from journald's main stack into the
mmap region, even on amd64.

On amd64, as described in the "64-bit exploitation" of our Stack Clash
advisory, the randomized distance between the main stack and the mmap
region is shorter than 4GB with a probability of (approximately):

SUM(d = 0; d < 4GB; d++) d / (16GB * 1TB) ~= 1 / 2048

------------------------------------------------------------------------
Exploitation
------------------------------------------------------------------------

Jump (pogo, pogo, pogo, pogo, pogo, pogo, pogo)
-- System of a Down, "Bounce"

CVE-2018-16865 is basically a simplified Stack Clash vulnerability:

- Steps 1 (Clash) and 2 (Run) of the Stack Clash are not needed, since
the largest attacker-controlled alloca() is 4GB; only Steps 3 (Jump)
and 4 (Smash) are needed.

- In Step 4 (Smash), the alloca() is not necessarily fully written to:
if the size of an item is larger than 128MB (DEFAULT_MAX_SIZE_UPPER),
then journal_file_append_data() returns an error that breaks the "for"
loop in journal_file_append_entry() (at lines 1992-1994) and avoids a
crash into a read-only or unmapped memory region.

We eventually transformed this vulnerability into a crude
"write-what-where" (https://cwe.mitre.org/data/definitions/123.html):

- "write-where": We jump into and smash libc's read-write segment, and
thereby overwrite a function pointer. Unfortunately this "write-where"
is not surgical: the stack frames of the functions called from within
the "for" loop (in journal_file_append_entry()) smash a few kilobytes
below our target function pointer, and therefore overwrite vital libc
variables that may crash or deadlock journald. Consequently, we must
sometimes shift our alloca() jump slightly, to avoid overwriting such
vital variables.

- "write-what": We want to overwrite our target function pointer with
the address of another function or ROP chain, but unfortunately the
stack frames of the functions called from within the "for" loop (in
journal_file_append_entry()) do not contain any data that we control.
However, the 64-bit "hash" values that are written to the alloca()ted
"items" are produced by jenkins_hashlittle2(), a noncryptographic hash
function: we can easily find a short string (a preimage) that hashes
to a given value (the address that will overwrite our target function
pointer) and is also a valid_user_field() (or journal_field_valid()).

This "write-what" restricts our "write-where" to function pointers
whose address modulo 16 is equal to 8 (the offset of "hash" in the
EntryItem structure).

To complete our exploit, we need the address of journald's stack pointer
before the alloca() jump, and the address of our target function pointer
in libc's read-write segment -- we need an information leak.


========================================================================
CVE-2018-16866
========================================================================

------------------------------------------------------------------------
Analysis
------------------------------------------------------------------------

When they speak, we can peek from the windows of their mouths
-- System of a Down, "Know"

We discovered an out-of-bounds read in journald (CVE-2018-16866), and
transformed it into an information leak:

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++;

------------------------------------------------------------------------
Exploitation
------------------------------------------------------------------------

For today we will take the body parts and put them on the wall
-- System of a Down, "Dreaming"

To leak a stack address or an mmap address from journald:

- First, we send a large native message to /run/systemd/journal/socket;
journald mmap()s our message, and malloc()ates a large array of iovec
structures: most of these structures point into our mmap()ed message,
but some of them point to the stack (in dispatch_message_real()). The
contents of this iovec array (especially the mmap and stack pointers)
are preserved in a heap hole after free() (after journald finishes
processing our message).

- Next, we send a large syslog message to /run/systemd/journal/dev-log;
to receive our large message (in server_process_datagram()), journald
realloc()ates its server buffer into the heap hole that previously
contained the iovec array (and still contains remains of mmap and
stack pointers).

- Last, we send a large syslog message that exploits CVE-2018-16866;
journald receives our large message in its server buffer (in the heap
chunk that previously contained the iovec array), and if we carefully
choose the size of our message and position its terminating ":" in
front of a remaining mmap or stack pointer, then we can leak this
pointer (it is mistakenly read out-of-bounds as the body of our
message).

From this leaked stack pointer we easily deduce journald's stack pointer
before the alloca() jump, because the distance between the two depends
only on journald's executable.

From the leaked mmap address we can deduce libc's address, but chunks of
unknown sizes are mmap()ed between the two, and we must therefore adopt
different strategies based on our target architecture (i386 or amd64).


========================================================================
Combined Exploitation of CVE-2018-16865 and CVE-2018-16866
========================================================================

Don't leave your seats now
Popcorn everywhere ...
-- System of a Down, "CUBErt"

------------------------------------------------------------------------
amd64 Exploitation
------------------------------------------------------------------------

- To deduce libc's address from the leaked mmap address of our native
message, we arrange for this message to be mmap()ed into the 2MB hole
between ld.so's read-execute and read-only segments: from this hole's
address we deduce ld.so's address, and hence libc's address (with help
from ldd's output).

- If the resulting stack-to-libc distance is jumpable (if it is shorter
than 4GB), then we proceed with our "write-what-where"; otherwise, we
restart journald (we crash it with an alloca() of RLIMIT_STACK -- 8MB
by default) and try again.

We have a good chance of obtaining a jumpable stack-to-libc distance
(and hence a root shell) after 2048 tries * 2 seconds ~= 68 minutes
(by default, if journald crashes less than 5 times within 10 seconds,
it is restarted automatically by systemd).

- For the "write-where" part of our "write-what-where", we overwrite
libc's __free_hook function pointer, whose address modulo 16 is always
equal to 8 (on every amd64 distribution that we exploited).

- For the "write-what" part of our "write-what-where", we overwrite
__free_hook with the address of libc's system() function: whenever
journald free()s data that we control, we achieve arbitrary command
execution.

Last-minute note: on CentOS 7, the usual function pointers in libc's
read-write segment (__free_hook, __malloc_hook, etc) are not located at
multiples of 16 plus 8. To circumvent this problem:

- First, we overwrite the "_chain" pointer of stderr's FILE structure
with the address of our own fake FILE structure (this "_chain" pointer
is located at a multiple of 16 plus 8, in libc's read-write segment).

- Next, we corrupt one of malloc's internal variables (also in libc's
read-write segment).

- Last, we force a call to malloc() or free(), which detects the
corruption of its internal variable and calls abort(), which calls
_IO_flush_all_lockp(), which follows stderr's overwritten "_chain"
pointer to our fake FILE structure; we eventually achieve arbitrary
command execution by calling libc's system() via one of the function
pointers in our fake FILE structure.

------------------------------------------------------------------------
i386 Exploitation
------------------------------------------------------------------------

Our i386 exploit is very similar to the amd64 exploit, but:

- The stack-to-libc distance is always jumpable (it is roughly 128MB).

- There is no hole between ld.so's read-execute and read-only segments.
However, libc's address is randomized in a narrow range of 1MB and is
therefore brute forcible: we have a good chance of correctly guessing
libc's address after 1MB / 4KB = 256 tries * 2 seconds ~= 8 minutes.

- For the "write-where" part of our "write-what-where", we overwrite
libc's __malloc_hook function pointer (__free_hook was never located
at a multiple of 16 plus 8 or 12 on the i386 distributions that we
exploited, but __malloc_hook always is).

- For the "write-what" part of our "write-what-where", we overwrite
__malloc_hook with the address of a "mov esp, 0x89fffa5d ; ret" gadget
(or equivalent stack pivot): since our native message can be as large
as 768MB, we can mmap() it at 0x89fffa5d, take control of the stack,
and return into libc's execve().


========================================================================
Acknowledgments
========================================================================

We thank systemd's developers, Red Hat Product Security, and the members
of linux-distros@openwall.


========================================================================
Timeline
========================================================================

2018-11-26: Advisory sent to Red Hat Product Security (as recommended by
https://github.com/systemd/systemd/blob/master/docs/CONTRIBUTING.md#security-vulnerability-reports).

2018-12-26: Advisory and patches sent to linux-distros@openwall.

2019-01-09: Coordinated Release Date (6:00 PM UTC).

CmdrRiker
Apr 8, 2016

You dismally untalented little creep!

"all systemd-based Linux distributions are vulnerable"

Ha, that's pretty much every Linux distro I use. Still working my way through the report, though.

Mustache Ride
Sep 11, 2001



Some real SOAD fans at Qualys. I haven't heard CUBErt in like 20 years.

apseudonym
Feb 25, 2011

Vesi posted:

I'd like to know about this



Alright, posting time. I'm not going to compile the code I write here so if its slightly off :effort:

Pinning is about protecting yourself from a CA that is trusted by your device but is actually evil, so we assume the attacker owns a CA.

For the sake of naming, we've got the follow common certificates:
code:
CA_g --  a good CA that the real website uses
I -- intermediate issued by CA_g that issued the real certificate for the website, this is the certificate pinned  to.
CA_b -- evil CA we want pinning to protect us from
Evil -- Evil certificate for the website we want to MiTM that uses pinning
Also keep in mind that certificates form a graph which may have multiple possible paths between the leaf and a trusted issuer, path building is a straight up graph traversal problem, and this is important later.

The basic naive Java pinning is:

code:
public void checkPin(SSLSocket s) throws CertificateException {
	for (X509Certificate c : s.getSession().getPeerCertificates()) {
		if (PINS.contains(sha256(cert.getPublicKey().getEncoded())) {
			// Pin found!
			return;
		}
		throw new CertificateException("Pinning check failed!");
	}
Not having read the documentation involved this looks correct but its trivial to bypass because SSLSession.getPeerCertificates does not return the verified path but instead returns the bag of certificates provided by the server. The bag of certs is an arbitrary set of certificates which may or not be used in path building. The evil server just sends down {Evil, CA_b, I, CA_a}, the TrustManager will use the path [Evil, CA_b] which is valid and the pinning check will pass because I in included.

Ah, so you just need an API to get the actual path from the SSLSession, then its easy! Except Java doesn't give you such an API :smithicide:. So instead a number of people decided to try and do their own path building before they check pins. I could add a bunch of code here but :effort:, so let's just use an already existing implementation like this one. Its vulnerable and still not fixed but its publicly documented vulnerable on the issues page since 2017 so....

Now, this only works if you always build exactly the same certificate chain as the default TrustManager did, if you ever build a different one there's a problem. That's a terrible idea because a real path building is taking in account things like certificate usage, basic constraints, expiration, etc etc, whereas 'chain cleaners' only build the first possible path based on subject/issuer. In order to bypass this we would need to create a bag of certificates for our evil certificate wherethe real trust manager builds a valid chain to our evil CA but the path returned from the chain cleaner includes our pinned intermediate. With our evil CA this is pretty easy.

First we're going to get a valid leaf certificate from CA_g issued by I for a website under our control, call it notevil.com, since CA_g is in the business of issuing leaf certs for websites this is easy. Then we also issue an intermediate CA from CA_b with the same subject and key as our notevil.com leaf certificate and sign Evil with that.

The bag of certs we provide is then {Evil, notevil.com_leaf, notevil.com_intermediate, I, CA_g, CA_b}. There are two potential paths in this
code:
Path 1 -- [Evil, notevil.com_leaf, I, CA_g]
Path 2 -- [Evil, notevil.com_intermediate, CA_b]
Path 1 is not a trusted path since notevil.com_leaf will have the CA bit set in the basic constraints to false, but path 2 is a perfectly trusted path chaining to our evil CA. A trust manager that does everything in rfc4158 will try the first chain, reject it, and then try the second chain and see its valid. Chain cleaning however will build path 1 which will pass the pinning check.

Generally speaking anything that relies on two different implementations of the same spec behaving the exact same way is horribly broken in fun ways, but that's another topic for another post.


So you need to do one of: add an API that gives you the chain to make this trivial, write your own X509TrustManager that does pinning checks during chain validation, or figure out how to do it using the JCA APIs which if you can figure out correctly without losing your mind you're a better person than I am.


PS: Never pin to leafs and always include a backup SPKI hash if you really want to do pinning.


E: Also if you don't follow the cert chains I can make some actual certs as an example, but that's a lot of :effort:

apseudonym fucked around with this message at 03:33 on Jan 11, 2019

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Wait, so the validation APIs don't give you any way to tell "hey, here's the trust chain the platform used to determine that this certificate is valid"?

Are there any examples from whoever designed that api showing you how it's supposed to be used? Are you just supposed to do 100% of the certificate validation yourself and not rely on the platform doing anything?

Chris Knight
Jun 5, 2002

me @ ur posts


Fun Shoe
a miserable bag of certs

apseudonym
Feb 25, 2011

Jabor posted:

Wait, so the validation APIs don't give you any way to tell "hey, here's the trust chain the platform used to determine that this certificate is valid"?

Are there any examples from whoever designed that api showing you how it's supposed to be used? Are you just supposed to do 100% of the certificate validation yourself and not rely on the platform doing anything?

Yeah... about that.

Realistically you use some extensions/have the OS provide you abstractions so you never have to touch this because also you shouldn't try and write your own X509TrustManager please I beg you let us do it you will do it wrong.

CmdrRiker
Apr 8, 2016

You dismally untalented little creep!

apseudonym posted:

Yeah... about that.

Realistically you use some extensions/have the OS provide you abstractions so you never have to touch this because also you shouldn't try and write your own X509TrustManager please I beg you let us do it you will do it wrong.

I hope everyone knows that they should never roll their own encryption.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Though thinking about it, in common use cases (you're using certificate pinning to ensure you're talking to a server you control), wouldn't it be easy enough to fail validation if the certificate bag contains more certs than you expect?

Like, you expect it to contain the leaf cert, your pinned intermediate, and that intermediate's root cert, and absolutely nothing else.

apseudonym
Feb 25, 2011

Jabor posted:

Though thinking about it, in common use cases (you're using certificate pinning to ensure you're talking to a server you control), wouldn't it be easy enough to fail validation if the certificate bag contains more certs than you expect?

Like, you expect it to contain the leaf cert, your pinned intermediate, and that intermediate's root cert, and absolutely nothing else.

Good news your CA has changed their infrastructure and the intermediate is now no longer directly issuing certificates but is instead using another intermediate cert in between.


SPKI Pinning has lead to far more "welp guess all your clients can't connect anymore sorry pal" than it has prevented evil CA attacks.

CmdrRiker posted:

I hope everyone knows that they should never roll their own encryption.

Might want to check the author of the pinning library I linked

apseudonym fucked around with this message at 04:36 on Jan 11, 2019

Shame Boy
Mar 2, 2010

Mustache Ride posted:

Some real SOAD fans at Qualys. I haven't heard CUBErt in like 20 years.

there's a joke about leaving SSL keys up on a table here but i can't really make it work :effort:

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer

Shame Boy posted:

there's a joke about leaving SSL keys up on a table here but i can't really make it work :effort:

I don't think you trust
in my
self signed web certify

Carthag Tuek
Oct 15, 2005

Tider skal komme,
tider skal henrulle,
slægt skal følge slægters gang



CmdrRiker posted:

I hope everyone knows that they should never roll their own encryption.

*rolls d20*

critical... 1 :negative:

Carbon dioxide
Oct 9, 2012

E: meh

Carbon dioxide fucked around with this message at 21:44 on Jan 11, 2019

geonetix
Mar 6, 2011


because, did you expect anything else?

https://twitter.com/doctorow/status/1083444065146789889?s=21

Truga
May 4, 2014
Lipstick Apathy
effectively free data storage has done absolute wonders for privacy and security lmao

redleader
Aug 18, 2005

Engage according to operational parameters

jit bull transpile posted:

I don't think you trust
in my
self signed web certify

Chris Knight
Jun 5, 2002

me @ ur posts


Fun Shoe

CmdrRiker posted:

I hope everyone knows that they should never roll their own encryption.

Captain Foo
May 11, 2004

we vibin'
we slidin'
we breathin'
we dyin'

jit bull transpile posted:

I don't think you trust
in my
self signed web certify
i
cry
when thinking 'bout PKI

BangersInMyKnickers
Nov 3, 2004

I have a thing for courageous dongles


vehicle 3 has legs

Adbot
ADBOT LOVES YOU

Cybernetic Vermin
Apr 18, 2005

BangersInMyKnickers posted:

vehicle 3 has legs

the labels are (for some reason) right-aligned to the left of the box they are labeling

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply