0


渗透测试之内核安全系列课程:Rootkit技术初探(一)

今天,我们来讲一下内核安全!

本文章仅提供学习,切勿将其用于不法手段!

目前,在渗透测试领域,主要分为了两个发展方向,分别为Web攻防领域和PWN(二进制安全)攻防领域。在PWN的二进制领域,免杀技术,一直是后渗透利用阶段的重要安全技术之一。

想要免杀,需要了解的安全技术知识包括软件加壳、代码混淆(例如,使用花指令)、隐匿技术(例如,Rootkit技术)、动态加密等内容。

今天,我们主要讲一下,Rootkit 技术 !

Rootkit 是一种隐匿网络攻击的新技术!

Rootkit 通过修改 操作系统内核 或 更改指令执行路径 ,来隐藏系统对象(包括文件、进程、驱动、注册表项、开放端口、网络连接等),以逃避(或者说是,规避)标准系统机制的程序。

Rootkit 也是一种软件,只不过,是一种比较特殊的软件!

利用 Rootkit 技术,编写而成的 Rootkit 程序,一般情况下,都可以被称之为是 Rootkit 软件。

Rootkit 软件的开发者,可以借助于 Rookit 隐遁技术,在 渗透测试行为 的 后渗透阶段,对已被渗透的目标网络系统 进行 更深一层的 渗透测试行为!

由于 Rootkit 技术的 高隐匿特性,一般的 安全防护手段,可能难以对其进行有效防御和行为拦截!

很多能力较强的渗透测试工程师,会使用 Rootkit 隐匿攻击技术,去逃避安全检测和渗透行为取证!

由于 Windows 系列操作系统,在一些地区的拥有较高的市场份额占有率,因此,我们也主要来讨论 Rootkit 技术 在 Windows 系统环境中的技术实现,以及与之相对应的安全检测手段1

Rootkit 的 中文翻译为 : 恶意获取管理员特权的工具!

利用 Rootkit 技术,渗透测试工程师,往往可以在 靶机系统管理员 毫不知情的情况下,悄悄获取目标靶机的控制权!

Rootkit 的 核心特性,即为 高隐匿特性 !使用 Rootkit 技术编写的远程控制程序,可以避开大部分 安全软件 或 杀毒软件 的安全检测,有效突破靶机的防御环境!

Rootkit 技术,为什么强大呢?

Rootkit 软件,一般工作在 R0 层 !

注意,很多安全软件,也是运行于 R0 层!

所以,这意味着,Rootkit 软件 和 安全软件 工作于同一层次!它们,对于操作系统内核而言,具备同等的操作权限!无论是 Rootkit 软件,还是 其它 杀毒软件,想要驻留在内核层!就必须要注册成为 驱动程序!什么是驱动程序呢?简单点说,在Windows 系列的操作系统环境中,就是文件扩展名以 .sys 结尾的那些文件!

想要编写 Rootkit 软件,想要开发针对 Rootkit 软件的检测程序,我们就必须要学会编写驱动程序!也就是说,我们必须要学会内核编程!

想要进行内核编程!我们需要知道,什么是特权指令!

注意,内核级的软件程序,是可以访问所有内存地址空间的!

这意味着,内核级的软件,可以读写任意地址空间中的数据内容!

这才是内核编程的巨大魅力所在!

我们来科普一下,比较重要的操作系统内核级编程,需要用到的相关知识!

我们要知道 物理内存分段 和 编址机制 !

学习操作系统内核编程,我们一定要首先学会 汇编语言!

如果你接触过 汇编语言 ,你会知道,汇编语言中,存在 段 和 物理内存地址的概念!

在 汇编语言 的程序设计领域中,存在 实模式 编程 和 保护模式 编程 的区别!

在 操作系统的实模式环境下,内存地址 等于 内存物理地址!

在 操作系统的保护模式下,内存地址 等于 线性虚拟地址!

注意:线性虚拟地址 体现了 操作系统 对于 物理内存地址 的保护作用!

在操作系统的实模式环境下,一个汇编语言编写的程序,通常分为 代码段 ( .text )、数据段( .data )、栈段( .stack )等 实模式 下的物理内存分段!

