Skip to content

Commit 6fcf143

Browse files
hakatashiColdHeat
authored andcommitted
Fix rate-limiting of flag submission when using team mode (CTFd#977)
* Fix rate-limiting of flag submission when using team mode (Resolves CTFd#975) * Add tests for rate-limiting of flag submission
1 parent 3f4a242 commit 6fcf143

File tree

2 files changed

+51
-16
lines changed

2 files changed

+51
-16
lines changed

CTFd/api/v1/challenges.py

+7-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from flask import session, request, abort, url_for
1+
from flask import request, abort, url_for
22
from flask_restplus import Namespace, Resource
33
from CTFd.models import (
44
db,
@@ -376,7 +376,8 @@ def post(self):
376376
chal_class = get_chal_class(challenge.type)
377377

378378
# Anti-bruteforce / submitting Flags too quickly
379-
if current_user.get_wrong_submissions_per_minute(session['id']) > 10:
379+
kpm = current_user.get_wrong_submissions_per_minute(user.account_id)
380+
if kpm > 10:
380381
if ctftime():
381382
chal_class.fail(
382383
user=user,
@@ -388,7 +389,7 @@ def post(self):
388389
'submissions',
389390
"[{date}] {name} submitted {submission} with kpm {kpm} [TOO FAST]",
390391
submission=request_data['submission'].encode('utf-8'),
391-
kpm=current_user.get_wrong_submissions_per_minute(session['id'])
392+
kpm=kpm
392393
)
393394
# Submitting too fast
394395
return {
@@ -432,8 +433,7 @@ def post(self):
432433
'submissions',
433434
"[{date}] {name} submitted {submission} with kpm {kpm} [CORRECT]",
434435
submission=request_data['submission'].encode('utf-8'),
435-
kpm=current_user.get_wrong_submissions_per_minute(
436-
session['id'])
436+
kpm=kpm
437437
)
438438
return {
439439
'success': True,
@@ -456,8 +456,7 @@ def post(self):
456456
'submissions',
457457
"[{date}] {name} submitted {submission} with kpm {kpm} [WRONG]",
458458
submission=request_data['submission'].encode('utf-8'),
459-
kpm=current_user.get_wrong_submissions_per_minute(
460-
session['id'])
459+
kpm=kpm
461460
)
462461

463462
if max_tries:
@@ -491,9 +490,7 @@ def post(self):
491490
'submissions',
492491
"[{date}] {name} submitted {submission} with kpm {kpm} [ALREADY SOLVED]",
493492
submission=request_data['submission'].encode('utf-8'),
494-
kpm=current_user.get_wrong_submissions_per_minute(
495-
user.account_id
496-
)
493+
kpm=kpm
497494
)
498495
return {
499496
'success': True,

tests/api/v1/test_challenges.py

+44-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
gen_flag,
1212
gen_user,
1313
gen_team,
14-
gen_solve)
14+
gen_solve,
15+
gen_fail)
1516
from freezegun import freeze_time
1617

1718

@@ -308,19 +309,56 @@ def test_api_challenge_attempt_post_private():
308309
"""Can an private user post /api/v1/challenges/attempt"""
309310
app = create_ctfd()
310311
with app.app_context():
311-
gen_challenge(app.db)
312-
gen_flag(app.db, 1)
312+
challenge_id = gen_challenge(app.db).id
313+
gen_flag(app.db, challenge_id)
313314
register_user(app)
314315
with login_as_user(app) as client:
315-
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": 1, "submission": "wrong_flag"})
316+
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": challenge_id, "submission": "wrong_flag"})
316317
assert r.status_code == 200
317318
assert r.get_json()['data']['status'] == 'incorrect'
318-
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": 1, "submission": "flag"})
319+
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": challenge_id, "submission": "flag"})
319320
assert r.status_code == 200
320321
assert r.get_json()['data']['status'] == 'correct'
321-
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": 1, "submission": "flag"})
322+
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": challenge_id, "submission": "flag"})
322323
assert r.status_code == 200
323324
assert r.get_json()['data']['status'] == 'already_solved'
325+
challenge_id = gen_challenge(app.db).id
326+
gen_flag(app.db, challenge_id)
327+
with login_as_user(app) as client:
328+
for i in range(10):
329+
gen_fail(app.db, user_id=2, challenge_id=challenge_id)
330+
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": challenge_id, "submission": "flag"})
331+
assert r.status_code == 429
332+
assert r.get_json()['data']['status'] == 'ratelimited'
333+
destroy_ctfd(app)
334+
335+
app = create_ctfd(user_mode="teams")
336+
with app.app_context():
337+
challenge_id = gen_challenge(app.db).id
338+
gen_flag(app.db, challenge_id)
339+
register_user(app)
340+
team_id = gen_team(app.db).id
341+
user = Users.query.filter_by(id=2).first()
342+
user.team_id = team_id
343+
app.db.session.commit()
344+
with login_as_user(app) as client:
345+
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": challenge_id, "submission": "wrong_flag"})
346+
assert r.status_code == 200
347+
assert r.get_json()['data']['status'] == 'incorrect'
348+
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": challenge_id, "submission": "flag"})
349+
assert r.status_code == 200
350+
assert r.get_json()['data']['status'] == 'correct'
351+
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": challenge_id, "submission": "flag"})
352+
assert r.status_code == 200
353+
assert r.get_json()['data']['status'] == 'already_solved'
354+
challenge_id = gen_challenge(app.db).id
355+
gen_flag(app.db, challenge_id)
356+
with login_as_user(app) as client:
357+
for i in range(10):
358+
gen_fail(app.db, user_id=2, team_id=team_id, challenge_id=challenge_id)
359+
r = client.post('/api/v1/challenges/attempt', json={"challenge_id": challenge_id, "submission": "flag"})
360+
assert r.status_code == 429
361+
assert r.get_json()['data']['status'] == 'ratelimited'
324362
destroy_ctfd(app)
325363

326364

0 commit comments

Comments
 (0)