xp_cmdshell Proxy not Executing - sql-server

I created a Proxy account with Sysadmin access.
Users use this to execute a bcp command of their choosing.
However when the users want's to execute the proc they get: EXECUTE permission was denied on the object 'xp_cmdshell', database 'mssqlsystemresource', schema 'sys'
Here is my Proc:
CREATE PROCEDURE spCMDProxy
(
#SQLSTATEMENT VARCHAR(1000),
#FILENAME VARCHAR(1000)
)
WITH ENCRYPTION
AS
BEGIN
DECLARE #PrepStatement VARCHAR(1000)
SET #PrepStatement = 'bcp ' + '"'+ #SQLSTATEMENT + '" queryout C:\SamsungEDI\' + #FILENAME + ' -U************ -P************ -c -t"||" -S UECZAERP01'
EXEC xp_cmdshell #PrepStatement
END
My Proxy account is a local Sysadmin account.

I found the problem, Could not execute due to the fact that the user cannot execute on xp_cmdshell:
USE master
GRANT EXECUTE on xp_cmdshell to [mydomain\myAccount]
Also found this Article

Related

AWS RDS for SQL Server - how to create startup stored proc?

We are moving to RDS and one of our apps needs access to tempdb and I am trying to figure out the best way to create a startup job that works with RDS. Currently we are able to create a stored proc that sets up the necessary permissions in the master database and use the EXEC sp_procoption 'AddPermissionsToTempDb', 'startup', 'true' command to set it to start at boot.
In RDS however we are not able to create stored procs in the master database. I tried creating the stored proc in a user-owned db but when I then try to create the startup job with EXEC sp_procoption 'mydb.dbo.AddPermissionsToTempDb', 'startup', 'true' it says it can't find the stored procedure or I do not have permission... Is there another way to accomplish this on RDS?
Was able to find a solution based on Jeroen Mostert's comment so credit goes to them. Here is the full query I used to create the startup job to grant permissions to a list of users to create, control and execute stored procedures on tempdb on an AWS RDS SQL Server instance:
USE msdb
go
declare #job_name varchar(50)
set #job_name = 'AddTempDBPermissionsOnStartup'
exec dbo.sp_delete_job #job_name = #job_name
declare #sql varchar(max)
select #sql = '
Declare #Users Table (username varchar(100) )
insert #Users(username) values (''[user1]''),
(''[user2]''),
(''[user3]'')
use tempdb
CREATE ROLE sp_executor GRANT EXECUTE TO sp_executor
CREATE ROLE sp_manipulator
GRANT CREATE PROCEDURE TO sp_manipulator
GRANT CONTROL TO sp_manipulator
DECLARE #username as NVARCHAR(100);
DECLARE User_Cursor CURSOR FOR
SELECT * from #Users
OPEN User_Cursor;
FETCH NEXT FROM User_Cursor INTO #username;
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #username
IF EXISTS(SELECT * FROM [tempdb].sys.database_principals WHERE type_desc = ''SQL_USER'' AND name = #username)
PRINT '' - user already exists''
ELSE
BEGIN
PRINT '' - creating user''
DECLARE #Sql VARCHAR(MAX)
SET #Sql =
''USE Tempdb'' + char(13) +
''CREATE USER '' + #username + '' FOR LOGIN '' + #username + char(13) +
''EXEC sp_addrolemember sp_executor, '' + #username + char(13) +
''EXEC sp_addrolemember sp_manipulator, '' + #username
EXEC (#Sql)
END
FETCH NEXT FROM User_Cursor INTO #username;
END;
CLOSE User_Cursor;
DEALLOCATE User_Cursor;
GO
'
--Add a job
EXEC dbo.sp_add_job
#job_name = #job_name ;
--Add a job step to run the command
EXEC sp_add_jobstep
#job_name = #job_name,
#step_name = N'job step',
#subsystem = N'TSQL',
#command = #sql
--Schedule the job to run at startup
exec sp_add_jobschedule #job_name = #job_name,
#name = 'RunAtStartSchedule',
#freq_type=64
--Add the job to the SQL Server Server
EXEC dbo.sp_add_jobserver
#job_name = #job_name

Executing exe file in xp_cmdshell doesn't work

I have created a user in SQL Server with:
CREATE LOGIN adminuser WITH PASSWORD = 'ABCDegf123';
GO
EXEC master..sp_addsrvrolemember #loginame = N'adminuser', #rolename = N'sysadmin'
GO
Then I connected with this user.
What I want to do, is trigger this ftp command:
ftp -s:C:\Users\sss\Documents\script_ftp\ftp.txt
So I created a trigger:
CREATE TRIGGER sss14
ON Table_1
AFTER INSERT
AS
DECLARE #CMDSQL VARCHAR(1000)
SET #CMDSQL = 'ftp -s:C:\Users\sss\Documents\script_ftp\ftp.txt'
EXEC master..xp_cmdshell #CMDSQL
However, this doesn't work.
Note that creating a folder with xp_cmdshell works correctly. and when I run 'code' it's launch visual studio code as background process
When xp_cmdshell is called, SQL Server does not care about the output and does not consider any failure.
However, you can insert the output to temp table and see the result. Please run below in SSMS to check.
DECLARE #CMDSQL VARCHAR(1000)
SET #CMDSQL = 'ftp -s:C:\Users\sss\Documents\script_ftp\ftp.txt'
create table #output(output varchar(2000))
insert into #output
Exec master..xp_cmdshell #CMDSQL
select * from #output
drop table #output
The command run with xp_cmdshell use SQL Server service account to run OS commands. Please check if SQL Server service account has got permission to perform ftp. If not, grant the appropriate permission.

I am trying to alter the user password through a stored procedure

I am trying to alter the user password through a stored procedure.
DECLARE #newpwd VARCHAR(20)
DECLARE #usrid VARCHAR(50)
DECLARE #SQL NVARCHAR(4000)
DECLARE #oldpass VARCHAR(50)
SET #usrid = 'ddladmin'
SET #newpwd = 'demo#121245'
SET #oldpass = 'demo#123'
SET #SQL = 'ALTER LOGIN ' + #usrid + ' WITH PASSWORD = ' + QUOTENAME(#newpwd, '''') + ' OLD_PASSWORD = ' + QUOTENAME(#oldpass, '''');
EXEC sp_executesql #SQL
With the above query I'm getting an error:
Cannot alter the login 'ddladmin', because it does not exist or you do not have permission.
But when I try to alter it directly through alter script, e.g.
ALTER LOGIN ddladmin WITH PASSWORD ='demo#12121'
it is working. Can anyone please help?
The error message is quite clear:
because it does not exist or you do not have permission.
I have tried to run your script and it worked without any error for me.
So assuming that the login ddladmin exists on your server, it means that you do not have permissions to change the login. You should check under which user you are running the query and eventually change the execution context:
SELECT USER_NAME(), SUSER_NAME()
EXEC sp_executesql #SQL
EXECUTE AS LOGIN ='SA'
SELECT USER_NAME(), SUSER_NAME()
EXEC sp_executesql #SQL
REVERT

Security for requesting temporary logins

I need to set up a system which will allow developers to request an emergency ID for a database. They will be assigned to a role called 'analyst' which will provide them a drop down box with the databases they can gain access to. They will submit the request and a temporary SQL Login will be generated and displayed on screen. The login will have some elevated privs. The login will be removed after 12 hours.
I've got the whole thing working myself as an SA on ASP.net, but now I'm working on modifying the procedures to work using a SQL Login in the application connection string.
I've tried a few things to get it working, but have run into a roadblock.
Here's my procedure that does the real work.
USE [SQLEmergencyLoginRequest]
GO
/****** Object: StoredProcedure [dbo].[SQLELR_Login_CREATE] Script Date: 12/08/2009 14:48:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SQLELR_Login_CREATE]
#SERVER VARCHAR(50),
#DATABASE VARCHAR(50),
#NTLOGIN VARCHAR(50),
#IR INT,
#LOGIN VARCHAR(50) OUTPUT,
#PWD VARCHAR(20) OUTPUT,
#NotifyDBA INT
WITH EXECUTE AS OWNER
AS
/*
Emergency_Access_Login_CREATE: Create Login/PWD, Create User, Create Role, Add User to Role, return Login/PWD.
*/
DECLARE #Random_Login_Extension VARCHAR(20)
DECLARE #sql VARCHAR(1000)
SET #Database = QUOTENAME(#Database);
BEGIN TRANSACTION
--CREATE LOGIN/PWD
EXEC dbo.random_password #Random_Login_Extension OUTPUT;
EXEC dbo.random_password #PWD OUTPUT;
SET #LOGIN = 'Emergency_Login_' + #Random_Login_Extension;
SET #sql= 'CREATE LOGIN [' + #LOGIN + ']' +
'WITH PASSWORD= ''' + #PWD + ''', DEFAULT_DATABASE=[master], ' +
'CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF';
EXEC(#sql);
--CREATE USER
DECLARE #User_Cmd VARCHAR(1000);
SET #User_Cmd = 'USE ' + #DATABASE + ';' +
'CREATE USER [' + #LOGIN + '] FOR LOGIN [' + #LOGIN + '];' +
'EXEC sp_addrolemember N''db_datareader'',''' + #LOGIN + ''';' +
'EXEC sp_addrolemember N''db_datawriter'',''' + #LOGIN + ''';' +
'EXEC sp_addrolemember N''db_ddladmin'',''' + #LOGIN + ''';';
EXEC (#User_Cmd);
INSERT INTO dbo.SQLELR_Emergency_Logins
([CreationTime]
,[NTLogin]
,[IR]
,[SERVER]
,[DATABASE]
,SQLLoginCreated)
VALUES
(GETDATE()
,#NTLOGIN
,#IR
,#SERVER
,#DATABASE
,#LOGIN)
DECLARE #MYBODY VARCHAR(500)
SET #MYBODY = #NTLOGIN + ' has created a temporary login in the ' + #Database + ' Database. The login name is ' + #LOGIN;
DECLARE #MYSUBJECT VARCHAR(500)
SET #MYSUBJECT = 'Emergency Login Creation ON server ' + ##SERVERNAME;
IF #NotifyDBA = 1
BEGIN
EXEC msdb.dbo.sp_notify_operator
#profile_name = 'SQLDBA',
#name = 'SQLDBA',
#subject = #MYSUBJECT,
#body = #MYBODY;
END
COMMIT TRANSACTION
I don't want the application account to be highly privileged in every DB, so I created another account which will go into every db and have db_owner. Evidently the sp_addrolemember using fixed db roles needs a db_owner to work, which is why the acct is db_owner. I'd prefer security admin, but it seems it's not possible.
Back to the problem - using EXECUTE AS with dynamic code does not work.
Is the only way to get this done by creating a stored procedure in every database which creates the user?
We're doing this because we'd like to crank down security on this server and take away db_owner from developers which has been the norm for years. Creating this mechanism will satisfy their only remaining complaint about not having access. They are afraid we won't answer a page and they will be unable to resolve an issue, so this will take care of that.
Of course, any advice on security holes here would be appreciated as well.
The EXECUTE AS clause on the work procedure puts you into the 'execute as' cage, see Extending Database Impersonation by Using EXECUTE AS. Because the EXECUTE AS of the procedure is an database principal, the execute as context will be trusted only inside the database.
There are two workarounds, the 500lb sledge hammer of ALTER DATABASE [SQLEmergencyLoginRequest] SET TRUSTWORTHY ON or the surgical precission tool of code signing, see Call a procedure in another database from an activated procedure for an example. I highly recommend the code signing approach:
craete a certificate in SQLEmergencyLoginRequest
sign the procedure
drop the private key of the certificate to prevent future use for signing
export the certificate
import the certificate in master
create a login derived from the certificate
grant AUTHENTICATE on SERVER to the certificate derived login
grant all other priviledges needed for the procedure to this derived login
This would ensure that the procedure has all the needed priviledges to do its work, in any database. You have to redo the whole signing procedure every time you alter it.

Script SQL Server login with Windows authentication without machine name

I want to write a SQL 2005 script to create a new login that uses Windows authentication. The Windows user is a local account (not a domain one). A local account with the same name exists on many SQL Server machines and I want to run the same script on all of them.
It seemed simple enough:
CREATE LOGIN [MyUser]
FROM WINDOWS
However, that doesn't work! SQL returns an error, saying Give the complete name: <domain\username>.
Of course, I can do that for one machine and it works, but the same script will not work on other machines.
Looks like sp_executesql is the answer, as beach posted. I'll post mine as well, because ##SERVERNAME doesn't work correctly if you use named SQL instances, as we do.
DECLARE #loginName SYSNAME
SET #loginName = CAST(SERVERPROPERTY('MachineName') AS SYSNAME) + '\MyUser'
IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE [name] = #loginName)
BEGIN
DECLARE #sql NVARCHAR(1000)
SET #sql = 'CREATE LOGIN [' + #loginName + '] FROM WINDOWS'
EXEC sp_executesql #sql
END
This just worked for me:
DECLARE #sql nvarchar(1000)
SET #SQL = 'CREATE LOGIN [' + ##SERVERNAME + '\MyUser] FROM WINDOWS'
EXEC sp_executeSQL #SQL

Resources