
Linux local root exploit for CVE-2014-0038 - res0nat0r
https://github.com/saelo/cve-2014-0038
======
mjn
Original discussion of CVE-2014-0038:
[https://news.ycombinator.com/item?id=7154618](https://news.ycombinator.com/item?id=7154618)

------
sillysaurus2
Is this a universal exploit? Which distros are unaffected?

If it's non-universal, why is it? E.g. if it only affects Ubuntu, then what is
it about Ubuntu that allows this to work?

EDIT: This seems to be the answer:
[https://news.ycombinator.com/item?id=7154922](https://news.ycombinator.com/item?id=7154922)
... Any distro using the x32 ABI is vulnerable, and Ubuntu just recently
enabled the x32 ABI.

~~~
mjn
I believe only Ubuntu is affected, of the major distros. The bug affects
kernels compiled with CONFIG_X86_X32, which enables the new-ish x32 ABI, a way
for processes to use x86-64 features like the extended register set, while
retaining the 32-bit pointer size. The more conventional approach to 32/64-bit
code mixing (e.g. in Debian) is that 32-bit processes use the old x86 ABI,
while 64-bit processes use the new x86-64 ABI. The x32 ABI was borne out of
people noticing that the x86-64 architecture's improvements weren't all about
64-bitness, and that some of them were relevant to 32-bit programs too. So it
keeps 32-bit pointers, but otherwise uses x86-64 features, so even 32-bit
processes can take advantage of running on x86-64 chips (everything except the
64-bit part). Nothing inherently wrong with the idea, but it introduces some
new critical codepaths into the kernel that have to be thoroughly tested.

------
smtddr
Hmm...

    
    
      #define PAYLOADSIZE 0x2000
      code += PAYLOADSIZE - 1024;
      memcpy((void*)code, &kernel_payload, 1024);
    

Does anybody know if it's possible to find out the size of a function during
run time? Could you like say, put a return at the end of the function then do
a for-loop with memcpy() for each byte until you run into the OPCODE for RET?
I guess I could do a test.

~~~
userbinator
RET is 195 or C3 in hex which also corresponds to modrm operands "eax, ebx" or
"ebx, eax" so there's a pretty good chance of say a MOV instruction e.g. 89
C3, "mov ebx, eax" or something else also having that byte inside it, not to
mention constants and offsets. (If you work with x86 asm enough, you _will_
start memorising opcodes...)

~~~
smtddr
Hmm... so after looking at
[http://ref.x86asm.net/coder32.html](http://ref.x86asm.net/coder32.html)
apparently 0xC2 and 0xC3 are RET. On my 32bit Linux machine, the following
code printed _" Okay! c2 found @ 174"_ Is this code correct in any way??? I
guess the fact that I'm assuming every byte is a whole instruction; not even
accounting for the operands is already a problem. But am I even reading the
bytes properly at all?

    
    
      #include <stdio.h>
    
      void rightmeow()
      {
          int q;
          for(q = 0; q < 10 ; q++)
              printf("It's new!\n");
          return;
      }
    
      int main(int argc, char** argv)
      {
        int i;
        unsigned char bytecode;
        for(i = 0; i < 9999 ; i++)
        {  
            bytecode = (unsigned char)(**(rightmeow+i));//--- does this really work?
            if (bytecode == 0xC2 || bytecode == 0xC3)
                break;
        }
        if( i == 9999)
            printf("No good.\n");
        else
            printf("Okay! %x found @ %d\n",bytecode,i);
    
        return 0;
      }

~~~
userbinator
You probably mean

    
    
         *(((unsigned char *)rightmeow)+i)
    

but just change the "q < 10" line to "q < 195" and you should see the output
change, since that immediate constant is going to be present at least once
before the final ret. For me, changing that changes the output from c3 being
found at 47 to it being found at 25.

~~~
smtddr
Nice! For me it changed from being found at 38, to 34. I wonder why you get C3
while I get C2.

~~~
userbinator
C2 is RET iw, i.e. has 16-bit immediate value following the instruction, the #
of bytes of parameters to pop from the stack. That should be 0 in this case so
it could use C3 and save 2 bytes, but compilers aren't always really
intelligent, although this is the first time I've seen that.

Then again, it could be something else and not the actual return you found.

------
microcolonel
You should clarify that it only applies to the x32 ABI.

Which is only used on the(already vastly irresponsibly-constructed) Ubuntu
13.10.

~~~
taf2
why is it "vastly irresponsibly-constructed" ? I mean major hosting providers
like rackspace use it... so ??

~~~
rodgerd
Here's why the Fedora maintainers rejected request to enable it:
[https://bugzilla.redhat.com/show_bug.cgi?id=854317](https://bugzilla.redhat.com/show_bug.cgi?id=854317)

* It's new and unanalyzed for security flaws.

* It's useless without the right userland tools, which don't exist.

Ubuntu switched it on either because they have no clues, or because they
wanted a checkbox to say "look, we have features no-one else does!!!!".

~~~
aortega
The main problem with Fedora is that it usually doesn't work. At all.

~~~
growupkids
Is this a joke?

~~~
jjoonathan
I wish.

-Someone who just spent half of a perfectly good day wrestling with their buggy installer

------
dewyatt
Manjaro has CONFIG_X86_X32=y for the kernel I'm running (3.12.8). I can't
figure out PTMX_FOPS so I can't test whether it's affected by this. :/

~~~
dewyatt
Apparently affected
([http://forum.manjaro.org/index.php?topic=10498.0](http://forum.manjaro.org/index.php?topic=10498.0))

------
aortega
Tested on ubuntu 13.10 with latest updates.

Doesn't work, but DID crash the kernel, so it's vulnerable.

------
digitalpig
tested on Ubuntu 13.10 with kernel 3.11.0-15-generic. CONFIG_X86_X32=y

the program did not get the root privilege. Kernel did not crash either.
Strange.

------
seletskiy
To make it work you need to patch exploit to your platform, like this (see
defines section):
[https://github.com/seletskiy/cve-2014-0038/commit/d8daf0ff41...](https://github.com/seletskiy/cve-2014-0038/commit/d8daf0ff41dfad72a0d59dcac4a61e8c2e291772)

Just patched it to 3.8 kernel and it works.

