adding validated services? patching forcad_local.py
This commit is contained in:
1
ctfcup2025-school-final/checkers/sonobank/checker_stress_test/.gitignore
vendored
Executable file
1
ctfcup2025-school-final/checkers/sonobank/checker_stress_test/.gitignore
vendored
Executable file
@@ -0,0 +1 @@
|
||||
detailed.log
|
||||
@@ -0,0 +1,160 @@
|
||||
from pathlib import Path
|
||||
import asyncio
|
||||
import random
|
||||
import string
|
||||
import time
|
||||
|
||||
# run cargo build or cargo build --release before this
|
||||
|
||||
OK = 101
|
||||
CORRUPT = 102
|
||||
MUMBLE = 103
|
||||
DOWN = 104
|
||||
CHECKER_ERROR = 110
|
||||
|
||||
|
||||
RELEASE = True
|
||||
EXPECTED_CHECK_CODE = OK
|
||||
EXPECTED_PUT_CODE = OK
|
||||
EXPECTED_GET_CODE = OK
|
||||
CHECKS_PER_SECOND = 5
|
||||
CHECKS_PER_REPORT = 100
|
||||
MAX_PARALLEL_CHECKS = CHECKS_PER_SECOND * 3
|
||||
VULNS = 1
|
||||
TIMEOUT = 30
|
||||
HOST = "127.0.0.1"
|
||||
|
||||
assert VULNS == 1, "multiple vulns not supported."
|
||||
|
||||
check_period = 1 / CHECKS_PER_SECOND
|
||||
|
||||
if RELEASE:
|
||||
checker_binary_path = Path("../target/release/checker")
|
||||
else:
|
||||
checker_binary_path = Path("../target/debug/checker")
|
||||
|
||||
detailed_log_filepath = Path("detailed.log")
|
||||
|
||||
def returncode_to_string(returncode):
|
||||
if returncode == 101:
|
||||
return "OK"
|
||||
elif returncode == 102:
|
||||
return "CORRUPT"
|
||||
elif returncode == 103:
|
||||
return "MUMBLE"
|
||||
elif returncode == 104:
|
||||
return "DOWN"
|
||||
elif returncode == 110:
|
||||
return "CHECKER_ERROR"
|
||||
else:
|
||||
return "UNEXPECTED"
|
||||
|
||||
def get_random_flag():
|
||||
return "S" + "".join(random.choices(string.ascii_uppercase + string.digits, k=30)) + "="
|
||||
|
||||
output_lock = asyncio.locks.Lock()
|
||||
async def write_to_detailed_log(entry, *, also_print=False):
|
||||
async with output_lock:
|
||||
with open(detailed_log_filepath, "a") as f:
|
||||
f.write(entry + "\n")
|
||||
if also_print:
|
||||
print(entry)
|
||||
|
||||
assert checker_binary_path.exists(), "checker binary doesn't exist. run cargo build or cargo build --release before this."
|
||||
|
||||
async def do_all_checks_once():
|
||||
flag = get_random_flag()
|
||||
|
||||
check_process = await asyncio.create_subprocess_exec(
|
||||
checker_binary_path, "check", HOST,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE
|
||||
)
|
||||
try:
|
||||
stdout_data, stderr_data = await asyncio.wait_for(check_process.communicate(), timeout=TIMEOUT)
|
||||
except asyncio.TimeoutError:
|
||||
stdout_data, stderr_data = await check_process.stdout.read(), await check_process.stderr.read()
|
||||
await write_to_detailed_log(
|
||||
f"CHECK({flag}): Stuck for {TIMEOUT} seconds. Make sure the checker code has it's own timeouts. stdout={stdout_data} stderr={stderr_data}",
|
||||
also_print=True
|
||||
)
|
||||
check_process.kill()
|
||||
else:
|
||||
returncode = check_process.returncode
|
||||
await write_to_detailed_log(
|
||||
f"CHECK({flag}): {returncode_to_string(returncode)} ({returncode}) stdout={stdout_data} stderr={stderr_data}",
|
||||
also_print=(EXPECTED_CHECK_CODE is not None and returncode != EXPECTED_CHECK_CODE)
|
||||
)
|
||||
|
||||
put_process = await asyncio.create_subprocess_exec(
|
||||
checker_binary_path, "put", HOST, "", flag, "1",
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE
|
||||
)
|
||||
try:
|
||||
stdout_data, stderr_data = await asyncio.wait_for(put_process.communicate(), timeout=TIMEOUT)
|
||||
except asyncio.TimeoutError:
|
||||
stdout_data, stderr_data = await put_process.stdout.read(), await put_process.stderr.read()
|
||||
await write_to_detailed_log(
|
||||
f"PUT({flag}): Stuck for {TIMEOUT} seconds. Make sure the checker code has it's own timeouts. stdout={stdout_data} stderr={stderr_data}",
|
||||
also_print=True
|
||||
)
|
||||
put_process.kill()
|
||||
failed = True
|
||||
else:
|
||||
returncode = put_process.returncode
|
||||
await write_to_detailed_log(
|
||||
f"PUT({flag}): {returncode_to_string(returncode)} ({returncode}) stdout(public)={stdout_data} stderr(private)={stderr_data}",
|
||||
also_print=(EXPECTED_PUT_CODE is not None and returncode != EXPECTED_PUT_CODE)
|
||||
)
|
||||
flag_id = stderr_data
|
||||
failed = returncode != OK
|
||||
|
||||
if failed:
|
||||
await write_to_detailed_log(
|
||||
f"GET({flag}): SKIPPED since PUT failed.",
|
||||
also_print=(EXPECTED_GET_CODE is not None)
|
||||
)
|
||||
return
|
||||
|
||||
get_process = await asyncio.create_subprocess_exec(
|
||||
checker_binary_path, "get", HOST, flag_id, flag, "1",
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE
|
||||
)
|
||||
try:
|
||||
stdout_data, stderr_data = await asyncio.wait_for(get_process.communicate(), timeout=TIMEOUT)
|
||||
except asyncio.TimeoutError:
|
||||
stdout_data, stderr_data = await get_process.stdout.read(), await get_process.stderr.read()
|
||||
await write_to_detailed_log(
|
||||
f"GET({flag}): Stuck for {TIMEOUT} seconds. Make sure the checker code has it's own timeouts. stdout={stdout_data} stderr={stderr_data}",
|
||||
also_print=True
|
||||
)
|
||||
get_process.kill()
|
||||
else:
|
||||
returncode = get_process.returncode
|
||||
await write_to_detailed_log(
|
||||
f"GET({flag}): {returncode_to_string(returncode)} ({returncode}) stdout(public)={stdout_data} stderr(private)={stderr_data}",
|
||||
also_print=(EXPECTED_GET_CODE is not None and returncode != EXPECTED_GET_CODE)
|
||||
)
|
||||
|
||||
|
||||
async def main():
|
||||
pending_tasks = []
|
||||
checks_done = 0
|
||||
while True:
|
||||
if len(pending_tasks) > 0 and pending_tasks[0].done() and (checks_done + 1) % CHECKS_PER_REPORT == 0:
|
||||
print(f"Already done {checks_done + 1} checks. {len(pending_tasks) - 1} running in parallel.")
|
||||
while len(pending_tasks) > 0 and pending_tasks[0].done():
|
||||
pending_tasks.pop(0)
|
||||
checks_done += 1
|
||||
if len(pending_tasks) <= MAX_PARALLEL_CHECKS:
|
||||
pending_tasks.append(asyncio.create_task(asyncio.wait_for(do_all_checks_once(), timeout=TIMEOUT * 3 + 10)))
|
||||
else:
|
||||
print(f"Throttling checks since there are at least {MAX_PARALLEL_CHECKS} running")
|
||||
await asyncio.sleep(check_period)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
|
||||
Reference in New Issue
Block a user