登陆一下好吗
首先看到两个输入框,分别对应账号密码,随手输个admin,admin进去,提交后发现有回显,既然题目说了过滤了一切,那就先看看过滤了些啥
经过一波测试,发现服务器过滤了union,select,or,for,#,/,*
这就很让人头疼了,没了or就没了万能密码,select也被过滤,我还真想不起来有什么注入语句了
只能去翻看wp学习一下了
一看真的是觉得脑洞大开
方法1:
username--> '='
password--> '='
膜一下大佬的思路:
首先猜测sql语句为:select * from user where username=’用户名’ and password=’密码’
这样当我们提交以上的payload后,查询语句就成了: select * from user where username=''='' and password=''=''
这里 ''='' 即 (空=空) 返回就是True,所以and前后都为True,查询语句就正确执行了
方法2:
利用mysql的数据类型转换:
原理是这样的:username是字符串类型的,当它接收到整型变量且值为0时,就会返回库内所有数据
这里同时也要用到mysql的数据类型转换,拿这里来说username=0与username='a'+0返回的结果是一样的('a'+0会自动进行类型转换,结果还是0)
目的是要构造sql语句:select * from user where username=0
还有另外一个小知识点:mysql的注释不仅有– ,/**/,#,还有一个 ;%00
所以这里第二种payload如下:
username--> a'+0;%00
passward-->
但我并没有成功,不过知道学到原理,要有成功的老哥请告诉我如何操作
方法3
原理同2,不过构造语句的思路不同
先给payload:
username--> \
passward--> ^'a
还是之前的查询语句,这次提交后变为select * from user where username='\' and password='^'a'
根据运算的优先级,这里会先比较两个字符串'\' and password='与'a'异或的结果会返回0
这也就达到了我们上面所描述的目的了
你真的会PHP吗?
在响应头中看到提示:6c525af4059b4fe7d8c33a.txt,应该就是一个代码审计
1 <?php 2 3 4 $info = ""; 5 $req = []; 6 $flag="xxxxxxxxxx"; 7 8 ini_set("display_error", false); 9 error_reporting(0); 10 11 //判断是否以POST 方式传入number,若没有就返回“have a fun!!” 12 if(!isset($_POST['number'])){ 13 header("hint:6c525af4059b4fe7d8c33a.txt"); 14 15 die("have a fun!!"); 16 } 17 //遍历POST数组中的键与值,将键赋给key,再将值得两侧去掉空格,再判断值是否是字符串,若是则将其中的特殊字符转义后赋给req数组 18 foreach([$_POST] as $global_var) { 19 foreach($global_var as $key => $value) { 20 $value = trim($value); 21 is_string($value) && $req[$key] = addslashes($value); 22 } 23 } 24 25 //构造的一个函数来判断传入的number是否是回文格式的,即一二三三二一这种格式 26 function is_palindrome_number($number) { 27 $number = strval($number); 28 $i = 0; 29 $j = strlen($number) - 1; 30 while($i < $j) { 31 if($number[$i] !== $number[$j]) { 32 return false; 33 } 34 $i++; 35 $j--; 36 } 37 return true; 38 } 39 40 /*
首先获取number的值,判断是不是纯数字,若不是,则判断req数组中number键对应的值是否等于值本身int化再字符串化的值,若相等,接着判断int化的number对应的值是否
等于其反转后的值,若相等就判断number的值是否是回文形式,不是的话就返回flag
*/
41 if(is_numeric($_REQUEST['number'])){ 42 43 $info="sorry, you cann't input a number!"; 44 45 }elseif($req['number']!=strval(intval($req['number']))){ 46 47 $info = "number must be equal to it's integer!! "; 48 49 }else{ 50 51 $value1 = intval($req["number"]); 52 $value2 = intval(strrev($req["number"])); 53 54 if($value1!=$value2){ 55 $info="no, this is not a palindrome number!"; 56 }else{ 57 58 if(is_palindrome_number($req["number"])){ 59 $info = "nice! {$value1} is a palindrome number!"; 60 }else{ 61 $info=$flag; 62 } 63 } 64 65 } 66 67 echo $info;
代码分析就请看代码中的注释,我给每段都进行了说明
这里再给出几个函数的解释:
trim(str):去除str字符串两端的空格
addslashes(str):在str中的预定义字符前加上反斜杠,预定义字符有:单引号(')、双引号(")、反斜杠(\)、NULL
strval()/intval():将值转换为字符串/整型
strrev():反转字符串,比如将abc转为cba
总结一下这里要获取flag的要求:
1.以POST方式传入number的值
2.number的值为字符串且不能是纯数字的字符串
3.number的值=strval(intval($req['number']))
4.number整型化的值要与反转后的number整型化的值要相等
5.number的值不能是回文形式
这里的条件2,3是一对矛盾,4,5又是一对矛盾
要求number不是纯数字字符串那么intval后会把后面的字符给省略,这样就与3矛盾
4,5一看就是一对矛盾
经过一番搜索,参考了数篇wp,我了解到:
2,3可以通过空字符来绕过(如:%00)
is_numeric会判断%00为非数值,而且%00并不会被trim影响
接着就是解决4,5的矛盾
这里也有两种方法
方法1:intval函数溢出绕过
Intval最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval(‘1000000000000’) 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。这里就是应用最大值得反转,2147483647反转后为7463847412明显大于2147483647了,那它的值就会等于最大值2147483647,而且不是回文形式,所以这里POST的number=2147483647%00
方法2:用科学计数法构造0=0
构造number=0e-0%00,可直接绕过了