Simplewall: Windows Update Service Solution

Created on 5 May 2020  ·  5Comments  ·  Source: henrypp/simplewall

I was wondering if you were aware of the following solution to the firewall being unable to identify the windows update service:

  1. Create a copy (or hardlink) of svchost.exe, called e.g. wusvc.exe
  2. Change ImagePath in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\wuauserv to use wusvc.exe
  3. Restart Windows Update Service, e.g. sc stop wuauserv then sc start wuauserv

Now you can whitelist wusvc.exe. This seems like it might be a better solution than having to maintain a list of IP ranges, and could be implemented in code easily.

Just wanted to make sure you knew about this.

development

All 5 comments

Simplewall can detect services, as far as I remember, but they have to be run in separate process.
As pointed up in here: https://netlimiter.com/docs/basic-concepts/filters/system-services-and-windows-store-apps
it should be sufficient to make service run in a separate process.

Although I would assume that one wants to use firewall precisely to stop updates from being forced on them... :)

I must say I'm growing more and more depressed seeing that one cannot rely on "personal firewalls" to disable all unauthorized network traffic. Every firewall seems to have a hole in them.
I was only able to stop Win10 from communicating using 2 firewalls at once: simplewall and Net Peeker. Perhaps Net Peeker is better suited to stop unauthorized traffic because it installs driver in network interface. But even it allows one connection to get through.

You misunderstand the problem, WFP supports creating rules by AppContainer SID (FWPM_CONDITION_ALE_PACKAGE_ID), Image (FWPM_CONDITION_ALE_APP_ID), User (FWPM_CONDITION_ALE_USER_ID), or a ton of others.

The problem is that when you add the wuauserv SID with FWPM_CONDITION_ALE_USER_ID, It still doesn't work.

You can verify this like so:

C:\> sc showsid wuauserv

NAME: wuauserv
SERVICE SID: S-1-5-80-1014140700-3308905587-3330345912-272242898-93311788
STATUS: Active
````

Now create a firewall rule to block Outbound traffic from that SID:

````powershell
New-NetFirewallRule -DisplayName "Test One" -Enabled True -Direction Outbound -Action Block -LocalUser "D:(A;;CC;;;S-1-5-80-1014140700-3308905587-3330345912-272242898-93311788)"
````

If you try to check for updates, it still works. The reason is that `wuauserv` uses `ImpersonateLoggedOnUser()` before `WinHTTPOpen()`, so WFP sees your Logon SID, not the Service SID.

You can verify it like this, first get your SID:

C:\ > whoami.exe /user

Now put that SID into a `FWPM_CONDITION_ALE_USER_ID` Rule:

```powershell
New-NetFirewallRule -DisplayName "Test Two" -Enabled True  -Direction Outbound -Action Block -LocalUser "D:(A;;CC;;;YOURSID)"

Now windows update doesn't work.

Use Remove-NetFirewallRule to delete them, or use the GUI, just type wf.msc into the Run dialog.

Obviously, you can't realistically block or allow all the connections from your SID! 😆 The current solution used by @henrypp is to add a FWPM_CONDITION_IP_REMOTE_ADDRESS rule to allow (or block) all traffic (from any SID or APP ID) to known Windows Update servers. That works too, but it requires maintaining a list of update servers that changes over time, and you can't make it apply to just one service.

Here's that big list of update servers:

https://github.com/henrypp/simplewall/blob/master/bin/blocklist.xml#L566

And here's where those rules get applied:

https://github.com/henrypp/simplewall/blob/6bd53e2ebf8f11879c97e6bc9285a5feeef0debb/src/profile.cpp#L935

The workaround I'm suggesting is to use a FWPM_CONDITION_ALE_APP_ID rule instead of a FWPM_CONDITION_ALE_USER_ID rule. I think it feels like a better solution, but still requires a bit of a hack. 🤷‍♂️

I just wanted to check if @henrypp had considered it 😄

Here is proof the problem is Impersonation:

0:020> |
.  0    id: 1f8 attach  name: C:\WINDOWS\system32\svchost.exe
0:020> bp winhttp!WinHttpOpen
0:020> g
Breakpoint 0 hit
WINHTTP!WinHttpOpen:
00007ff9`583c1100 4055            push    rbp
0:020> kv
 # Child-SP          RetAddr           : Args to Child                                                           : Call Site
