DR Linux 2.6 rootkit released

From: Bas Alberts <bas.alberts-AT-immunityinc.com> To: dailydave-AT-lists.immunitysec.com Subject: DR Linux 2.6 rootkit released Date: Wed, 03 Sep 2008 16:32:54 -0400 Message-ID: <48BEF476.6040103@immunityinc.com> Archive-link: Article, Thread

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 All, Immunity is releasing the DR Linux 2.6 IA32 rootkit under the GPLv2. It is supported by CANVAS (and is thus commercially supported for your penetration-testing needs) but is suitable for standalone use. Currently the rootkit can: o Hide processes o Hide network sockets o Hide files o Get a remote MOSDEF Node (via hidden userland-backdoor) The major benefit of the DR rootkit is that all this happens transparently to the end user. The children of a hidden process are also automatically hidden. The sockets a hidden process creates are also hidden. But if you are a hidden process, you can see hidden resources. This makes the DR rootkit nicely manageable. DR loads via insmod - we've tested the rootkit on a number of Linux distributions including CentOS and Ubuntu. The CANVAS support and backdoor logic were written by Daniel Palacio during his Immunity summer internship. He provided both the kernel hooks and the userland backdoor to the project. The rootkit engine (DR.c) was written by Bas Alberts and consists of a debug register based hooking engine that does not modify the IDT or syscall table at all. It was written as a reference implementation for people wanting to experiment with such a rootkit technology, and was designed to be able to integrate easily into existing syscall hook based rootkits. It has known limitations and considerations which you can read about in the attached README. You can find the source to the DR rootkit at: URL: http://www.immunityinc.com/downloads/linux_rootkit_source... MD5SUM: 1256523fa8a87949c5e588c981108ee8 Any questions or ideas for this project can be sent to DD or your friendly neighborhood CANVAS support address! (support@immunityinc.com) Thanks, Team Immunity Debug Register Rootkit 0.1 - reference implementation ===================================================== About ===== DR features a reference implementation of a IA32 debug register based rootkit hooking engine. It does not modify IDT or syscall_table at all but still provides transparent syscall hooking on IA32 Linux 2.6. Features ======== SystemCall hooking without modifying IDT, or syscall_table, at all. Not even for a milisecond(tm). Using hardware execute and read breakpoints. Details ======= DR places a hardware breakpoint on the syscall handler, and the resulting trap places a memory watch on the syscall_table entry for the __NR_syscall of the intercepted syscall. It does this for both INT 0x80 and sysenter based system calls. When the memory watch for the syscall_table entry kicks in, the trap handler then redirects execution for that syscall to a syscall hook. Example Flow ============ Execute global breakpoint on syscall handler in dr0, syscall is called, breakpoint kicks in. Modified do_debug handler places global read watch on syscall_table[__NR_syscall]. When syscall is called, memory access breakpoint kicks in. Modified do_debug handler places function pointer to hooked syscall in task regs eip. Execution is redirected to hooked syscall. Repeat. [ 864.447800] ******* LOADING IA32 DR HOOKING ENGINE ******* [ 864.447868] *** loader: handler for INT 128: C0104210 [ 864.447923] *** loader: syscall_table: C02FC540 [ 864.447934] *** loader: syscall_call call *table(,eax,4): C010424B [ 864.447952] *** loader: handler for INT 1: C02F4360 [ 864.448085] *** loader: INT 1 handler patched to use __my_do_debug [ 864.448165] *** loader: initialized hook_table [ 864.448199] *** loader: systenter_entry call *table(,eax,4): C01041CB [ 871.592214] *** dr0/dr1 trap: setting read watch on syscall_NR of 220 at C02FC8B0 [ 871.598191] *** got dr2 trap (syscall_table watch) [ 871.598723] *** hooked __NR_220 to E0AC7350 Using the memory watch approach, one does not have to modify IDT or syscall_table ever. This is an original approach, but considering we _are_ the debugger .. one could dream up a million other viable and fruitful solutions to non-memory modifying DR rootkits. Limitations =========== This is a reference implementation. A lot more can be done to actually be hidden. Production code will include kmalloc based non-LKM code handling. Full Global Detect debug register access detection support, and additional memory watching for the debug ENTRY call offset patch. Additional testing is required to check for scheduler issues and other racy problems. This reference implementation is intended as a case study into the general rootkit approach now that the cat is out of the bag. The provided example hooks serve as a basic example rootkit known to suffer the following limitations: Detection ========= In it's current form there is no prevention of someone else accessing the debug registers. This could be easily added with GD access flag control, however this is left as an exercise to the reader. Furthermore this module behaves like a normal LKM in that is has symbols and is resident in memory like a normal LKM. This can be bypassed by porting the module init to a kmalloc based loading logic. To be added in v0.2. - - Detection via module based symbols - - Detection via granted access to hardware debug registers - - Detection via timing logic - - Detection via open("/proc/hiddenpid/stat"); success Adding/Changing hooks ===================== All hooks are defined in hooktable.h. A good example template is the hook_example_exit function. Once a hook is added to the global hook table, it will be automagically used by the hooking engine. 10 asmlinkage static void hook_example_exit(int status); ... 149 asmlinkage /* required: args passed on stack to syscall */ 150 static void hook_example_exit(int status) 151 { 152 /* standard hook prologue */ 153 asmlinkage int (*orig_exit)(int status); 154 void **sys_p = (void **)sys_table_global; 155 orig_exit = (int (*)())sys_p[__NR_exit]; ... 167 else 168 return orig_exit(status); 169 } You then initialize this function in the global hook_table as such: 121 hook_table[__NR_exit] = (void *)hook_example_exit; The hooking engine was designed to be very friendly and open to modification/extension. It was designed to provide a more current hooking engine for existing sycall_table based rootkit logic. All rootkit specific logic lives in hooktable.h. Todo ==== - - move to kmalloc based init loader, -EINVAL return - - improve hooks to do proper '/proc' and getdents handling - - move /proc handling to inode based checks - - instruction emulation for outside debug register access GD stylee Credits ======= The debug register based hooking engine was written by Bas Alberts, all additional hooks contained in hooktable.h, besides the example hook_exit were written by Daniel Palacio. References ========== 1) The IA32 Software Developers Manual Vol. 3B, Chapter 18 2) Mistifying the debugger, Phrack 65-8, halfdead License ======= GPLv2 Contact ======= bas.alberts@immunityinc.com / support@immunityinc.com -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFIvvR2LpdA2Ju9tfcRAvVmAJ41wqdf6AFpI1RDEjkf+gA3v9Zd5gCgg3C5 cV6vD5lSvq1hjX64ElgjVSE= =82MQ -----END PGP SIGNATURE-----