slub allocator之kernel UAF
slub allocator之kernel UAFUAF 即 Use After Free,通常指的是对于释放后未重置的垂悬指针的利用,此前在用户态下的 heap 阶段对于 ptmalloc 的利用很多都是基于 UAF 漏洞进行进一步的利用。
在 CTF 当中,内核的 “堆内存” 主要指的是直接映射区(direct mapping area),常用的分配函数 kmalloc 从此处分配内存,常用的分配器为 slub,若是在 kernel 中存在着垂悬指针,我们同样可以以此完成对 slab/slub 内存分配器的利用,通过 Kernel UAF 完成提权。
内核堆利用与绑核slub allocator 会优先从当前核心的 kmem_cache_cpu 中进行内存分配,在多核架构下存在多个 kmem_cache_cpu ,由于进程调度算法会保持核心间的负载均衡,因此我们的 exp 进程可能会被在不同的核心上运行,这也就导致了利用过程中 kernel object 的分配有可能会来自不同的 kmem_cache_cpu ,这使得利用模型变得复杂,也降低了漏洞利用的成功率。
比如说 ...
Qemu 模拟环境
Qemu 模拟环境这一章节主要介绍如何使用 QEMU 来搭建调试分析环境。为了使用 qemu 启动和调试内核,我们需要内核、qemu、文件系统。
准备内核这个在之前已经编译完成了。
QEMU关于 QEMU 的介绍与安装请参考 ctf-tools。
文件系统这里我们使用 busybox 来构建一个简单的文件系统。
下载编译 busybox下载 BUSYBOX12❯ wget https://busybox.net/downloads/busybox-1.32.1.tar.bz2❯ tar -jxf busybox-1.32.1.tar.bz2
配置1❯ make menuconfig
在 Setttings 选中 Build static binary (no shared libs),将 busybox 编译为静态链接的文件;在 Linux System Utilities 中取消选中 Support mounting NFS file systems on Linux < 2.6.23 (NEW);在 Networking Utilities 中取消选中 inetd。
编译 ...
kernel的保护机制
kernel的保护机制前言我们从隔离、访问控制、异常检测、随机化这四种方式来介绍内核中的防御机制。
隔离在内核的防御机制中,根据隔离的主体,我们将隔离分为两种
内核态和用户态的隔离
内核自身内部不同对象间的隔离
内核态和用户态的隔离这里主要有
默认:用户态不可直接访问内核态的数据、执行内核态的代码
SMEP:内核态不可执行用户态的代码
SMAP:内核态不可访问用户态的数据
KPTI:用户态不可看到内核态的页表;内核态不可执行用户态的代码(模拟)
用户代码不可执行起初,在内核态执行代码时,可以直接执行用户态的代码。那如果攻击者控制了内核中的执行流,就可以执行处于用户态的代码。由于用户态的代码是攻击者可控的,所以更容易实施攻击。为了防范这种攻击,研究者提出当位于内核态时,不能执行用户态的代码。在 Linux 内核中,这个防御措施的实现是与指令集架构相关的。
x86 - SMEP - Supervisor Mode Execution Protectionx86 下对应的保护机制的名字为 SMEP。CR4 寄存器中的第 20 位用来标记是否开启 SMEP 保护。
开启
默认情况下, ...
缓冲区溢出原理
缓冲区溢出原理 缓冲区是程序运行时计算机内存中的一块连续的地址空间,它用于保存给定类型的数 据。在一些高级语言的函数调用中,缓冲区是在堆栈上进行分配的。堆栈是一个后进先出的 队列,它的生长方向与内存的生长方向正好相反。具体如图所示
在正常情况下,处理器在函数调用时,将函数的参数、返回地址(即进行函数调用的那 条指令的下一条指令的地址)及基址寄存器EBP(该寄存器存储的内存地址为函数在参数和 变量压栈之前的内存地址)压入堆栈中,然后把当前的栈指针(ESP)作为新的基地址。如果 函数有局部变量,则函数会把堆栈指针ESP 减去某个值,为需要的动态局部变量腾出所需的内存空间,函数内使用的缓冲区就分配在腾出的这段内存空间上。函数返回时,弹出EBP 恢复堆栈到函数调用前的地址,弹出返回地址到EIP 以继续执行原程序。假设程序从攻击者处接收一长度超过缓冲区长度的字符串, 则会出现安全漏洞。由于堆 栈的生长方向与内存的生长方向正好相反, 如果接收的是超长字符串,EBP 和EIP 的值就 有可能被覆盖。一般情况下,会导致程序运行失败,但如果覆盖EIP 的值刚好是攻击代码的 内存地址,从而 ...
漏洞利用开发--shellcode开发
漏洞利用开发–shellcode开发shellcode 的基本原理shellcode 通常使用机器语言编写,是一段用于利用软件漏洞而执行的代码。
shellcode根据它是让攻击者控制它所运行的机器,还是用过网络控制另一台机器,可以分为本地和远程两种类型。本地shellcode常用于提权,攻击者利用高权限程序中的漏洞(例如缓存区溢出),获得与目标进程相同的权限。远程shellcode则用于攻击网络上的另一台机器,通过TCP/IP套接字为攻击者提供shell访问。根据连接的方式不同,可以分为反向shell(由shellcode建立与攻击者机器的连接),绑定shell(shellcode绑定到端口,由攻击者发起连接)和套接字重用shell(重用exploit所建立的连接,从而绕过防火墙)。
有时候,攻击者注入目标进程中的字节数是被限制的,因此可以将shellcode分阶段执行,有前一段比较简短的shellcode将一阶段复杂的shellcode(或者可执行文件)下载并执行,这是恶意程序常见的一种操作。但有时候攻击者并不能确切的知道后一阶段的shellcode被加载到内存的哪个位置 ...
格式化字符串漏洞
格式化字符串漏洞初学pwn,学到了格式化字符串漏洞,总结一下。
格式化字符串函数:格式化字符串函数就是将计算机内存中表示的数据转化为我们人类可读的字符串格式。
漏洞printf(s)
用 printf() 为例,它的第一个参数就是格式化字符串 :”Color %s,Number %d,Float %4.2f”
然后 printf 函数会根据这个格式化字符串来解析对应的其他参数
%d - 十进制 - 输出十进制整数
%s - 字符串 - 从内存中读取字符串
%x - 十六进制 - 输出十六进制数
%c - 字符 - 输出字符
%p - 指针 - 指针地址
%n - 到目前为止所写的字符数
%hhn - 写1字节
%hn - 写2字节
%ln - 写4个字节
%lln - 写8字节
格式转换格式化字符串是由普通字符(包括%)和转换规则构成的字符序列。普通字符被原封不动地复制到输出流中。转换规则根据与实参对应的转换指示符对其进行转换,然后将结果写入到输出流中。
转换规则由可选的部分和必选部分组成。其中只有转换指示符type是必选部分,用来表示转换类型。
可选部分如下:
可 ...
格式化字符串在堆上的利用
格式化字符串在堆上的利用前言在面试星盟的时候,面试的师傅考到了这个问题。才明白过来,其实自己对于格式化字符串的理解还是太浅了。于是就按照书上的教程又学习了一下
格式化字符串不在栈上的利用方式所谓堆上的格式化字符串指的是格式化字符串本身存储在堆上,这个主要增加了我们获取对应偏移的难度,而一般来说,该格式化字符串都是很有可能被复制到栈上的。
本来一般的格式化字符串是可以通过栈的压栈传参来控制后面的数据,达到任意地址写和任意地址读的,但是在堆上的,我们便无法去控制这些数据
于是我们就有了新的利用方法,通过在栈上三重指针p1 -> p2 -> p3 , 通过p1 去控制p2 的指针,然后我们就可以通过p2的指针去控制p3的值,于是我们便可以在p3上写入地址,然后通过p3指针去修改值。
下面是书上的源文件
1234567891011121314151617181920212223242526272829303132333435#include<stdio.h>#include<unistd.h>void init(){ setbuf(stdi ...
栈溢出保护原理——Stack Canaries
栈溢出保护原理——Stack CanariesStack Canaries (取名自地下煤矿的金丝雀,因为它能比矿工更早地发现煤气泄露,有预警的作用)
是一种对抗栈溢出攻击的技术,即SSP安全机制
Canary的值是栈上的一个随机数,在程序启动时随机生成并保存在比函数返回地址更低的位置。由于栈溢出是从低地址向高地址进行覆盖,因此攻击者要想控制函数的返回指针,就一定要先覆盖到Canary。程序只需要在函数返回前检查Canary是否被篡改,就可以达到保护栈的目的。
一,Canaries的分类canaries 通常可分为3类:terminator,random 和random XOR,具体的实现有StackGuard,StackShield,proPoliced等。
Terminator canaries:由于许多栈溢出都是由于字符串操作(如strcpy)不当所产生的,而这些字符串由NULL“\x00”结尾,换个角度看就是会被“\x00”所截断。基于这一点,terminator canaries将低位设置为“\x00”,既可以防止被泄露,也可以防止被伪造,截断字符还包括CR(0x0d ...
条件竞争的利用
条件竞争的利用构造例子源代码源代码如下
已复制
12345678910111213141516171819202122232425262728293031323334353637383940414243444546#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <unistd.h>void showflag() { system("cat flag"); }void vuln(char *file, char *buf) { int number; int index = 0; int fd = open(file, O_RDONLY); if (fd == -1) { perror("open file failed!!"); return; } ...
条件竞争漏洞复现(Race Condition)
条件竞争漏洞复现(Race Condition)0x00概述条件竞争是指一个系统的运行结果依赖于不受控制的事件的先后顺序。当这些不受控制的事情没有按照开发者想要的方式运行时,就可能出现bug。这个术语最初来自两个电信号相互竞争来影响输出结果。
条件竞争主要出现在如下领域
电子系统,尤其是逻辑电路
计算机,尤其是多线程程序和分布式程序
由于目前的系统中大量采用并发编程,经常对资源进行共享,往往会产生条件竞争漏洞。
这里我们主要考虑计算机程序方面的条件竞争。当一个软件的运行结果依赖于进程或线程的顺序时,就可能会出现条件竞争。简单考虑一下,就可以知道条件竞争需要如下条件:
并发,即至少存在两个并发执行流。这里的执行流包括线程,进程,任务等级别的执行流。
共享对象,即多个并发流会访问同一个对象。常见的共享对象有共享内存,文件系统,信号。一般来说,这些共享对象是用来使得多个程序执行流相互交流。此外,我们称共享对象的代码为 临界区。在正常写代码时,这部分应该加锁。
改变对象,即至少有一个控制流会改变竞争对象的状态。因为如果程序只是对对象进行读操作,
由于在并发时,执行流的不确定性很大,条 ...