在操作系统的保护模式环境下,一个汇编语言编写的程序,通常分为 代码段 ( .text .plt )、数据段( .data .rodata .bss .got )、栈段( .stack )等 保护模式 下的物理内存分段!

有些童鞋儿说,LINUX 和 WINDOWS 的 保护模式 的 汇编源码中,是没有栈段(.stack)的,但我想说,不要被现有系统的设计局限住,只要CPU的技术体系支持,那么一切能够实现的,应该实现的,还是要去实现它。虽然在 WINDOWS 和 LINUX 源代码中没有对于栈段的定义,但是在程序载入内存,形成进程之后,栈段(.stack)是真实存在的!也许栈段(.stack)是由操作系统自动创建的,但是,那也意味着,栈段,是真实存在的!

对于保护模式下的线性虚拟地址而言,涉及到的知识点,包括 GDT(全局描述符表)、LDT(本地描述符表)、PD(页目录表)、IDT(中断描述符表)、SSDT(系统服务描述表)、IRP(I O 操作调度表)等!

下面,我们就来讲解一下,这些基础知识内容!

对于这些知识的透彻理解,是进行操作系统内核编程的基础!

下面,我们 以 32 位 操作系统 为例,进行相关知识点的内容讲解(向下兼容的特性需求)!

我们所编写的程序,应该是在 32位系统 和 64位系统 中,都能够正常运行的!

说到 GDT 全局描述符表,我们就必须要提一下,GDTR 全局描述符表寄存器 !

在 实模式环境下,CS 寄存器,存储 CS 段( .text 代码段)的 起始地址!

在 实模式环境下,DS 寄存器,存储 DS 段( .data 数据段)的 起始地址!

在 实模式环境下,SS 寄存器,存储 SS 段( .stack 栈段)的 起始地址!

我们需要知道 段寄存器(CS、DS、SS、ES、FS) 的存储空间,都是 16 位的 !

在 实模式环境下,段地址是20位的!而段寄存器只能存储16位大小的数据!

在 实模式环境 下,段地址 = 段寄存器内容 乘以 16 !段地址的最后一位,一定是 0 !

在 实模式环境 下,内存物理地址 = 段地址 + 偏移地址!

注意,代码段 的 偏移地址,存储在 IP 寄存器中!在无跳转的情况下,IP寄存器的值,向上递增!

但是!在有跳转的情况下,例如、JMP指令、CALL 、RET 等 指令,都可以改变IP寄存器的值 !

在 JMP、CALL、RET 等跳转指令的影响下,IP寄存器的值,并不一定是一直递增的!IP寄存器的值 是进行 增加操作,还是进行减少操作,取决于 跳转指令 所指向的 内存地址 比IP寄存器中的当前值,是大,还是小!如果是大,执行的就是增加操作!如果是小,执行的就是减少操作 !

注意,栈段 的 偏移地址,存储在 SP 寄存器中!在数据入栈的时,SP寄存器的值,向下递减!

注意,栈段 的 偏移地址,存储在 SP 寄存器中!在数据出栈的时,SP寄存器的值,向上递增!

对于栈段的操作,主要使用 PUSH 数据入栈指令 和 POP 数据出栈指令。

PUSH 数据入栈指令,等同于 首先 SUB SP , 2 ,然后 MOV SS : [ SP ] , DATA 。

PUSH 数据出栈指令,等同于 首先 MOV [ DATA ADDR ] , SS : [ SP ] , 然后 ADD SP , 2 。

PUSH 数据入栈指令,等同于 首先 SUB ESP , 4 ,然后 MOV SS : [ SP ] , DATA 。

PUSH 数据出栈指令,等同于 首先 MOV [ DATA ADDR ] , SS : [ ESP ] , 然后 ADD ESP , 4 。

PUSH 数据入栈指令,等同于 首先 SUB RSP , 8 ,然后 MOV SS : [ RSP ] , DATA 。

PUSH 数据出栈指令,等同于 首先 MOV [ DATA ADDR ] , SS : [ RSP ] , 然后 ADD SP , 8 。

SUB 指令,是 递减指令,ADD 指令,是 递增指令!

话题,回到 GDTR 全局描述符表 寄存器上来!

在 保护模式环境 下,CS、DS、SS 、ES、FS 等段寄存器中,不再存储 段地址 数据 !

