Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LKRG immunity module & kernel vaccination #150

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
.tmp_versions
Module.symvers
modules.order
*.mod
*.dwo
*.cmd
*.ko
*.mod.c
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ $(TARGET)-objs += src/modules/ksyms/p_resolve_ksym.o \
src/modules/exploit_detection/syscalls/p_scm_send/p_scm_send.o \
src/modules/exploit_detection/p_selinux_state.o \
src/modules/exploit_detection/p_exploit_detection.o \
src/modules/immunity/p_immunity.o \
src/p_lkrg_main.o


Expand Down
4 changes: 4 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ The sysctl's are (with default values specified in braces):
Please note that LKRG can be easily detected by other means anyway, such as
through the presence of its sysctl's.

- lkrg.vaccinate (1)
Whether or not LKRG should try to immunize the kernel to obstruct its version
detection. Allowed values are 0 and 1.

- lkrg.kint_validate (3)
Whether and when to validate global kernel integrity. Allowed values are 0
(disabled), 1 (only when manually triggered by lkrg.trigger), 2 (also
Expand Down
37 changes: 37 additions & 0 deletions src/modules/comm_channel/p_comm_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ static int p_hide_lkrg_min = 0;
static int p_hide_lkrg_max = 1;
#endif

static int p_vaccinate_min = 0;
static int p_vaccinate_max = 1;

static int p_heartbeat_min = 0;
static int p_heartbeat_max = 1;

Expand Down Expand Up @@ -109,6 +112,8 @@ static int p_sysctl_trigger(struct ctl_table *p_table, int p_write,
static int p_sysctl_hide(struct ctl_table *p_table, int p_write,
void __user *p_buffer, size_t *p_len, loff_t *p_pos);
#endif
static int p_sysctl_vaccinate(struct ctl_table *p_table, int p_write,
void __user *p_buffer, size_t *p_len, loff_t *p_pos);
static int p_sysctl_heartbeat(struct ctl_table *p_table, int p_write,
void __user *p_buffer, size_t *p_len, loff_t *p_pos);
#if defined(CONFIG_X86)
Expand Down Expand Up @@ -137,6 +142,7 @@ static int p_sysctl_profile_enforce(struct ctl_table *p_table, int p_write,
void __user *p_buffer, size_t *p_len, loff_t *p_pos);



struct ctl_table p_lkrg_sysctl_base[] = {
{
.procname = "lkrg",
Expand Down Expand Up @@ -230,6 +236,15 @@ struct ctl_table p_lkrg_sysctl_table[] = {
.extra2 = &p_hide_lkrg_max,
},
#endif
{
.procname = "vaccinate",
.data = &P_CTRL(p_vaccinate),
.maxlen = sizeof(unsigned int),
.mode = 0600,
.proc_handler = p_sysctl_vaccinate,
.extra1 = &p_vaccinate_min,
.extra2 = &p_vaccinate_max,
},
{
.procname = "heartbeat",
.data = &P_CTRL(p_heartbeat),
Expand Down Expand Up @@ -587,6 +602,28 @@ static int p_sysctl_hide(struct ctl_table *p_table, int p_write,
}
#endif

static int p_sysctl_vaccinate(struct ctl_table *p_table, int p_write,
void __user *p_buffer, size_t *p_len, loff_t *p_pos) {

int p_ret;
unsigned int p_tmp;

p_tmp = P_CTRL(p_vaccinate);
p_lkrg_open_rw();
if ( (p_ret = proc_dointvec_minmax(p_table, p_write, p_buffer, p_len, p_pos)) == 0 && p_write) {
if (P_CTRL(p_vaccinate)) {
P_CTRL(p_vaccinate) = p_tmp; // Restore previous state - for sync
p_vaccinate(); // vaccinate kernel!
} else {
P_CTRL(p_vaccinate) = p_tmp; // Restore previous state - for sync
p_devaccinate(); // devaccinate kernel!
}
}
p_lkrg_close_rw();

return p_ret;
}

static int p_sysctl_heartbeat(struct ctl_table *p_table, int p_write,
void __user *p_buffer, size_t *p_len, loff_t *p_pos) {

Expand Down
92 changes: 92 additions & 0 deletions src/modules/immunity/p_immunity.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* pi3's Linux kernel Runtime Guard
*
* Component:
* - (Un)Immunization module
*
* Notes:
* - Gives kernel a dose of vaccine
*
* Timeline:
* - Created: 20.I.2022
*
* Author:
* - Ilya 'milabs' Matveychikov (https://github.com/milabs)
*
*/

#include "../../p_lkrg_main.h"

static struct {
const char * name;
struct path path;
umode_t mode;
} p_paths_to_fix[] = {
{ "/boot" },
{ "/lib/modules" },
};

static void *p__cmdline_proc_show = NULL;
static void *p__saved_command_line = NULL;

static int p_cmdline_proc_show(struct seq_file *m, void *v) {
if (uid_eq(current_cred()->uid, GLOBAL_ROOT_UID)) {
seq_puts(m, *(char **)p__saved_command_line);
} else {
seq_puts(m, "ro");
}
seq_putc(m, '\n');
return 0;
}

void p_vaccinate(void) {
int i;

for (i = 0; i < ARRAY_SIZE(p_paths_to_fix); i++) {
if (!p_paths_to_fix[i].name)
continue;
if (kern_path(p_paths_to_fix[i].name, LOOKUP_FOLLOW, &p_paths_to_fix[i].path)) {
p_print_log(P_LKRG_WARN,
"Unable to fix path %s\n", p_paths_to_fix[i].name);
p_paths_to_fix[i].name = NULL;
} else {
p_paths_to_fix[i].mode = p_paths_to_fix[i].path.dentry->d_inode->i_mode;
p_paths_to_fix[i].path.dentry->d_inode->i_mode &= 077700;
}
}

/* FIXME: lookup /proc/cmdline dentry & replace show callback */

p__cmdline_proc_show = p__cmdline_proc_show ?:
(void *)P_SYM(p_kallsyms_lookup_name)("cmdline_proc_show");
p__saved_command_line = p__saved_command_line ?:
(void *)P_SYM(p_kallsyms_lookup_name)("saved_command_line");

if (p__cmdline_proc_show &&
p__saved_command_line) {
remove_proc_entry("cmdline", NULL);
proc_create_single("cmdline", 0, NULL, p_cmdline_proc_show);
} else {
p_print_log(P_LKRG_WARN,
"Unable to forge /proc/cmdline");
}

/* TODO: forge utsname */
}

void p_devaccinate(void) {
int i;

for (i = 0; i < ARRAY_SIZE(p_paths_to_fix); i++) {
if (!p_paths_to_fix[i].name)
continue;
p_paths_to_fix[i].path.dentry->d_inode->i_mode = p_paths_to_fix[i].mode;
path_put(&p_paths_to_fix[i].path);
}

if (p__cmdline_proc_show &&
p__saved_command_line) {
remove_proc_entry("cmdline", NULL);
proc_create_single("cmdline", 0, NULL, p__cmdline_proc_show);
}
}
24 changes: 24 additions & 0 deletions src/modules/immunity/p_immunity.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* pi3's Linux kernel Runtime Guard
*
* Component:
* - (Un)Immunization module
*
* Notes:
* - Gives kernel a dose of vaccine
*
* Timeline:
* - Created: 20.I.2022
*
* Author:
* - Ilya 'milabs' Matveychikov (https://github.com/milabs)
*
*/

#ifndef P_LKRG_IMMUNITY_MODULE_H
#define P_LKRG_IMMUNITY_MODULE_H

void p_vaccinate(void);
void p_devaccinate(void);

#endif
7 changes: 7 additions & 0 deletions src/p_lkrg_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ p_ro_page p_ro __p_lkrg_read_only = {
.p_log_level = 3, // log_level
.p_trigger = 0, // trigger
.p_block_modules = 0, // block_modules
.p_vaccinate = 1, // vaccinate
.p_hide_lkrg = 0, // hide_lkrg
.p_heartbeat = 0, // heartbeat
#if defined(CONFIG_X86)
Expand Down Expand Up @@ -636,6 +637,10 @@ static int __init p_lkrg_register(void) {
goto p_main_error;
}

if (P_CTRL(p_vaccinate)) {
p_vaccinate();
}

if (P_CTRL(p_hide_lkrg)) {
p_hide_itself();
}
Expand Down Expand Up @@ -722,6 +727,8 @@ static void __exit p_lkrg_deregister(void) {

p_deregister_comm_channel();

p_devaccinate();

#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
unregister_hotcpu_notifier(&p_cpu_notifier);
Expand Down
3 changes: 3 additions & 0 deletions src/p_lkrg_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <linux/cpu.h>
#include <linux/random.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/version.h>
#include <linux/cpufreq.h>
Expand Down Expand Up @@ -157,6 +158,7 @@ typedef struct _p_lkrg_global_conf_structure {
unsigned int p_pint_enforce;
unsigned int p_kint_enforce;
unsigned int p_trigger;
unsigned int p_vaccinate;
unsigned int p_hide_lkrg;
unsigned int p_umh_enforce;
/* Profiles */
Expand Down Expand Up @@ -376,6 +378,7 @@ static inline int p_lkrg_counter_lock_val_read(p_lkrg_counter_lock *p_arg) {
#include "modules/integrity_timer/p_integrity_timer.h" // Integrity timer module
#include "modules/kmod/p_kmod.h" // Kernel's modules module
#include "modules/notifiers/p_notifiers.h" // Notifiers module
#include "modules/immunity/p_immunity.h" // Immunity module
#include "modules/self-defense/hiding/p_hiding.h" // Hiding module
#include "modules/exploit_detection/p_exploit_detection.h" // Exploit Detection
#include "modules/wrap/p_struct_wrap.h" // Wrapping module
Expand Down