BUUCTF_October 2019 Twice SQL Injection
October 2019 Twice SQL Injection
参考:
场景:
一个登录页面,跟之前一样,先走一遍网页全部的业务逻辑,再来寻找存在的漏洞。
注册一个账户:
登录我们注册的账户:
登录结果:
随便写一下info的内容:
响应结果:
我们写入的内容被重新回显到了网页上,这里可能存在mysql的二次注入漏洞,先将我们的数据插入到mysql中,然后再取出来回显到网页上。
测试二次注入:
payload:
1 |
|
响应结果:
我们输入的字符串内容中的特殊字符被加入了\,这就导致我们普通的注入方式失效了,同时也可以确定,网页显示的Info的内容确实是从数据库中显示的,不然也不用担心我们使用单引号进行危险注入,直接前端显示就行了。
这里由于直接采用了\对特殊字符转义,所以就只能先放弃这个注入点了,根据网上的师傅的wp发现都是对用户名进行注入。
通过用户名注入达到二次注入的目的:
存在漏洞的sql语句:
1 |
|
所以将database()的值回显到info所在的网页位置上。
注册:
payload:
1 |
|
该注册方式能够被成功注册,但是使用本地测试时,这是会导致报错的。
本地测试注册:
1 |
|
但是网页能成功注册,就说明在注册界面中,对用户输入的内容进行了’\‘的转义,才能让该内容被成功插入数据库。
登录:
1 |
|
登录界面的sql语句猜测:
sql1:
1 |
|
如果是该sql语句,那么select * from users where username=’666’回显的所有字段的数量就和select database()回显的字段数不同,从而导致报错(666用户不存在时):
在理论上是会报错的无法运行的,但是当我们在登录界面输入我们的用户名和密码时,却成功登录并回显了database()的信息:
得到数据库信息为:ctftraining,说明在登录界面上的sql语句应该为:
sql2:
1 |
|
这样就可以使select info from users where username=’666’搜索的字段数量和select database()所回显的字段数一致,又因为666这个用户不存在,所以最终回显的为database()的信息:
即使666用户不存在,但是由于整个拼接的sql语句回显了记录,所以在网页的内部判断中认为该用户是存在的,所以就可以成功登录了,又因为回显的记录值只有database()的信息,所以登录后网页回显的内容为数据库信息,同时也验证了在登录界面没有对用户输入的内容进行’\‘转义的处理。
假如666用户存在:
我们先注册一个666用户:
1 |
|
登录:
index界面:
显示的内容为,正常用户登录后的结果,即默认显示的内容,默认可以是前端赋值,或者数据库默认存储再取出。
我们再用我们的payload登录:
1 |
|
index界面:
发现是登录666用户时的正常index页面回显结果。
使用本地测试:
sql1:
1 |
|
正常的登录情况的返回结果,虽然info没有值,但是666存在所以依然可以返回结果集,前端可以判断结果集info的值来确定是不是null从而赋值默认值。
sql2:
1 |
|
这是我们进行恶意登录的情况,这次是由于666用户存在,所以第一条记录为null,不像之前666不存在时,直接第一条记录就是database(),前端依然可以通过只判断第一条记录是不是为null来决定是否赋值默认内容。
这也就是为什么我们注册666用户后,再用恶意payload登录时,回显的却是正常的用户登录结果。
明确了网页的漏洞后,我们就可以进行攻击了,本质就是常规的union注入配合二次注入
获取数据库表的信息:
payload:
1 |
|
注册:
登录:
index界面:
发现flag表
爆表的字段名:
payload:
1 |
|
得到字段名为flag
爆字段信息:
payload:
1 |
|
flag=flag{47be8e14-bae6-4158-9c41-f92df44c27b2}