Thursday, July 2, 2009

Even when one byte matters

Common Vulnerabilities and Exposures
"The console selection feature in the Linux kernel 2.6.28 before, 2.6.25, and possibly earlier versions, when the UTF-8 console is used, allows physically proximate attackers to cause a denial of service (memory corruption) by selecting a small number of 3-byte UTF-8 characters, which triggers an "an off-by-two memory error. NOTE: it is not clear whether this issue crosses privilege boundaries."

Ubuntu Security Notice USN-751-1
"The virtual consoles did not correctly handle certain UTF-8 sequences. A local attacker on the physical console could exploit this to cause a system crash, leading to a denial of service."

RedHat Security Advisory
"An off-by-two error was found in the set_selection() function of the Linux kernel. This could allow a local, unprivileged user to cause a denial of service when making a selection of characters in a UTF-8 console. Note: physical console access is required to exploit this issue."

When I was looking at vendor advisories regarding SCTP remote issue i got attracted by another bug regarding hypothetical kernel heap overflow.
For the umpteenth time the impact of the vulnerability is : DoS only.
The impact of this issue is highly limited because of you need a VC attached to your process to exploit it, but it's worth spending some time on it since it's not an everyday bug to find in the kernel.. it's an interesting scenario: an off-by-one(two) kernel heap overflow.

As I did for the previous post, I'm not going to give any detailed
description of the exploit: it should be straightforward enough to
everyone who's used to play with internal kernel structures.
What I'm about to do is, once again, just briefly introduce the
vulnerability and then spend some time on showing how it is possible to
turn it in a nearly one-shot exploit.

Before going on i want to include a digression about this blog:
the original idea was to publish a month by month exploit regarding DoS-claiming-only vulnerability in the linux kernel.
After publishing the first post, about SCTP remote exploit, i received some roasts.
Someone pulled me down about disclosing a few cool stuff.
I want to point out that i just wrote the exploit: i did not kill the vulnerability.
I don't like full disclosure, at least i don't like what full disclosure has become today: a freaking race between killer-vulns-guys.
Even if i think there's a big difference between killing vulnerabilities and writing good exploit code i 'm not sure if i'll continue publishing these stuffs.

The buffer is allocated here:
file: /drivers/char/selection.c
func: set_selection()

multiplier = use_unicode ? 3 : 1;
bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL);

then the function copies the buffer:

sel_buffer = bp;
obp = bp;
for (i = sel_start; i <= sel_end; i += 2) {
c = sel_pos(i);
if (use_unicode)
bp += store_utf8(c, bp);

The loop goes from sel_start to sel_end (inclusive). The last character is not multiplied by multiplier (which has value 3) and so we can overflow the buffer by 1 or 2 byte. To make the overflow meaningful we have to allocate a buffer close to the size of a cache object slab or the overflow will end up in the pad zone. Since we can control the "delta" between sel_start and sel_end we can arbitrary choose the slub to be used.

On of the better slub to pick usually is the 96 bytes slub.. but it doesn't fulfill our goal because:

63 / 2 * 3 + 1 = 94
(if we overflow 2 byte we get 96.. no meaningful overflow happens..)
64 / 2 * 3 + 1= 97
(too large to fit in..)
We pick instead the 128 slub cache.. using a gap equal to:
84 / 2 * 3 = 127
(if we overflow 2 bytes we have meaningful off-by-one heap overflow)

Now we can overflow into another 128 byte object which has some interesting meaningful pointer or we can smash internal SLUB structure.

The exploit takes the latter approach smashing internal SLUB structure taking full control of the SLUB allocation engine.
I decide to use again a previously disclosed structure as a placeholder: SCTP ssnmap struct.
This can lead to some problem with SELinux.
There are other interesting structures to pick in the place of SCTP ones but it is not worth showing them here for such an not useful exploit.

A couple of words about lack of full-recovery in the exploit. On boxes protected by zero mapping kernel protection the code leaves two descriptors holding smashed pointers in its internal structures. Before executing the shell the code migrates those descriptors inside a child process. When this child process will be killed (after reboot?) the kernel oops.

A different way could be:
- migrate descriptors inside some daemon using ptrace()/SCM_RIGHT
- directly patch smashed pointers adding code to the ring0 shellcode
- using a stupid lkm

The exploit works only on x86-64 platform with SLUB allocator but anyone can run it on x86 kernel modifying a couple of lines.

Talking about "external resources", the exploit uses "/proc/slabinfo" and "/proc/kallsyms". The former is not crucial but increases the exploitation odds close to 100% on idle boxes. The latter is not needed if you have access to the kernel image.

I'd like to thank twiz for his pioneer work on original old SLAB exploitation approach: it helps me much in abusing new SLUB counterpart.

Tested on target:
Ubuntu 8.04 x86_64 (generic/server)
Ubuntu 8.10 x86_64 (generic/server)
Fedora Core 10 x86_64 (default installed kernel - without SElinux)

$ ./tioctl_houdini
[**] Patching ring0 shellcode with userspace addr: 0x4017e0
[**] Using port: 25433
[**] Getting slab info...
[**] Mapping Segments...
[**] Trying mapping safe page...Page Protection Present (Unable to Map Safe Page)
[**] Mapping High Address Page (don't kill placeholder child)
[**] Mapping Code Page... Done
[**] Binding on CPU 0
[**] Start Server Thread..
[**] Umapped end-to-end fd: 212
[**] Unsafe fd: ( 210 224 214 212 )
[**] Hijacking fops...
[**] Migrate evil unsafe fds to child process..
[**] Child process 25463 _MUST_ NOT die..keep it alive:)
[**] Got root!
# id
uid=0(root) gid=0(root) groups=1001(anon)


The exploit code can be downloaded here.