hfiref0x / UACME

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

UAC bypass via "ms-windows-store://" handler hijack & WSReset.exe trigger #97

Closed AzAgarampur closed 3 years ago

AzAgarampur commented 3 years ago

Hello,

I have method https://github.com/AzAgarampur/byeintegrity7-uac/ that is pretty simple and would be nice if it is included. Title of this issue says it all, and it should work from Windows 8 and above. It uses classic UserAssocSet signatures as always, so I've only included latest W10 & 8 signatures in them, just like before.

Thanks.

hfiref0x commented 3 years ago

Hello,

page unavailable?

AzAgarampur commented 3 years ago

Oops it was private...

Try it again now

hfiref0x commented 3 years ago

Thanks. I'll look on it and later integrate this if everything goes well. No date yet.

hfiref0x commented 3 years ago

There is seems to be shell32 update (at least in 17763) old signature is no longer working. Which mean I need all recent shell32 versions from 18362/18363/19041/19042/19043 as well.

This is from new shell32 (17763.1728), unique pattern

.text:000000018002D9B7 41 8B C9 mov ecx, r9d .text:000000018002D9BA 4C 8B C7 mov r8, rdi .text:000000018002D9BD 48 8B D6 mov rdx, rsi .text:000000018002D9C0 E8 33 03 00 00 call UserAssocSet

It is from SetAssocationfromAssociationsXml routine. If you have recent full updated shell32 from Windows 10 you use, please share your code bytes too :)

This also mean that uacme pattern find need rewrite as I wasn't expecting these bytes are changing between small updates too.

AzAgarampur commented 3 years ago

Hmm, odd. I have latest W10 19042 and current signature works... Never mind, there's a cumulative update - lemme install it and report back.

Alright it's broken. Here are latest fully updated 19042 signatures: From SetAssociationFromAssociationsXml:

41b902000000    mov     r9d,2
4c8bc7          mov     r8,rdi
488bd6          mov     rdx,rsi
418bc9          mov     ecx,r9d
e8e0000000      call    SHELL32!UserAssocSet

Actual UserAssocSet function: (I'm just throwing this in here; probably won't use it directly.)

4053            push    rbx
4883ec20        sub     rsp,20h
e835000000      call    SHELL32!SetUserAssoc
8bd8            mov     ebx,eax
85c0            test    eax,eax
791d            jns     SHELL32!UserAssocSet+0x2e
AzAgarampur commented 3 years ago

Remember how in #87 we attempted to use https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-iapplicationassociationregistration and the Chinese blogpost about the IApplicationAssociationRegistrationInternal interface?

Well I tried to mess around with that again and I figured out a way to get it to work -- no signatures for UserAssocSet needed. Apparently there's a function called ResetDefault() in IApplicationAssociationRegistrationInternal, and by following the CALL instructions in the function we can get ResetDefault -> SetAssociationFromAssociationsXml -> UserAssocSet. Here is some sample code I wrote up to test this out really quickly. I tested this on W10 19042, fully updated & everything.

https://gist.github.com/AzAgarampur/ceb6f34e8faf1b6bfefe06211ac6912b

This is a really crappy example without proper checks, but I wrote it up real quick just to show that it does work on 19042. Maybe we can use this instead of signatures now?

hfiref0x commented 3 years ago

IMO it only worth if you are using this UserAssocSet somewhere in everyday use program, besides it still will have a switch as this interface has at least two variants with different IID. I will just remake existing signature lookup routines.

hfiref0x commented 3 years ago

So far I'm missing shell32 from 18363 and ~19043~.

hfiref0x commented 3 years ago

I cannot reproduce this bypass. My variant does nothing for me on 17763 and 18362 - wsreset starts and quits. Your variant cannot work because it lacks signatures for those versions.

On 19042.844 your variant is stuck on waiting for wsreset exit with no observed result, my variant does nothing too.

All the above Windows versions are clean installs with updates applied.

17763.1250 18362.1350 19042.844

p.s. Wsreset is known to be very unstable if we speak for UAC bypasses based on it. It triggers a lot of crap on PC in a different ways so it hard to find exact problem.

AzAgarampur commented 3 years ago

