Re:Zero 부터 시작하는 Flash Player CVE 분석 H3X0R 김도현 지금부터 Re:Zero부터 시작하는 Flash Player CVE 분석 발표를 시작 하겠습니다.
Agenda Basic Knowledge Of AVM Native Level Debugging CVE-2015-0311 Use-After-Free CVE-2015-5119 Use-After-Free Conclusion 다음은 목차입니다만, 이번에는 CVE-2015-0311까지만 발표 하도록 하겠습니다.
Who Am I 김도현 H3X0R H3X0R CTF1, CTF2 주최 명호고등학교 저에 대한 소개입니다.
1 Basic Knowledge Of AVM
Basic Knowledge Of AVM Q : What is AVM? AVM (Action Script Virtual Machine) was designed to execute programs written in the Actionscript 3.0 language -avm2overview 먼저 Flash Player의 AVM이란 놈에 대해 알아봅시다. AVM이란 Actionscript 3.0 언어로 써진 프로그램을 실행 하기 위해 설계된 프로그램입니다.
Basic Knowledge Of AVM Q : How It Works? Compiler AVM Source Code ActionScript ByteCode (.swf) Machine Code ( Assembly ) Compiler AVM 다음은 그 구조입니다. 먼저 action script source code를 컴파일러단에서 ActionScript ByteCode로 컴파일 합니다. 그러면 해당 바이트코드를 AVM에서 해석하여 어셈블리레벨에서 해당 작업을 수행 하게 되는 것입니다. 이런 구조를 JIT라고 합니다.
Native Level Debugging 2 Native Level Debugging
Native Level Debugging Environment Setting Adobe Flash Player 16.0.0.287 Internet Explorer 8.0 Windows 7 Windbg (x86) Pykd bindiff 다음은 환경 세팅입니다.
Native Level Debugging Useful Thing AVM+ Source Code ( Github ) 다음은 분석 하는데 많은 도움을 받은 자룡입니다.
Native Level Debugging 인터넷 익스플로러에 attach 하여 플래시 Active X를 분석하는 방법을 알려 드리겠습니다. Internet Options On Connect ( Stand-by )
Native Level Debugging 알림창을 띄워논 상태로 ... Check Process Windbg - Attach
Native Level Debugging Process Attached Module Loaded ( Flash32_16_0_0_287.ocx )
3 CVE-2015-0311
CVE-2015-0311 UAF https://cve.mitre.org https://www.rapid7.com 우선 취약점에 대한 정보를 수집 해 봤습니다. 취약점은 ByteArray의 UncompressViaZlibVariant 함수에서 발생 한다고 합니다. https://www.rapid7.com
Save original data before uncompress CVE-2015-0311 UAF 그렇다면 지금부터 깃허브의 소스 코드를 보며 분석 해 보도록 하겠습니다. 먼저 압축하기 전의 데이터를 실제 압축 하는 과정의 함수에 인자로 줍니다. Save original data before uncompress
ByteArray::UncompressViaZlibVariant() CVE-2015-0311 UAF ByteArray::UncompressViaZlibVariant() ( L1735~L1745 ) ByteArray::Write() 그리고 UncompressViaZlibVariant를 보게 되면 inflate 하여 압축 해제를 진행 하고 Write를 통해 데이터를 ByteArray에 쓰는 것을 알 수 있습니다. 그렇다면 Write를 봐야 되는데 Write 함수가 패치되어 과거의 커밋을 보며 분석을 진행 했습니다.
Original ByteArray::Write() CVE-2015-0311 UAF 진짜 Write 함수를 보게 되면 Grower라는 메소드로 ByteArray의 버퍼를 확장시킨 후 move_or_copy 함수로 데이터를 옮겨 씁니다. Something Patched Original ByteArray::Write()
Grower::EnsureWritableCapacity() CVE-2015-0311 UAF EnsureWritableCapacity 함수가 새로 버퍼를 확장 하고 Grower::EnsureWritableCapacity()
CVE-2015-0311 UAF Grower::~Grower()
Grower::NotifySubscribers() CVE-2015-0311 UAF 다음은 그 과정입니다. 참조자의 수에 따라 루프를 돌며 notifyGlobalMemoryChanged 함수를 수행 하여 Grower::NotifySubscribers()
Grower::notifyGlobalMemoryChanged() CVE-2015-0311 UAF 결론적으로는 notifyGlobalMemoryChanged 함수로 새로 배치된 메모리로 교체작업을 합니다. Grower::notifyGlobalMemoryChanged()
ByteArray::UncompressViaZlibVariant() CVE-2015-0311 UAF 그렇다면 다시 ByteArray::Uncompress 함수로 돌아와 봅시다. ByteArray::Uncompress의 압축 해제 도중 에러가 발생 했을때, Grower로 자라나고 있던 메모리를 해제 하고 이전의 저장된 값들을 가져와 ByteArray의 데이터는 복구 시킵니다. 하지만 이 코드 어디에도 참조자에게 데이터값들이 원래대로 돌아갔고, 현재의 Grower는 삭제해야된다는 내용의 코드는 보이지 않습니다. 이로 인해 참조자는 ByteArray의 Grower중에 생긴 메모리의 포인터를 들고 있으며 그 메모리는 앞서 에러 처리 과정에서 free되어 uaf가 트리거 됩니다. ByteArray::UncompressViaZlibVariant() ( L1767~L1796 )
Compress & Set domainMemory CVE-2015-0311 UAF PoC Compress & Set domainMemory Trigger UAF 그럼 이제 PoC를 분석 해 보도록 합시다. PoC에서는 ba에 총 4000 바이트를 쓰고 압축을 합니다. 그 후에 domainMemory라는 간단히 말하자면 프로세스끼리 정보 교환을 하기 위한 메모리 영역인데 여기에 ba를 할당 합니다. 그 후에 0x200 지점부터 널바이트를 끝까지 쓰고 uncompress를 불러 에러를 유도 합니다. 그리고 새로운 Vector를 할당 하고 casi32로 해당 메모리의 길이값을 제한값을 넘어 모든 영역에 read write가 가능하게 길이를 무한정으로 늘렸습니다. 참고로 여기서 0x200지점 뒤부터 널바이트를 쓰는 이유는 앞쪽에는 중요한 zlib 헤더가 있기 떄문입니다. Allocate New Vector
CVE-2015-0311 UAF PoC * Crash *
CVE-2015-0311 UAF PoC ‘mms.cfg’ Trace result
CVE-2015-0311 UAF Analyze Two ways to analyze ocx Binary Diffing ( Using bindiff ) String Search & Xref Search
CVE-2015-0311 UAF Analyze Q : What is binary diffing? A B C D E F G H I A B C D E E G H I Comparing Difference
CVE-2015-0311 UAF Analyze Bindiff Result
CVE-2015-0311 UAF Analyze Bindiff Flowgraph
CVE-2015-0311 UAF Analyze
CVE-2015-0311 UAF Analyze ByteArrayObject::algorithmToEnum() Use string value “algorithm”
String search “algorithm” CVE-2015-0311 UAF Analyze String search “algorithm”
sub_10691de0 == algorithmToEnum CVE-2015-0311 UAF Analyze sub_10691de0 == algorithmToEnum
compress, uncompress uses algorithmToEnum() CVE-2015-0311 UAF Analyze compress, uncompress uses algorithmToEnum()
Xrefs to algorithmToEnum CVE-2015-0311 UAF Analyze Xrefs to algorithmToEnum
ByteArray::Uncompress CVE-2015-0311 UAF Analyze ByteArray::Uncompress
CVE-2015-0311 UAF Analyze
CVE-2015-0311 UAF Analyze Pykd Script Executed
CVE-2015-0311 UAF Analyze Set Breakpoints & Run
CVE-2015-0311 UAF Analyze ByteArray::Buffer = *( ( ecx + 24h ) + 4h ) ByteArray::Buffer->Array = *( *( ( ecx + 24h ) + 4h ) + 8h ) ByteArray::Buffer.Capacity = *( ( ecx + 24h ) + 4h ) + Ch ByteArray::Buffer.Length = *( ( ecx + 24h ) + 4h ) + 10h ecx = ByteArray ( ba )
CVE-2015-0311 UAF Analyze Zlib encoded Breakpoint #1 ba.buffer, ba.buffer->array Breakpoint #2 ba.buffer, ba.buffer->array
CVE-2015-0311 UAF Analyze domainmemory
CVE-2015-0311 UAF Analyze ByteArray::Buffer->Array = +0 ByteArray::Buffer.length = +4 ByteArrayObject::this = +8
CVE-2015-0311 UAF Analyze Breakpoint #3 Breakpoint #4 Before Uncompress() Breakpoint #4 After Uncompress()
CVE-2015-0311 UAF Analyze Breakpoint #4 Breakpoint #5 Before Declaring Vector Breakpoint #5 After Declaring Vector
CVE-2015-0311 UAF Analyze Breakpoint #5 Breakpoint #6 Before execute casi32() Breakpoint #6 After execute casi32()
4 CVE-2015-5119
CVE-2015-5119 UAF https://cve.mitre.org https://www.rapid7.com
https://wikileaks.org/hackingteam/emails/emailid/513536 CVE-2015-5119 UAF Leaked Data https://wikileaks.org/hackingteam/emails/emailid/513536
https://wikileaks.org/hackingteam/emails/emailid/513536 CVE-2015-5119 UAF Leaked Data https://wikileaks.org/hackingteam/emails/emailid/513536
Allocate New Object & New ByteArray CVE-2015-5119 UAF Leaked Data Allocate New Object & New ByteArray
CVE-2015-5119 UAF Leaked Data Call Object.valueOf()
CVE-2015-5119 UAF Leaked Data Object.valueOf()
CVE-2015-5119 UAF PoC
CVE-2015-5119 UAF Analyze * Crash *
CVE-2015-5119 UAF Analyze ‘mms.cfg’ Trace result
ByteArrayObject::setUintProperty() CVE-2015-5119 UAF Analyze ByteArrayObject::setUintProperty()
ByteArrayObject::setUintProperty() CVE-2015-5119 UAF Analyze ByteArrayObject::setUintProperty()
CVE-2015-5119 UAF Analyze AvmCore::integer()
ScriptObject::defaultValue() CVE-2015-5119 UAF Analyze case kObjectType: AvmCore::number() ScriptObject::defaultValue()
CVE-2015-5119 UAF Analyze Code Memory ba = new ByteArray() ba.length = 0xfa0 ba[3] = o.valueOf() o.valueOf = function(){ ba.length = 0x1100 uv = new Vector(0x3e0) return 0xff } Memory … Heap(??) ba
CVE-2015-5119 UAF Analyze Code Memory ba = new ByteArray() ba.length = 0xfa0 ba[3] = o.valueOf() o.valueOf = function(){ ba.length = 0x1100 uv = new Vector(0x3e0) return 0xff } Memory … Heap(??) Heap(0xfa0) ba
CVE-2015-5119 UAF Analyze Code Memory ba = new ByteArray() ba.length = 0xfa0 ba[3] = o.valueOf() o.valueOf = function(){ ba.length = 0x1100 uv = new Vector(0x3e0) return 0xff } Memory … Heap(??) Heap(0xfa0) ba Heap(0x1100) ba
CVE-2015-5119 UAF Analyze Code Memory ba = new ByteArray() ba.length = 0xfa0 ba[3] = o.valueOf() o.valueOf = function(){ ba.length = 0x1100 uv = new Vector(0x3e0) return 0xff } Memory … Heap(??) Heap(0xfa0) ba , uv Heap(0x1100) ba
CVE-2015-5119 UAF Analyze Code Memory ba = new ByteArray() ba.length = 0xfa0 ba[3] = o.valueOf() o.valueOf = function(){ ba.length = 0x1100 uv = new Vector(0x3e0) return 0xff } Memory … Heap(??) Heap(0xfa0) ba , uv Heap(0x1100) ba
CVE-2015-5119 UAF Analyze Code Memory ba = new ByteArray() ba.length = 0xfa0 ba[3] = o.valueOf() o.valueOf = function(){ ba.length = 0x1100 uv = new Vector(0x3e0) return 0xff } Memory … Heap(??) Heap(*) ba , uv Heap(0x1100) ba
Set Breakpoint ‘Object.toString()’ CVE-2015-5119 UAF Debugging Set Breakpoint ‘Object.toString()’
CVE-2015-5119 UAF Debugging Search ByteArray
CVE-2015-5119 UAF Debugging After Define Vector
After Return o.valueOf() CVE-2015-5119 UAF Debugging After Return o.valueOf()
5 Conclusion
Conclusion – Demo CVE-2015-5119
Conclusion AVM CVE = Funny AVM CVE Exploit = Funny * 2 AVM 1-Day Exploit = Funny * 3 AVM 0-Day Exploit = Funny * 4 (?)
References & Thanks To Special Thanks To Hacklab.kr hdarwin https://github.com/adobe/avmplus http://reversing.fr/adobe-flash-player-bytearray-use-after-free-cve-2015-5119 https://wikileaks.org/hackingteam/emails/emailid/513536 https://recon.cx/2012/schedule/attachments/43_Inside_AVM_REcon2012.pdf http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/actionscript/articles/avm2overview.pdf http://hacklab.kr