Saturday, November 15, 2014

Detecting Shadow TrustedBSD Policy Tables In Mac Memory

In this blog post the reference of the _mac_policy_list in _mac_proc_check_get_task will be modified to reference the 'shadow' TrustedBSD policy table and a Volatility Framework plugin to detect this type of hooking will be presented.




Find a location to potentially inject the code, in this case 0xffffff7f8c04d6e5

## This section gets the address for possible code injection in the com.vmware.kext.vmhgfs kext
#get address for the kernel extension (kext) list
p = self.addrspace.profile.get_symbol("_kmod")
kmodaddr = obj.Object("Pointer", offset = p, vm = self.addrspace)
kmod = kmodaddr.dereference_as("kmod_info")
#loop thru list to find suitable target to place the trampoline in
while kmod.is_valid():
    str(kmod.name)
    if str(kmod.name) == "com.vmware.kext.vmhgfs":
        mh = obj.Object('mach_header_64', offset = kmod.address,vm = self.addrspace)
        o = mh.obj_offset
        # skip header data
        o += 32
        txt_data_end = 0
        # loop thru segments to find __TEXT
        for i in xrange(0, mh.ncmds):
            seg = obj.Object('segment_command_64', offset = o, vm = self.addrspace)
            if seg.cmd not in [0x26]:
                for j in xrange(0, seg.nsects):
                    sect = obj.Object('section_64', offset = o + 0x48 + 80*(j), vm = self.addrspace)
                    sect_name = "".join(map(str, sect.sectname)).strip(' \t\r\n\0')
                    # find __text section
                    if seg.cmd == 0x19 and str(seg.segname) == "__TEXT" and sect_name == "__text":
                        print "{0:#10x} {1:#2x} {2} {3}".format(sect.addr,seg.cmd, seg.segname, sect_name)
                        txt_data_end = sect.addr + sect.m('size') - 50
                        break
            if txt_data_end != 0:
                break
        print "The fake function will be at {0:#10x}".format(txt_data_end)
        break
    kmod = kmod.next

The addresses for the functions in question in the original memory sample:

Name                  Original Address
_mac_proc_check_get_task 0xffffff800ac8ee20
_mac_policy_list  0xffffff800aef4d28

The disassembly of the original _mac_proc_check_get_task showing the reference to _mac_policy_list:

0xffffff800ac8ee20 55                               PUSH RBP
0xffffff800ac8ee21 4889e5                           MOV RBP, RSP
0xffffff800ac8ee24 4157                             PUSH R15
0xffffff800ac8ee26 4156                             PUSH R14
0xffffff800ac8ee28 4155                             PUSH R13
0xffffff800ac8ee2a 4154                             PUSH R12
0xffffff800ac8ee2c 53                               PUSH RBX
0xffffff800ac8ee2d 50                               PUSH RAX
0xffffff800ac8ee2e 4989f6                           MOV R14, RSI
0xffffff800ac8ee31 4989ff                           MOV R15, RDI
0xffffff800ac8ee34 488d05ed5e2600                   LEA RAX, [RIP+0x265eed]
0xffffff800ac8ee3b 8b400c                           MOV EAX, [RAX+0xc]


The instruction in bold uses relative addressing, therefore [RIP+0x265eed] actually translates to 0xffffff800aef4d28 (current instruction address + displacement + OP size = 0xffffff800ac8ee34 + 0x265eed + 7), which is the original address of the _mac_policy_list.

Modify the LEA instruction to refer to the fake location (0xffffff7f8c04d6e5): In this case we need to modify the displacement value (0x265EED) so it points to the fake policy list. The fake displacement is calculated by reversing the operations used to calculate the _mac_policy_list (fake address - current instruction address - OP size = 0xffffff7f8c04d6e5 - 0xffffff800ac8ee34 – 7 = 0x813BE8AA).

Original Displacement Fake Displacement
0x00265EED         0x813BE8AA

Original Code Fake Code
488d05ed5e2600 488d05AAE83B81

\x48\x8d\x05 indicates that the operand size is 64 bit (0x48, REX.W), the instruction is LEA (0x8d) and using the register RIP + disp32 with RAX (0x05). The following value in bold is the displacement amount.

After we rewrite the code at the original LEA at 0xffffff800ac8ee34, the disassembly will look like the following:

0xffffff800ac8ee20 55                               PUSH RBP
0xffffff800ac8ee21 4889e5                           MOV RBP, RSP
0xffffff800ac8ee24 4157                             PUSH R15
0xffffff800ac8ee26 4156                             PUSH R14
0xffffff800ac8ee28 4155                             PUSH R13
0xffffff800ac8ee2a 4154                             PUSH R12
0xffffff800ac8ee2c 53                               PUSH RBX
0xffffff800ac8ee2d 50                               PUSH RAX
0xffffff800ac8ee2e 4989f6                           MOV R14, RSI
0xffffff800ac8ee31 4989ff                           MOV R15, RDI
0xffffff800ac8ee34 488d05aae83b81                   LEA RAX, [RIP-0x7ec41756]
0xffffff800ac8ee3b 8b400c                           MOV EAX, [RAX+0xc]

The reference to the mac_policy_list has been modified to point to the fake location 0xffffff7f8c04d6e5 (0xffffff800ac8ee34 + -0x7ec41756 + 7).

The output for the plugin after modifying the memory sample is as follows:



The plugin check_shadow_trustedbsd.py can be found at my GitHub repository [3].

References
[1] http://reverse.put.as/2014/03/18/teaching-rex-another-trustedbsd-trick-to-hide-from-volatility/
[2] http://ref.x86asm.net/geek.html#x0F2D
[3] https://github.com/siliconblade/volatility/blob/master/mac/check_shadow_trustedbsd.py

No comments:

Post a Comment