CTFHub_2017-赛客夏令营-Web-Injection V2.0(SQL注入、order by注入)
进入场景后,是个登录框
这里介绍以下,用户登录时后端主要有两种业务查询方式:
第一种:用户名和密码的验证同时进行
第二种:先查询用户名,如果用户存在则验证密码是不是和数据库里面的密码一样
判断:若回显的结果是“用户名或者密码错误”,大概率判断登录是否成功用的是第一种方式,若回显的是“用户名不存在”或“密码错误”,大概率是第二种方式。
第一次输入admin:123提示用户不存在,第二次输入aaa:123提示密码错误,据此确定应该是第二种业务查询模式,否则应当均提示用户名或密码输入错误。
第一想法尝试爆破数据库,找到flag,输入各种提交参数都被过滤了,响应中提示hack。
逐一尝试过滤的参数:(),space, ’ , " , ‘+’, ‘/’,union,order,or,and等等,注意逐一测试时不要引进其他非法参数,遵循单一变量原则
测试发现,空格、括号、加号都被过滤,其他没有被过滤。
空格被过滤可以使用/**/绕过,但是括号被过滤,想要爆破数据库就不可能了,因为各种爆破语句都离不开(),也没有绕过()的方法,所以爆破方法就不可行。
既然爆破不可行,我们就尝试登陆吧,根据代码逻辑
$username=$_POST['user']; $password=$_POST['pass']; $sql='select password from user where username='$username''; #查询 if($row){ if($row['password']==$password) { echo 'success';} else{ echo '密码错误';} } else{ echo '用户不存在'; }
关键要构造两次密码是一样的,即第一次从数据库查询的密码和我们输入的密码一样。
方式1
联合查询没被过滤,那么我们可以构造联合查询,并且用/**/代替空格,查询时让用户名为false,使得查询语句的结果是我们输入的密码。
因为不知道admin的闭合方式是双引号闭合还是单引号或者是其他方式,所以需要逐一尝试
payload:
双引号闭合
user=aaa"/**/union/**/select/**/1/**/or/**/"1"="1
&pass=1
单引号闭合
user=aaa'/**/union/**/select/**/1/**/or/**/'1'='1
&pass=1
最终得到的payload是单引号闭合那一条
payload解释:将payload拼接原来的sql变成:
select password from user where username='aaa' union select 1 or '1'='1'
这里union之前sql为select password from xx where username='aaa' ,由于aaa用户不存在,所以返回为空;union之后sql为select 1 or '1'='1',返回1;因此整体sql返回为1,也就是查询到的密码为1,因此只要让我们输入的密码也为1,就可以匹配成功,登录并返回flag。
方式2
order和by也没有被过滤,因此我们还可以使用order by注入。
payload: user=admin'/**/union/**/select/**/3/**/order/**/by/**/1# &pass=1
payload解释:将payload拼接原来的sql变成:
select password from user where username='admin' union select 3 order by 1#'
这里union之前sql为select password from user where username='admin' ,由于admin用户存在,所以返回为真正的密码;union之后sql为select 3,返回3;后面order by 1#'中,#注释掉后面的单引号,order by 1表示根据第1列返回值排序(默认由小到大),由于真正的密码比3大,因此先返回3,也就是查询到的密码为3,因此只要让我们输入的密码也为3,就可以匹配成功,登录并返回flag。
扩展:https://yang1k.github.io/post/sql注入之order-by注入/
参考:
https://blog.csdn.net/Mr_Shiyang/article/details/107974827
https://www.freesion.com/article/99431436580/