ctf-attackapi 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ctf_attackapi-0.1.0/PKG-INFO +231 -0
- ctf_attackapi-0.1.0/README.md +197 -0
- ctf_attackapi-0.1.0/pyproject.toml +73 -0
- ctf_attackapi-0.1.0/src/attackapi/__init__.py +4 -0
- ctf_attackapi-0.1.0/src/attackapi/async_api/__init__.py +4 -0
- ctf_attackapi-0.1.0/src/attackapi/async_api/api.py +225 -0
- ctf_attackapi-0.1.0/src/attackapi/async_api/decoders.py +173 -0
- ctf_attackapi-0.1.0/src/attackapi/async_api/filelock.py +30 -0
- ctf_attackapi-0.1.0/src/attackapi/functional.py +46 -0
- ctf_attackapi-0.1.0/src/attackapi/models.py +134 -0
- ctf_attackapi-0.1.0/src/attackapi/py.typed +0 -0
- ctf_attackapi-0.1.0/src/attackapi/server/__init__.py +2 -0
- ctf_attackapi-0.1.0/src/attackapi/server/__main__.py +29 -0
- ctf_attackapi-0.1.0/src/attackapi/server/docs.py +76 -0
- ctf_attackapi-0.1.0/src/attackapi/server/server.py +109 -0
- ctf_attackapi-0.1.0/src/attackapi/server/worker.py +19 -0
- ctf_attackapi-0.1.0/src/attackapi/sync_api.py +29 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ctf-attackapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Get attack infos in attack-defense CTFs quickly to your exploits. CTF-agnostic and cached.
|
|
5
|
+
Keywords: Attack-Defense,CTF,Attack API,Attack Info,Flag IDs,FAUST CTF,ENOWARS,saarCTF
|
|
6
|
+
Author: Markus Bauer
|
|
7
|
+
Author-email: Markus Bauer <markus.bauer@cispa.saarland>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Intended Audience :: Education
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Security
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Dist: aiohttp>=3.13.3
|
|
22
|
+
Requires-Dist: aiologic>=0.16.0
|
|
23
|
+
Requires-Dist: filelock>=3.19.1
|
|
24
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
25
|
+
Requires-Dist: typing-extensions>=4.15.0
|
|
26
|
+
Requires-Dist: gunicorn>=23.0.0 ; extra == 'server'
|
|
27
|
+
Requires-Python: >=3.9
|
|
28
|
+
Project-URL: Homepage, https://github.com/Attacking-Lab/ctf-attackapi
|
|
29
|
+
Project-URL: Repository, https://github.com/Attacking-Lab/ctf-attackapi
|
|
30
|
+
Project-URL: Issues, https://github.com/Attacking-Lab/ctf-attackapi/issues
|
|
31
|
+
Project-URL: Background, https://wiki.attacking-lab.com/attack-defense/
|
|
32
|
+
Provides-Extra: server
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
CTF AttackAPI - Cached and Unified!
|
|
36
|
+
===================================
|
|
37
|
+
|
|
38
|
+
[](https://opensource.org/license/mit)
|
|
39
|
+

|
|
40
|
+

|
|
41
|
+
[](https://github.com/Attacking-Lab/ctf-attackapi/actions/workflows/python-package.yml)
|
|
42
|
+
[](https://pypi.org/project/ctf-attackapi)
|
|
43
|
+

|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
Gather attack information quickly in your attack-defense CTF exploits!
|
|
48
|
+
|
|
49
|
+
During [attack-defense CTF competitions](https://wiki.attacking-lab.com/attack-defense/), you have to write exploits
|
|
50
|
+
quickly and run them on a large scale.
|
|
51
|
+
These exploits often require information about the targets to attack (teams and sometimes usernames).
|
|
52
|
+
This attack info is available as a big JSON file which is updated every few minutes.
|
|
53
|
+
Downloading that file for every exploit you're firing is costing time and bandwidth.
|
|
54
|
+
|
|
55
|
+
This package fetches, parses, and caches attack info for you, so you can focus on writing exploits!
|
|
56
|
+
|
|
57
|
+
Features
|
|
58
|
+
--------
|
|
59
|
+
|
|
60
|
+
- Efficient caching between threads, processes, or containers
|
|
61
|
+
- Direct access from your Python exploits ([sync](./examples/basic.py) or [async](./examples/basic_async.py))
|
|
62
|
+
- Optional REST API for exploits in other languages (with [OpenAPI spec](./api.yaml))
|
|
63
|
+
- Unifies team, IP, and flag info lookup between different CTFs:
|
|
64
|
+
- Supports [ENOWARS](https://enowars.com)
|
|
65
|
+
- Supports [FAUST CTF](https://faustctf.net)
|
|
66
|
+
- Supports [saarCTF](https://ctf.saarland) (including ECSC gameserver)
|
|
67
|
+
|
|
68
|
+
Quick-Start
|
|
69
|
+
-----------
|
|
70
|
+
See [examples](./examples) directory for more full scripts.
|
|
71
|
+
|
|
72
|
+
Install the package (possibly in a virtual environment):
|
|
73
|
+
|
|
74
|
+
```shell
|
|
75
|
+
pip install ctf-attackapi
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Get attack infos for your python exploit:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from attackapi import *
|
|
82
|
+
|
|
83
|
+
# 1. Set the API URL in code (or use CTF_API environment variable)
|
|
84
|
+
configure("https://scoreboard.ctf.saarland/api/attack.json")
|
|
85
|
+
# 2. Get attack infos!
|
|
86
|
+
for username in attack_info().flag_id_flat("no-service", "10.32.1.2"):
|
|
87
|
+
pwn("10.32.1.2", username)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
List all teams that you can attack:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from attackapi import *
|
|
94
|
+
|
|
95
|
+
configure("https://scoreboard.ctf.saarland/api/attack.json")
|
|
96
|
+
for team in attack_info().teams:
|
|
97
|
+
print(team.id, team.ip, team.name)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Get attack infos from REST API if you're not pwning in Python:
|
|
101
|
+
|
|
102
|
+
```shell
|
|
103
|
+
python -m attackapi.server --url "https://scoreboard.ctf.saarland/api/attack.json"
|
|
104
|
+
curl "http://localhost:14320/api/v1/teams"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The server has documentation on its frontpage, and here is [the OpenAPI specification](./api.yaml).
|
|
108
|
+
|
|
109
|
+
If you're not pwning in Python and dislike pip, try docker:
|
|
110
|
+
```shell
|
|
111
|
+
# edit compose.yaml and insert your CTF API URL
|
|
112
|
+
docker compose up -d
|
|
113
|
+
# visit http://localhost:14320/
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
Structure
|
|
118
|
+
---------
|
|
119
|
+
|
|
120
|
+
- Attack info data is retrieved and cached twice: in-memory and on disk (`/tmp` by default)
|
|
121
|
+
- Each request goes to the caches. If the cached data is outdated, it is refreshed in the background.
|
|
122
|
+
- No concurrent requests are made to the game API.
|
|
123
|
+
- Game-specific decoders process the game APIs data and make it accessible.
|
|
124
|
+
- You can query the data via python API from your exploits, or via REST API from other languages.
|
|
125
|
+
- Relying on the disk cache is good enough for typical exploitation scenarios.
|
|
126
|
+
|
|
127
|
+
Python Library Documentation
|
|
128
|
+
----------------------------
|
|
129
|
+
There are different ways to get an `AttackInfo` object:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
# 1. Functional
|
|
133
|
+
from attackapi import *
|
|
134
|
+
|
|
135
|
+
# Set the API URL in code (or use CTF_API environment variable)
|
|
136
|
+
configure("https://scoreboard.ctf.saarland/api/attack.json")
|
|
137
|
+
# sync:
|
|
138
|
+
info: AttackInfo = attack_info()
|
|
139
|
+
# async
|
|
140
|
+
info: AttackInfo = await attack_info_async()
|
|
141
|
+
|
|
142
|
+
# 2. By manually using the classes
|
|
143
|
+
from attackapi.sync_api import AdCtfApiSync
|
|
144
|
+
from attackapi.async_api import AdCtfApiAsync
|
|
145
|
+
|
|
146
|
+
api = AdCtfApiSync("https://scoreboard.ctf.saarland/api/attack.json")
|
|
147
|
+
info = api.attack_info()
|
|
148
|
+
api2 = AdCtfApiAsync("https://scoreboard.ctf.saarland/api/attack.json")
|
|
149
|
+
info = await api2.attack_info()
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Optional parameters can be passed to the `configure` function or the API constructors:
|
|
153
|
+
|
|
154
|
+
- `url: str` (default: `CTF_API` environment variable)
|
|
155
|
+
- `tmp_directory: str | Path` (default: `/tmp` or OS-specific alternative)
|
|
156
|
+
- `lifetime: float` (default: 30 seconds) - after this time, cached data is invalidated and refreshed
|
|
157
|
+
- `timeout: float` (default: 10 seconds) - abort game API requests after this duration
|
|
158
|
+
- `decoder: Decoder` (default: generic decoder) - custom decoder, if your game's format is different from what we've
|
|
159
|
+
seen so far
|
|
160
|
+
- `aiohttp_arguments: dict` - additional arguments passed to the aiohttp Session which contacts the game API
|
|
161
|
+
|
|
162
|
+
The `AttackInfo` class itself has these methods:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
info: AttackInfo
|
|
166
|
+
|
|
167
|
+
# Get attackable teams
|
|
168
|
+
print(info.teams) # list of Team objects
|
|
169
|
+
print(info.teams[0].id, info.teams[0].ip, info.teams[0].name) # Team is ID, IP, and optional name
|
|
170
|
+
print(info.team("10.32.1.2")) # query Team object by ID, IP, or name
|
|
171
|
+
|
|
172
|
+
# set of service names
|
|
173
|
+
print(info.services)
|
|
174
|
+
|
|
175
|
+
# raw flag IDs for a service and team.
|
|
176
|
+
# team can be ID, IP, or name.
|
|
177
|
+
# Return data format is determined by game API.
|
|
178
|
+
print(info.flag_id_raw("servicename", "10.32.1.2"))
|
|
179
|
+
# => {"227": "abc", "228": "def", ...}
|
|
180
|
+
|
|
181
|
+
# Get flag IDs as string list (independent of game API format, but less precise)
|
|
182
|
+
print(info.flag_id_flat("servicename", "10.32.1.2"))
|
|
183
|
+
# => ["abc", "def"]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Server Documentation
|
|
187
|
+
--------------------
|
|
188
|
+
|
|
189
|
+
```shell
|
|
190
|
+
# Simple usage:
|
|
191
|
+
python -m attackapi.server --help
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Options:
|
|
195
|
+
|
|
196
|
+
- `--port PORT`
|
|
197
|
+
- `--url URL`: API url to get CTF info from.
|
|
198
|
+
- `--tmp-directory TMP_DIRECTORY`: Cache directory
|
|
199
|
+
- `--lifetime LIFETIME`: Lifetime of cached data in seconds
|
|
200
|
+
- `--timeout TIMEOUT`: Timeout for API calls in seconds
|
|
201
|
+
|
|
202
|
+
```shell
|
|
203
|
+
# Usage for higher load scenarios:
|
|
204
|
+
pip install ctf-attackapi[gunicorn]
|
|
205
|
+
gunicorn attackapi.server:create_app --bind :14320 --worker-class attackapi.server.worker.MyGunicornWebWorker --workers 4
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Environment variables:
|
|
209
|
+
|
|
210
|
+
- `CTF_API`: URL to get CTF info from.
|
|
211
|
+
- `CTF_API_TMP_DIR`: Cache directory (gunicorn only)
|
|
212
|
+
- `CTF_API_LIFETIME`: Lifetime of cached data in seconds (gunicorn only)
|
|
213
|
+
- `CTF_API_TIMEOUT`: Timeout for API calls in seconds (gunicorn only)
|
|
214
|
+
|
|
215
|
+
You can also use docker to run the server:
|
|
216
|
+
```shell
|
|
217
|
+
# edit compose.yaml and insert your CTF API URL before!
|
|
218
|
+
docker compose up -d
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
Using attackapi for other information (scoreboard etc.)
|
|
223
|
+
-------------------------------------------------------
|
|
224
|
+
Feel free to re-use the caching layers for other information, like the current scoreboard.
|
|
225
|
+
The class `JsonAdCtfApiAsync` accepts arbitrary JSON endpoints:
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
from attackapi.async_api import JsonAdCtfApiAsync
|
|
229
|
+
|
|
230
|
+
info = await JsonAdCtfApiAsync("https://scoreboard.ctf.saarland/api/scoreboard_current.json").retrieve()
|
|
231
|
+
```
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
CTF AttackAPI - Cached and Unified!
|
|
2
|
+
===================================
|
|
3
|
+
|
|
4
|
+
[](https://opensource.org/license/mit)
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
[](https://github.com/Attacking-Lab/ctf-attackapi/actions/workflows/python-package.yml)
|
|
8
|
+
[](https://pypi.org/project/ctf-attackapi)
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Gather attack information quickly in your attack-defense CTF exploits!
|
|
14
|
+
|
|
15
|
+
During [attack-defense CTF competitions](https://wiki.attacking-lab.com/attack-defense/), you have to write exploits
|
|
16
|
+
quickly and run them on a large scale.
|
|
17
|
+
These exploits often require information about the targets to attack (teams and sometimes usernames).
|
|
18
|
+
This attack info is available as a big JSON file which is updated every few minutes.
|
|
19
|
+
Downloading that file for every exploit you're firing is costing time and bandwidth.
|
|
20
|
+
|
|
21
|
+
This package fetches, parses, and caches attack info for you, so you can focus on writing exploits!
|
|
22
|
+
|
|
23
|
+
Features
|
|
24
|
+
--------
|
|
25
|
+
|
|
26
|
+
- Efficient caching between threads, processes, or containers
|
|
27
|
+
- Direct access from your Python exploits ([sync](./examples/basic.py) or [async](./examples/basic_async.py))
|
|
28
|
+
- Optional REST API for exploits in other languages (with [OpenAPI spec](./api.yaml))
|
|
29
|
+
- Unifies team, IP, and flag info lookup between different CTFs:
|
|
30
|
+
- Supports [ENOWARS](https://enowars.com)
|
|
31
|
+
- Supports [FAUST CTF](https://faustctf.net)
|
|
32
|
+
- Supports [saarCTF](https://ctf.saarland) (including ECSC gameserver)
|
|
33
|
+
|
|
34
|
+
Quick-Start
|
|
35
|
+
-----------
|
|
36
|
+
See [examples](./examples) directory for more full scripts.
|
|
37
|
+
|
|
38
|
+
Install the package (possibly in a virtual environment):
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
pip install ctf-attackapi
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Get attack infos for your python exploit:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from attackapi import *
|
|
48
|
+
|
|
49
|
+
# 1. Set the API URL in code (or use CTF_API environment variable)
|
|
50
|
+
configure("https://scoreboard.ctf.saarland/api/attack.json")
|
|
51
|
+
# 2. Get attack infos!
|
|
52
|
+
for username in attack_info().flag_id_flat("no-service", "10.32.1.2"):
|
|
53
|
+
pwn("10.32.1.2", username)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
List all teams that you can attack:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from attackapi import *
|
|
60
|
+
|
|
61
|
+
configure("https://scoreboard.ctf.saarland/api/attack.json")
|
|
62
|
+
for team in attack_info().teams:
|
|
63
|
+
print(team.id, team.ip, team.name)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Get attack infos from REST API if you're not pwning in Python:
|
|
67
|
+
|
|
68
|
+
```shell
|
|
69
|
+
python -m attackapi.server --url "https://scoreboard.ctf.saarland/api/attack.json"
|
|
70
|
+
curl "http://localhost:14320/api/v1/teams"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The server has documentation on its frontpage, and here is [the OpenAPI specification](./api.yaml).
|
|
74
|
+
|
|
75
|
+
If you're not pwning in Python and dislike pip, try docker:
|
|
76
|
+
```shell
|
|
77
|
+
# edit compose.yaml and insert your CTF API URL
|
|
78
|
+
docker compose up -d
|
|
79
|
+
# visit http://localhost:14320/
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
Structure
|
|
84
|
+
---------
|
|
85
|
+
|
|
86
|
+
- Attack info data is retrieved and cached twice: in-memory and on disk (`/tmp` by default)
|
|
87
|
+
- Each request goes to the caches. If the cached data is outdated, it is refreshed in the background.
|
|
88
|
+
- No concurrent requests are made to the game API.
|
|
89
|
+
- Game-specific decoders process the game APIs data and make it accessible.
|
|
90
|
+
- You can query the data via python API from your exploits, or via REST API from other languages.
|
|
91
|
+
- Relying on the disk cache is good enough for typical exploitation scenarios.
|
|
92
|
+
|
|
93
|
+
Python Library Documentation
|
|
94
|
+
----------------------------
|
|
95
|
+
There are different ways to get an `AttackInfo` object:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
# 1. Functional
|
|
99
|
+
from attackapi import *
|
|
100
|
+
|
|
101
|
+
# Set the API URL in code (or use CTF_API environment variable)
|
|
102
|
+
configure("https://scoreboard.ctf.saarland/api/attack.json")
|
|
103
|
+
# sync:
|
|
104
|
+
info: AttackInfo = attack_info()
|
|
105
|
+
# async
|
|
106
|
+
info: AttackInfo = await attack_info_async()
|
|
107
|
+
|
|
108
|
+
# 2. By manually using the classes
|
|
109
|
+
from attackapi.sync_api import AdCtfApiSync
|
|
110
|
+
from attackapi.async_api import AdCtfApiAsync
|
|
111
|
+
|
|
112
|
+
api = AdCtfApiSync("https://scoreboard.ctf.saarland/api/attack.json")
|
|
113
|
+
info = api.attack_info()
|
|
114
|
+
api2 = AdCtfApiAsync("https://scoreboard.ctf.saarland/api/attack.json")
|
|
115
|
+
info = await api2.attack_info()
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Optional parameters can be passed to the `configure` function or the API constructors:
|
|
119
|
+
|
|
120
|
+
- `url: str` (default: `CTF_API` environment variable)
|
|
121
|
+
- `tmp_directory: str | Path` (default: `/tmp` or OS-specific alternative)
|
|
122
|
+
- `lifetime: float` (default: 30 seconds) - after this time, cached data is invalidated and refreshed
|
|
123
|
+
- `timeout: float` (default: 10 seconds) - abort game API requests after this duration
|
|
124
|
+
- `decoder: Decoder` (default: generic decoder) - custom decoder, if your game's format is different from what we've
|
|
125
|
+
seen so far
|
|
126
|
+
- `aiohttp_arguments: dict` - additional arguments passed to the aiohttp Session which contacts the game API
|
|
127
|
+
|
|
128
|
+
The `AttackInfo` class itself has these methods:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
info: AttackInfo
|
|
132
|
+
|
|
133
|
+
# Get attackable teams
|
|
134
|
+
print(info.teams) # list of Team objects
|
|
135
|
+
print(info.teams[0].id, info.teams[0].ip, info.teams[0].name) # Team is ID, IP, and optional name
|
|
136
|
+
print(info.team("10.32.1.2")) # query Team object by ID, IP, or name
|
|
137
|
+
|
|
138
|
+
# set of service names
|
|
139
|
+
print(info.services)
|
|
140
|
+
|
|
141
|
+
# raw flag IDs for a service and team.
|
|
142
|
+
# team can be ID, IP, or name.
|
|
143
|
+
# Return data format is determined by game API.
|
|
144
|
+
print(info.flag_id_raw("servicename", "10.32.1.2"))
|
|
145
|
+
# => {"227": "abc", "228": "def", ...}
|
|
146
|
+
|
|
147
|
+
# Get flag IDs as string list (independent of game API format, but less precise)
|
|
148
|
+
print(info.flag_id_flat("servicename", "10.32.1.2"))
|
|
149
|
+
# => ["abc", "def"]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Server Documentation
|
|
153
|
+
--------------------
|
|
154
|
+
|
|
155
|
+
```shell
|
|
156
|
+
# Simple usage:
|
|
157
|
+
python -m attackapi.server --help
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Options:
|
|
161
|
+
|
|
162
|
+
- `--port PORT`
|
|
163
|
+
- `--url URL`: API url to get CTF info from.
|
|
164
|
+
- `--tmp-directory TMP_DIRECTORY`: Cache directory
|
|
165
|
+
- `--lifetime LIFETIME`: Lifetime of cached data in seconds
|
|
166
|
+
- `--timeout TIMEOUT`: Timeout for API calls in seconds
|
|
167
|
+
|
|
168
|
+
```shell
|
|
169
|
+
# Usage for higher load scenarios:
|
|
170
|
+
pip install ctf-attackapi[gunicorn]
|
|
171
|
+
gunicorn attackapi.server:create_app --bind :14320 --worker-class attackapi.server.worker.MyGunicornWebWorker --workers 4
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Environment variables:
|
|
175
|
+
|
|
176
|
+
- `CTF_API`: URL to get CTF info from.
|
|
177
|
+
- `CTF_API_TMP_DIR`: Cache directory (gunicorn only)
|
|
178
|
+
- `CTF_API_LIFETIME`: Lifetime of cached data in seconds (gunicorn only)
|
|
179
|
+
- `CTF_API_TIMEOUT`: Timeout for API calls in seconds (gunicorn only)
|
|
180
|
+
|
|
181
|
+
You can also use docker to run the server:
|
|
182
|
+
```shell
|
|
183
|
+
# edit compose.yaml and insert your CTF API URL before!
|
|
184
|
+
docker compose up -d
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
Using attackapi for other information (scoreboard etc.)
|
|
189
|
+
-------------------------------------------------------
|
|
190
|
+
Feel free to re-use the caching layers for other information, like the current scoreboard.
|
|
191
|
+
The class `JsonAdCtfApiAsync` accepts arbitrary JSON endpoints:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
from attackapi.async_api import JsonAdCtfApiAsync
|
|
195
|
+
|
|
196
|
+
info = await JsonAdCtfApiAsync("https://scoreboard.ctf.saarland/api/scoreboard_current.json").retrieve()
|
|
197
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ctf-attackapi"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Get attack infos in attack-defense CTFs quickly to your exploits. CTF-agnostic and cached."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license_files = ["LICENSE.txt"]
|
|
8
|
+
keywords = ["Attack-Defense", "CTF", "Attack API", "Attack Info", "Flag IDs", "FAUST CTF", "ENOWARS", "saarCTF"]
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Markus Bauer", email = "markus.bauer@cispa.saarland" }
|
|
11
|
+
]
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Intended Audience :: Education",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Programming Language :: Python :: 3.14",
|
|
24
|
+
"Topic :: Security",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"aiohttp>=3.13.3",
|
|
29
|
+
"aiologic>=0.16.0",
|
|
30
|
+
"filelock>=3.19.1",
|
|
31
|
+
"pyyaml>=6.0.3",
|
|
32
|
+
"typing-extensions>=4.15.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
server = [
|
|
37
|
+
"gunicorn>=23.0.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://github.com/Attacking-Lab/ctf-attackapi"
|
|
42
|
+
Repository = "https://github.com/Attacking-Lab/ctf-attackapi"
|
|
43
|
+
Issues = "https://github.com/Attacking-Lab/ctf-attackapi/issues"
|
|
44
|
+
Background = "https://wiki.attacking-lab.com/attack-defense/"
|
|
45
|
+
|
|
46
|
+
[build-system]
|
|
47
|
+
requires = ["uv_build>=0.9.27,<0.10.0"]
|
|
48
|
+
build-backend = "uv_build"
|
|
49
|
+
|
|
50
|
+
[project.scripts]
|
|
51
|
+
ctf-attackapi-server = "attackapi.server:main"
|
|
52
|
+
|
|
53
|
+
[dependency-groups]
|
|
54
|
+
dev = [
|
|
55
|
+
"mypy>=1.19.1",
|
|
56
|
+
"pytest>=8.4.2",
|
|
57
|
+
"types-pyyaml>=6.0.12.20250915",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[tool.uv.build-backend]
|
|
61
|
+
module-name = "attackapi"
|
|
62
|
+
|
|
63
|
+
[[tool.uv.index]]
|
|
64
|
+
name = "testpypi"
|
|
65
|
+
url = "https://test.pypi.org/simple/"
|
|
66
|
+
publish-url = "https://test.pypi.org/legacy/"
|
|
67
|
+
explicit = true
|
|
68
|
+
|
|
69
|
+
[tool.mypy]
|
|
70
|
+
python_version = "3.9"
|
|
71
|
+
disallow_untyped_defs = true
|
|
72
|
+
packages = ["attackapi", "tests", "examples"]
|
|
73
|
+
mypy_path = ["./src", "./tests", "./examples"]
|