在 保护模式环境 下,CS、DS、SS 、ES、FS 等段寄存器中,被用于存储各自段的 “ 段选择子 ” 内容 !那么,什么是 “ 段选择子 ” 呢?说到 “ 段选择子 ”,我们就必须要提一下,段描述符表!

在 保护模式环境 下,段寄存器,也叫做 “ 段选择器 ”,段选择器 中存储的 “ 段选择子 ” 存储着 段描述符表 中各子项(段描述符)所对应的索引信息、段选择子 的 请求特权级( RPL )信息、段选择子 的 表指示位( TI )信息 !

注意,本章中的 比特位排序,是从 数字 1 开始计算的,第N位 对应的 比特位索引 为 第N位 - 1 。

注意,本章中的 字节排序,是从 数字 1 开始计算的,第N个字节 对应的 字节索引 为 第N位 - 1 。

什么是 ” 段选择子 ” 呢?段选择器(保护模式下的段寄存器)的内容值,就是段选择子!

在 段选择器 中,段选择子的 高13位,是指向 段描述符表 中 对应着 段描述符 的 段描述表子项 的 相应 索引 信息!

在 段选择器 中,段选择子的 第1-2位 共同代表当前 段选择子 的 RPL 优先级( 0、1、2、3,数字越大,权限越小)!RPL 优先级,主要被用于进行特权检查!RPL 优先级,决定了段描述符是否能够被成功使用!注意,使用 段描述符,是需要权限的,而 RPL 优先级,则对应了相关的使用权限!

在 段选择器 中,段选择子 的 第3位,代表段描述符的所在位置,值为 0 ,代表 段描述符 在 GDT 全局描述符表中,值为 1 ,代表 段描述符 在 LDT 本地描述符表中!

注意,段描述符表的各子项内容,即为 段描述符 !段描述符,是8个字节(64位)大小的!段描述符 中存储着 指定段的起始位置、段的大小长度、段的访问控制权限的状态信息!

段描述符中,存储着 最为关键的 3 个类型 的字段内容,类型分别为:段基地址、段限长、段属性!

段基地址,顾名思义,这里讲的就是 段的起始地址!

注意,这里的 段基地址,不是 实模式下 的 物理地址!而是 虚拟线性地址!

注意,段描述符中,第17-32位,存储着 段地址 的 第1-16位 ,第33-40位,存储着 段地址 的 第17-24位,第57-64位,存储着 段地址 的 第25-32位 。

段限长,顾名思义,这里代表的就是 段的长度大小!

注意,这里的 段限长 的含义,受 段描述符(64位)中的 第 56 位 影响!

如果 段描述符(64位)中的 第 56 位 ,内容为 0 ,则 段限长 最大为 1 MB,基础单位为 1 B 。

如果 段描述符(64位)中的 第 56 位 ,内容为 1 ,则 段限长 最大为 4 GB,基础单位为 4 K B 。

注意,段描述符中,第1-16位,存储着 段限长 的 第1-16位,第48-52位,存储着 段限长 的 第17-20位。

段的属性,顾名思义,这里代表着 每个段 是会 存在 相应的 属性信息 的!

注意,段描述符中,第 56 位,存储着 颗粒度标志 G ,其影响着,段限长 的 长度含义!

注意,段描述符中,第 55 位,存储着 D / B 位 ,其影响着,段的寻址方式!如果 第55位 的值为 1 , 则代表着采用 32位 的寻址方式,如果 第 55位 的值为 0 ,则代表着采用 16位 的寻址方式!

注意,段描述符中,第 54 位,是保留位,暂时未作为具体用途使用!

注意,段描述符中,第 53 位,是 AVL 位,这是一个灵活度较高的自定义用途位,可以由软件程序自定义其所代表的含义!

注意,段描述符中,第 48 位,是 P 位,其代表着 对应的段是否存在!如果值为 1 ,则代表这个段是存在的!如果值为 0 ,则代表着 对应的段,是不存在的!如果值为 0 ,意味着,这个段描述符,也会是无效的!

