题目
<?php
//mysql_query('set names utf8')
function check_username($str){
if(preg_match("/^admin$/i",$str)){
return 1;
}
for($i=195;$i<240;$i++){
if(preg_match("/".chr($i)."/i",$str)){
return 1;
}
}
return 0;
}
function check_password($str){
if(preg_match("/admins/i",$str)){
return 1;
}
return 0;
}
$link=connect();
$u=$_GET['username'];
$p=$_GET['password'];
if(check_username($u)==1||check_password($p)==1){
die("admin can not Login");
}
$query="select * from user where username=' $u'and password='$p'";
$res = mysqLi_query($link,$query);
echo $res;
题目大致代码如上,要求当我们使用admin用户成功登录之后就会得到flag
分析
从代码上可以看见用户名为admin,密码为admins
首先对于用户名admin,check_username()要求我们不能以admin开头并且以admin结尾,即只输入admin不行的。我们需要在admin前后加一个或多个字符让其绕过preg_match(),但是加的字符转换成数字不能在【195-239】之间。
其次对于密码admins,check_password()要求我们输入的密码中不能包含admins字符串。所以我们需要找一个字符串他不会被preg_match()匹配到admins,但是要能在mysql里面被当作admins处理。
知识点
从一道题深入mysql字符集与比对方法collation · sky's blog
当Mysql字段的字符集和php mysqli客户端设置的字符集不相同时会有转换漏洞:
在默认情况下,mysql字符集为latin1,而如果在客户端使用
set names utf8
将客户端的字符集设置为utf8。如果在客户端输入不完整的汉字的utf-8编码,latin1又不支持汉字就会将其忽略,从而达到绕过。
\xC2
~\xEF 会被忽略从而
返回admin的结果
我们可以在admin前后加上%c2~%ef之间的一个字符就能绕过,for循环的意思是避免我们用latin1字符绕过。
对于密码只做了preg_match()处理,所以可以用latin1字符绕过。latin1全部字符
为什么能绕过呢?mysql字符集默认为latin1,而latin1里的å并不等于阿拉伯数字a
最终传入?username=admin%c2&password=ådmins即可得到flag。