Fix/WUA applicability subfeatures UI#19
Open
mawussid wants to merge 2 commits intoGoSecure:masterfrom
Open
Conversation
|
Seems like you went really deep into this, this looks very very cool, nice work, going to test this as well 😁 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix pywsus for modern Windows (10/11/Server 2025): XML resource overhaul & Code improvements
Hi everyone ! Over the past few weeks I've been digging into the subject. I spent a lot of time reading the MS-WUSP spec, comparing XML exchanges in Wireshark against a WSUS server, and testing on multiple VM builds while upgrading the tool in real time. Turns out the root cause was in the XML resource files.
I've put together what I think is a pretty complete fix, tested on:
In short, these are my results from my lab environment (domain-joined clients pointing directly at pywsus via GPO). I'd love to hear if your results vary depending on your setup.
What was actually broken?
First, some additional information related to PR #18:
The WUA (Windows Update Agent) evaluates updates in 3 steps:
If any step fails, the update is silently dropped: no error, no log, just "no updates found" (the exact symptom described in issue #17).
The original
sync-updates.xmlhad this in the Install parent's<Xml>fragment:That GUID references a specific WSUS category that pywsus never serves. Here's the chain reaction:
<AtLeastOne>condition fails (category not in client's local DB)GetExtendedUpdateInfonever calledI removed the
<Prerequisites>block entirely. Without prerequisites, the ruleset is satisfied by default.The full evaluation logic is documented in the CSAPI Update Schema and MS-WUSP §3.2.1 (Client Abstract Data Model).
I saw @5tuk0v's PR that also mentions misconfigurations in the XML files. We converge on the core fix (
<Prerequisites>removal andget-config.xmlrework), but my work also includes a bunch of additional sub-features that came out of my testing:check_build.pyscraper to keepwin_builds.jsonup to date with new Windows buildsknown_clients.json)Happy to discuss and merge efforts if that makes more sense.
What this PR changes
XML resources (the actual fixes)
These are the changes to the XML templates that pywsus serves to the WUA. This is where the real breakage was: the Python code was fine, the XML wasn't.
sync-updates.xml<Prerequisites>blocksync-updates.xmlLastChangeTime-> dynamic{last_change}2020-02-29sync-updates.xmlDriverSyncNotNeeded=false+FlagBitmaskNewUpdatesviasync-updates-empty.xmlmatches real WSUS behaviorsync-updates.xmlw4->w3namespace linkget-config.xmlConfigurationPropertyblockMaxExtendedUpdatesPerRequestis a MUST in the spec,ProtocolVersion=3.2for proper negotiationget-config.xmlIsRegistrationRequired=trueRegisterComputer-> enables OS fingerprinting for targeted KB titlesget-config.xmlAuthInfowith emptyPlugInIDGetAuthorizationCookieis never calledget-extended-update-info.xml{kb_number}/{kb_title}, per-client renderingKB1234567/Probably-legal-update. Now rendered on the fly per IP with realistic metadata (support URLs, bulletin ID, Microsoft format)sync-updates-empty.xmlNewUpdatesresponse for driver sync requestsPython: HTTP handler improving
Wireshark comparison between pywsus and a real WSUS showed several fingerprinting differences. Some of these were already mentioned as comments in the source code, so I went ahead and implemented them to make pywsus responses match what a real IIS/WSUS server returns:
Server: Microsoft-IIS/10.0headerBaseHTTP/0.6 Python/3.x.x. Achieved viaversion_string()overrideCache-Control,Content-Type,Server,X-AspNet-Version,X-Powered-By,Date,Content-Length: usingsend_response_only()to control emission orderContent-Lengthon all SOAP responsesContent-Typecasing +charsettypoContent-type->Content-Type,chartset->charset<SystemSpec>)os.urandom(47))b'A'*47->QUFBQUFB..., felt worth replacing with something more realistic. New cookie per session/rotationPython: Code improvements
On top of the fixes, I added some tooling to make the tool more practical to use during engagements:
rmanual rotation,qquit), and 3-level verbosity (-vmetadata,-vvfull XML in log file withCLIENT ->/<- SERVERdirections)RegisterComputer: generates targeted KB titles per client (e.g.2026-04 Cumulative Update for Windows 11, version 25H2 for x64-based Systems (KB5064579) (26200)) via two-pass lookup indata/win_builds.jsonknown_clients.json. Includescheck_build.pyto scrape Microsoft Release Health pages for new builds--rotate HOURS) + manual (rkey), hot swap without server restart, client data carried overReportEventBatchparsing (brand, model, status in terminal), lxml version bump, threading architecture for concurrent keyboard/timer handlingHere is a quick demo with the new changes:
What I observed during my tests
A few things worth noting from my Wireshark captures and WUA logs:
Driver sync is always performed: on Win11 24H2+ and Server 2025, the WUA systematically does two
SyncUpdatespasses (software then driver with<SystemSpec>), regardless ofDriverSyncNotNeeded. Responding with software updates to a driver sync didn't cause a confirmed bug in my tests, but returning an empty response matches what a real WSUS does, so that's what I went with. I feel like sending software blocks when driver blocks are expected could lead to abnormal behavior.One-session delay: I repeatedly observed a behavior where the current session's update wouldn't install, but the previous session's would. I investigated
Content-Lengthand driver sync as causes but couldn't confirm either in isolation: the original code works without both. It might be related to VMware snapshot cache state (see operational notes in the changelog). TheContent-Lengthand driver sync detection are added as preventive conformity measures, because I could sometimes reproduce the bug without these features, but not consistently.Win11 25H2 reports
OSDescription: "Windows 10 Pro": the kernel is still NT 10.0, so the fingerprinting code does a two-pass lookup (first by OSDescription match, then fallback across all client sections) to handle this. Build 26100 is also shared between Win11 24H2 and Server 2025: the lookup uses a server/client split to disambiguate.If you want more details, check out the changelog: it documents all the work with MS-WUSP spec references and operational notes.
Cheers ^^