注意,段描述符中,第 46-47 位,是 DPL ,其代表着 段描述符 的 访问权限 !它,也是 段描述符 的 特权级别 !如果 段选择子 的 RPL 优先级权限 数字 大于 或者 等于 段描述符 的 DPL 中存储的 代表 段描述符访问权限的数字时,通过 段选择子 才能 有权限 去访问 对应的 段描述符 中的数据!换句话说,如果 段选择子 的 RPL 优先级权限 数字 小于 段描述符中 的 DPL 的数字,那么,通过 段选择子 去访问 对应 段描述符 的行为,只会失败,而不会成功!

注意,段描述符中,第 45 位,是 S 位 ,其代表着 段描述符 的 类型 !如果 段描述符中 第 44 位 的 内容值 为 1 ,则代表 这个段描述符 是 代码段描述符 或 数据段描述符 !如果 段描述符中 第 45 位 的 内容值 为 0 ,则代表 这个段描述符 是 系统段描述符(例如,调用门,中断门等)!

注意,段描述符中,第 41-44 位,是 TYPE ,其 配合 段描述符 中的 第 45 位 S 位 的值,来确定 当前 段描述符 所指向的 段空间 是 数据段空间,还是 代码段空间 !如果 段描述符 的 第 41-44 位 的 TYPE 类型 值 小于 数字 8 ,则代表 这个段描述符 指向 的 段空间 是 数据段空间 !如果 段描述符 的 第 41-44 位 的 TYPE 类型 值 大于 或 等于 数字 8 ,则代表 这个段描述符 指向 的 段空间 是 代码段空间 !

注意,下面是 段描述符中,第 41-44 位 TYPE 类型 字段,不同的值,代表的不同访问权限!

第 41-44 位 TYPE 类型 字段,值 为 0 时,其代表的 访问权限 为 只读 !

第 41-44 位 TYPE 类型 字段,值 为 1 时,其代表的 访问权限 为 只读,已访问 !

第 41-44 位 TYPE 类型 字段,值 为 2 时,其代表的 访问权限 为 可读,可写 !

第 41-44 位 TYPE 类型 字段,值 为 3 时,其代表的 访问权限 为 可读,可写,已访问 !

第 41-44 位 TYPE 类型 字段,值 为 4 时,其代表的 访问权限 为 向下扩展,只读 !

第 41-44 位 TYPE 类型 字段,值 为 5 时,其代表的 访问权限 为 向下扩展,只读,已访问 !

第 41-44 位 TYPE 类型 字段,值 为 6 时,其代表的 访问权限 为 向下扩展,可读,可写 !

第 41-44 位 TYPE 类型 字段,值 为 7 时,其代表的 访问权限 为 向下扩展,可读,可写,已访问 !

第 41-44 位 TYPE 类型 字段,值 为 8 时,其代表的 访问权限 为 可执行 !

第 41-44 位 TYPE 类型 字段,值 为 9 时,其代表的 访问权限 为 可执行,已访问 !

第 41-44 位 TYPE 类型 字段,值 为 10 时,其代表的 访问权限 为 可读,可执行 !

第 41-44 位 TYPE 类型 字段,值 为 11 时,其代表的 访问权限 为 可读,可执行,已访问 !

第 41-44 位 TYPE 类型 字段,值 为 12 时,其代表的 访问权限 为 一致性段,可执行 !

第 41-44 位 TYPE 类型 字段,值 为 13 时,其代表的 访问权限 为 一致性段,可执行,已访问 !

第 41-44 位 TYPE 类型 字段,值 为 14 时,其代表的 访问权限 为 一致性段,可读,可执行 !

第 41-44 位 TYPE 类型 字段,值 为 15 时,其代表的 访问权限 为 一致性段,可读,可执行,已访问 !

注意,说到,一致性段!就一定要了解一下 特权级 CPL、DPL、RPL !

RPL ,我们已经了解过了,就是 段选择器中 代表 当前 段选择子 访问权限 的 字段!

DPL ,我们已经了解过了,就是 段描述符中 代表 当前 段描述符 访问权限 的 字段!

那么,CPL 是什么呢?

CPL 中的 C ,指的是 CPU !

顾名思义,CPL 是存在于 CPU 的 CS 寄存器中的 !

CPL ,直接受 RPL 的影响, RPL 会刷新 CPL 中的 值 !

CPL ,是指当前执行任务的或程序的特权级!