00 0000004a`59f7d788 00007ff9`583d3096 : 00000000`00000001 00007ff9`583d2eee 00000000`00000000 000001c2`599bb410 : WINHTTP!WinHttpOpen
01 0000004a`59f7d790 00007ff9`583d2bfd : 0000004a`59f7d910 00000000`00000000 00000000`599bb320 000001c2`6499db90 : WINHTTP!WinHttpClientSession::AcquireSession+0xb6
02 0000004a`59f7d810 00007ff9`583d2893 : 00000000`00000000 00007ff9`6025b7cc 00000000`00000000 00000000`00000000 : WINHTTP!WinHttpClientResolver::GetProxyForUrlImpl+0x2fd
03 0000004a`59f7d960 00007ff9`583d36e9 : 00000000`00000000 000001c2`6499de90 00000000`00000001 00000000`00000000 : WINHTTP!WinHttpClientCompletion::StartProxyResolve+0xa3
04 0000004a`59f7d9d0 00007ff9`583d339c : 000001c2`653f8ee8 00007ff9`6025b7cc 000001c2`62b10730 000001c2`62b10730 : WINHTTP!WxProxyManager::OnProcessGetProxyForUrl+0x209
05 0000004a`59f7da80 00007ff9`583d3220 : 0000004a`59f7dbc9 00000000`00000000 00000000`00000000 0000004a`59f7dbc0 : WINHTTP!WxProxyManager::GetProxyForUrlImpl+0x12c
06 0000004a`59f7daf0 00007ff9`583ba036 : 00000000`00000000 000001c2`6499dc90 000001c2`6499dc90 00000000`00000000 : WINHTTP!WxGetProxyContext::StartProxyResolve+0x70
07 0000004a`59f7db50 00007ff9`583b9a01 : 00000000`00000001 000001c2`5991c900 000001c2`664e8000 00000000`00000000 : WINHTTP!HTTP_USER_REQUEST::_CallGetProxyForUrl+0x426
08 0000004a`59f7dc30 00007ff9`583b95cf : 00000000`00000000 000001c2`5991c900 000001c2`5991c900 000001c2`664e8000 : WINHTTP!HTTP_USER_REQUEST::_SendRequestWithDrainComplete+0xa1
09 0000004a`59f7dcd0 00007ff9`583b9170 : 000001c2`5991c900 0000004a`59f7ddb9 000001c2`664e8000 000001c2`664e8000 : WINHTTP!HTTP_USER_REQUEST::_SendRequestWithProxyInitialized+0x87
0a 0000004a`59f7dd00 00007ff9`583c8ac5 : 000001c2`59923b80 00007ff9`4029b970 000001c2`59923b80 000001c2`5991c900 : WINHTTP!HTTP_USER_REQUEST::SendRequest+0x3b0
0b 0000004a`59f7de00 00007ff9`402a0028 : 000001c2`00000002 00000000`00000000 000001c2`65211e00 000001c2`64853bf8 : WINHTTP!WinHttpSendRequest+0x585
0c 0000004a`59f7df60 00007ff9`402a30d0 : 000001c2`64853bf8 000001c2`6483bcd8 000001c2`648f2970 000001c2`6483bcc0 : webservices!HttpRequest::StartSyncSendHeaders+0x120
0d 0000004a`59f7dfe0 00007ff9`402a457e : 000001c2`64853bf8 000001c2`6483c0d8 000001c2`6483bce0 000001c2`6483bcd8 : webservices!HttpRequestChannel::OnEnterSendRequestHeadersWithRetry+0x120
0e 0000004a`59f7e050 00007ff9`402a32f8 : 00000000`00000000 00000000`00000000 000001c2`6483bcc0 000001c2`648f2970 : webservices!StateMachine<HttpRequestChannel>::Execute+0x2b2
0f 0000004a`59f7e0a0 00007ff9`402a322f : 000001c2`6483bcc0 000001c2`6483bce0 00000000`00000000 000001c2`648f2970 : webservices!HttpRequestChannel::SendHeaders+0xac
10 0000004a`59f7e110 00007ff9`402a43ab : 000001c2`6483c048 000001c2`6483c058 000001c2`6483bcc0 00007ff9`402a41c3 : webservices!HttpRequestChannel::OnEnterSendHeadersEnd+0x7f
11 0000004a`59f7e150 00007ff9`402a22e7 : 00000000`00000000 000001c2`6483bcd8 000001c2`6483bcc0 000001c2`648f2970 : webservices!StateMachine<HttpRequestChannel>::Execute+0xdf
12 0000004a`59f7e1a0 00007ff9`4029fa54 : 0000004a`59f7e2e0 00000000`00000000 0000004a`59f7e2e0 00000000`00001000 : webservices!HttpRequestChannel::WriteMessageEnd+0xd7
13 0000004a`59f7e200 00007ff9`4029fbd1 : 0000004a`59f7e2e0 00000000`00000001 00000000`00000001 00000000`00000000 : webservices!RequestReplyHelper::RequestReply2+0x88
14 0000004a`59f7e240 00007ff9`4029f3ef : 0000004a`59f7e2e0 000001c2`648f2970 00000000`00000001 00000000`00000001 : webservices!AsyncState::Execute+0xdd
15 0000004a`59f7e2a0 00007ff9`402c49f0 : 000001c2`648d1440 00007ff9`0f781150 000001c2`658eadc0 00380050`00610073 : webservices!RequestReplyHelper::RequestOnePossibleReply+0x14b
16 0000004a`59f7e3f0 00007ff9`402c487d : 00007ff9`0f781150 000001c2`5913db10 0000004a`59f7e6e0 00007ff9`0f5b29aa : webservices!Ws::RequestReply+0x160
17 0000004a`59f7e4a0 00007ff9`0f7386ea : 000001c2`6499da10 000001c2`5913db10 0000004a`59f7e6e0 00000000`00000001 : webservices!WsRequestReply+0xad
18 0000004a`59f7e530 00007ff9`0f73a81d : 00000000`00000000 0000004a`59f7e6e0 00000000`00000000 00000000`0000002d : wuaueng!CNativeWebServiceBase::NwsCallWithRetries<<lambda_e5ffb2a0669c673f603e0114b54352cb> >+0x102
19 0000004a`59f7e5e0 00007ff9`0f675293 : 000001c2`59191470 0000004a`59f7e7e8 000001c2`59191440 00300030`002d0030 : wuaueng!CClientService_Nws::SyncUpdates+0x13d
1a 0000004a`59f7e780 00007ff9`0f6741ff : 0000004a`59f7f430 000001c2`59191440 0000004a`59f7f430 00000000`00000000 : wuaueng!CAgentProtocolTalker::SyncUpdates_WithRecovery+0x11b
1b 0000004a`59f7e830 00007ff9`0f672ed2 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : wuaueng!CAgentProtocolTalker::SyncServerUpdatesInternal+0x1247
1c 0000004a`59f7f0a0 00007ff9`0f61522f : 000001c2`59134fe8 000001c2`59107e90 0000004a`59f7f290 000001c2`59134cc0 : wuaueng!CAgentProtocolTalker::SyncServerUpdates+0xf6
1d 0000004a`59f7f140 00007ff9`0f5857f5 : 00000000`00000004 00000000`00000000 00000000`00000004 00000000`00000000 : wuaueng!CAgentUpdateManager::FindUpdates+0x6cc53
1e 0000004a`59f7f8f0 00007ff9`0f5db429 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : wuaueng!CSearchCall::Execute+0xa5
1f 0000004a`59f7f940 00007ff9`5f997bd4 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : wuaueng!CClientCallRecorder::ParallelScanProc+0x29
20 0000004a`59f7f970 00007ff9`6028ce51 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
21 0000004a`59f7f9a0 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21
0:020> !token -n
...
Impersonation Level: Impersonation
TokenType: Impersonation
...

This makes sense, and I think your solution is rather elegant.

Not sure it's completely within the scope of simplewall, though: I'm leaning towards 'yes', but the fact that it requires a hack makes me think that people who want to block Windows Updates might as well go for something like https://www.sordum.org/9470/windows-update-blocker-v1-5/ so that the block isn't on the network level anymore.

I was wondering if you were aware of the following solution to the firewall being unable to identify the windows update service:

  1. Create a copy (or hardlink) of svchost.exe, called e.g. wusvc.exe
  2. Change ImagePath in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\wuauserv to use wusvc.exe
  3. Restart Windows Update Service, e.g. sc stop wuauserv then sc start wuauserv

I stumbled upon this github issue today when I was looking for some details on similar solution myself. Someone said here:

Create a hardlink to svchost.exe. Sadly this is not possible because svchost.exe is already a hardlink and as far as I know, there cannot be hardlinks to hardlinks.

Which I found very odd. Extensive googling did not bring any results as well. Anyway, I tested both copying and hardlink methods and both work perfectly. Hardlink initially requires ownership but then you can return it back. Since it is a hl, all updates are propagated back to it when original changes.

This is probably the best solution. For the simplefirewall needs if you need more elegant and maintainable solution that uses this method - you can optimize it if you create just one hardlink for svchost.exe and then just group whitelisted services via ImagePath to run from it. This way you can maintain simple catalogue of allowed services.

@taviso

Here is proof the problem is Impersonation:
...
Impersonation Level: Impersonation
TokenType: Impersonation
...
```

I was wondering if targeting SID works if you change service's ObjectName? There are a few pre-defined like NetworkService fake user that runs some services in its own container. Wuauserv uses LocalSystem as login object. What I'm thinking is this - what if you create another user acc or even fake user acc and try to run service under it?

@osmin1

I must say I'm growing more and more depressed seeing that one cannot rely on "personal firewalls" to disable all unauthorized network traffic. Every firewall seems to have a hole in them.
I was only able to stop Win10 from communicating using 2 firewalls at once: simplewall and Net Peeker.

If you set "Block All" mode in Windows Firewall for all domains you can block all traffic, provided you clean up default allow rules for crap like Cortana and such. I'm yet to see solid evidence from someone with background and reputation that something built-in deep into Win10 bypasses WFP/WF. I mean, I wouldnt be surprised about telemetry endpoints straight in the Kernel because it is MS, but as I said - there is no evidence

Was this page helpful?
0 / 5 - 0 ratings

Related issues

callmenemo491 picture callmenemo491  ·  3Comments

xnoreq picture xnoreq  ·  3Comments

pwn0r picture pwn0r  ·  4Comments

Chaython picture Chaython  ·  4Comments

Jtasiu picture Jtasiu  ·  4Comments