Skip to content

Commit

Permalink
fix: image register race condition
Browse files Browse the repository at this point in the history
  • Loading branch information
bchmnn committed Jul 7, 2024
1 parent 5f19142 commit b379a54
Show file tree
Hide file tree
Showing 7 changed files with 4,615 additions and 36 deletions.
439 changes: 412 additions & 27 deletions checker/poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion checker/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ websockets = "^12.0"
[tool.poetry.group.dev.dependencies]
enochecker-cli = "^0.7.1"
enochecker-test = "^0.9.0"
sympy = "^1.12"
aiohttp = "^3.9.5"

[build-system]
requires = ["poetry-core"]
Expand Down
208 changes: 208 additions & 0 deletions documentation/benchmark/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import asyncio
import base64
import fcntl
import hashlib
import secrets
import socket
import struct
import time
from typing import Any, Mapping

import aiohttp
from aiohttp.client import ClientSession


def get_ip_address(ifname):
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
return socket.inet_ntoa(
fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack("256s", bytes(ifname[:15], "utf-8")),
)[20:24]
)


CHECKER_ADDR = "http://127.0.0.1:16969"
SERVICE_ADDR = get_ip_address("wlp3s0")

"""
200
{
"result": "OK",
"message": "string",
"attackInfo": "string",
"flag": "string"
}
"""

"""
422
{
"detail": [
{
"loc": [
"string",
0
],
"msg": "string",
"type": "string"
}
]
}
"""


def generate_dummyflag() -> str:
flag = "ENO" + base64.b64encode(secrets.token_bytes(36)).decode()
assert len(flag) == 51
return flag


class Round:
round_id: int
chain_prefix: str
flag: str
attack_info: str

def __init__(self, round_id: int):
self.round_id = round_id
self.chain_prefix = secrets.token_hex(20)
self.flag = generate_dummyflag()
self.attack_info = ""

@property
def putflag_chain_id(self) -> str:
return f"{self.chain_prefix}_flag_s0_r{self.round_id}_t0_i0"

@property
def getflag_chain_id(self) -> str:
return f"{self.chain_prefix}_flag_s0_r{self.round_id}_t0_i0"

@property
def exploit_chain_id(self) -> str:
return f"{self.chain_prefix}_exploit{self.round_id}_t0_i0"

@property
def putflag_payload(self) -> Mapping[str, Any]:
return {
"address": SERVICE_ADDR,
"attackInfo": None,
"currentRoundId": self.round_id,
"flag": self.flag,
"flagHash": None,
"flagRegex": None,
"method": "putflag",
"relatedRoundId": self.round_id,
"roundLength": 60000,
"taskChainId": self.putflag_chain_id,
"taskId": self.round_id,
"teamId": 0,
"teamName": "teamname",
"timeout": 10000,
"variantId": 0,
}

@property
def getflag_payload(self) -> Mapping[str, Any]:
return {
"address": SERVICE_ADDR,
"attackInfo": None,
"currentRoundId": self.round_id,
"flag": self.flag,
"flagHash": None,
"flagRegex": None,
"method": "getflag",
"relatedRoundId": self.round_id,
"roundLength": 60000,
"taskChainId": self.getflag_chain_id,
"taskId": self.round_id,
"teamId": 0,
"teamName": "teamname",
"timeout": 10000,
"variantId": 0,
}

@property
def exploit_payload(self) -> Mapping[str, Any]:
return {
"address": SERVICE_ADDR,
"attackInfo": self.attack_info,
"currentRoundId": self.round_id,
"flag": None,
"flagHash": hashlib.sha256(self.flag.encode()).hexdigest(),
"flagRegex": "ENO[A-Za-z0-9+\\/=]{48}",
"method": "exploit",
"relatedRoundId": self.round_id,
"roundLength": 60000,
"taskChainId": self.exploit_chain_id,
"taskId": self.round_id,
"teamId": 0,
"teamName": "teamname",
"timeout": 10000,
"variantId": 0,
}


async def putflag(client: ClientSession, round: Round):
start = time.monotonic()
async with client.post(
CHECKER_ADDR,
json=round.putflag_payload,
) as response:
if response.status == 200:
payload = await response.json()
print(
f"PUTFLAG {round.round_id}: ({str(time.monotonic() - start)[:5]}) {payload['result']} - {payload['message']}"
)
round.attack_info = payload["attackInfo"]
else:
print(
f"PUTFLAG {round.round_id}: ({str(time.monotonic() - start)[:5]}) {response.status}"
)


async def getflag(client: ClientSession, round: Round):
start = time.monotonic()
async with client.post(
CHECKER_ADDR,
json=round.getflag_payload,
) as response:
if response.status == 200:
payload = await response.json()
print(
f"GETFLAG {round.round_id}: ({str(time.monotonic() - start)[:5]}) {payload['result']} - {payload['message']}"
)
else:
print(
f"GETFLAG {round.round_id}: ({str(time.monotonic() - start)[:5]}) {response.status}"
)


async def exploit(client: ClientSession, round: Round):
start = time.monotonic()
async with client.post(
CHECKER_ADDR,
json=round.exploit_payload,
) as response:
if response.status == 200:
payload = await response.json()
print(
f"EXPLOIT {round.round_id}: ({str(time.monotonic() - start)[:5]}) {payload['result']} - {payload['message']}"
)
else:
print(
f"EXPLOIT {round.round_id}: ({str(time.monotonic() - start)[:5]}) {response.status}"
)


async def main():
async with aiohttp.ClientSession() as client:
round = Round(0)
await putflag(client, round)
await getflag(client, round)
futures = [exploit(client, round) for _ in range(100)]
await asyncio.gather(*futures)


asyncio.run(main())
Loading

0 comments on commit b379a54

Please sign in to comment.