CPL,经常与 DPL 一起,用来共同决定,下一个中断,是否能够被执行!如果 DPL 中的 数字 小于 CPL 中的数字,则会产生一个 General protection 异常(一般保护错误,是在 英特尔x86架构 、AMDx86-64架构 ,以及其它架构中被定义的一种错误!或者说,是一种中断!对于错误的处理,有些时候,也是基于中断的!General protection 是指,正在运行的 内核态程序 或 用户态程序,违反了处理器架构中的保护措施后发生的情况!例如,产生了这个异常)!

我们再来复习和预习一下,特权级的相关类型!

1、请求特权级( RPL ,Request Privilege Level );

2、描述符特权级( DPL ,Descriptor Privilege Level );

3、当前特权级( CPL ,Current Privilege Level );

4、输出特权级( IOPL ,I/O Privilege Level )。

以及,我们还要记住,特权指令( Privileged Instructions )!

当然,特权指令( Privileged Instructions ),会在下一节内容中,有所介绍!

现在,我们来说一下 ,一致性 代码段 和 非一致性 代码段 !

在 x86系列环境 的 CPU体系架构 中,数据内容 和 代码内容,都是按照 “段” 的概念 来进行存放的!数据内容,被存放在 数据段( .data .rodata . bss . got 等 ) 中,也可以叫做 数据节 Data Section !代码内容,被存放在 代码段( .text .plt 等 ) 中,也可以叫做 代码节 Code Section !

GDT 全局描述符表 的每个 段描述符 被设置 有不同的 特权级DPL !

LDT 本地描述符表 的每个 段描述符 被设置 有不同的 特权级DPL !

计算机程序,通过 “选择子” 和 “调用门” 等 技术实现手段,来在不同段之间进行切换!

计算机程序,通过 “选择子” 和 “调用门” 等 技术实现手段,实现用户态程序 和 系统态程序 的调用跳转!

如同 GDT 全局描述符表中的 段描述符,CPU 中央处理器 内的 寄存器中 的每个 选择子 或 门调用 都是存在等级划分的!大家可以了解下,段选择器中的第1位和第2位 代表的RPL 优先级内容!

什么是一致性代码段呢?

简单来说,大家可以思考下,共享库!例如,Windows 操作系统环境 中的 DLL 动态链接库 ,或 者 Linux 操作系统环境 中的 SO 动态链接库!

我们可以简单点去理解,就是操作系统特意贡献出来,让所有内核态程序 或用户态程序去公共使用的代码段内容!

一般来说,DLL 动态链接库中的代码段,即属于 一致性代码段!

一致性代码段的限制:

1、特权级别高的程序代码,被禁止去访问特权级别低的程序数据(例如,核心态的程序代码,不能去访问用户态的程序数据)!

2、特权级别低的程序代码,被允许去访问特权级别高的程序数据。但是!特权级别低的程序代码,去访问特权级别高的程序数据的这种行为,并不能够改变,低特权级别的程序代码,仍然是低特权级别的程序代码的现状(程序代码的特权级别,是不会发生改变的!用户态程序,依然还会是,用户态的程序)!

什么是非一致性代码段呢?

非一致性代码段,是指操作系统为了防御低特权级别的程序代码去直接访问系统内核代码,而设置的一种保护性措施设计(简而言之,非一致性的代码段中的代码内容,一般是指操作系统的内核代码。这些操作系统内核代码,已经被操作系统认真地保护起来了)!

非一致性代码段的限制:

1、只允许同特权级别程序间的互相访问(就是说,运行于R0级别的内核程序,只允许被同样运行于R0级别的内核程序访问,例如 驱动程序 等)!

2、绝对禁止不同特权级别的程序之间进行互相访问(核心态的程序,不直接访问用户态的程序代码或者程序数据,用户态的程序,也不直接访问核心态的程序代码或者程序数据)!

(未完待续)

请关注下一篇,渗透测试之内核安全系列课程:Rootkit技术初探(二)

标签: 安全 linux windows

本文转载自: https://blog.csdn.net/fearhacker/article/details/139494318
版权归原作者 黑客影儿 所有, 如有侵权,请联系我们删除。

“渗透测试之内核安全系列课程:Rootkit技术初探(一)”的评论:

还没有评论