19042 & 17763 work for me, can't test 18362 right now. Can you confirm that WinStore opens when you run wsreset.exe normally on the builds where the bypass won't work?

The only behavior of Wsreset I'm betting on is the jump that occurs at the start of wmain that goes near the end of wmain and does some directory deleting for Windows store package, calls licensemanagerapi.dll!Reset(), then will do ShellExecute ms-windows-store:purgecaches. I don't know why this wouldn't call ShellExecute as the execution path is pretty simple, the only thing I can think of that is messing something up is licensemanagerapi.dll!Reset() - it contains some RPC call stuff. Even with services that have the RPC server disabled, wsreset.exe does not spend time doing anything, instead it immediately calls ShellExecute and closes.

hfiref0x commented 3 years ago

I will look into this issue and post results here as usual. And there will be uacme update because of new shell32 versions.

hfiref0x commented 3 years ago

17763, here are the results from Event Log (Microsoft->Windows->Store->Operational) when used uacme

1) Process Name: C:\WINDOWS\system32\WSReset.exe Module Name: C:\WINDOWS\system32\licensemanagerapi.dll Build: 17763.1.amd64fre.rs5_release.180914-1434

2) canDisableApps value is 1 Function: InitStoreAppsAreDisabled Source: onecoreuap\enduser\winstore\licensemanager\apisethost\activationapis.cpp (165)

3) Refreshing licenses with quality 2130706432 Function: OneStoreApplicationLicenseManager::GetInstalledLicensesWithMinQuality Source: onecoreuap\enduser\winstore\licensemanager\lib\onestoreapplicensemanager.cpp (691)

Nothing happens next. Your program does not work because of no signatures for this version.

When run wsreset standalone (without reg protocol hijack) result is message "you need a new app to open this ms-windows-store". Event Log entries added the same as above.

This is LTSC version of Windows with many bloatware features disabled or not installed by default.

19042 full patch

On uacme run - multiple events added to the log. No bypass observed. On bye-integrity7 run - multiple events added to the log - program waits for wsreset about a minute then "select program to open this file" dialog appears - if you select windows store - store application will launch. Bye-Integrity reports [%] *** Exploit successful. No bypass observed.

When wsreset run standalone - it takes around 30 seconds to open actual Microsoft Store. It is working and operational. During this timeout wsreset console window does nothing - I assume it is all because it busy doing it stuff.

Event logs from both runs attached.

logs.zip

AzAgarampur commented 3 years ago

When run wsreset standalone (without reg protocol hijack) result is message "you need a new app to open this ms-windows-store". Event Log entries added the same as above.

I tested mine with a signature for 17763 LTSC and I can confirm that file open dialog pops up. This is because there is no ms-windows-store protocol defined because there is no windows store. I'll try and create my own ms-windows-store protocol and observe result.

On bye-integrity7 run - multiple events added to the log - program waits for wsreset about a minute then "select program to open this file" dialog appears - if you select windows store - store application will launch. Bye-Integrity reports [%] *** Exploit successful. No bypass observed.

I have not encountered this problem yet, but I think it's asking what program to choose because we created new association for ms-windows-store: (I think). Creating a new DWORD at HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Windows\Explorer called NoNewAppAlert and making it 0x1, then restarting explorer will disable the new app notification. Does this work for you?

hfiref0x commented 3 years ago

I have not encountered this problem yet

This is performance issue of this particular VM. I've multiple VM sessions at the same time, where these Win10 variants works from slow HDD and has limited memory amount (4gb each). Simulates some typical low cost PC with Win10 installed.

Creating a new DWORD at HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Windows\Explorer called NoNewAppAlert and making it 0x1, then restarting explorer will disable the new app notification. Does this work for you?

I will try this and report here result.

Edit: Applying this setting and restarting explorer makes this method work on my 19042 VM.

hfiref0x commented 3 years ago

There is a problem seems, HKEY_CURRENT_USER\SOFTWARE\Policies etc cannot be modified without elevation.

AzAgarampur commented 3 years ago

OK, so calling UserAssocSet with UASET_CLEAR (0) (I think that's what it's called), then calling UserAssocSet again with the correct parameters to set the association should also get around the new app notification prompt. Does this work for you?

UserAssocSetInternal(nullptr, L"http", L"", 0);
UserAssocSetInternal(nullptr, L"http", L"ChromeHTML", 1):

