Skip to content

SharpWSUS continues publishing when the payload copy fails #5

Description

@emdnaia

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

  1. Run SharpWSUS create with a readable signed payload.
  2. Cause the destination copy to fail, for example by denying write access to
    <WsusContent>\wuagent.exe or making the destination unavailable.
  3. Observe Function error - FbCopyFile in the output.
  4. Observe that SharpWSUS nevertheless continues through ImportUpdate,
    PrepareXMLtoClient, InjectURL2Download, and reports Create complete.
  5. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions