Sledgehammer - Windows 10 Update Control

Discussion in 'MDL Projects and Applications' started by pf100, Nov 28, 2016.

  1. Windows_Addict

    Windows_Addict MDL Addicted

    Jul 19, 2018
    637
    1,181
    30
  2. grumple

    grumple MDL Novice

    Aug 11, 2020
    3
    0
    0
    Will future updates to Sledgehammer note in the changelog if it's recommended people upgrade (and run it) in cases where it's blocking updates currently but Microsoft may employ additional subterfuge to undo the changes/approach Sledgehammer has set? I am not sure if such a thing is possible but would not be surprised. Perhaps it's not a concern however and if updates are currently frozen then there's no way Microsoft can undermine that state?

    I've only started using it since the last version so have not read prior changelogs but that might be useful for folks who follow it and don't want surprises from Redmond. Thank you so much for developing this essential tool and bravo to you for Open Sourcing it as well!
     
  3. pf100

    pf100 MDL Expert

    Oct 22, 2010
    1,872
    2,862
    60
    @grumple Whenever the script needs to be updated I post it at the top of the first post and I post it here in the thread, or somebody else does first. If I get a report of a vulnerability with the script, I fix it and post an update.

    If an upgrade creates an x:\windows.old folder the script should be run again because the \windows folder has been replaced so previously locked files aren't locked anymore; however, the LockFiles task will rename or lock the required system files so it should be mostly okay since rempl and update assistant most likely won't be included in a feature update anyway.

    I can say that right now with v2.7.2 of the script, if you run Sledgehammer and close it, I have a 100% certainty that Microsoft can't override it.

    Using the script normally, doing updates manually, I'm about 99.999% sure Microsoft can't override it.
     
  4. Whistler4

    Whistler4 MDL Member

    Jul 30, 2015
    154
    133
    10
    #1645 Whistler4, Sep 5, 2020
    Last edited: Sep 5, 2020
    I'm still using v2.7.0 on Windows 10 1909, and it's working effectively after monthly updates through August. But I wouldn't trust Sledgehammer versions before 2.7.2 for Windows 10 2004. As FAQ C4 says about Windows Feature Updates in the Readme file, ". . . always use the latest version of the script."
     
  5. spanishfly

    spanishfly MDL Junior Member

    Dec 5, 2018
    64
    76
    0
    #1646 spanishfly, Sep 8, 2020
    Last edited: Sep 8, 2020
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  6. BAU

    BAU MDL Addicted

    Feb 10, 2009
    728
    1,350
    30
  7. pf100

    pf100 MDL Expert

    Oct 22, 2010
    1,872
    2,862
    60
    @spanishfly @BAU Thanks for the info and to both of you and others involved for doing this work.
     
  8. spanishfly

    spanishfly MDL Junior Member

    Dec 5, 2018
    64
    76
    0
    #1649 spanishfly, Sep 10, 2020
    Last edited: Sep 10, 2020
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  9. BAU

    BAU MDL Addicted

    Feb 10, 2009
    728
    1,350
    30
  10. spanishfly

    spanishfly MDL Junior Member

    Dec 5, 2018
    64
    76
    0
    #1652 spanishfly, Sep 11, 2020
    Last edited: Sep 11, 2020
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  11. BAU

    BAU MDL Addicted

    Feb 10, 2009
    728
    1,350
    30
    Snippet tries to keep original owner when run recursively by design and that will spew an error when it cannot add permissions, but then it will retry, this time after taking ownership, so if you base your conclusion only on the script output, you might be wrong.

    Did you actually check the permissions in the registry after running #2 as-is?
    Chances are high you will see Everyone denied on each and every key.

    In any case, this is not the right thread for an extended discussion about reg_own
     
  12. spanishfly

    spanishfly MDL Junior Member

    Dec 5, 2018
    64
    76
    0
    #1654 spanishfly, Sep 11, 2020
    Last edited: Sep 12, 2020
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  13. BAU

    BAU MDL Addicted

    Feb 10, 2009
    728
    1,350
    30
    Anyway, there is one situation where reg_own fails to set permissions without intermediate call:
    - Exclusive own by TrustedInstaller, with just read permissions defined for System and Administrators
    So the snippet is denied change permissions since it runs under Administrators account by default (powershell)

    Simple fix is to first add FullControl for Administrators and then do your initial operation.

    Better fix is to first add FullControl for a surrogate account (as to not override built-in Administrators),
    do your initial operations, then remove the surrogate account.

    Example

    Code:
    Path   : Microsoft.PowerShell.Core\Registry::HKLM\SOFTWARE\SomeKey
    Owner  : NT SERVICE\TrustedInstaller
    Group  : NT SERVICE\TrustedInstaller
    Access : NT AUTHORITY\SYSTEM Allow  -2147483648
             NT AUTHORITY\SYSTEM Allow  ReadKey
             BUILTIN\Administrators Allow  -2147483648
             BUILTIN\Administrators Allow  ReadKey
             BUILTIN\Users Allow  ReadKey
             BUILTIN\Users Allow  -2147483648
             NT SERVICE\TrustedInstaller Allow  FullControl
             NT SERVICE\TrustedInstaller Allow  268435456
             APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow  -2147483648
             APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow  ReadKey
    
    To just change somevalue and keep everything as is (sneaky), could call the snippet like this:
    Code:
    :: 1. first make sure we have permissions to make changes by using the surrogate admin group S-1-5-114
    call :reg_own "HKLM\SOFTWARE\SomeKey" all S-1-5-114 "" Allow "FullControl"
    :: 2. do our thing
    reg add "HKLM\SOFTWARE\SomeKey" /f /v somevalue /d snippetrullz
    :: could now add any permissions without getting access denied errors (commented below)
    rem call :reg_own "HKLM\SOFTWARE\SomeKey" all S-1-5-18 "" Deny "FullControl"
    reg add "HKLM\SOFTWARE\SomeKey\More" /f /v othervalue /d 1 /t reg_dword
    :: 3. once done, remove surrogate admin group - the original Administrators remains unchanged
    call :reg_own "HKLM\SOFTWARE\SomeKey" none S-1-5-114 ""
    
    This is probably the GOLD showcase usage for my reg_own snippet
    adjusting any values without leaving changed permissions and changed ownership behind,
    something much harder to do in regedit and other tools when processing keys recursively...
    :rolleyes:
     
  14. spanishfly

    spanishfly MDL Junior Member

    Dec 5, 2018
    64
    76
    0
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  15. BAU

    BAU MDL Addicted

    Feb 10, 2009
    728
    1,350
    30
    Well the last example was meant for the standard use case of changing a value that was locked by the OS, while your use case is different.
    Denying permissions works absolutely fine for a specific key, but when doing it recursively we need to be smart about it,
    as you can end up with "put the cart before the horses" situation - effectively denying yourself making further permission changes to subkeys.
    So, never use FullControl when setting deny permissions recursively. WriteKey will also deny "Read Control" so don't use that either.
    Instead, just deny all write permissions explicitly: "SetValue,CreateSubkey,CreateLink,Delete,ChangePermissions,TakeOwnership"
    So for your use case, this should work:
    Code:
    @echo off &title reg_own deny experiment
    
    :::: Ask for elevation passing any batch arguments (don't care for passing user or ti here since we deny write for everyone)
    set _=call "%~f0" %*&reg query HKU\S-1-5-19>nul 2>nul||(powershell -nop -c start cmd -args '/d/x/q/r',$env:_ -verb runas & exit)
    
    :::: 1. make sure we have permissions to make changes by adding S-1-1-0 (Everyone) recursively
    REM call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-1-0 "" Allow "FullControl"
    
    :::: 2. do our thing with the above registry key - if not doing anything to it 1. is not needed and only doing 3. is enough to lock key
    
    :::: 3. deny write for S-1-1-0 (Everyone) and set owner to S-1-2-3 (dummy) - must be last and use explicit write when recursively
    set VO=verbose-output :: now silent by default, only lists rights if VO is defined; to undefine: set "VO="
    set write="SetValue,CreateSubkey,CreateLink,Delete,ChangePermissions,TakeOwnership"
    call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-1-0 S-1-2-3 Deny %write%
    
    ECHO:
    ECHO:
    ECHO Your key is now locked and it's safe to update windows
    
    ECHO:
    pause
    exit/b
    
    :reg_own #key [optional] all user owner access permission  :  call :reg_own "HKCU\My" "" S-1-5-32-545 S-1-5-18 Allow FullControl
    powershell -nop -c $A='%~1','%~2','%~3','%~4','%~5','%~6';iex(([io.file]::ReadAllText('%~f0')-split':Own1\:.*')[1])&exit/b:Own1:
    $D1=[IO.IODescriptionAttribute].Module.GetType('System.Diagnostics.Process').GetMethods(42) |? {$_.Name -eq 'SetPrivilege'}
    'SeSecurityPrivilege','SeTakeOwnershipPrivilege','SeBackupPrivilege','SeRestorePrivilege' |% {$D1.Invoke($null, @("$_",2))}
    $path=$A[0]; $rk=$path-split'\\',2; $HK=gi -lit Registry::$($rk[0]) -fo; $s=$A[1]; $sps=[Security.Principal.SecurityIdentifier]
    $u=($A[2],'S-1-5-32-544')[!$A[2]];$o=($A[3],$u)[!$A[3]];$w=$u,$o |% {new-object $sps($_)}; $old=!$A[3];$own=!$old; $y=$s-eq'all'
    $rar=new-object Security.AccessControl.RegistryAccessRule( $w[0], ($A[5],'FullControl')[!$A[5]], 1, 0, ($A[4],'Allow')[!$A[4]] )
    $x=$s-eq'none'; function Own1($k){$t=$HK.OpenSubKey($k,2,'TakeOwnership'); 0,4 |% {try{$o=$t.GetAccessControl($_)}catch{$old=0}}
    if($old){$own=1;$w[1]=$o.GetOwner($sps)};$o.SetOwner($w[0]);$t.SetAccessControl($o); $c=$HK.OpenSubKey($k,2,'ChangePermissions')
    $p=$c.GetAccessControl(2);if($y){$p.SetAccessRuleProtection(1,1)};$p.ResetAccessRule($rar);if($x){$p.RemoveAccessRuleAll($rar)}
    $c.SetAccessControl($p);if($own){$o.SetOwner($w[1]);$t.SetAccessControl($o)};if($s){$subkeys=$HK.OpenSubKey($k).GetSubKeyNames()
    foreach($n in $subkeys){Own1 "$k\$n"}}};Own1 $rk[1];if($env:VO){get-acl Registry::$path|fl} #:Own1: lean & mean snippet by AveYo
    ::-_-::
    
    
    Could instead Allow FullControl for Everyone, then Allow just ReadKey for specific accounts, and finally remove Everyone:
    Code:
    @echo off &title reg_own readkey only experiment
    
    :::: Define TI sid (TrustedInstaller)
    for /f "tokens=3" %%a in ('sc.exe showsid TrustedInstaller') do set TI=%%a >nul
    :::: Define USER sid before asking for elevation since it gets replaced for limited accounts
    set _=call "%~f0" %* &if "%USER%"=="" for /f "tokens=2" %%u in ('whoami /user /fo list') do set USER=%%u
    :::: Ask for elevation passing USER and any batch arguments - ps also enables debug priviledge unlike vbs
    reg query HKU\S-1-5-19>nul 2>nul||(powershell -nop -c start cmd -args '/d/x/q/rset USER=%USER%^&',$env:_ -verb runas &exit)
    
    :::: 1. make sure we have permissions to make changes by adding S-1-1-0 (Everyone) recursively
    call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-1-0 "" Allow "FullControl"
    
    :::: 2. only allow ReadKey for S-1-5-32-544 (Administrators), S-1-5-18 (SYSTEM) and %TI% (TrustedInstaller) to prevent OS changes
    call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-5-32-544 "" Allow ReadKey
    call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-5-18 "" Allow ReadKey
    call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all %TI% "" Allow ReadKey
    :::: Cleanup previous experiment with S-1-5-114 (surrogate admins group)
    call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" none S-1-5-114 ""
    
    set VO=verbose-output :: snippet now silent by default, will only lists rights if VO is defined; to undefine: set "VO="
    
    :::: 3.a either remove S-1-1-0 (Everyone) and set owner to S-1-2-3 (dummy) - here preferred over using global deny but both are fine
    call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" none S-1-1-0 S-1-2-3
    :::: 3.b or deny write for S-1-1-0 (Everyone) - must be last and should use explicit write when run recursively, not FUllControl
    REM set write="SetValue,CreateSubkey,CreateLink,Delete,ChangePermissions,TakeOwnership"
    REM call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-1-0 S-1-2-3 Deny %write%
    
    ECHO:
    ECHO:
    ECHO Your key is now locked and it's safe to update windows
    
    ECHO:
    pause
    exit/b
    
    :reg_own #key [optional] all user owner access permission  :  call :reg_own "HKCU\My" "" S-1-5-32-545 S-1-5-18 Allow FullControl
    powershell -nop -c $A='%~1','%~2','%~3','%~4','%~5','%~6';iex(([io.file]::ReadAllText('%~f0')-split':Own1\:.*')[1])&exit/b:Own1:
    $D1=[IO.IODescriptionAttribute].Module.GetType('System.Diagnostics.Process').GetMethods(42) |? {$_.Name -eq 'SetPrivilege'}
    'SeSecurityPrivilege','SeTakeOwnershipPrivilege','SeBackupPrivilege','SeRestorePrivilege' |% {$D1.Invoke($null, @("$_",2))}
    $path=$A[0]; $rk=$path-split'\\',2; $HK=gi -lit Registry::$($rk[0]) -fo; $s=$A[1]; $sps=[Security.Principal.SecurityIdentifier]
    $u=($A[2],'S-1-5-32-544')[!$A[2]];$o=($A[3],$u)[!$A[3]];$w=$u,$o |% {new-object $sps($_)}; $old=!$A[3];$own=!$old; $y=$s-eq'all'
    $rar=new-object Security.AccessControl.RegistryAccessRule( $w[0], ($A[5],'FullControl')[!$A[5]], 1, 0, ($A[4],'Allow')[!$A[4]] )
    $x=$s-eq'none'; function Own1($k){$t=$HK.OpenSubKey($k,2,'TakeOwnership'); 0,4 |% {try{$o=$t.GetAccessControl($_)}catch{$old=0}}
    if($old){$own=1;$w[1]=$o.GetOwner($sps)};$o.SetOwner($w[0]);$t.SetAccessControl($o); $c=$HK.OpenSubKey($k,2,'ChangePermissions')
    $p=$c.GetAccessControl(2);if($y){$p.SetAccessRuleProtection(1,1)};$p.ResetAccessRule($rar);if($x){$p.RemoveAccessRuleAll($rar)}
    $c.SetAccessControl($p);if($own){$o.SetOwner($w[1]);$t.SetAccessControl($o)};if($s){$subkeys=$HK.OpenSubKey($k).GetSubKeyNames()
    foreach($n in $subkeys){Own1 "$k\$n"}}};Own1 $rk[1];if($env:VO){get-acl Registry::$path|fl} #:Own1: lean & mean snippet by AveYo
    ::-_-::
    
    
    So you see, the snippet is quite versatile, it's just that I haven't given good directions :)
    One improvement would be doing recursiveness in reverse, but that would bloat the 12-lines snippet and it's not really needed if planning changes like above.
     
  16. spanishfly

    spanishfly MDL Junior Member

    Dec 5, 2018
    64
    76
    0
    Part of giving good directions is having bright students! I'm finding out that I really didn't know as much as I thought I did about OS privilege manipulation. I think understanding and managing permissions is crucial if you're trying to gain control of an online system. I feel honored that you've taken as much time as you have to expand my knowledge bubble a bit further. So thank you for taking me through some more examples. I feel like I'm getting closer to understanding the power and versatility of the snippet tool.

    The several examples you've shared with the embedded explanations are very helpful for me to grasp the logic of the reg-own tool.
    When I was playing around with reg-own in my earlier tests, I accidentally managed to do something really cool. Unfortunately, I didn't notice right away and I then couldn't duplicate the steps I took.The "cool thing" I accidentally did is what you purposefully demonstrated in the second script "reg_own readkey only experiment" Thanks!

    I like how "set VO=verbose-output" (if($env:VO)) makes this script more end-user friendly.

    If I understood DOS scripting better, I could grasp what you're doing differently when you "Define TI sid (TrustedInstaller)" to also "enable debug privilege unlike vbs" I can see there is a difference with your earlier script, but ... yeah ...

    One comment on utility of the"%write%" parameters used in the first script "reg_own deny experiment"
    The list of parameters assigned to %write% (which match the parameters you used in "reg_own snippet usage - mdl TrustedInstaller example #2") is possibly enough to lock down some keys and maybe even locks down most keys. However, with "InboxApplications", only denying "FullControl" works to stop Windows from accessing the "child-keys" and provisioning System Application packages. If you're interested in how Windows uses the "InboxApplications" key then take a look at post #5587 by @GodHand.​
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  17. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    529
    832
    30
    I see I have multiple alerts in this thread but there's way too much information to try to sift through as to what is being requested. Please summarize what I'm specifically being tagged for, in particular in connection with said comment:

    For the record I have never withheld any information I have asserted as knowing with complete certainty. Moreover, I do not make posts that give any definitive source of information while also withholding specific details that directly pertain to said information.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  18. Homer712

    Homer712 MDL Junior Member

    Oct 22, 2018
    90
    22
    0
    Quick question (off the topic of the last couple of pages/posts). Once you trigger the Sledgehammer script and go through the process and get to the Wumgr window, there is an entry (if memory serves me) to do the updates offline. Does that mean that it's possible to download the updates (via the Windows 10 Forums site) and then have Wumgr install the already downloaded updates from there?