I used this sample test code to test out if the new app notification would be bypassed if I installed a new web browser, like chrome, for example. It worked for me. No need for explorer restart.

hfiref0x commented 3 years ago

Calling UserAssocSet(UASET_CLEAR , L"ms-windows-store", NULL, 0);resulted in HRESULT 0 (success) but the selection dialog still popups. When selected ms store - store app loads. Second run of exploit triggers bypass silently. Unsure what is wrong here.

I've a feeling we are missing something in registration process. Perhaps this new entry should contain some additional value. What about availability of this method, if it will produce stable work on 19041/19042 I will limit it to these versions (and beyond).

AzAgarampur commented 3 years ago

So on versions without the Windows Store, creating the registry key HKEY_CURRENT_USER\SOFTWARE\Classes\ms-windows-store and creating a REG_EZ called URL Protocol and creating an empty string as its value. Then from that key create shell\open\command, default value is C:\WINDOWS\System32\cmd.exe. Then we skip the whole UserAssocSet thing and just launch WSReset.exe. Then it'll work. This is on the LTSC version of Windows.

Calling UserAssocSet(UASET_CLEAR , L"ms-windows-store", NULL, 0); resulted in HRESULT 0 (success) but the selection dialog still popups. When selected ms store - store app loads.

Did you call UserAssocSet(UASET_APPLICATION, L"ms-windows-store", L"uacme-progid", 0); immediately after call to UserAssocSet(UASET_CLEAR, ...);?

hfiref0x commented 3 years ago

I'm taking all tests on 19042.

Well it takes some little time because UserAssocSet call is part of subroutine that opens Classes subkey etc, sets association keys etc.

Procmon shows OpenWith.exe spawn which if you select "open with store" will reset association to store. However this doesn't explain why on second attempt this exploit actually works.

AzAgarampur commented 3 years ago

Procmon shows OpenWith.exe spawn which if you select "open with store" will reset association to store. However this doesn't explain why on second attempt this exploit actually works.

I think its because some internal flag has been set that tells openwith.exe that a default has been set and there is no need to prompt, so even if we change default, this flag will remain and openwith will not prompt.

Well it takes some little time because UserAssocSet call is part of subroutine that opens Classes subkey etc, sets association keys etc.

Yeah makes sense, I was just asking if the call to clear the association is followed by a call to set the association.

hfiref0x commented 3 years ago

So on versions without the Windows Store, creating the registry key HKEY_CURRENT_USER\SOFTWARE\Classes\ms-windows-store and creating a REG_EZ called URL Protocol and creating an empty string as its value. Then from that key create shell\open\command, default value is C:\WINDOWS\System32\cmd.exe. Then we skip the whole UserAssocSet thing and just launch WSReset.exe. Then it'll work. This is on the LTSC version of Windows.

You were right. The question here is how to detect MS Store state.

AzAgarampur commented 3 years ago

I think there are many ways to check. We can check if the key HKLM(HKCU)\SOFTWARE\Classes\ms-windows-store exists or not. We can check if %LOCALAPPDATA%\Packages\Microsoft.WindowsStore_8wekyb3d8bbwe exists or not. We can even use the appx package API to query the list and see if it's installed. https://docs.microsoft.com/en-us/windows/win32/appxpkg/functions

AzAgarampur commented 3 years ago

19042 full patch On uacme run - multiple events added to the log. No bypass observed. On bye-integrity7 run - multiple events added to the log - program waits for wsreset about a minute then "select program to open this file" dialog appears - if you select windows store - store application will launch. Bye-Integrity reports [%] *** Exploit successful. No bypass observed.

Sorry I cannot reproduce this problem. I just clean installed 19042 and fully updated it without touching anything related to associations. On first run of byeintegrity/uacme it works fine.

