Windows 内核实验 ——— 中断提权

前言

本实验过程相当于复现周壑大佬的相关实验过程,期间可能存在许多理解错误或者是不正确的地方,还请多多指正

内容来源:windows内核实验02_中断提权

环境搭建

在开始实验之前你需要一个虚拟机(本文以XP为示例)、VS进行开发以及一个WinDbg来对内核进行调试

虚拟机部分

我们创建一个32位的XP虚拟机,具体创建过程略去

在创建完成后,我们需要对虚拟机进行设置

将原来打印机带的串口删除后,我们添加一个自己的串口:\\.\pipe\com_1,之后我们将通过WinDbg来进行链接此串口

开启虚拟机,在运行中打开boot.ini(修改启动项,然后开启调试模式),可以输入如下命令:C:\boot.ini

之后再里面添加对应命令:

1
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /debug /debugport=com_1 /baudrate=115200

之后在运行中输入:msconfig

之后在打开的页面修改Boot.ini,将我们修改的设置为默认项,然后将超时时间修改短一些

image-20230323234412153

至此虚拟机设置部分就已经完成了

VS 部分

因为微软已经停止了对 XP 的维护,导致我们在高版本的 VS 下编译的程序无法在 XP 中正确运行,对此我们需在在 VS 的组件中添加一下相关组件

然后再开启的项目中进行一些其他的设置:

WinDbg 部分

网上有些搭建教程上会要求去下载 WDK 开发包,然后在里面带有的 WinDbg 设置相关启动参数来进行调试操作,笔者感觉可能较为复杂,因此建议可以去微软官方工具库里下载一个新版的 WinDbg 即可,而不用煞费苦心的装半天 WDK 然后发现VS插件不兼容,然后折腾半天

又回想起来当初跟着别人教程装了半天都没折腾明白的环境以及VS插件不兼容问题…

在 WinDbg 下载完成后,我们选择附加到内核

设置完毕后 WinDbg 会弹出如下信息:

出现如下信息后,我们重启一下虚拟机,等待一段时间便会出现相应的链接信息,然后自己断下

之后就可以开始你的实验之旅了

可能在后续的实验操作中不会出现 WinDbg 自己下载符号加载符号的过程,可以尝试在主机中添加对应的环境变量值,然后让其下载然后加载对应符号,其中的路径可以自己改成你想要存放符号表的位置

1
_NT_SYMBOL_PATH     SRV\*D:\Myself_Software\Windows_soft\symbols\* http://msdl.microsoft.com/download/symbols

实验过程

我们可以下载一个 PCHunter 来观察系统中断表,方便我们后续对其进行修改后的观察

下载链接:http://www.xuetr.com/

我们中断下来虚拟机后,输入指令来进行看中断描述表寄存器的地址

1
r idtr

image-20230324155624582

可以发现中间有许多未使用的 00 ,而我们此次实验的目标是将中断表进行修改,我们插入一个我们自己的函数地址,通过中断来获取 Ring 0 权限,进而达到提权的目的

对此我们使用一个裸函数(不会开辟栈帧),方便我们更精准的控制对应执行的细节,我们创建代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

DWORD g_tmp = 0;
void __declspec(naked) IdtEntry() { // 裸函数,不会产生对应的开辟栈帧过程
// 进入到此处是就是 ring 0 的权限
// 此处注意用一些 ring 3 的指令可能会存在些问题,一般进入到 ring 0 权限后尽量少做操作 ;
__asm {
push eax
mov eax, dword ptr ds : [0x8003f400] ; 因为现在处于 ring 0 需要我们指定对应的段寄存器
mov g_tmp, eax
pop eax
iretd ; 中断返回
}
}
void crash() {
__asm {
int 0x20 // 我们创建的中断
}
}
int main() {
if ((DWORD)IdtEntry != 0x00401040) { // 此处固定了基址,同时关闭了地址随机化,通过printf进行输出得到
printf("wrong addr : %p ", IdtEntry);
exit(-1);
}
crash();
printf("%x\n", g_tmp); // 打印对应地址内容
system("pause");
return 0;
}

同样的我们在 WinDbg 里面将8003f500处插入我们的00401040地址,同时需要注意的是其地址不是连续的中间插入了一段东西,我们可以看到有些中间的是8e开头,有的是ee开头,我们此处需要改为ee开头的,8e为系统调用,当我们调用的时候会产生错误而导致程序崩溃,而系统弹出对应的提示信息,第一个ee开头的根据PCHunter可以看到是int 3,这个是可以被我们所手动调用的,因此我们把地址修改为同样的形式: 0040ee00`00081040

image-20230327123040186

修改成功后我们将VS编译运行的程序放入到 WinXP 中去,运行我们可以看到对应的输出结果是地址0x8003f400处的值

注意一下编译的程序需要处于 x86 下以及是 Release 版本

image-20230327124135766

我们也可以通过 WinDbg 来观察对应地址处的值

image-20230327124327680

可以发现我们程序输出值和 WinDbg 获取的值一样,至此判断实验成功完成

总结

此次实验主要通过修改系统中断表,将处理函数设置为我们自己的。之后我们通过程序手动调用中断,系统通过中断表找到我们的程序对应处理函数,将其设置为 Ring 0 权限,进而执行一些内核代码。进而达到提权的目的。

需要注意的是正常系统一般是不能完成上述过程,因为我们将虚拟机设置为了调试模式,因此我们 WinDbg 才可以进行连接上虚拟机,然后进行调试,是操作系统将权限交给了 WinDbg,之后我们才能进行后续的操作。


Windows 内核实验 ——— 中断提权
https://equinox-shame.github.io/2023/03/27/Windows 内核实验 — 中断提权/
作者
梓曰
发布于
2023年3月27日
许可协议