I. Basics
1. What are LKMs
2. What are Syscalls
3. What is the Kernel-Symbol-Table
4. How to transform Kernel to User Space Memory
5. Ways to use user space like functions
6. List of daily needed Kernelspace Functions
7. What is the Kernel-Daemon
8. Creating your own Devices
II. Fun & Profit
1. How to intercept Syscalls
2. Interesting Syscalls to Intercept
III. Soltutions (for admins)
1. LKM Detector Theory & Ideas
IV. Some Better Ideas (for hackers)
1. Tricks to beat admin LKMs
2. Patching the whole kernel - or creating the Hacker-OS
V. The near future : Kernel 2.2
1. Main Difference for LKM writer's
VI. Last Words
1. The 'LKM story' or 'how to make a system plug & hack compatible'
2. Links to other Resources
Appendix
A - Source Codes
The use of Linux in server environments is growing from second to second. So
hacking Linux becomes more interesting every day. One of the best techniques to
attack a Linux system is using kernel code. Due to its feature called Loadable
Kernel Modules (LKMs) it is possible to write code running in kernel space, which
allows us to access very sensitive parts of the OS. There were some texts and
files concerning LKM hacking before (Phrack, for example) which were very good.
They introduced new ideas, new methodes and complete LKMs doing anything a
hacker ever dreamed of. Also some public discussion (Newsgroups, Mailinglists)
in 1998 were very interesting.
So why do I write again a text about LKMs. Well there are several reasons :
systemcall | description |
---|---|
int sys_brk(unsigned long new_brk); | changes the size of used DS (data segment) ->this systemcall will be discussed in I.4 |
int sys_fork(struct pt_regs regs); | systemcall for the well-know fork() function in user space |
int sys_getuid
() int sys_setuid (uid_t uid) ... |
systemcalls for managing UID etc. |
int sys_get_kernel_sysms(struct kernel_sym *table) | systemcall for accessing the kernel system table (-> I.3) |
int sys_sethostname
(char *name,
int len); int sys_gethostname (char *name, int len); |
sys_sethostname is responsible for setting the hostname, and sys_gethostname for retrieving it |
int sys_chdir
(const char *path); int sys_fchdir (unsigned int fd); |
both function are used for setting the current directory (cd ...) |
int sys_chmod
(const char
*filename, mode_t
mode); int sys_chown (const char *filename, mode_t mode); int sys_fchmod (unsigned int fildes, mode_t mode); int sys_fchown (unsigned int fildes, mode_t mode); |
functions for managing permissions and so on |
int sys_chroot (const char *filename); | sets root directory for calling process |
int sys_execve (struct pt_regs regs); | important systemcall -> it is responsible for executing file (pt_regs is the register stack) |
long sys_fcntl (unsigned int fd, unsigned int cmd, unsigned long arg); | changing characteristics of fd (opened file descr.) |
int sys_link
(const char *oldname,
const char *newname); int sym_link (const char *oldname, const char *newname); int sys_unlink (const char *name); |
systemcalls for hard- / softlinks management |
int sys_rename (const char *oldname, const char *newname); | file renaming |
int sys_rmdir
(const char* name); int sys_mkdir (const *char filename, int mode); |
creating & removing directories |
int sys_open
(const char *filename,
int mode); int sys_close (unsigned int fd); |
everything concering opening files (also creation), and also closing them |
int sys_read
(unsigned int fd,
char *buf, unsigned int
count); int sys_write (unsigned int fd, char *buf, unsigned int count); |
systemcalls for writing & reading from Files |
int sys_getdents (unsigned int fd, struct dirent *dirent, unsigned int count); | systemcall which retrievs file listing (ls ... command) |
int sys_readlink (const char *path, char *buf, int bufsize); | reading symbolic links |
int sys_selectt (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp); | multiplexing of I/O operations |
sys_socketcall (int call, unsigned long args); | socket functions |
unsigned long
sys_create_module
(char *name, unsigned
long size); int sys_delete_module (char *name); int sys_query_module (const char *name, int which, void *buf, size_t bufsize, size_t *ret); |
used for loading / unloading LKMs and querying |
function/macro | description |
---|---|
int sprintf
(char *buf,
const char *fmt,
...); int vsprintf (char *buf, const char *fmt, va_list args); |
functions for packing data into strings |
printk (...) | the same as printf in user space |
void *memset
(void *s, char c,
size_t count); void *memcpy (void *dest, const void *src, size_t count); char *bcopy (const char *src, char *dest, int count); void *memmove (void *dest, const void *src, size_t count); int memcmp (const void *cs, const void *ct, size_t count); void *memscan (void *addr, unsigned char c, size_t size); |
memory functions |
int register_symtab (struct symbol_table *intab); | see I.1 |
char *strcpy
(char *dest, const char
*src); char *strncpy (char *dest, const char *src, size_t count); char *strcat (char *dest, const char *src); char *strncat (char *dest, const char *src, size_t count); int strcmp (const char *cs, const char *ct); int strncmp (const char *cs,const char *ct, size_t count); char *strchr (const char *s, char c); size_t strlen (const char *s); size_t strnlen (const char *s, size_t count); size_t strspn (const char *s, const char *accept); char *strpbrk (const char *cs, const char *ct); char *strtok (char *s, const char *ct); |
string compare functions etc. |
unsigned long simple_strtoul (const char *cp, char **endp, unsigned int base); | converting strings to number |
get_user_byte
(addr); put_user_byte (x, addr); get_user_word (addr); put_user_word (x, addr); get_user_long (addr); put_user_long (x, addr); |
functions for accessing user memory |
suser(); fsuser(); |
checking for SuperUser rights |
int register_chrdev
(unsigned int major,
const char *name,
struct file_o perations
*fops); int unregister_chrdev (unsigned int major, const char *name); int register_blkdev (unsigned int major, const char *name, struct file_o perations *fops); int unregister_blkdev (unsigned int major, const char *name); |
functions which register device driver ..._chrdev -> character devices ..._blkdev -> block devices |
function | description | |
---|---|---|
int sprintf
(char *buf,
const char *fmt,
...); int vsprintf (char *buf, const char *fmt, va_list args); |
functions for packing data into strings | |
int request_module (const char *name); | says kerneld that the kernel requires a certain module (given a name or gerneric ID / name) | |
int release_module (const char* name, int waitflag); | unload a module | |
int delayed_release_module (const char *name); | delayed unload | |
int cancel_release_module (const char *name); | cancels a call of delayed_release_module | |
"This patch isn't really much of a patch. It simply bumps the securelevel up, to 1 from 0. This freezes the immutable and append-only bits on files, keeping anyone from changing them (from the normal chattr interface). Before turning this on, you should of course make certain key files immutable, and logfiles append-only. It is still possible to open the raw disk device, however. Your average cut and paste hacker will probably not know how to do this."Ok this one is really easy to implement as a LKM. We are lucky because the symbol responsible for the securelevel is public (see /proc/ksyms) so we can easily change it. I won't present an example for this bit of code, just import secure level and set it in the module's init function.
macro | description |
---|---|
EXPORT_NO_SYMBOLS; | this one is equal to register_symtab(NULL) for older kernel versions |
EXPORT_SYMTAB; | this one must be defined before linux/module.h if you want to export some symbols |
EXPORT_SYMBOL(name); | export the symbol named 'name' |
EXPORT_SYMBOL_NOVERS (name); | export without version information |
function | description |
---|---|
int access_ok (int type, unsigned long addr, unsigned long size); | this function checks whether the current process is allowed to access addr |
unsigned long copy_from_user (unsigned long to, unsigned long from, unsigned long len); | this is the 'new' memcpy_tofs function |
unsigned long copy_to_user (unsigned long to, unsigned long from, unsigned long len); | this is the counterpart of copy_from_user(...) |
[Books]
Linux-Kernel-Programming (Addison Wesley)
A very good book. I read the german version but I think there is also an english
version.
Linux Device Drivers (O'Reilly)
A bit off topic, but also very interesting. The focus is more on writing LKMs
as device drivers.
Thanks for sources / ideas fly to :
plaguez, Solar Designer, halflife, Michal Zalewski, Runar Jensen, Aleph1, Stealthf0rk/SVAT, FLoW/HISPAHACK, route, Andrew Tridgell, Silvio Cesare, daemon9, Nergal, van Hauser (especially for showing me some bugs) and those nameless individuals providing us with their ideas (there are so many) !
personal :
background music groups (helping me to concentrate on writing :):
Neuroactive, Image Transmission, Panic on the Titanic, Dracul
A - Appendix
Here you will find some sources.If the author of the LKM also published some
notes / texts which are interesting, they will also be printed.