I don't seem to get this "new app registration found" behavior that your 19042 VM has been experiencing. So all my suggestions to workarounds are speculations as I can't really test them. The only place I can get this "new registration" dialog is if I create another registration for another protocol, like http: for example. After installing browser and then attempting to open http: I get the "how do you want to open this link" message. (I think this is what you're getting). However, once again my tests show that two calls to UserAssocSet can get around this message, so not sure what's going on.

Edit: Also, I've noticed that sometimes it succeeds but cmd.exe is hidden and invisible. I think it's because cmd inherits wsreset.exe's console, but it exits really fast and cmd is left without a console. Might wanna change default program to cmd.exe /C start cmd.exe to really open it in a new console.

hfiref0x commented 3 years ago

I've noticed that sometimes it succeeds but cmd.exe is hidden and invisible. I think it's because cmd inherits wsreset.exe's console, but it exits really fast and cmd is left without a console. Might wanna change default program to cmd.exe /C start cmd.exe to really open it in a new console.

That's already in uacme. There was another method for wsreset before and this behavior is known since then.

I will try to detect Ms Store state however I can't use most of this fancy API because it brings a lot of unneeded dependencies.

As of "OpenWith" issue it need more tests as it always spawns for me at first run of exploit.

AzAgarampur commented 3 years ago

By any chance on the machine where you keep getting openwith prompt on first run is there a registry key HKEY_CURRENT_USER\SOFTWARE\Classes\ms-windows-store2?

hfiref0x commented 3 years ago

Yes this key present.

p.s. Can you verify that PC with Store enabled always had AppX Deployment Service (AppXSVC) running?

AzAgarampur commented 3 years ago

Can you verify that PC with Store enabled always had AppX Deployment Service (AppXSVC) running?

Yes, this is true.

If we forget about the whole UserAssocSet thing and just write cmd.exe to default value at HKEY_CURRENT_USER\SOFTWARE\Classes\AppX82a6gwre4fdg3bt635tn5ctqjf8msdd2\Shell\open\command it also works for me. Does this work for you? Note that we need to delete all values under the open key.

hfiref0x commented 3 years ago

Probably there is a better solution.

Having this AppXSvc running on LTSC 1809 version triggers exploit ms-windows-store through UserAssocSet exploit and does this immediately.

Edit:

HKEY_CURRENT_USER\SOFTWARE\Classes\AppX82a6gwre4fdg3bt635tn5ctqjf8msdd2\Shell\open\command

Will check this later on 19042.

hfiref0x commented 3 years ago

Oh I forgot about this.

AppX82a6gwre4fdg3bt635tn5ctqjf8msdd2 hijack already in uacme as method 56 IIRC.

AzAgarampur commented 3 years ago

Having this AppXSvc running on LTSC 1809 version triggers exploit ms-windows-store through UserAssocSet exploit and does this immediately.

Was it really that little service messing it up 😂 How did you figure that out? Anyways, I'm glad you got something good that works for 17763.

AppX82a6gwre4fdg3bt635tn5ctqjf8msdd2 hijack already in uacme as method 56 IIRC.

Hmm, before ending up using same method I want to figure out more of why openwith keeps prompting, will continue on it later.

hfiref0x commented 3 years ago

How did you figure that out?

Well this service is responsible for handling all these fancy new appx crap. By default it is turned off on LTSC. Btw probably no elevation required to launch it.

AzAgarampur commented 3 years ago

It looks like function responsible for reading NoNewAppAlert and displaying openwith is windows.storage.dll!CBindAndInvokeStaticVerb::ConfirmUserChoiceIfNewHandlersAvailable. Actual explorer.exe has nothing to do with this. I was able to spoof NoNewAppAlert and modify this function's behavior via iat hook, but this only works for current process so we can't do this for wsreset.exe. Still need to investigate more.

AzAgarampur commented 3 years ago

Ok I finally got the problems that your 19042 has. For me, simply starting the appxservice solved the problem. Instead of testing if service is not running, then using alternate method, I think starting the service is better. If it's stuck, then we can use alternate method - but I doubt it'll be stuck like that. Also appxservice start eliminates the need for alternate winstore method on LTSC.

hfiref0x commented 3 years ago

The problem still persist.

Untitled

If you select "Microsoft Store" in this dialog and click OK - it will spawn store app. After that, when you run akagi again - it will successfully run exploit with no "OpenWith" dialogs etc.

Which mean we are missing some protocol registration details here (which are set when OpenWith does it job).

Some additional notes about AppxSvc. On 19042 without elevation you can't stop this service. However you can start it without elevation.

AzAgarampur commented 3 years ago

Oh, Microsoft store is showing up as new app for you. Ok in that case, can you try this - can you delete the value AppXsb211bcrztxd4cmckh0b70ma9bfkhrv6 at HKEY_CURRENT_USER\SOFTWARE\RegisteredApplications right before calling UserAssocSet?

hfiref0x commented 3 years ago

I don't have such entry on my VM.

AzAgarampur commented 3 years ago

Hmm that's strange because CBindAndInvokeStaticVerb::ConfirmUserChoiceIfNewHandlersAvailable seems to scan this list for new appx registrations. You don't have any values in that RegisteredApplications key that contains the string Microsoft.WindowsStore in it?

hfiref0x commented 3 years ago

Name: AppXnxybh9gej9ah7k6wcw3g39f2ssczetzq Value: Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\Microsoft.WindowsStore_11910.1002.5.0_x64__8wekyb3d8bbwe\App\Capabilities

This is the only one value in this key HKEY_CURRENT_USER\SOFTWARE\RegisteredApplications

AzAgarampur commented 3 years ago

Hmm if you delete that key right before calling UserAssocSet does it clear the "new microsoft store" prompt?

hfiref0x commented 3 years ago

After removing this value "OpenWith" dialog still popups.

AzAgarampur commented 3 years ago

In that case I really don't know what else to try as I can't repo this issue myself. Running Remove-AppxPackage Microsoft.WindowsStore_12011.1001.1.0_x64__8wekyb3d8bbwe from a standard powershell will unregister ms store from current user and prompt will disappear but obviously I don't think removing the store is a good idea... unless there's something else that's being checked that I missed.

Edit: Does deleting value named ms-windows-store at HKEY_CURRENT_USER\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\Microsoft.WindowsStore_12011.1001.1.0_x64__8wekyb3d8bbwe\App\Capabilities\URLAssociations before calling UserAssocSet do anything?

hfiref0x commented 3 years ago

This key has permissions that prevents deleting it. If I manually take ownership above this key and remove it after - exploit will work.

AzAgarampur commented 3 years ago

Strange, I have full control granted to this key by default on 19042

hfiref0x commented 3 years ago

Untitled Untitled2

Maybe you altered some keys before? Or perhaps some powershell script reset them?

AzAgarampur commented 3 years ago

Yeah I think using powershell changed it. For now I'm lost as I have no idea what else is scanned to check for new programs, but I'll see later.

Edit: Wsreset has a condition where it attempts to install store, I think this is happening and thats why store is showing up as new app. Ok I can finally repro this "new application" issue that you're getting now. However deleting the store value at HKCU\SOFTWARE\RegisteredApplications manually before running uacme fixes problem...

hfiref0x commented 3 years ago

I'll make standalone test application for this method and post it here.

AzAgarampur commented 3 years ago

Ok I think I found a solution - create an empty REG_SZ named NoOpenWith under HKEY_CURRENT_USER\SOFTWARE\Classes\AppX82a6gwre4fdg3bt635tn5ctqjf8msdd2.

hfiref0x commented 3 years ago

Seems like this one work, good job. Another question now is how to 100% identify store app key as it seems different and depends on app/windows version. Also let me know if you still need test application, basically it is method 68 from uacme + code copy-pasted from wsreset for tests.

AzAgarampur commented 3 years ago

Another question now is how to 100% identify store app key as it seems different and depends on app/windows version.

HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Extensions\ProgIDs contains list of keys named AppX..., and each key has first value (not default) with app name. So we can check if it contains "WindowsStore"

Another way (faster) is to query first child key of HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Extensions\windows.protocol\ms-windows-store, as the child of this key will be named the correct AppX... and have a string value with the full package name as well. However, this isn't reliable because pc's (like my main one) are missing a child key or the ms-windows-store key is missing entirely, so I'd go with the first method.

AzAgarampur commented 3 years ago

Also there is 3rd way which I think is good:

  1. Enumerate HKEY_CURRENT_USER\SOFTWARE\RegisteredApplications
  2. Find value which data string contains "WindowsStore"
  3. Open key HKCU + found data string + \URLAssociations
  4. Enumerate values of this key until ms-windows-store name is found
  5. Data of this key contains the correct AppX... name.