SharpWSUS continues publishing when the payload copy fails
Summary
ClFile attempts to copy the selected payload to the WSUS content directory as
wuagent.exe. FbCopyFile() catches copy errors and returns false, but the
constructor ignores that return value. Create then continues importing and
publishing the update.
This produces an update that looks successfully created from the CLI but whose
content is unavailable. In a reproduced case, the resulting WSUS state was:
PublicationState : Published
State : Failed
Size : 0
The injected source URL also returned 404:
GET http://<wsus>:8530/Content/wuagent.exe -> 404
The target reported the update as applicable (NotInstalled) but could not
download or install it.
Affected code
Commit inspected: 53b1a71754ef44118b3756dd9ff9b68fadd97fae
- The constructor discards the return value:
|
public ClFile(string sPFilePath, string sPArgs, string sContentLocation, bool bPCopyFile) |
|
{ |
|
sFilePath = sPFilePath; |
|
sFileName = System.IO.Path.GetFileName(sFilePath); |
|
sArgs = HttpUtility.HtmlEncode(HttpUtility.HtmlEncode(sPArgs)); |
|
if (bPCopyFile == true) |
|
{ |
|
FbCopyFile(sFilePath, sContentLocation); |
|
} |
|
lSize = new System.IO.FileInfo(sFilePath).Length; |
|
sSHA1 = GetBase64EncodedSHA1Hash(sFilePath); |
|
sSHA256 = GetBase64EncodedSHA256Hash(sFilePath); |
|
} |
- The copy method catches the exception and returns
false:
|
public static bool FbCopyFile(string sFilePath, string sContentLocation) |
|
{ |
|
try |
|
{ |
|
//Console.WriteLine(sFilePath); |
|
//Console.WriteLine(sContentLocation); |
|
File.Copy(sFilePath, sContentLocation + @"\wuagent.exe", true); |
|
return true; |
|
} |
|
catch (Exception e) |
|
{ |
|
Console.WriteLine("\r\nFunction error - FbCopyFile."); |
|
|
|
Console.WriteLine($"Error Message: {e.Message}"); |
|
return false; |
|
} |
|
} |
- Update creation proceeds after
new ClFile(...):
|
ClGuid.GenerateUpdateGUID(); |
|
ClGuid.GenerateBundleGUID(); |
|
|
|
ClFile clFileData = new ClFile(PayloadPath, PayloadArgs, Server.sLocalContentCacheLocation, true); |
|
|
|
Console.WriteLine("[*] Creating patch to use the following:"); |
|
Console.WriteLine("[*] Payload: {0}",ClFile.sFileName); |
|
Console.WriteLine("[*] Payload Path: {0}", ClFile.sFilePath); |
|
Console.WriteLine("[*] Arguments: {0}", PayloadArgs); |
|
Console.WriteLine("[*] Arguments (HTML Encoded): {0}", ClFile.sArgs); |
|
|
|
if (!Enum.FbGetWSUSConfigSQL(sqlComm)) |
The problematic flow is:
if (bPCopyFile == true)
{
FbCopyFile(sFilePath, sContentLocation); // false is ignored
}
Reproduction
- Run
SharpWSUS create with a readable signed payload.
- Cause the destination copy to fail, for example by denying write access to
<WsusContent>\wuagent.exe or making the destination unavailable.
- Observe
Function error - FbCopyFile in the output.
- Observe that SharpWSUS nevertheless continues through
ImportUpdate,
PrepareXMLtoClient, InjectURL2Download, and reports Create complete.
- Query the published update through the WSUS Administration API. It eventually
enters State=Failed, with no downloadable content.
Expected behavior
Update creation should stop immediately when the payload cannot be copied to the
content source location. It should return a non-zero process exit code and should
not import or publish incomplete update metadata.
Suggested minimal fix
Check the Boolean result and throw before calculating hashes or publishing:
if (bPCopyFile && !FbCopyFile(sFilePath, sContentLocation))
{
throw new IOException(
$"Unable to stage payload at {Path.Combine(sContentLocation, "wuagent.exe")}."
);
}
A more structured follow-up would propagate the original exception instead of
logging it inside FbCopyFile, then catch it at the command boundary to emit a
concise error and non-zero exit status.
Verified workaround
After manually placing the exact signed payload at
<WsusContent>\wuagent.exe and calling the WSUS Administration API download
retry methods, the same update transitioned from Failed to NotReady, then
to Ready, and content download completed successfully.
sharpwsus-copy-failure.patch
SharpWSUS continues publishing when the payload copy fails
Summary
ClFileattempts to copy the selected payload to the WSUS content directory aswuagent.exe.FbCopyFile()catches copy errors and returnsfalse, but theconstructor ignores that return value.
Createthen continues importing andpublishing the update.
This produces an update that looks successfully created from the CLI but whose
content is unavailable. In a reproduced case, the resulting WSUS state was:
The injected source URL also returned
404:The target reported the update as applicable (
NotInstalled) but could notdownload or install it.
Affected code
Commit inspected:
53b1a71754ef44118b3756dd9ff9b68fadd97faeSharpWSUS/SharpWSUS/lib/ClFile.cs
Lines 16 to 28 in 53b1a71
false:SharpWSUS/SharpWSUS/lib/ClFile.cs
Lines 29 to 45 in 53b1a71
new ClFile(...):SharpWSUS/SharpWSUS/Commands/Create.cs
Lines 75 to 86 in 53b1a71
The problematic flow is:
Reproduction
SharpWSUS createwith a readable signed payload.<WsusContent>\wuagent.exeor making the destination unavailable.Function error - FbCopyFilein the output.ImportUpdate,PrepareXMLtoClient,InjectURL2Download, and reportsCreate complete.enters
State=Failed, with no downloadable content.Expected behavior
Update creation should stop immediately when the payload cannot be copied to the
content source location. It should return a non-zero process exit code and should
not import or publish incomplete update metadata.
Suggested minimal fix
Check the Boolean result and throw before calculating hashes or publishing:
A more structured follow-up would propagate the original exception instead of
logging it inside
FbCopyFile, then catch it at the command boundary to emit aconcise error and non-zero exit status.
Verified workaround
After manually placing the exact signed payload at
<WsusContent>\wuagent.exeand calling the WSUS Administration API downloadretry methods, the same update transitioned from
FailedtoNotReady, thento
Ready, and content download completed successfully.sharpwsus-copy-failure.patch