Gl.ib.ly

(glibly); Just another techie blog.

Adding a malicious system call to the Linux kernel

Posted by Tariq • Thursday, December 11. 2008 • Category: Security
Today I am adding a malicious system call to the Linux kernel which will allow the caller to do something they cannot normally do in user mode. When attacking a Linux box our goal is usually to become root; as root we can do anything we like, so the system call I will add to the Linux kernel gives the caller real and effective user ids of zero.

There are relatively few tutorials out there on how to do this, unfortunately there a little differences between versions of Linux that can easily stump beginners, so this tutorial tries to give you an environment which you can easily replicate using a virtual machine and go through the tutorial.


The System


In this tutorial I use Microsoft® Virtual PC 6.0.156.0 which is free and easily available to windows users. I'd highly recommend VirtualBox which I use more often. My virtual machine had Virtual Hard Disk of 4GB and 512mb of RAM. The OS used was OpenSuse 10.2 (x86)
YaST Control Center: Selecting Software Management
Look for the following on the web:
  • openSUSE-10.2-GM-i386-CD1.iso
  • openSUSE-10.2-GM-i386-CD2.iso
  • openSUSE-10.2-GM-i386-CD3.iso
  • openSUSE-10.2-GM-i386-CD4.iso
  • openSUSE-10.2-GM-i386-CD5.iso

  • Once fully installed su to the root account (simply type su at the console) and enter your root password. Then type yast and hit enter.

    Enter Software Management as there is a good few packages we need, namely: gcc, gdb, make, automake, autoconf, kernel-source. Add these packages by searching for them, checking them and then installing them.

    I have also read a suggestion that ArchLinux is a good no nonsense distro which is good for getting your hands dirty. I haven't used it yet but it sounds like it is worth looking into.


Adding the System Call


After installing kernel-source, the kernel sources should be available at /usr/src/. Inside this directory there should be symbolic link called linux to whichever sources where installed, in my case I had the following:
Listing the contents of the /usr/src directory.
You might notice linux-2.6.18.2-34_orig from the ls above, this is just a copy of the original sources before I started editing them; also, the packages directory is created during the make process.

Get yourself into /usr/src/linux and let’s get editing >;-D. All paths given below are relative to this directory.
  1. Create the file kernel/rootkit.h and paste in the code from the rootkit.h part of the appendix.
  2. Create the file kernel/rootkit.c and paste in the code from the rootkit.c part of the appendix.
  3. Open arch/i386/kernel/syscall.S and add the following to the end:
    .long sys_rootkit

    As you may have guessed my new system call is going to be called rootkit -- as it will give us root on the affected box; while this is all nice dandy for our purposes, rootkits should be a great deal stealthier .
  4. Open kernel/Makefile and add the following to the right hand side of “obj-i =”:
    rootkit.o
  5. Open include/asm/unistd.h. You should see many lines of the format #define __NR_ , scroll to the last such line and add the following:
    #define __NR_rootkit 318
  6. The number on the right (above) should be one greater than the number on the preceding line, in my case this was 318. In addition we must also edit the system call counter to reflect there being one more system call. This should be located a couple of lines below your new line. It should now read:
    #define NR_systemcalls 319
  7. Copy the configuration file for the existing kernel (as we know it works) by entering cp /boot/config-`uname –r`./.config at the command prompt, to our source directory.
  8. Type make menuconfig, this will bring up a console configuration menu. Select Load an alternative file and confirm the usage of the .config file. I like to edit General Settings -> Local Version to read rootkit, just so I don’t forget what this kernel contains!
  9. Type make rpm and hit return to kick off compilation. This process can take a long time, typically 15-20 minutes.
  10. When compilation has finished do the following:
    Shows our kernel image in the /usr/src/packages/RPMS/i386 directory
    Brilliant! Our kernel rpm is good to go, for this system and others ! Let’s install the kernel by typing rpm -ivh kernel-2.6.18.234rootkit-1.i386.rpm (use the --force option for subsequent installations on the same system, for which you can omit all later steps).Shows output of rpm -ivh kernel-2.6.18.234rootkit-1.i386.rpm
  11. Next we need to create a ramdisk for our new kernel, otherwise we may run into boot problems. Do this my typing mkinitrd at the prompt and hitting return.
  12. Start yast and follow the screen shots.
    YaST Control Center: Selecting Boot Loader

    YaST Control Center: Selecting Boot Loader -> Add

    YaST Control Center: Selecting Boot Loader -> Section Management -> Clone Selected Section -> Next

    YaST Control Center: Selecting Boot Loader -> Section Management -> Section Editor -> Modify
    Select correct Kernel image and Initial RAM disk and hit OK.
    YaST Control Center: Boot Loader -> Modify
    Move our Rootkit version to the top and set as the default boot option. Then exit yast and type shutdown -r now!

  13. You should be greeted by the following on reboot.OpenSuSE 10.2 Startup Options
  14. When the system has fully loaded, open up a terminal and the following:
    Running uname -rThis confirms that our new kernel is in action!


  15. Using the System call


    1. I like everything in userland to reflect the changes in the kernel. To do this open up /usr/include/asm/unistd.h (you will need to be root) and edit as we did in step 5 of Adding the System Call. Also, open up /usr/include/bits/syscall.h and add the following line wherever you want.

      #define SYS_rootkit __NR_rootkit
    2. Login as a non privileged user, create a myprog.c file in your home directory and paste in the contents of the myprog.c section in the appendix.
    3. Compile the program by typing in gcc myprog.c. This will create an executable file called a.out.
    4. Execute a.out by typing ./a.out at the prompt. If everything goes well you should see the following.
      Dmesg output from our system call

      To see some further debugging output type dmesg | less at a prompt. You’ll get something like this at the end:
      Dmesg output from our system call


    Appendix


    System Call


    Most accurate source is available at http://gist.github.com/163266.

    rootkit.h



    rootkit.c



    Userland Program

    myprog.c



    Please note the #define above. Many HOWTOs on the net state that you should use _syscall2(int, rootkit, ...); to establish the rootkit macro; however, all of these _syscall (...) have been moved to kernel only spaces (older kernels are not affected). From now on you should use syscall (type man syscall at a prompt for further info).
Vote for articles fresher than 90 days!
Current karma: 4.73 of 5, 11 vote(s) 18556 hits
Bookmark Adding a malicious system call to the Linux kernel  at del.icio.us Digg Adding a malicious system call to the Linux kernel Bloglines Adding a malicious system call to the Linux kernel Technorati Adding a malicious system call to the Linux kernel Fark this: Adding a malicious system call to the Linux kernel Bookmark Adding a malicious system call to the Linux kernel  at YahooMyWeb Bookmark Adding a malicious system call to the Linux kernel  at Furl.net Bookmark Adding a malicious system call to the Linux kernel  at blogmarks Stumble It!

0 Trackbacks

  1. No Trackbacks

2 Comments

Display comments as (Linear | Threaded)
  1. Nice article! One thing though, there is an unused parameter, mode, in rootkit.c's sys_rootkit function.
  2. Thanks, and well caught!

    I removed a good bit of the code before posting. My system call could do a good few extra tricks. Also, if you're going to experiment you may want to stick debugging output everywhere, recompiling the kernel because a function is not returning what you expected is a real pain ... eh, I mean fun.

Add Comment


Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

You can use [geshi lang=lang_name [,ln={y|n}]][/geshi] tags to embed source code snippets.