├── .github └── workflows │ ├── build.yml │ └── deploy.yml ├── .gitignore ├── README.md ├── ctf.json ├── data ├── events │ ├── *CTF 2021.json │ ├── 0CTF-TCTF 2021 Finals.json │ ├── 0CTF-TCTF 2021 Quals.json │ ├── 0x41414141 CTF.json │ ├── 3kCTF 2021.json │ ├── ASIS CTF Quals 2021.json │ ├── Aero CTF 2021.json │ ├── Asian Cyber Security Challenge 2021.json │ ├── BCACTF 2.0.json │ ├── BSides Noida CTF.json │ ├── BSidesSF 2021 CTF.json │ ├── Balsn CTF 2021.json │ ├── BlueHens CTF 2021.json │ ├── COMPFEST CTF 2021.json │ ├── CSAW CTF Qualification Round 2021.json │ ├── CakeCTF 2021.json │ ├── Codefest CTF 2020.json │ ├── Crypto CTF 2021.json │ ├── DCTF 2021.json │ ├── DEF CON CTF Qualifier 2021.json │ ├── DUNGEON - BSides Ahmedabad CTF 2021.json │ ├── DaVinciCTF 2021.json │ ├── DawgCTF 2021.json │ ├── DiceCTF.json │ ├── DownUnderCTF 2021 (Online).json │ ├── FooBar CTF 2021.json │ ├── Google Capture The Flag 2021.json │ ├── HSCTF 8.json │ ├── Hack.lu CTF 2021.json │ ├── HackPack CTF 2021.json │ ├── ICHSA CTF.json │ ├── IJCTF 2021.json │ ├── ImaginaryCTF 2021.json │ ├── Incognito 2.0.json │ ├── Intent CTF 2021.json │ ├── LINE CTF.json │ ├── Midnightsun CTF 2021 Finals.json │ ├── Midnightsun CTF 2021.json │ ├── N1CTF 2021.json │ ├── NahamCon CTF 2021.json │ ├── OMH 2021 CTF.json │ ├── PlaidCTF 2021.json │ ├── RITSEC CTF 2021.json │ ├── RaRCTF 2021.json │ ├── S4CTF 2021.json │ ├── SPRUSH CTF Quals 2021.json │ ├── Securinets CTF Quals 2021.json │ ├── Sunshine CTF 2021.json │ ├── TMUCTF 2021.json │ ├── TSG CTF 2021.json │ ├── TastelessCTF 2021.json │ ├── Tenable CTF 2021.json │ ├── TyphoonCon CTF 2021.json │ ├── UIUCTF 2021.json │ ├── UMDCTF 2021.json │ ├── UMassCTF 2021.json │ ├── UTCTF 2021.json │ ├── Union CTF.json │ ├── Valentine CTF 21'.json │ ├── Zh3r0 CTF V2.json │ ├── b01lers CTF 2021.json │ ├── corCTF 2021.json │ ├── darkCON CTF.json │ ├── justCTF [*] 2020.json │ ├── m0leCon 2021 Teaser CTF.json │ ├── pbctf 2021.json │ ├── redpwnCTF 2021.json │ ├── wtfctf.json │ ├── zer0pts CTF 2021.json │ └── ångstromCTF 2021.json └── teams │ ├── alles.json │ ├── kalmarunionen.json │ ├── mslc.json │ ├── superguesser.json │ └── zer0pts.json ├── front ├── .gitignore ├── assets │ └── css │ │ └── main.css ├── components │ ├── challengepanel.vue │ ├── date.vue │ ├── ratecolor.vue │ └── teamRow.vue ├── layouts │ └── default.vue ├── nuxt.config.js ├── package.json ├── pages │ ├── event │ │ └── _name.vue │ ├── events.vue │ ├── index.vue │ ├── redirect.vue │ └── team │ │ ├── _name.vue │ │ └── _name │ │ └── _ctf.vue ├── plugins │ └── vue-virtual-scroll-list.js ├── static │ └── 404.html ├── store │ └── index.js └── yarn.lock ├── lib ├── __init__.py ├── difficulty.py ├── perf.py ├── scraper │ ├── __init__.py │ ├── angstromctf.py │ ├── asisctf.py │ ├── bcactf.py │ ├── bsidessf.py │ ├── ctfd.py │ ├── ctfd_legacy.py │ ├── ctfx.py │ ├── d3ctf.py │ ├── defcon.py │ ├── hacklu.py │ ├── imaginaryctf.py │ ├── midnightsun.py │ ├── n1ctf.py │ ├── p4.py │ ├── plaidctf.py │ ├── rctf.py │ ├── tctf.py │ └── the3000.py └── types.py ├── makedb.py ├── poetry.lock ├── pyproject.toml └── script.py /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: 3 | pull_request: 4 | paths: 5 | - 'data/**/*.json' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@master 13 | - uses: actions/setup-python@v2 14 | with: 15 | python-version: '3.9' 16 | - uses: abatilo/actions-poetry@v2.0.0 17 | with: 18 | poetry-version: '1' 19 | - uses: actions/cache@v2 20 | id: cache-venv 21 | with: 22 | path: .venv 23 | key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} 24 | - run: poetry install 25 | # if: steps.cache-venv.outputs.cache-hit != 'true' 26 | - run: poetry run python makedb.py 27 | - uses: stefanzweifel/git-auto-commit-action@v4 28 | if: success() 29 | with: 30 | commit_message: "build ctf.json" 31 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: deploy 2 | on: 3 | push: 4 | branches: 5 | - main 6 | workflow_dispatch: 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@master 13 | - uses: actions/setup-node@v2 14 | with: 15 | node-version: '15' 16 | - run: echo "::set-output name=dir::$(yarn cache dir)" 17 | id: yarn-cache-dir-path 18 | working-directory: ./front 19 | - uses: actions/cache@v2 20 | id: cache-yarn 21 | with: 22 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 23 | key: yarn-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} 24 | - run: yarn 25 | working-directory: ./front 26 | - run: yarn build && yarn generate 27 | working-directory: ./front 28 | - uses: peaceiris/actions-gh-pages@v3 29 | with: 30 | github_token: ${{ secrets.GITHUB_TOKEN }} 31 | publish_dir: ./front/dist 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.pyc 3 | .vim 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CTF-Ratings 2 | 3 | ctftime.org じゃないレーティングシステム考えて、ついでに色がついたら最高だよねというプロダクト 4 | 5 | 6 | ## レートとパフォーマンス 7 | 8 | 基本的にAtCoderに準拠している。 9 | 10 | - コンテストの対象レーティングが存在しない 11 | - 初期パフォーマンスは1200 12 | - レーティング上限なし 13 | 14 | ## Difficulty 15 | 16 | レートXのチームがその問題を解ける確率が50%のとき、その問題のDifficultyはX 17 | 18 | 19 | ## How to contribute? 20 | 21 | ### Add CTF Result 22 | 23 | Add `.json` to `./data/events/`. Scoreboard format is following mainly https://ctftime.org/json-scoreboard-feed. 24 | 25 | ```json 26 | { 27 | "tasks": ["task1", "task2", ...], 28 | "standings": [ 29 | { 30 | "pos": 1, 31 | "team": "teamName", 32 | "score": 1333, 33 | "taskStats": { 34 | "task1": { 35 | "points": 1, 36 | "time": 1615117300 37 | }, 38 | "task2": { 39 | "points": 1, 40 | "time": 1615117300 41 | } 42 | } 43 | }, 44 | { ... } 45 | ], 46 | "date": 1600000000, // added 47 | "name": "CTF Name" // added 48 | } 49 | ``` 50 | 51 | ### Add your team alias 52 | 53 | See example https://github.com/theoremoon/ctf-ratings/blob/main/data/teams/zer0pts.json 54 | 55 | ## Missing CTFs 56 | 57 | - D^3 CTF (scoreserver is closed) 58 | - vishwaCTF 2021 (cloudflare protection) 59 | - BCA CTF 2021 (no scoreserver) 60 | - White-Hats Break the Syntax CTF (ssl handshake failed) 61 | - Volga CTF2021 Qualifier (non-scrapable original platform) 62 | - BSides Canberra CTF 2021 (scoreboard closed already) 63 | - Cyber Apocalypse 2021 (how do I scrape htb ctf platform?) 64 | - Hero CTF v3 (bot check) 65 | - WPICTF (cloudflare) 66 | - TAMU CTF (cannot see solved tasks of other teams) 67 | - pwn2win (I forgot to collect the scoreboard ;_;) 68 | - Circle City Con CTF 2021 (scoreboard closed immediately after the competition) 69 | - THC CTF 2021 (registration closed immediately after the competition and challenges were only opened for the competitors) 70 | - CyberThreatForce CTF | 2021 (registration is closed / scoreboard not available) 71 | - CyBRICS CTF (I cannot know each teams solved what challenges) 72 | - ~~RAR CTF (I cannot know each teams solved what challenges)~~ added by @willwam845 at (https://github.com/theoremoon/ctf-ratings/pull/57) 73 | - Really Awesome CTF (ditto) 74 | - InCTF (scoreserver is closed) 75 | - FwordCTF 2021 (scoreserver is unstable to scrape) 76 | - YauzaCTF 2021 (cannot see solved tasks of other teams) 77 | - WORMCON 0x01 (UserAgent Denied) 78 | - GrabCON (cloudflare protection) 79 | - RCTF 2021 (XCTF) 80 | 81 | ## Author 82 | 83 | - theoremoon (zer0pts) 84 | 85 | ## License 86 | 87 | Apache 2.0 88 | -------------------------------------------------------------------------------- /data/events/0CTF-TCTF 2021 Finals.json: -------------------------------------------------------------------------------- 1 | { 2 | "standings": [ 3 | { 4 | "pos": 1, 5 | "team": "organizers", 6 | "score": "6668", 7 | "taskStats": { 8 | "eeenginx": null, 9 | "ezMat": null, 10 | "Secure JIT II": null, 11 | "boynextdoor": null, 12 | "0VM": null, 13 | "kbrop": null, 14 | "Win-Win": null, 15 | "babalogin": null, 16 | "ezRSA": null, 17 | "ezHash": null, 18 | "ezRSA+": null, 19 | "useCTF()": null, 20 | "babylogin": null, 21 | "how_to_generate": null, 22 | "kernote": null, 23 | "halfhalf": null, 24 | "favourite fruit": null 25 | } 26 | }, 27 | { 28 | "pos": 2, 29 | "team": "r3kapig", 30 | "score": "6098", 31 | "taskStats": { 32 | "Secure JIT II": null, 33 | "eeenginx": null, 34 | "boynextdoor": null, 35 | "babylogin": null, 36 | "ezMat": null, 37 | "0VM": null, 38 | "Win-Win": null, 39 | "promise": null, 40 | "bali": null, 41 | "ezRSA": null, 42 | "how_to_generate": null, 43 | "halfhalf": null, 44 | "buggyLoader": null, 45 | "kbrop": null, 46 | "BabaHeap": null, 47 | "NaiveHeap": null 48 | } 49 | }, 50 | { 51 | "pos": 3, 52 | "team": "Balsn", 53 | "score": "6085", 54 | "taskStats": { 55 | "Secure JIT II": null, 56 | "eeenginx": null, 57 | "ezMat": null, 58 | "boynextdoor": null, 59 | "NaiveHeap": null, 60 | "Win-Win": null, 61 | "0VM": null, 62 | "babylogin": null, 63 | "babalogin": null, 64 | "ezRSA": null, 65 | "kbrop": null, 66 | "ezRSA+": null, 67 | "favourite fruit": null, 68 | "kernote": null, 69 | "BabaHeap": null, 70 | "how_to_generate": null 71 | } 72 | }, 73 | { 74 | "pos": 4, 75 | "team": "NeSE", 76 | "score": "5915", 77 | "taskStats": { 78 | "Secure JIT II": null, 79 | "eeenginx": null, 80 | "0VM": null, 81 | "Win-Win": null, 82 | "0bf": null, 83 | "buggyLoader": null, 84 | "kbrop": null, 85 | "ezRSA": null, 86 | "babylogin": null, 87 | "promise": null, 88 | "RevengePHP": null, 89 | "ezMat": null, 90 | "NaiveHeap": null 91 | } 92 | }, 93 | { 94 | "pos": 5, 95 | "team": "More Smoked Leet Chicken", 96 | "score": "5694", 97 | "taskStats": { 98 | "eeenginx": null, 99 | "babylogin": null, 100 | "ezMat": null, 101 | "boynextdoor": null, 102 | "Win-Win": null, 103 | "favourite fruit": null, 104 | "Secure JIT II": null, 105 | "how_to_generate": null, 106 | "useCTF()": null, 107 | "RevengePHP": null, 108 | "ezRSA": null, 109 | "ezRSA+": null, 110 | "ezHash": null, 111 | "bali": null, 112 | "halfhalf": null 113 | } 114 | }, 115 | { 116 | "pos": 6, 117 | "team": "perfect blue", 118 | "score": "4922", 119 | "taskStats": { 120 | "Secure JIT II": null, 121 | "eeenginx": null, 122 | "ezMat": null, 123 | "babylogin": null, 124 | "promise": null, 125 | "0VM": null, 126 | "bali": null, 127 | "kbrop": null, 128 | "ezRSA": null, 129 | "ezRSA+": null, 130 | "ezHash": null, 131 | "halfhalf": null, 132 | "how_to_generate": null, 133 | "Win-Win": null 134 | } 135 | }, 136 | { 137 | "pos": 7, 138 | "team": "Nu1L", 139 | "score": "4033", 140 | "taskStats": { 141 | "boynextdoor": null, 142 | "eeenginx": null, 143 | "Secure JIT II": null, 144 | "ezMat": null, 145 | "Win-Win": null, 146 | "how_to_generate": null, 147 | "ezRSA": null, 148 | "babalogin": null, 149 | "ezRSA+": null, 150 | "favourite fruit": null, 151 | "BabaHeap": null, 152 | "halfhalf": null 153 | } 154 | }, 155 | { 156 | "pos": 8, 157 | "team": "hxp", 158 | "score": "3594", 159 | "taskStats": { 160 | "Secure JIT II": null, 161 | "boynextdoor": null, 162 | "eeenginx": null, 163 | "ezMat": null, 164 | "babylogin": null, 165 | "favourite fruit": null, 166 | "Win-Win": null, 167 | "how_to_generate": null, 168 | "ezRSA": null, 169 | "bali": null, 170 | "ezRSA+": null, 171 | "halfhalf": null 172 | } 173 | }, 174 | { 175 | "pos": 9, 176 | "team": "DiceGang", 177 | "score": "2615", 178 | "taskStats": { 179 | "Secure JIT II": null, 180 | "ezMat": null, 181 | "favourite fruit": null, 182 | "bali": null, 183 | "how_to_generate": null, 184 | "boynextdoor": null, 185 | "eeenginx": null, 186 | "halfhalf": null, 187 | "ezRSA": null 188 | } 189 | }, 190 | { 191 | "pos": 10, 192 | "team": "Dragon Sector", 193 | "score": "2396", 194 | "taskStats": { 195 | "Secure JIT II": null, 196 | "eeenginx": null, 197 | "ezMat": null, 198 | "Win-Win": null, 199 | "NaiveHeap": null, 200 | "boynextdoor": null, 201 | "0VM": null, 202 | "how_to_generate": null 203 | } 204 | }, 205 | { 206 | "pos": 11, 207 | "team": "zer0pts", 208 | "score": "658", 209 | "taskStats": { 210 | "Secure JIT II": null, 211 | "ezMat": null, 212 | "ezRSA": null 213 | } 214 | }, 215 | { 216 | "pos": 12, 217 | "team": "r00timentary", 218 | "score": "658", 219 | "taskStats": { 220 | "Secure JIT II": null, 221 | "ezMat": null, 222 | "ezRSA": null 223 | } 224 | } 225 | ], 226 | "tasks": [ 227 | "useCTF()", 228 | "kernote", 229 | "0VM", 230 | "bali", 231 | "Secure JIT II", 232 | "promise", 233 | "eeenginx", 234 | "babylogin", 235 | "babalogin", 236 | "RevengePHP", 237 | "buggyLoader", 238 | "0bf", 239 | "favourite fruit", 240 | "boynextdoor", 241 | "tile++", 242 | "NaiveHeap", 243 | "BabaHeap", 244 | "Win-Win", 245 | "ezMat", 246 | "binlog", 247 | "how_to_generate", 248 | "ezHash", 249 | "kbrop", 250 | "zer0boot", 251 | "ezRSA", 252 | "ezRSA+", 253 | "halfhalf" 254 | ], 255 | "date": 1632495600, 256 | "name": "0CTF/TCTF 2021 Finals" 257 | } -------------------------------------------------------------------------------- /data/events/3kCTF 2021.json: -------------------------------------------------------------------------------- 1 | { 2 | "standings": [ 3 | { 4 | "pos": 1, 5 | "team": "Never Stop Exploiting", 6 | "score": 8353, 7 | "taskStats": { 8 | "sponsors": null, 9 | "crypto warmup": null, 10 | "Emoji": null, 11 | "masterc": null, 12 | "online_compiler": null, 13 | "Crackme": null, 14 | "echo": null, 15 | "Layers": null, 16 | "ASR": null, 17 | "SMS": null, 18 | "Microscopic Revenge": null, 19 | "secure roots": null, 20 | "p(a)wnshop": null, 21 | "HelloWorld": null, 22 | "Password Manager": null, 23 | "Feedback": null, 24 | "Imposter": null, 25 | "Handvm": null, 26 | "iterrun": null 27 | } 28 | }, 29 | { 30 | "pos": 2, 31 | "team": "Black Bauhinia", 32 | "score": 7887, 33 | "taskStats": { 34 | "sponsors": null, 35 | "SMS": null, 36 | "crypto warmup": null, 37 | "secure roots": null, 38 | "online_compiler": null, 39 | "Emoji": null, 40 | "Crackme": null, 41 | "Imposter": null, 42 | "Digital": null, 43 | "Mokdad's Memories": null, 44 | "Layers": null, 45 | "p(a)wnshop": null, 46 | "ASR": null, 47 | "Feedback": null, 48 | "masterc": null, 49 | "ppaste": null, 50 | "3K_SIGNER": null, 51 | "Password Manager": null 52 | } 53 | }, 54 | { 55 | "pos": 3, 56 | "team": "zer0pts", 57 | "score": 7871, 58 | "taskStats": { 59 | "crypto warmup": null, 60 | "secure roots": null, 61 | "echo": null, 62 | "masterc": null, 63 | "Emoji": null, 64 | "online_compiler": null, 65 | "sponsors": null, 66 | "ASR": null, 67 | "Imposter": null, 68 | "SMS": null, 69 | "p(a)wnshop": null, 70 | "klibrary": null, 71 | "Mokdad's Memories": null, 72 | "iterrun": null, 73 | "Digital": null, 74 | "Feedback": null, 75 | "stdout": null, 76 | "Crackme": null 77 | } 78 | }, 79 | { 80 | "pos": 4, 81 | "team": "greunion", 82 | "score": 6411, 83 | "taskStats": { 84 | "sponsors": null, 85 | "online_compiler": null, 86 | "Crackme": null, 87 | "Emoji": null, 88 | "crypto warmup": null, 89 | "SMS": null, 90 | "Layers": null, 91 | "Imposter": null, 92 | "Password Manager": null, 93 | "secure roots": null, 94 | "Microscopic Revenge": null, 95 | "ASR": null, 96 | "3K_SIGNER": null, 97 | "Feedback": null, 98 | "p(a)wnshop": null 99 | } 100 | }, 101 | { 102 | "pos": 5, 103 | "team": "zh3r0", 104 | "score": 6396, 105 | "taskStats": { 106 | "sponsors": null, 107 | "masterc": null, 108 | "crypto warmup": null, 109 | "SMS": null, 110 | "stdout": null, 111 | "online_compiler": null, 112 | "Crackme": null, 113 | "iterrun": null, 114 | "ASR": null, 115 | "Feedback": null, 116 | "echo": null, 117 | "secure roots": null, 118 | "Emoji": null, 119 | "Handvm": null, 120 | "p(a)wnshop": null 121 | } 122 | }, 123 | { 124 | "pos": 6, 125 | "team": "Kalmarunionen", 126 | "score": 4958, 127 | "taskStats": { 128 | "sponsors": null, 129 | "crypto warmup": null, 130 | "online_compiler": null, 131 | "SMS": null, 132 | "echo": null, 133 | "Digital": null, 134 | "Feedback": null, 135 | "p(a)wnshop": null, 136 | "secure roots": null, 137 | "Emoji": null, 138 | "ASR": null, 139 | "klibrary": null 140 | } 141 | }, 142 | { 143 | "pos": 7, 144 | "team": "Fword", 145 | "score": 3980, 146 | "taskStats": { 147 | "crypto warmup": null, 148 | "sponsors": null, 149 | "SMS": null, 150 | "masterc": null, 151 | "online_compiler": null, 152 | "Crackme": null, 153 | "Emoji": null, 154 | "Layers": null, 155 | "Microscopic Revenge": null, 156 | "Feedback": null 157 | } 158 | }, 159 | { 160 | "pos": 8, 161 | "team": "RadboudInstOfPwning", 162 | "score": 3978, 163 | "taskStats": { 164 | "sponsors": null, 165 | "crypto warmup": null, 166 | "online_compiler": null, 167 | "Emoji": null, 168 | "SMS": null, 169 | "p(a)wnshop": null, 170 | "Layers": null, 171 | "masterc": null, 172 | "echo": null, 173 | "Feedback": null 174 | } 175 | }, 176 | { 177 | "pos": 9, 178 | "team": "ISITDTU", 179 | "score": 3967, 180 | "taskStats": { 181 | "sponsors": null, 182 | "crypto warmup": null, 183 | "online_compiler": null, 184 | "Emoji": null, 185 | "SMS": null, 186 | "masterc": null, 187 | "Crackme": null, 188 | "Imposter": null, 189 | "Feedback": null, 190 | "p(a)wnshop": null 191 | } 192 | }, 193 | { 194 | "pos": 10, 195 | "team": "Wanna.One", 196 | "score": 3499, 197 | "taskStats": { 198 | "crypto warmup": null, 199 | "sponsors": null, 200 | "online_compiler": null, 201 | "Emoji": null, 202 | "Imposter": null, 203 | "SMS": null, 204 | "Feedback": null, 205 | "Crackme": null, 206 | "Microscopic Revenge": null 207 | } 208 | }, 209 | { 210 | "pos": 11, 211 | "team": "blackpinker", 212 | "score": 3484, 213 | "taskStats": { 214 | "crypto warmup": null, 215 | "sponsors": null, 216 | "SMS": null, 217 | "Emoji": null, 218 | "online_compiler": null, 219 | "secure roots": null, 220 | "Crackme": null, 221 | "ASR": null, 222 | "Feedback": null 223 | } 224 | }, 225 | { 226 | "pos": 12, 227 | "team": "0nlyFlags", 228 | "score": 3001, 229 | "taskStats": { 230 | "sponsors": null, 231 | "crypto warmup": null, 232 | "SMS": null, 233 | "Crackme": null, 234 | "secure roots": null, 235 | "online_compiler": null, 236 | "Feedback": null, 237 | "Emoji": null 238 | } 239 | }, 240 | { 241 | "pos": 13, 242 | "team": "DSCVIT", 243 | "score": 2099, 244 | "taskStats": { 245 | "sponsors": null, 246 | "Emoji": null, 247 | "p(a)wnshop": null, 248 | "crypto warmup": null, 249 | "online_compiler": null, 250 | "Feedback": null 251 | } 252 | }, 253 | { 254 | "pos": 14, 255 | "team": "0x62EEN7EA", 256 | "score": 2088, 257 | "taskStats": { 258 | "sponsors": null, 259 | "crypto warmup": null, 260 | "Crackme": null, 261 | "online_compiler": null, 262 | "SMS": null, 263 | "Feedback": null 264 | } 265 | }, 266 | { 267 | "pos": 15, 268 | "team": "d4rkc0de", 269 | "score": 2056, 270 | "taskStats": { 271 | "sponsors": null, 272 | "crypto warmup": null, 273 | "online_compiler": null, 274 | "SMS": null, 275 | "Emoji": null, 276 | "Feedback": null 277 | } 278 | }, 279 | { 280 | "pos": 16, 281 | "team": "ANWP", 282 | "score": 2056, 283 | "taskStats": { 284 | "sponsors": null, 285 | "crypto warmup": null, 286 | "SMS": null, 287 | "online_compiler": null, 288 | "Emoji": null, 289 | "Feedback": null 290 | } 291 | }, 292 | { 293 | "pos": 17, 294 | "team": "icypete", 295 | "score": 2056, 296 | "taskStats": { 297 | "sponsors": null, 298 | "crypto warmup": null, 299 | "online_compiler": null, 300 | "Emoji": null, 301 | "SMS": null, 302 | "Feedback": null 303 | } 304 | }, 305 | { 306 | "pos": 18, 307 | "team": "M30W", 308 | "score": 1939, 309 | "taskStats": { 310 | "masterc": null, 311 | "echo": null, 312 | "iterrun": null, 313 | "Handvm": null 314 | } 315 | }, 316 | { 317 | "pos": 19, 318 | "team": "CSI", 319 | "score": 1674, 320 | "taskStats": { 321 | "crypto warmup": null, 322 | "sponsors": null, 323 | "Emoji": null, 324 | "echo": null, 325 | "Feedback": null 326 | } 327 | }, 328 | { 329 | "pos": 20, 330 | "team": "CTF.SG", 331 | "score": 1661, 332 | "taskStats": { 333 | "sponsors": null, 334 | "crypto warmup": null, 335 | "online_compiler": null, 336 | "echo": null, 337 | "Feedback": null 338 | } 339 | }, 340 | { 341 | "pos": 21, 342 | "team": "NicDumZ", 343 | "score": 1621, 344 | "taskStats": { 345 | "sponsors": null, 346 | "crypto warmup": null, 347 | "online_compiler": null, 348 | "Emoji": null, 349 | "Feedback": null 350 | } 351 | }, 352 | { 353 | "pos": 22, 354 | "team": "Kubie", 355 | "score": 1273, 356 | "taskStats": { 357 | "sponsors": null, 358 | "crypto warmup": null, 359 | "SMS": null, 360 | "secure roots": null 361 | } 362 | }, 363 | { 364 | "pos": 23, 365 | "team": "OpenToAll", 366 | "score": 1268, 367 | "taskStats": { 368 | "online_compiler": null, 369 | "sponsors": null, 370 | "Emoji": null, 371 | "Feedback": null 372 | } 373 | }, 374 | { 375 | "pos": 24, 376 | "team": "R4v3ns", 377 | "score": 1226, 378 | "taskStats": { 379 | "sponsors": null, 380 | "online_compiler": null, 381 | "Emoji": null, 382 | "crypto warmup": null 383 | } 384 | }, 385 | { 386 | "pos": 25, 387 | "team": "Applied Cybersecurity Society", 388 | "score": 1226, 389 | "taskStats": { 390 | "sponsors": null, 391 | "crypto warmup": null, 392 | "online_compiler": null, 393 | "Emoji": null 394 | } 395 | }, 396 | { 397 | "pos": 26, 398 | "team": "miniPwny", 399 | "score": 1193, 400 | "taskStats": { 401 | "sponsors": null, 402 | "crypto warmup": null, 403 | "SMS": null, 404 | "Feedback": null 405 | } 406 | }, 407 | { 408 | "pos": 27, 409 | "team": "[email protected]", 410 | "score": 1193, 411 | "taskStats": { 412 | "sponsors": null, 413 | "crypto warmup": null, 414 | "SMS": null, 415 | "Feedback": null 416 | } 417 | }, 418 | { 419 | "pos": 28, 420 | "team": "Jacobs", 421 | "score": 1193, 422 | "taskStats": { 423 | "sponsors": null, 424 | "crypto warmup": null, 425 | "SMS": null, 426 | "Feedback": null 427 | } 428 | }, 429 | { 430 | "pos": 29, 431 | "team": "empty_", 432 | "score": 1183, 433 | "taskStats": { 434 | "sponsors": null, 435 | "crypto warmup": null, 436 | "online_compiler": null, 437 | "Feedback": null 438 | } 439 | }, 440 | { 441 | "pos": 30, 442 | "team": "patientTeam", 443 | "score": 958, 444 | "taskStats": { 445 | "Crackme": null, 446 | "Microscopic Revenge": null 447 | } 448 | }, 449 | { 450 | "pos": 31, 451 | "team": "bot3310", 452 | "score": 883, 453 | "taskStats": { 454 | "masterc": null, 455 | "Feedback": null, 456 | "sponsors": null 457 | } 458 | }, 459 | { 460 | "pos": 32, 461 | "team": "xisop", 462 | "score": 863, 463 | "taskStats": { 464 | "online_compiler": null, 465 | "Emoji": null 466 | } 467 | }, 468 | { 469 | "pos": 33, 470 | "team": "byc_404", 471 | "score": 863, 472 | "taskStats": { 473 | "online_compiler": null, 474 | "Emoji": null 475 | } 476 | }, 477 | { 478 | "pos": 34, 479 | "team": "Killer Queen", 480 | "score": 801, 481 | "taskStats": { 482 | "sponsors": null, 483 | "crypto warmup": null, 484 | "Emoji": null 485 | } 486 | }, 487 | { 488 | "pos": 35, 489 | "team": "Enterprize1", 490 | "score": 798, 491 | "taskStats": { 492 | "crypto warmup": null, 493 | "SMS": null, 494 | "sponsors": null 495 | } 496 | }, 497 | { 498 | "pos": 36, 499 | "team": "K3RN3L4RMY", 500 | "score": 798, 501 | "taskStats": { 502 | "sponsors": null, 503 | "crypto warmup": null, 504 | "SMS": null 505 | } 506 | }, 507 | { 508 | "pos": 37, 509 | "team": "sounds_bad", 510 | "score": 798, 511 | "taskStats": { 512 | "sponsors": null, 513 | "crypto warmup": null, 514 | "SMS": null 515 | } 516 | }, 517 | { 518 | "pos": 38, 519 | "team": "BearRepubl1c", 520 | "score": 798, 521 | "taskStats": { 522 | "sponsors": null, 523 | "crypto warmup": null, 524 | "SMS": null 525 | } 526 | }, 527 | { 528 | "pos": 39, 529 | "team": "wiwam845", 530 | "score": 798, 531 | "taskStats": { 532 | "crypto warmup": null, 533 | "SMS": null, 534 | "sponsors": null 535 | } 536 | }, 537 | { 538 | "pos": 40, 539 | "team": "haihoadao", 540 | "score": 798, 541 | "taskStats": { 542 | "crypto warmup": null, 543 | "sponsors": null, 544 | "SMS": null 545 | } 546 | }, 547 | { 548 | "pos": 41, 549 | "team": "BoRa9", 550 | "score": 788, 551 | "taskStats": { 552 | "sponsors": null, 553 | "online_compiler": null, 554 | "crypto warmup": null 555 | } 556 | }, 557 | { 558 | "pos": 42, 559 | "team": "HugsForBugs", 560 | "score": 758, 561 | "taskStats": { 562 | "sponsors": null, 563 | "crypto warmup": null, 564 | "Feedback": null 565 | } 566 | }, 567 | { 568 | "pos": 43, 569 | "team": "NotSoPros", 570 | "score": 758, 571 | "taskStats": { 572 | "sponsors": null, 573 | "crypto warmup": null, 574 | "Feedback": null 575 | } 576 | }, 577 | { 578 | "pos": 44, 579 | "team": "Jump2Flag", 580 | "score": 758, 581 | "taskStats": { 582 | "sponsors": null, 583 | "crypto warmup": null, 584 | "Feedback": null 585 | } 586 | }, 587 | { 588 | "pos": 45, 589 | "team": "Sinception", 590 | "score": 758, 591 | "taskStats": { 592 | "sponsors": null, 593 | "crypto warmup": null, 594 | "Feedback": null 595 | } 596 | }, 597 | { 598 | "pos": 46, 599 | "team": "Root Lee", 600 | "score": 758, 601 | "taskStats": { 602 | "sponsors": null, 603 | "crypto warmup": null, 604 | "Feedback": null 605 | } 606 | }, 607 | { 608 | "pos": 47, 609 | "team": "TeamName", 610 | "score": 758, 611 | "taskStats": { 612 | "sponsors": null, 613 | "crypto warmup": null, 614 | "Feedback": null 615 | } 616 | }, 617 | { 618 | "pos": 48, 619 | "team": "BirdPerson", 620 | "score": 488, 621 | "taskStats": { 622 | "sponsors": null, 623 | "echo": null 624 | } 625 | }, 626 | { 627 | "pos": 49, 628 | "team": "kasiatutej", 629 | "score": 475, 630 | "taskStats": { 631 | "secure roots": null 632 | } 633 | }, 634 | { 635 | "pos": 50, 636 | "team": "jay", 637 | "score": 438, 638 | "taskStats": { 639 | "Emoji": null 640 | } 641 | } 642 | ], 643 | "tasks": [ 644 | "telnet", 645 | "babyrtos", 646 | "ppaste", 647 | "HelloWorld", 648 | "3K_SIGNER", 649 | "klibrary", 650 | "stdout", 651 | "Mokdad's Memories", 652 | "Digital", 653 | "Handvm", 654 | "Password Manager", 655 | "iterrun", 656 | "Layers", 657 | "Microscopic Revenge", 658 | "Imposter", 659 | "ASR", 660 | "echo", 661 | "masterc", 662 | "p(a)wnshop", 663 | "secure roots", 664 | "Crackme", 665 | "Emoji", 666 | "SMS", 667 | "online_compiler", 668 | "Feedback", 669 | "crypto warmup", 670 | "sponsors" 671 | ], 672 | "date": 1621004400, 673 | "name": "3kCTF 2021" 674 | } -------------------------------------------------------------------------------- /data/events/Aero CTF 2021.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | "House Builder", 4 | "Shell Master", 5 | "Shell Master 2", 6 | "Localization is hard", 7 | "horcrux", 8 | "phoenix", 9 | "Dummyper", 10 | "Not received prize", 11 | "boggart", 12 | "custom", 13 | "Target Attack", 14 | "Scheme", 15 | "BashD00R" 16 | ], 17 | "standings": [ 18 | { 19 | "pos": 1, 20 | "team": "Super Guesser", 21 | "taskStats": { 22 | "House Builder": null, 23 | "Shell Master": null, 24 | "Shell Master 2": null, 25 | "Localization is hard": null, 26 | "horcrux": null, 27 | "phoenix": null, 28 | "Dummyper": null, 29 | "Not received prize": null, 30 | "boggart": null, 31 | "custom": null 32 | } 33 | }, 34 | { 35 | "pos": 8, 36 | "team": "bi0s", 37 | "taskStats": { 38 | "House Builder": null, 39 | "Localization is hard": null, 40 | "Not received prize": null, 41 | "Shell Master": null, 42 | "Shell Master 2": null 43 | } 44 | }, 45 | { 46 | "pos": 37, 47 | "team": "1eq0and1ne0", 48 | "taskStats": { 49 | "Not received prize": null, 50 | "Localization is hard": null 51 | } 52 | }, 53 | { 54 | "pos": 67, 55 | "team": "STT", 56 | "taskStats": { 57 | "Localization is hard": null 58 | } 59 | }, 60 | { 61 | "pos": 70, 62 | "team": "n0n$la$", 63 | "taskStats": { 64 | "Localization is hard": null 65 | } 66 | }, 67 | { 68 | "pos": 45, 69 | "team": "ARESx", 70 | "taskStats": { 71 | "House Builder": null, 72 | "Localization is hard": null 73 | } 74 | }, 75 | { 76 | "pos": 48, 77 | "team": "m1t0", 78 | "taskStats": { 79 | "Shell Master": null 80 | } 81 | }, 82 | { 83 | "pos": 60, 84 | "team": "N0Named", 85 | "taskStats": { 86 | "Localization is hard": null 87 | } 88 | }, 89 | { 90 | "pos": 29, 91 | "team": "Kernel Sanders", 92 | "taskStats": { 93 | "Not received prize": null, 94 | "House Builder": null 95 | } 96 | }, 97 | { 98 | "pos": 82, 99 | "team": "KUDoS", 100 | "taskStats": { 101 | "Localization is hard": null 102 | } 103 | }, 104 | { 105 | "pos": 63, 106 | "team": "Fword", 107 | "taskStats": { 108 | "Localization is hard": null 109 | } 110 | }, 111 | { 112 | "pos": 15, 113 | "team": "dcua", 114 | "taskStats": { 115 | "House Builder": null, 116 | "Shell Master": null, 117 | "Shell Master 2": null 118 | } 119 | }, 120 | { 121 | "pos": 44, 122 | "team": "5h4d0wb10k3r", 123 | "taskStats": { 124 | "Dummyper": null 125 | } 126 | }, 127 | { 128 | "pos": 28, 129 | "team": "DarkArmy", 130 | "taskStats": { 131 | "Dummyper": null, 132 | "House Builder": null 133 | } 134 | }, 135 | { 136 | "pos": 21, 137 | "team": "efiens", 138 | "taskStats": { 139 | "Dummyper": null, 140 | "phoenix": null 141 | } 142 | }, 143 | { 144 | "pos": 6, 145 | "team": "Kalmarunionen", 146 | "taskStats": { 147 | "House Builder": null, 148 | "Not received prize": null, 149 | "Shell Master": null, 150 | "Localization is hard": null, 151 | "Shell Master 2": null, 152 | "Scheme": null 153 | } 154 | }, 155 | { 156 | "pos": 30, 157 | "team": "skiddies", 158 | "taskStats": { 159 | "House Builder": null, 160 | "Shell Master": null 161 | } 162 | }, 163 | { 164 | "pos": 16, 165 | "team": "jt", 166 | "taskStats": { 167 | "House Builder": null, 168 | "Shell Master": null, 169 | "Shell Master 2": null 170 | } 171 | }, 172 | { 173 | "pos": 50, 174 | "team": "HsVcs", 175 | "taskStats": { 176 | "House Builder": null 177 | } 178 | }, 179 | { 180 | "pos": 57, 181 | "team": "BinaryBears", 182 | "taskStats": { 183 | "Localization is hard": null 184 | } 185 | }, 186 | { 187 | "pos": 84, 188 | "team": "Red Knights", 189 | "taskStats": { 190 | "Localization is hard": null 191 | } 192 | }, 193 | { 194 | "pos": 78, 195 | "team": "0x8Layer", 196 | "taskStats": { 197 | "Localization is hard": null 198 | } 199 | }, 200 | { 201 | "pos": 76, 202 | "team": "Zepto", 203 | "taskStats": { 204 | "Localization is hard": null 205 | } 206 | }, 207 | { 208 | "pos": 83, 209 | "team": "e^iπ+1day", 210 | "taskStats": { 211 | "Localization is hard": null 212 | } 213 | }, 214 | { 215 | "pos": 34, 216 | "team": "c0r3dump", 217 | "taskStats": { 218 | "Dummyper": null, 219 | "Localization is hard": null 220 | } 221 | }, 222 | { 223 | "pos": 7, 224 | "team": "ELT", 225 | "taskStats": { 226 | "Localization is hard": null, 227 | "House Builder": null, 228 | "Shell Master": null, 229 | "Not received prize": null, 230 | "Shell Master 2": null 231 | } 232 | }, 233 | { 234 | "pos": 11, 235 | "team": "CyKor", 236 | "taskStats": { 237 | "Dummyper": null, 238 | "Localization is hard": null, 239 | "Shell Master": null, 240 | "House Builder": null 241 | } 242 | }, 243 | { 244 | "pos": 14, 245 | "team": "RedRocket", 246 | "taskStats": { 247 | "House Builder": null, 248 | "Shell Master": null, 249 | "Shell Master 2": null 250 | } 251 | }, 252 | { 253 | "pos": 20, 254 | "team": "mode13h", 255 | "taskStats": { 256 | "BashD00R": null, 257 | "Dummyper": null 258 | } 259 | }, 260 | { 261 | "pos": 4, 262 | "team": "RootMeUpBeforeYouGoGo", 263 | "taskStats": { 264 | "Shell Master": null, 265 | "Localization is hard": null, 266 | "Shell Master 2": null, 267 | "House Builder": null, 268 | "Dummyper": null, 269 | "Target Attack": null, 270 | "Not received prize": null 271 | } 272 | }, 273 | { 274 | "pos": 35, 275 | "team": "FAUST", 276 | "taskStats": { 277 | "Not received prize": null, 278 | "Localization is hard": null 279 | } 280 | }, 281 | { 282 | "pos": 55, 283 | "team": "BambooFox", 284 | "taskStats": { 285 | "House Builder": null 286 | } 287 | }, 288 | { 289 | "pos": 51, 290 | "team": "Itemize", 291 | "taskStats": { 292 | "House Builder": null 293 | } 294 | }, 295 | { 296 | "pos": 32, 297 | "team": "Shellphish", 298 | "taskStats": { 299 | "Scheme": null, 300 | "Localization is hard": null 301 | } 302 | }, 303 | { 304 | "pos": 41, 305 | "team": "skateboarding dog", 306 | "taskStats": { 307 | "phoenix": null 308 | } 309 | }, 310 | { 311 | "pos": 27, 312 | "team": "Mayas", 313 | "taskStats": { 314 | "House Builder": null, 315 | "Shell Master": null, 316 | "Localization is hard": null 317 | } 318 | }, 319 | { 320 | "pos": 25, 321 | "team": "Contrail", 322 | "taskStats": { 323 | "Not received prize": null, 324 | "House Builder": null, 325 | "Localization is hard": null 326 | } 327 | }, 328 | { 329 | "pos": 5, 330 | "team": "C4T BuT S4D", 331 | "taskStats": { 332 | "Shell Master": null, 333 | "Shell Master 2": null, 334 | "House Builder": null, 335 | "Localization is hard": null, 336 | "Target Attack": null, 337 | "Dummyper": null 338 | } 339 | }, 340 | { 341 | "pos": 72, 342 | "team": "Scavenger Security", 343 | "taskStats": { 344 | "Localization is hard": null 345 | } 346 | }, 347 | { 348 | "pos": 31, 349 | "team": "srdnlen", 350 | "taskStats": { 351 | "House Builder": null, 352 | "Shell Master": null 353 | } 354 | }, 355 | { 356 | "pos": 85, 357 | "team": "ShroomZ", 358 | "taskStats": { 359 | "Localization is hard": null 360 | } 361 | }, 362 | { 363 | "pos": 68, 364 | "team": "flib", 365 | "taskStats": { 366 | "Localization is hard": null 367 | } 368 | }, 369 | { 370 | "pos": 47, 371 | "team": "CSI", 372 | "taskStats": { 373 | "Not received prize": null 374 | } 375 | }, 376 | { 377 | "pos": 12, 378 | "team": "SPRUSH", 379 | "taskStats": { 380 | "House Builder": null, 381 | "Localization is hard": null, 382 | "Dummyper": null, 383 | "Shell Master": null 384 | } 385 | }, 386 | { 387 | "pos": 9, 388 | "team": "Black Bauhinia", 389 | "taskStats": { 390 | "horcrux": null, 391 | "boggart": null, 392 | "phoenix": null 393 | } 394 | }, 395 | { 396 | "pos": 42, 397 | "team": "meltdown", 398 | "taskStats": { 399 | "Dummyper": null 400 | } 401 | }, 402 | { 403 | "pos": 75, 404 | "team": "Nupakachi", 405 | "taskStats": { 406 | "Localization is hard": null 407 | } 408 | }, 409 | { 410 | "pos": 79, 411 | "team": "beerpwn", 412 | "taskStats": { 413 | "Localization is hard": null 414 | } 415 | }, 416 | { 417 | "pos": 80, 418 | "team": "TEAM0001", 419 | "taskStats": { 420 | "Localization is hard": null 421 | } 422 | }, 423 | { 424 | "pos": 18, 425 | "team": "ret2school", 426 | "taskStats": { 427 | "BashD00R": null, 428 | "Dummyper": null, 429 | "Localization is hard": null 430 | } 431 | }, 432 | { 433 | "pos": 43, 434 | "team": "cew", 435 | "taskStats": { 436 | "Dummyper": null 437 | } 438 | }, 439 | { 440 | "pos": 17, 441 | "team": "./Vespiary", 442 | "taskStats": { 443 | "Not received prize": null, 444 | "House Builder": null, 445 | "Shell Master": null 446 | } 447 | }, 448 | { 449 | "pos": 22, 450 | "team": "just4fun", 451 | "taskStats": { 452 | "Dummyper": null, 453 | "phoenix": null 454 | } 455 | }, 456 | { 457 | "pos": 40, 458 | "team": "TheGoonies", 459 | "taskStats": { 460 | "Shell Master": null, 461 | "Localization is hard": null 462 | } 463 | }, 464 | { 465 | "pos": 10, 466 | "team": "Keyboard Monkeys", 467 | "taskStats": { 468 | "Scheme": null, 469 | "phoenix": null, 470 | "House Builder": null 471 | } 472 | }, 473 | { 474 | "pos": 19, 475 | "team": "CeSeNA_Ulisse", 476 | "taskStats": { 477 | "Dummyper": null, 478 | "Not received prize": null, 479 | "Localization is hard": null 480 | } 481 | }, 482 | { 483 | "pos": 46, 484 | "team": "Enumerati", 485 | "taskStats": { 486 | "Not received prize": null 487 | } 488 | }, 489 | { 490 | "pos": 2, 491 | "team": "VztekOverflow", 492 | "taskStats": { 493 | "Dummyper": null, 494 | "House Builder": null, 495 | "Shell Master": null, 496 | "Shell Master 2": null, 497 | "custom": null, 498 | "Localization is hard": null, 499 | "Target Attack": null 500 | } 501 | }, 502 | { 503 | "pos": 74, 504 | "team": "h4ck0c10ck", 505 | "taskStats": { 506 | "Localization is hard": null 507 | } 508 | }, 509 | { 510 | "pos": 36, 511 | "team": "ripp3rs", 512 | "taskStats": { 513 | "Not received prize": null, 514 | "Localization is hard": null 515 | } 516 | }, 517 | { 518 | "pos": 61, 519 | "team": "born2scan", 520 | "taskStats": { 521 | "Localization is hard": null 522 | } 523 | }, 524 | { 525 | "pos": 3, 526 | "team": "BuddiesTeam", 527 | "taskStats": { 528 | "House Builder": null, 529 | "Localization is hard": null, 530 | "Shell Master": null, 531 | "Shell Master 2": null, 532 | "Not received prize": null, 533 | "Dummyper": null, 534 | "custom": null 535 | } 536 | }, 537 | { 538 | "pos": 13, 539 | "team": "10sec", 540 | "taskStats": { 541 | "Localization is hard": null, 542 | "Not received prize": null, 543 | "House Builder": null, 544 | "Shell Master": null 545 | } 546 | }, 547 | { 548 | "pos": 23, 549 | "team": "Pentahex and some other skids", 550 | "taskStats": { 551 | "Not received prize": null, 552 | "House Builder": null, 553 | "Localization is hard": null 554 | } 555 | }, 556 | { 557 | "pos": 24, 558 | "team": "flagbot", 559 | "taskStats": { 560 | "Dummyper": null, 561 | "Shell Master": null 562 | } 563 | }, 564 | { 565 | "pos": 26, 566 | "team": "Demon", 567 | "taskStats": { 568 | "Not received prize": null, 569 | "House Builder": null, 570 | "Localization is hard": null 571 | } 572 | }, 573 | { 574 | "pos": 33, 575 | "team": "ptm", 576 | "taskStats": { 577 | "phoenix": null, 578 | "Localization is hard": null 579 | } 580 | }, 581 | { 582 | "pos": 38, 583 | "team": "SHRECS", 584 | "taskStats": { 585 | "Not received prize": null, 586 | "Localization is hard": null 587 | } 588 | }, 589 | { 590 | "pos": 39, 591 | "team": "Bushwhackers", 592 | "taskStats": { 593 | "Not received prize": null, 594 | "Localization is hard": null 595 | } 596 | }, 597 | { 598 | "pos": 49, 599 | "team": "Maher", 600 | "taskStats": { 601 | "House Builder": null 602 | } 603 | }, 604 | { 605 | "pos": 52, 606 | "team": "Echo", 607 | "taskStats": { 608 | "House Builder": null 609 | } 610 | }, 611 | { 612 | "pos": 53, 613 | "team": "softliberalhands", 614 | "taskStats": { 615 | "House Builder": null 616 | } 617 | }, 618 | { 619 | "pos": 54, 620 | "team": "contrail", 621 | "taskStats": { 622 | "House Builder": null 623 | } 624 | }, 625 | { 626 | "pos": 56, 627 | "team": "LSE", 628 | "taskStats": { 629 | "Localization is hard": null 630 | } 631 | }, 632 | { 633 | "pos": 58, 634 | "team": "MadrHacks", 635 | "taskStats": { 636 | "Localization is hard": null 637 | } 638 | }, 639 | { 640 | "pos": 59, 641 | "team": "mdisec_unofficial", 642 | "taskStats": { 643 | "Localization is hard": null 644 | } 645 | }, 646 | { 647 | "pos": 62, 648 | "team": "BunG", 649 | "taskStats": { 650 | "Localization is hard": null 651 | } 652 | }, 653 | { 654 | "pos": 64, 655 | "team": "이사하는 중", 656 | "taskStats": { 657 | "Localization is hard": null 658 | } 659 | }, 660 | { 661 | "pos": 65, 662 | "team": "day_is_bright_and_without_errors", 663 | "taskStats": { 664 | "Localization is hard": null 665 | } 666 | }, 667 | { 668 | "pos": 66, 669 | "team": "sztykiryki", 670 | "taskStats": { 671 | "Localization is hard": null 672 | } 673 | }, 674 | { 675 | "pos": 69, 676 | "team": "Red Cadets", 677 | "taskStats": { 678 | "Localization is hard": null 679 | } 680 | }, 681 | { 682 | "pos": 71, 683 | "team": "Hyp3rFlow", 684 | "taskStats": { 685 | "Localization is hard": null 686 | } 687 | }, 688 | { 689 | "pos": 73, 690 | "team": "0x01d5", 691 | "taskStats": { 692 | "Localization is hard": null 693 | } 694 | }, 695 | { 696 | "pos": 77, 697 | "team": "SqU4dR0n", 698 | "taskStats": { 699 | "Localization is hard": null 700 | } 701 | }, 702 | { 703 | "pos": 81, 704 | "team": "Not The PPP", 705 | "taskStats": { 706 | "Localization is hard": null 707 | } 708 | } 709 | ], 710 | "name": "Aero CTF 2021", 711 | "date": 1614351600 712 | } -------------------------------------------------------------------------------- /data/events/Midnightsun CTF 2021 Finals.json: -------------------------------------------------------------------------------- 1 | { 2 | "standings": [ 3 | { 4 | "pos": 1, 5 | "team": "perfect blue", 6 | "score": 6879, 7 | "taskStats": { 8 | "Graphiti": null, 9 | "TownOfSaleaem": null, 10 | "SuperSe...": null, 11 | "plolard": null, 12 | "flåarb.tar.xz": null, 13 | "sillyeilish": null, 14 | "Climb t...": null, 15 | "easyOS": null, 16 | "locksmith": null, 17 | "secret-diary": null, 18 | "lockdown": null, 19 | "memery": null, 20 | "QRona": null, 21 | "Tabula RSA": null 22 | } 23 | }, 24 | { 25 | "pos": 2, 26 | "team": "RedRocket", 27 | "score": 6074, 28 | "taskStats": { 29 | "Graphiti": null, 30 | "TownOfSaleaem": null, 31 | "SuperSe...": null, 32 | "plolard": null, 33 | "flåarb.tar.xz": null, 34 | "not backdoored": null, 35 | "sillyeilish": null, 36 | "easyOS": null, 37 | "risque": null, 38 | "locksmith": null, 39 | "secret-diary": null, 40 | "lockdown": null, 41 | "memery": null, 42 | "QRona": null, 43 | "Tabula RSA": null 44 | } 45 | }, 46 | { 47 | "pos": 3, 48 | "team": "Armia Prezesa", 49 | "score": 5566, 50 | "taskStats": { 51 | "Graphiti": null, 52 | "TownOfSaleaem": null, 53 | "SuperSe...": null, 54 | "flåarb.tar.xz": null, 55 | "sillyeilish": null, 56 | "Climb t...": null, 57 | "easyOS": null, 58 | "locksmith": null, 59 | "secret-diary": null, 60 | "lockdown": null, 61 | "Crack M...": null 62 | } 63 | }, 64 | { 65 | "pos": 4, 66 | "team": "bootplug", 67 | "score": 4860, 68 | "taskStats": { 69 | "Graphiti": null, 70 | "SuperSe...": null, 71 | "plolard": null, 72 | "flåarb.tar.xz": null, 73 | "sillyeilish": null, 74 | "Climb t...": null, 75 | "easyOS": null, 76 | "locksmith": null, 77 | "secret-diary": null 78 | } 79 | }, 80 | { 81 | "pos": 5, 82 | "team": "An Equal Mix", 83 | "score": 4479, 84 | "taskStats": { 85 | "Graphiti": null, 86 | "TownOfSaleaem": null, 87 | "SuperSe...": null, 88 | "flåarb.tar.xz": null, 89 | "sillyeilish": null, 90 | "Climb t...": null, 91 | "easyOS": null, 92 | "locksmith": null, 93 | "secret-diary": null, 94 | "Crack M...": null, 95 | "Tabula RSA": null 96 | } 97 | }, 98 | { 99 | "pos": 6, 100 | "team": "watevr", 101 | "score": 4332, 102 | "taskStats": { 103 | "Graphiti": null, 104 | "TownOfSaleaem": null, 105 | "SuperSe...": null, 106 | "plolard": null, 107 | "flåarb.tar.xz": null, 108 | "sillyeilish": null, 109 | "easyOS": null, 110 | "locksmith": null, 111 | "lockdown": null 112 | } 113 | }, 114 | { 115 | "pos": 7, 116 | "team": "KTHCTF0x1", 117 | "score": 4017, 118 | "taskStats": { 119 | "Graphiti": null, 120 | "SuperSe...": null, 121 | "flåarb.tar.xz": null, 122 | "not backdoored": null, 123 | "sillyeilish": null, 124 | "easyOS": null, 125 | "locksmith": null, 126 | "lockdown": null 127 | } 128 | }, 129 | { 130 | "pos": 8, 131 | "team": "More Smoked Leet Chicken", 132 | "score": 3978, 133 | "taskStats": { 134 | "Graphiti": null, 135 | "TownOfSaleaem": null, 136 | "SuperSe...": null, 137 | "plolard": null, 138 | "flåarb.tar.xz": null, 139 | "not backdoored": null, 140 | "sillyeilish": null, 141 | "easyOS": null, 142 | "locksmith": null, 143 | "secret-diary": null 144 | } 145 | }, 146 | { 147 | "pos": 9, 148 | "team": "WreckTheLine", 149 | "score": 3487, 150 | "taskStats": { 151 | "Graphiti": null, 152 | "TownOfSaleaem": null, 153 | "SuperSe...": null, 154 | "flåarb.tar.xz": null, 155 | "sillyeilish": null, 156 | "easyOS": null, 157 | "locksmith": null, 158 | "lockdown": null, 159 | "memery": null 160 | } 161 | }, 162 | { 163 | "pos": 10, 164 | "team": "uuunderflow", 165 | "score": 2977, 166 | "taskStats": { 167 | "Graphiti": null, 168 | "SuperSe...": null, 169 | "flåarb.tar.xz": null, 170 | "sillyeilish": null, 171 | "easyOS": null, 172 | "locksmith": null, 173 | "lockdown": null, 174 | "memery": null, 175 | "QRona": null 176 | } 177 | }, 178 | { 179 | "pos": 11, 180 | "team": "DTTAlH3", 181 | "score": 1934, 182 | "taskStats": { 183 | "SuperSe...": null, 184 | "locksmith": null 185 | } 186 | }, 187 | { 188 | "pos": 12, 189 | "team": "bumbodosan", 190 | "score": 1375, 191 | "taskStats": { 192 | "SuperSe...": null, 193 | "flåarb.tar.xz": null, 194 | "locksmith": null 195 | } 196 | }, 197 | { 198 | "pos": 13, 199 | "team": "h4tum", 200 | "score": 1013, 201 | "taskStats": { 202 | "SuperSe...": null, 203 | "lockdown": null, 204 | "memery": null 205 | } 206 | }, 207 | { 208 | "pos": 14, 209 | "team": "kthxbye", 210 | "score": 549, 211 | "taskStats": { 212 | "SuperSe...": null, 213 | "flåarb.tar.xz": null 214 | } 215 | } 216 | ], 217 | "tasks": [ 218 | "Graphiti", 219 | "TownOfSaleaem", 220 | "SuperSe...", 221 | "plolard", 222 | "flåarb.tar.xz", 223 | "not backdoored", 224 | "sillyeilish", 225 | "inspectorgadget", 226 | "Climb t...", 227 | "easyOS", 228 | "risque", 229 | "locksmith", 230 | "King of Fuzz", 231 | "secret-diary", 232 | "lockdown", 233 | "memery", 234 | "QRona", 235 | "Crack M...", 236 | "Tabula RSA" 237 | ], 238 | "date": 1631890800, 239 | "name": "Midnightsun CTF 2021 Finals" 240 | } 241 | -------------------------------------------------------------------------------- /data/events/SPRUSH CTF Quals 2021.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | "SecretTactics", 4 | "Randsino", 5 | "Survey", 6 | "REVKERnel", 7 | "MEPhI Gates", 8 | "Jackpot collection", 9 | "Stand up and Go", 10 | "Hydra casino", 11 | "Weird Full House", 12 | "Revocryptoforensics", 13 | "There are no windows in casino", 14 | "ASSembly", 15 | "Unsigned winner", 16 | "Private casino", 17 | "Casifax", 18 | "babypwn" 19 | ], 20 | "standings": [ 21 | { 22 | "id": "12", 23 | "team": "C4T BuT S4D", 24 | "pos": 1, 25 | "score": 5575, 26 | "taskStats": { 27 | "babypwn": { 28 | "points": "473", 29 | "time": 1616282411 30 | }, 31 | "Randsino": { 32 | "points": "449", 33 | "time": 1616284568 34 | }, 35 | "Casifax": { 36 | "points": "269", 37 | "time": 1616285767 38 | }, 39 | "ASSembly": { 40 | "points": "460", 41 | "time": 1616287417 42 | }, 43 | "Revocryptoforensics": { 44 | "points": "460", 45 | "time": 1616290298 46 | }, 47 | "Unsigned winner": { 48 | "points": "469", 49 | "time": 1616293673 50 | }, 51 | "Hydra casino": { 52 | "points": "500", 53 | "time": 1616294295 54 | }, 55 | "MEPhI Gates": { 56 | "points": "500", 57 | "time": 1616299387 58 | }, 59 | "There are no windows in casino": { 60 | "points": "500", 61 | "time": 1616304475 62 | }, 63 | "Jackpot collection": { 64 | "points": "500", 65 | "time": 1616315929 66 | }, 67 | "Survey": { 68 | "points": "0", 69 | "time": 1616317831 70 | }, 71 | "REVKERnel": { 72 | "points": "495", 73 | "time": 1616318073 74 | }, 75 | "Stand up and Go": { 76 | "points": "500", 77 | "time": 1616323803 78 | } 79 | } 80 | }, 81 | { 82 | "id": "110", 83 | "team": "SFT0", 84 | "pos": 2, 85 | "score": 2653, 86 | "taskStats": { 87 | "Unsigned winner": { 88 | "points": "469", 89 | "time": 1616286291 90 | }, 91 | "Casifax": { 92 | "points": "269", 93 | "time": 1616287461 94 | }, 95 | "Revocryptoforensics": { 96 | "points": "460", 97 | "time": 1616287747 98 | }, 99 | "ASSembly": { 100 | "points": "460", 101 | "time": 1616288655 102 | }, 103 | "REVKERnel": { 104 | "points": "495", 105 | "time": 1616303495 106 | }, 107 | "Private casino": { 108 | "points": "500", 109 | "time": 1616322379 110 | } 111 | } 112 | }, 113 | { 114 | "id": "54", 115 | "team": "fargate", 116 | "pos": 3, 117 | "score": 2580, 118 | "taskStats": { 119 | "Revocryptoforensics": { 120 | "points": "460", 121 | "time": 1616283608 122 | }, 123 | "Unsigned winner": { 124 | "points": "469", 125 | "time": 1616294600 126 | }, 127 | "Casifax": { 128 | "points": "269", 129 | "time": 1616299857 130 | }, 131 | "ASSembly": { 132 | "points": "460", 133 | "time": 1616300903 134 | }, 135 | "Randsino": { 136 | "points": "449", 137 | "time": 1616306404 138 | }, 139 | "Survey": { 140 | "points": "0", 141 | "time": 1616317725 142 | }, 143 | "babypwn": { 144 | "points": "473", 145 | "time": 1616320718 146 | } 147 | } 148 | }, 149 | { 150 | "id": "109", 151 | "team": "WreckTheLine", 152 | "pos": 4, 153 | "score": 2162, 154 | "taskStats": { 155 | "Casifax": { 156 | "points": "269", 157 | "time": 1616313425 158 | }, 159 | "Revocryptoforensics": { 160 | "points": "460", 161 | "time": 1616314836 162 | }, 163 | "babypwn": { 164 | "points": "473", 165 | "time": 1616316884 166 | }, 167 | "ASSembly": { 168 | "points": "460", 169 | "time": 1616317826 170 | }, 171 | "Jackpot collection": { 172 | "points": "500", 173 | "time": 1616325225 174 | } 175 | } 176 | }, 177 | { 178 | "id": "97", 179 | "team": "±!@#$%^&*()_+=-0987654321§", 180 | "pos": 5, 181 | "score": 1877, 182 | "taskStats": { 183 | "babypwn": { 184 | "points": "473", 185 | "time": 1616287785 186 | }, 187 | "Randsino": { 188 | "points": "449", 189 | "time": 1616290352 190 | }, 191 | "ASSembly": { 192 | "points": "460", 193 | "time": 1616291522 194 | }, 195 | "REVKERnel": { 196 | "points": "495", 197 | "time": 1616298321 198 | } 199 | } 200 | }, 201 | { 202 | "id": "88", 203 | "team": "BinaryBears", 204 | "pos": 6, 205 | "score": 1738, 206 | "taskStats": { 207 | "Casifax": { 208 | "points": "269", 209 | "time": 1616288493 210 | }, 211 | "Unsigned winner": { 212 | "points": "469", 213 | "time": 1616297636 214 | }, 215 | "Jackpot collection": { 216 | "points": "500", 217 | "time": 1616305614 218 | }, 219 | "SecretTactics": { 220 | "points": "500", 221 | "time": 1616314733 222 | }, 223 | "Survey": { 224 | "points": "0", 225 | "time": 1616318527 226 | } 227 | } 228 | }, 229 | { 230 | "id": "174", 231 | "team": "kks", 232 | "pos": 7, 233 | "score": 1693, 234 | "taskStats": { 235 | "REVKERnel": { 236 | "points": "495", 237 | "time": 1616298737 238 | }, 239 | "ASSembly": { 240 | "points": "460", 241 | "time": 1616316163 242 | }, 243 | "Casifax": { 244 | "points": "269", 245 | "time": 1616323436 246 | }, 247 | "Unsigned winner": { 248 | "points": "469", 249 | "time": 1616325472 250 | } 251 | } 252 | }, 253 | { 254 | "id": "19", 255 | "team": "Bulba Hackers", 256 | "pos": 8, 257 | "score": 1658, 258 | "taskStats": { 259 | "Casifax": { 260 | "points": "269", 261 | "time": 1616281692 262 | }, 263 | "Unsigned winner": { 264 | "points": "469", 265 | "time": 1616295628 266 | }, 267 | "Survey": { 268 | "points": "0", 269 | "time": 1616320243 270 | }, 271 | "Revocryptoforensics": { 272 | "points": "460", 273 | "time": 1616322461 274 | }, 275 | "ASSembly": { 276 | "points": "460", 277 | "time": 1616326061 278 | } 279 | } 280 | }, 281 | { 282 | "id": "61", 283 | "team": "eltech 🤡🍌🔞", 284 | "pos": 9, 285 | "score": 1651, 286 | "taskStats": { 287 | "Casifax": { 288 | "points": "269", 289 | "time": 1616286547 290 | }, 291 | "Revocryptoforensics": { 292 | "points": "460", 293 | "time": 1616297798 294 | }, 295 | "Survey": { 296 | "points": "0", 297 | "time": 1616317990 298 | }, 299 | "Randsino": { 300 | "points": "449", 301 | "time": 1616322367 302 | }, 303 | "babypwn": { 304 | "points": "473", 305 | "time": 1616323251 306 | } 307 | } 308 | }, 309 | { 310 | "id": "133", 311 | "team": "FAUST", 312 | "pos": 10, 313 | "score": 1178, 314 | "taskStats": { 315 | "Casifax": { 316 | "points": "269", 317 | "time": 1616287322 318 | }, 319 | "Randsino": { 320 | "points": "449", 321 | "time": 1616305275 322 | }, 323 | "ASSembly": { 324 | "points": "460", 325 | "time": 1616327645 326 | } 327 | } 328 | }, 329 | { 330 | "id": "17", 331 | "team": "Red Cadets", 332 | "pos": 11, 333 | "score": 922, 334 | "taskStats": { 335 | "Randsino": { 336 | "points": "449", 337 | "time": 1616290549 338 | }, 339 | "babypwn": { 340 | "points": "473", 341 | "time": 1616321909 342 | } 343 | } 344 | }, 345 | { 346 | "id": "185", 347 | "team": "Tеаm1", 348 | "pos": 12, 349 | "score": 920, 350 | "taskStats": { 351 | "Revocryptoforensics": { 352 | "points": "460", 353 | "time": 1616296423 354 | }, 355 | "ASSembly": { 356 | "points": "460", 357 | "time": 1616311475 358 | }, 359 | "Survey": { 360 | "points": "0", 361 | "time": 1616321558 362 | } 363 | } 364 | }, 365 | { 366 | "id": "186", 367 | "team": "splitline", 368 | "pos": 13, 369 | "score": 738, 370 | "taskStats": { 371 | "Unsigned winner": { 372 | "points": "469", 373 | "time": 1616292761 374 | }, 375 | "Casifax": { 376 | "points": "269", 377 | "time": 1616293412 378 | } 379 | } 380 | }, 381 | { 382 | "id": "124", 383 | "team": "SaturnX", 384 | "pos": 14, 385 | "score": 738, 386 | "taskStats": { 387 | "Casifax": { 388 | "points": "269", 389 | "time": 1616293274 390 | }, 391 | "Unsigned winner": { 392 | "points": "469", 393 | "time": 1616305152 394 | } 395 | } 396 | }, 397 | { 398 | "id": "26", 399 | "team": "AU_H@ck3rs", 400 | "pos": 15, 401 | "score": 718, 402 | "taskStats": { 403 | "Casifax": { 404 | "points": "269", 405 | "time": 1616296219 406 | }, 407 | "Survey": { 408 | "points": "0", 409 | "time": 1616320468 410 | }, 411 | "Randsino": { 412 | "points": "449", 413 | "time": 1616324623 414 | } 415 | } 416 | }, 417 | { 418 | "id": "81", 419 | "team": "Название команды", 420 | "pos": 16, 421 | "score": 500, 422 | "taskStats": { 423 | "MEPhI Gates": { 424 | "points": "500", 425 | "time": 1616306571 426 | }, 427 | "Survey": { 428 | "points": "0", 429 | "time": 1616317761 430 | } 431 | } 432 | }, 433 | { 434 | "id": "40", 435 | "team": "Blood Sugar", 436 | "pos": 17, 437 | "score": 500, 438 | "taskStats": { 439 | "Weird Full House": { 440 | "points": "500", 441 | "time": 1616307682 442 | }, 443 | "Survey": { 444 | "points": "0", 445 | "time": 1616318221 446 | } 447 | } 448 | }, 449 | { 450 | "id": "217", 451 | "team": "whoamiT", 452 | "pos": 18, 453 | "score": 473, 454 | "taskStats": { 455 | "babypwn": { 456 | "points": "473", 457 | "time": 1616310485 458 | } 459 | } 460 | }, 461 | { 462 | "id": "238", 463 | "team": "cew", 464 | "pos": 19, 465 | "score": 460, 466 | "taskStats": { 467 | "Revocryptoforensics": { 468 | "points": "460", 469 | "time": 1616309413 470 | } 471 | } 472 | }, 473 | { 474 | "id": "271", 475 | "team": "DarkArmy", 476 | "pos": 20, 477 | "score": 460, 478 | "taskStats": { 479 | "Revocryptoforensics": { 480 | "points": "460", 481 | "time": 1616322824 482 | } 483 | } 484 | }, 485 | { 486 | "id": "151", 487 | "team": "x6C6F747573", 488 | "pos": 21, 489 | "score": 449, 490 | "taskStats": { 491 | "Randsino": { 492 | "points": "449", 493 | "time": 1616282878 494 | } 495 | } 496 | }, 497 | { 498 | "id": "24", 499 | "team": "ThereIsNoInfoRoma", 500 | "pos": 22, 501 | "score": 449, 502 | "taskStats": { 503 | "Randsino": { 504 | "points": "449", 505 | "time": 1616296549 506 | } 507 | } 508 | }, 509 | { 510 | "id": "155", 511 | "team": "paulie", 512 | "pos": 23, 513 | "score": 449, 514 | "taskStats": { 515 | "Randsino": { 516 | "points": "449", 517 | "time": 1616320398 518 | }, 519 | "Survey": { 520 | "points": "0", 521 | "time": 1616322276 522 | } 523 | } 524 | }, 525 | { 526 | "id": "166", 527 | "team": "TourRadar", 528 | "pos": 24, 529 | "score": 269, 530 | "taskStats": { 531 | "Casifax": { 532 | "points": "269", 533 | "time": 1616282894 534 | } 535 | } 536 | }, 537 | { 538 | "id": "37", 539 | "team": "0x01d5", 540 | "pos": 25, 541 | "score": 269, 542 | "taskStats": { 543 | "Casifax": { 544 | "points": "269", 545 | "time": 1616282899 546 | }, 547 | "Survey": { 548 | "points": "0", 549 | "time": 1616318625 550 | } 551 | } 552 | }, 553 | { 554 | "id": "138", 555 | "team": "M3di0cr3s", 556 | "pos": 26, 557 | "score": 269, 558 | "taskStats": { 559 | "Casifax": { 560 | "points": "269", 561 | "time": 1616290258 562 | } 563 | } 564 | }, 565 | { 566 | "id": "197", 567 | "team": "phishing lvls?", 568 | "pos": 27, 569 | "score": 269, 570 | "taskStats": { 571 | "Casifax": { 572 | "points": "269", 573 | "time": 1616295884 574 | } 575 | } 576 | }, 577 | { 578 | "id": "65", 579 | "team": "Tkd-Alex", 580 | "pos": 28, 581 | "score": 269, 582 | "taskStats": { 583 | "Casifax": { 584 | "points": "269", 585 | "time": 1616302252 586 | } 587 | } 588 | }, 589 | { 590 | "id": "106", 591 | "team": "R0073R5", 592 | "pos": 29, 593 | "score": 269, 594 | "taskStats": { 595 | "Casifax": { 596 | "points": "269", 597 | "time": 1616304204 598 | } 599 | } 600 | }, 601 | { 602 | "id": "23", 603 | "team": "Omaviat", 604 | "pos": 30, 605 | "score": 269, 606 | "taskStats": { 607 | "Casifax": { 608 | "points": "269", 609 | "time": 1616311637 610 | }, 611 | "Survey": { 612 | "points": "0", 613 | "time": 1616319445 614 | } 615 | } 616 | }, 617 | { 618 | "id": "126", 619 | "team": "cntr0llz", 620 | "pos": 31, 621 | "score": 269, 622 | "taskStats": { 623 | "Casifax": { 624 | "points": "269", 625 | "time": 1616326885 626 | } 627 | } 628 | } 629 | ], 630 | "date": 1616252400, 631 | "name": "SPRUSH CTF Quals 2021" 632 | } -------------------------------------------------------------------------------- /data/events/TyphoonCon CTF 2021.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | "Impasse", 4 | "Network Configuration", 5 | "Mortal Kobat", 6 | "Clubmouse", 7 | "Exciting Offer", 8 | "Knock Knock", 9 | "Race to Win", 10 | "Interactive Sessions", 11 | "Building a House" 12 | ], 13 | "standings": [ 14 | { 15 | "team": "revbuster", 16 | "pos": 1, 17 | "score": 3163, 18 | "id": 937, 19 | "taskStats": { 20 | "Knock Knock": { 21 | "points": 300, 22 | "time": 1626188398 23 | }, 24 | "Mortal Kobat": { 25 | "points": 300, 26 | "time": 1626198789 27 | }, 28 | "Network Configuration": { 29 | "points": 863, 30 | "time": 1626210810 31 | }, 32 | "Building a House": { 33 | "points": 300, 34 | "time": 1626213380 35 | }, 36 | "Exciting Offer": { 37 | "points": 300, 38 | "time": 1626219581 39 | }, 40 | "Impasse": { 41 | "points": 100, 42 | "time": 1626221206 43 | }, 44 | "Race to Win": { 45 | "points": 600, 46 | "time": 1626223496 47 | }, 48 | "Clubmouse": { 49 | "points": 100, 50 | "time": 1626224955 51 | }, 52 | "Interactive Sessions": { 53 | "points": 300, 54 | "time": 1626261404 55 | } 56 | } 57 | }, 58 | { 59 | "team": "bootplug", 60 | "pos": 2, 61 | "score": 3163, 62 | "id": 406, 63 | "taskStats": { 64 | "Impasse": { 65 | "points": 100, 66 | "time": 1626115734 67 | }, 68 | "Race to Win": { 69 | "points": 600, 70 | "time": 1626120178 71 | }, 72 | "Clubmouse": { 73 | "points": 100, 74 | "time": 1626122335 75 | }, 76 | "Mortal Kobat": { 77 | "points": 300, 78 | "time": 1626185002 79 | }, 80 | "Knock Knock": { 81 | "points": 300, 82 | "time": 1626205093 83 | }, 84 | "Exciting Offer": { 85 | "points": 300, 86 | "time": 1626209827 87 | }, 88 | "Network Configuration": { 89 | "points": 863, 90 | "time": 1626219455 91 | }, 92 | "Building a House": { 93 | "points": 300, 94 | "time": 1626249709 95 | }, 96 | "Interactive Sessions": { 97 | "points": 300, 98 | "time": 1626261440 99 | } 100 | } 101 | }, 102 | { 103 | "team": "perfect blue", 104 | "pos": 3, 105 | "score": 3163, 106 | "id": 489, 107 | "taskStats": { 108 | "Network Configuration": { 109 | "points": 863, 110 | "time": 1626160580 111 | }, 112 | "Race to Win": { 113 | "points": 600, 114 | "time": 1626161699 115 | }, 116 | "Impasse": { 117 | "points": 100, 118 | "time": 1626176768 119 | }, 120 | "Building a House": { 121 | "points": 300, 122 | "time": 1626186571 123 | }, 124 | "Mortal Kobat": { 125 | "points": 300, 126 | "time": 1626192459 127 | }, 128 | "Knock Knock": { 129 | "points": 300, 130 | "time": 1626202270 131 | }, 132 | "Clubmouse": { 133 | "points": 100, 134 | "time": 1626203691 135 | }, 136 | "Exciting Offer": { 137 | "points": 300, 138 | "time": 1626241630 139 | }, 140 | "Interactive Sessions": { 141 | "points": 300, 142 | "time": 1626261872 143 | } 144 | } 145 | }, 146 | { 147 | "team": "Thehackerscrew", 148 | "pos": 4, 149 | "score": 1963, 150 | "id": 371, 151 | "taskStats": { 152 | "Impasse": { 153 | "points": 100, 154 | "time": 1626100473 155 | }, 156 | "Building a House": { 157 | "points": 300, 158 | "time": 1626124206 159 | }, 160 | "Race to Win": { 161 | "points": 600, 162 | "time": 1626126257 163 | }, 164 | "Clubmouse": { 165 | "points": 100, 166 | "time": 1626130722 167 | }, 168 | "Network Configuration": { 169 | "points": 863, 170 | "time": 1626148196 171 | } 172 | } 173 | }, 174 | { 175 | "team": "r3billions", 176 | "pos": 5, 177 | "score": 1600, 178 | "id": 63, 179 | "taskStats": { 180 | "Knock Knock": { 181 | "points": 300, 182 | "time": 1626134522 183 | }, 184 | "Impasse": { 185 | "points": 100, 186 | "time": 1626136065 187 | }, 188 | "Race to Win": { 189 | "points": 600, 190 | "time": 1626177753 191 | }, 192 | "Exciting Offer": { 193 | "points": 300, 194 | "time": 1626179016 195 | }, 196 | "Mortal Kobat": { 197 | "points": 300, 198 | "time": 1626187530 199 | } 200 | } 201 | }, 202 | { 203 | "team": "POLZZAG", 204 | "pos": 6, 205 | "score": 1600, 206 | "id": 660, 207 | "taskStats": { 208 | "Race to Win": { 209 | "points": 600, 210 | "time": 1626145289 211 | }, 212 | "Impasse": { 213 | "points": 100, 214 | "time": 1626160080 215 | }, 216 | "Mortal Kobat": { 217 | "points": 300, 218 | "time": 1626165188 219 | }, 220 | "Knock Knock": { 221 | "points": 300, 222 | "time": 1626171598 223 | }, 224 | "Building a House": { 225 | "points": 300, 226 | "time": 1626255691 227 | } 228 | } 229 | }, 230 | { 231 | "team": "CSALab_Sec", 232 | "pos": 7, 233 | "score": 1600, 234 | "id": 67, 235 | "taskStats": { 236 | "Impasse": { 237 | "points": 100, 238 | "time": 1626162334 239 | }, 240 | "Race to Win": { 241 | "points": 600, 242 | "time": 1626173163 243 | }, 244 | "Building a House": { 245 | "points": 300, 246 | "time": 1626219741 247 | }, 248 | "Mortal Kobat": { 249 | "points": 300, 250 | "time": 1626268788 251 | }, 252 | "Knock Knock": { 253 | "points": 300, 254 | "time": 1626275543 255 | } 256 | } 257 | }, 258 | { 259 | "team": "Organizers", 260 | "pos": 8, 261 | "score": 1300, 262 | "id": 535, 263 | "taskStats": { 264 | "Impasse": { 265 | "points": 100, 266 | "time": 1626105178 267 | }, 268 | "Mortal Kobat": { 269 | "points": 300, 270 | "time": 1626123974 271 | }, 272 | "Race to Win": { 273 | "points": 600, 274 | "time": 1626130313 275 | }, 276 | "Knock Knock": { 277 | "points": 300, 278 | "time": 1626256601 279 | } 280 | } 281 | }, 282 | { 283 | "team": "0nlyFlags", 284 | "pos": 9, 285 | "score": 1300, 286 | "id": 55, 287 | "taskStats": { 288 | "Impasse": { 289 | "points": 100, 290 | "time": 1626164545 291 | }, 292 | "Mortal Kobat": { 293 | "points": 300, 294 | "time": 1626179728 295 | }, 296 | "Knock Knock": { 297 | "points": 300, 298 | "time": 1626246678 299 | }, 300 | "Building a House": { 301 | "points": 300, 302 | "time": 1626279960 303 | }, 304 | "Exciting Offer": { 305 | "points": 300, 306 | "time": 1626345196 307 | } 308 | } 309 | }, 310 | { 311 | "team": "Social Engineering Experts", 312 | "pos": 10, 313 | "score": 1100, 314 | "id": 214, 315 | "taskStats": { 316 | "Impasse": { 317 | "points": 100, 318 | "time": 1626099160 319 | }, 320 | "Clubmouse": { 321 | "points": 100, 322 | "time": 1626152297 323 | }, 324 | "Race to Win": { 325 | "points": 600, 326 | "time": 1626173170 327 | }, 328 | "Interactive Sessions": { 329 | "points": 300, 330 | "time": 1626261481 331 | } 332 | } 333 | }, 334 | { 335 | "team": "AlphaSeal", 336 | "pos": 11, 337 | "score": 1100, 338 | "id": 219, 339 | "taskStats": { 340 | "Impasse": { 341 | "points": 100, 342 | "time": 1626167962 343 | }, 344 | "Clubmouse": { 345 | "points": 100, 346 | "time": 1626188220 347 | }, 348 | "Race to Win": { 349 | "points": 600, 350 | "time": 1626233674 351 | }, 352 | "Mortal Kobat": { 353 | "points": 300, 354 | "time": 1626264754 355 | } 356 | } 357 | }, 358 | { 359 | "team": "zer0pts", 360 | "pos": 12, 361 | "score": 1000, 362 | "id": 416, 363 | "taskStats": { 364 | "Impasse": { 365 | "points": 100, 366 | "time": 1626100565 367 | }, 368 | "Mortal Kobat": { 369 | "points": 300, 370 | "time": 1626237887 371 | }, 372 | "Exciting Offer": { 373 | "points": 300, 374 | "time": 1626247540 375 | }, 376 | "Knock Knock": { 377 | "points": 300, 378 | "time": 1626281626 379 | } 380 | } 381 | }, 382 | { 383 | "team": "goo", 384 | "pos": 13, 385 | "score": 900, 386 | "id": 646, 387 | "taskStats": { 388 | "Knock Knock": { 389 | "points": 300, 390 | "time": 1626127121 391 | }, 392 | "Mortal Kobat": { 393 | "points": 300, 394 | "time": 1626307487 395 | }, 396 | "Exciting Offer": { 397 | "points": 300, 398 | "time": 1626313586 399 | } 400 | } 401 | }, 402 | { 403 | "team": "Revers3c", 404 | "pos": 14, 405 | "score": 800, 406 | "id": 30, 407 | "taskStats": { 408 | "Clubmouse": { 409 | "points": 100, 410 | "time": 1626121171 411 | }, 412 | "Impasse": { 413 | "points": 100, 414 | "time": 1626130002 415 | }, 416 | "Race to Win": { 417 | "points": 600, 418 | "time": 1626187219 419 | } 420 | } 421 | }, 422 | { 423 | "team": "BreakingBread", 424 | "pos": 15, 425 | "score": 800, 426 | "id": 668, 427 | "taskStats": { 428 | "Impasse": { 429 | "points": 100, 430 | "time": 1626113608 431 | }, 432 | "Clubmouse": { 433 | "points": 100, 434 | "time": 1626139608 435 | }, 436 | "Race to Win": { 437 | "points": 600, 438 | "time": 1626187509 439 | } 440 | } 441 | }, 442 | { 443 | "team": "tata", 444 | "pos": 16, 445 | "score": 800, 446 | "id": 716, 447 | "taskStats": { 448 | "Impasse": { 449 | "points": 100, 450 | "time": 1626118102 451 | }, 452 | "Race to Win": { 453 | "points": 600, 454 | "time": 1626188091 455 | }, 456 | "Clubmouse": { 457 | "points": 100, 458 | "time": 1626192228 459 | } 460 | } 461 | }, 462 | { 463 | "team": "CyberErudites", 464 | "pos": 17, 465 | "score": 800, 466 | "id": 44, 467 | "taskStats": { 468 | "Impasse": { 469 | "points": 100, 470 | "time": 1626118625 471 | }, 472 | "Clubmouse": { 473 | "points": 100, 474 | "time": 1626130939 475 | }, 476 | "Race to Win": { 477 | "points": 600, 478 | "time": 1626271016 479 | } 480 | } 481 | }, 482 | { 483 | "team": "N33rdZ", 484 | "pos": 18, 485 | "score": 800, 486 | "id": 21, 487 | "taskStats": { 488 | "Race to Win": { 489 | "points": 600, 490 | "time": 1626286508 491 | }, 492 | "Impasse": { 493 | "points": 100, 494 | "time": 1626286530 495 | }, 496 | "Clubmouse": { 497 | "points": 100, 498 | "time": 1626286595 499 | } 500 | } 501 | }, 502 | { 503 | "team": "Fword", 504 | "pos": 19, 505 | "score": 800, 506 | "id": 76, 507 | "taskStats": { 508 | "Impasse": { 509 | "points": 100, 510 | "time": 1626111864 511 | }, 512 | "Clubmouse": { 513 | "points": 100, 514 | "time": 1626216987 515 | }, 516 | "Race to Win": { 517 | "points": 600, 518 | "time": 1626299246 519 | } 520 | } 521 | }, 522 | { 523 | "team": "Janggggg", 524 | "pos": 20, 525 | "score": 700, 526 | "id": 83, 527 | "taskStats": { 528 | "Impasse": { 529 | "points": 100, 530 | "time": 1626099602 531 | }, 532 | "Race to Win": { 533 | "points": 600, 534 | "time": 1626143005 535 | } 536 | } 537 | }, 538 | { 539 | "team": "osmanthusrabbit", 540 | "pos": 21, 541 | "score": 700, 542 | "id": 561, 543 | "taskStats": { 544 | "Impasse": { 545 | "points": 100, 546 | "time": 1626096108 547 | }, 548 | "Race to Win": { 549 | "points": 600, 550 | "time": 1626144824 551 | } 552 | } 553 | }, 554 | { 555 | "team": "uetctf", 556 | "pos": 22, 557 | "score": 700, 558 | "id": 539, 559 | "taskStats": { 560 | "Impasse": { 561 | "points": 100, 562 | "time": 1626164756 563 | }, 564 | "Race to Win": { 565 | "points": 600, 566 | "time": 1626172499 567 | } 568 | } 569 | }, 570 | { 571 | "team": "Nupakachi", 572 | "pos": 23, 573 | "score": 700, 574 | "id": 811, 575 | "taskStats": { 576 | "Race to Win": { 577 | "points": 600, 578 | "time": 1626172670 579 | }, 580 | "Impasse": { 581 | "points": 100, 582 | "time": 1626172681 583 | } 584 | } 585 | }, 586 | { 587 | "team": "Arf", 588 | "pos": 24, 589 | "score": 700, 590 | "id": 678, 591 | "taskStats": { 592 | "Building a House": { 593 | "points": 300, 594 | "time": 1626137970 595 | }, 596 | "Mortal Kobat": { 597 | "points": 300, 598 | "time": 1626184656 599 | }, 600 | "Impasse": { 601 | "points": 100, 602 | "time": 1626199465 603 | } 604 | } 605 | }, 606 | { 607 | "team": "ARESx", 608 | "pos": 25, 609 | "score": 700, 610 | "id": 553, 611 | "taskStats": { 612 | "Impasse": { 613 | "points": 100, 614 | "time": 1626103249 615 | }, 616 | "Mortal Kobat": { 617 | "points": 300, 618 | "time": 1626124524 619 | }, 620 | "Knock Knock": { 621 | "points": 300, 622 | "time": 1626239043 623 | } 624 | } 625 | }, 626 | { 627 | "team": "Kalmarunionen", 628 | "pos": 26, 629 | "score": 700, 630 | "id": 987, 631 | "taskStats": { 632 | "Race to Win": { 633 | "points": 600, 634 | "time": 1626215689 635 | }, 636 | "Impasse": { 637 | "points": 100, 638 | "time": 1626262394 639 | } 640 | } 641 | }, 642 | { 643 | "team": "NGA", 644 | "pos": 27, 645 | "score": 700, 646 | "id": 600, 647 | "taskStats": { 648 | "Impasse": { 649 | "points": 100, 650 | "time": 1626098155 651 | }, 652 | "Race to Win": { 653 | "points": 600, 654 | "time": 1626329970 655 | } 656 | } 657 | }, 658 | { 659 | "team": "CSKMA", 660 | "pos": 28, 661 | "score": 700, 662 | "id": 507, 663 | "taskStats": { 664 | "Impasse": { 665 | "points": 100, 666 | "time": 1626195669 667 | }, 668 | "Race to Win": { 669 | "points": 600, 670 | "time": 1626335090 671 | } 672 | } 673 | }, 674 | { 675 | "team": "OyuSec", 676 | "pos": 29, 677 | "score": 600, 678 | "id": 79, 679 | "taskStats": { 680 | "Knock Knock": { 681 | "points": 300, 682 | "time": 1626199677 683 | }, 684 | "Mortal Kobat": { 685 | "points": 300, 686 | "time": 1626209522 687 | } 688 | } 689 | }, 690 | { 691 | "team": "y0f4c3", 692 | "pos": 30, 693 | "score": 600, 694 | "id": 93, 695 | "taskStats": { 696 | "Knock Knock": { 697 | "points": 300, 698 | "time": 1626135068 699 | }, 700 | "Exciting Offer": { 701 | "points": 300, 702 | "time": 1626319102 703 | } 704 | } 705 | }, 706 | { 707 | "team": "AAA", 708 | "pos": 31, 709 | "score": 400, 710 | "id": 645, 711 | "taskStats": { 712 | "Impasse": { 713 | "points": 100, 714 | "time": 1626105618 715 | }, 716 | "Building a House": { 717 | "points": 300, 718 | "time": 1626183699 719 | } 720 | } 721 | }, 722 | { 723 | "team": "Boys Who Cry", 724 | "pos": 32, 725 | "score": 400, 726 | "id": 858, 727 | "taskStats": { 728 | "Impasse": { 729 | "points": 100, 730 | "time": 1626165747 731 | }, 732 | "Mortal Kobat": { 733 | "points": 300, 734 | "time": 1626212224 735 | } 736 | } 737 | }, 738 | { 739 | "team": "0xN1ghtR1ngs", 740 | "pos": 33, 741 | "score": 400, 742 | "id": 15, 743 | "taskStats": { 744 | "Exciting Offer": { 745 | "points": 300, 746 | "time": 1626240197 747 | }, 748 | "Impasse": { 749 | "points": 100, 750 | "time": 1626241363 751 | } 752 | } 753 | }, 754 | { 755 | "team": "Team-0x7", 756 | "pos": 34, 757 | "score": 400, 758 | "id": 540, 759 | "taskStats": { 760 | "Impasse": { 761 | "points": 100, 762 | "time": 1626176900 763 | }, 764 | "Mortal Kobat": { 765 | "points": 300, 766 | "time": 1626281975 767 | } 768 | } 769 | }, 770 | { 771 | "team": "4STRONAUTS", 772 | "pos": 35, 773 | "score": 400, 774 | "id": 14, 775 | "taskStats": { 776 | "Exciting Offer": { 777 | "points": 300, 778 | "time": 1626234273 779 | }, 780 | "Impasse": { 781 | "points": 100, 782 | "time": 1626285206 783 | } 784 | } 785 | }, 786 | { 787 | "team": "", 788 | "pos": 36, 789 | "score": 400, 790 | "id": 723, 791 | "taskStats": { 792 | "Building a House": { 793 | "points": 300, 794 | "time": 1626224519 795 | }, 796 | "Impasse": { 797 | "points": 100, 798 | "time": 1626312714 799 | } 800 | } 801 | }, 802 | { 803 | "team": "1gy", 804 | "pos": 37, 805 | "score": 400, 806 | "id": 901, 807 | "taskStats": { 808 | "Impasse": { 809 | "points": 100, 810 | "time": 1626264289 811 | }, 812 | "Building a House": { 813 | "points": 300, 814 | "time": 1626325672 815 | } 816 | } 817 | }, 818 | { 819 | "team": "SHA-5010", 820 | "pos": 38, 821 | "score": 400, 822 | "id": 842, 823 | "taskStats": { 824 | "Impasse": { 825 | "points": 100, 826 | "time": 1626158131 827 | }, 828 | "Building a House": { 829 | "points": 300, 830 | "time": 1626337017 831 | } 832 | } 833 | }, 834 | { 835 | "team": "Cybers", 836 | "pos": 39, 837 | "score": 400, 838 | "id": 575, 839 | "taskStats": { 840 | "Impasse": { 841 | "points": 100, 842 | "time": 1626125264 843 | }, 844 | "Mortal Kobat": { 845 | "points": 300, 846 | "time": 1626349549 847 | } 848 | } 849 | }, 850 | { 851 | "team": "turtles", 852 | "pos": 40, 853 | "score": 300, 854 | "id": 72, 855 | "taskStats": { 856 | "Impasse": { 857 | "points": 100, 858 | "time": 1626093592 859 | } 860 | } 861 | }, 862 | { 863 | "team": "fibonhack", 864 | "pos": 41, 865 | "score": 300, 866 | "id": 720, 867 | "taskStats": { 868 | "Mortal Kobat": { 869 | "points": 300, 870 | "time": 1626181017 871 | } 872 | } 873 | }, 874 | { 875 | "team": "PwN_3v3rY7h1nG", 876 | "pos": 42, 877 | "score": 300, 878 | "id": 396, 879 | "taskStats": { 880 | "Knock Knock": { 881 | "points": 300, 882 | "time": 1626241035 883 | } 884 | } 885 | }, 886 | { 887 | "team": "tbg", 888 | "pos": 43, 889 | "score": 300, 890 | "id": 413, 891 | "taskStats": { 892 | "Knock Knock": { 893 | "points": 300, 894 | "time": 1626256565 895 | } 896 | } 897 | }, 898 | { 899 | "team": "f0urty2", 900 | "pos": 44, 901 | "score": 300, 902 | "id": 966, 903 | "taskStats": { 904 | "Knock Knock": { 905 | "points": 300, 906 | "time": 1626256764 907 | } 908 | } 909 | }, 910 | { 911 | "team": "Luigi", 912 | "pos": 45, 913 | "score": 300, 914 | "id": 352, 915 | "taskStats": { 916 | "Interactive Sessions": { 917 | "points": 300, 918 | "time": 1626261575 919 | } 920 | } 921 | }, 922 | { 923 | "team": "Chúa Hề", 924 | "pos": 46, 925 | "score": 250, 926 | "id": 550, 927 | "taskStats": { 928 | "Impasse": { 929 | "points": 100, 930 | "time": 1626093950 931 | } 932 | } 933 | }, 934 | { 935 | "team": "s3qu3nc3", 936 | "pos": 47, 937 | "score": 200, 938 | "id": 529, 939 | "taskStats": { 940 | "Impasse": { 941 | "points": 100, 942 | "time": 1626095005 943 | } 944 | } 945 | }, 946 | { 947 | "team": "sherif hood", 948 | "pos": 48, 949 | "score": 200, 950 | "id": 64, 951 | "taskStats": { 952 | "Impasse": { 953 | "points": 100, 954 | "time": 1626110841 955 | }, 956 | "Clubmouse": { 957 | "points": 100, 958 | "time": 1626119492 959 | } 960 | } 961 | }, 962 | { 963 | "team": "5w4mptr0ll5", 964 | "pos": 49, 965 | "score": 200, 966 | "id": 258, 967 | "taskStats": { 968 | "Impasse": { 969 | "points": 100, 970 | "time": 1626166622 971 | }, 972 | "Clubmouse": { 973 | "points": 100, 974 | "time": 1626257870 975 | } 976 | } 977 | }, 978 | { 979 | "team": "0xL4ugh", 980 | "pos": 50, 981 | "score": 200, 982 | "id": 121, 983 | "taskStats": { 984 | "Impasse": { 985 | "points": 100, 986 | "time": 1626096493 987 | }, 988 | "Clubmouse": { 989 | "points": 100, 990 | "time": 1626345423 991 | } 992 | } 993 | }, 994 | { 995 | "team": "AC/DC rocks ", 996 | "pos": 51, 997 | "score": 100, 998 | "id": 554, 999 | "taskStats": { 1000 | "Impasse": { 1001 | "points": 100, 1002 | "time": 1626099149 1003 | } 1004 | } 1005 | }, 1006 | { 1007 | "team": "nwpder", 1008 | "pos": 52, 1009 | "score": 100, 1010 | "id": 593, 1011 | "taskStats": { 1012 | "Impasse": { 1013 | "points": 100, 1014 | "time": 1626101764 1015 | } 1016 | } 1017 | }, 1018 | { 1019 | "team": "M1rr0r_keep3rz", 1020 | "pos": 53, 1021 | "score": 100, 1022 | "id": 334, 1023 | "taskStats": { 1024 | "Impasse": { 1025 | "points": 100, 1026 | "time": 1626104565 1027 | } 1028 | } 1029 | }, 1030 | { 1031 | "team": "Cyb3rTh1eveZ", 1032 | "pos": 54, 1033 | "score": 100, 1034 | "id": 401, 1035 | "taskStats": { 1036 | "Impasse": { 1037 | "points": 100, 1038 | "time": 1626106063 1039 | } 1040 | } 1041 | }, 1042 | { 1043 | "team": "S3ct34m", 1044 | "pos": 55, 1045 | "score": 100, 1046 | "id": 597, 1047 | "taskStats": { 1048 | "Impasse": { 1049 | "points": 100, 1050 | "time": 1626106341 1051 | } 1052 | } 1053 | }, 1054 | { 1055 | "team": "vsloop", 1056 | "pos": 56, 1057 | "score": 100, 1058 | "id": 611, 1059 | "taskStats": { 1060 | "Impasse": { 1061 | "points": 100, 1062 | "time": 1626108233 1063 | } 1064 | } 1065 | }, 1066 | { 1067 | "team": "d4rkc0de", 1068 | "pos": 57, 1069 | "score": 100, 1070 | "id": 459, 1071 | "taskStats": { 1072 | "Impasse": { 1073 | "points": 100, 1074 | "time": 1626108397 1075 | } 1076 | } 1077 | }, 1078 | { 1079 | "team": "h3rmes", 1080 | "pos": 58, 1081 | "score": 100, 1082 | "id": 365, 1083 | "taskStats": { 1084 | "Impasse": { 1085 | "points": 100, 1086 | "time": 1626112134 1087 | } 1088 | } 1089 | }, 1090 | { 1091 | "team": "EthicalCookieLovers", 1092 | "pos": 59, 1093 | "score": 100, 1094 | "id": 376, 1095 | "taskStats": { 1096 | "Impasse": { 1097 | "points": 100, 1098 | "time": 1626114453 1099 | } 1100 | } 1101 | }, 1102 | { 1103 | "team": "DeepWater", 1104 | "pos": 60, 1105 | "score": 100, 1106 | "id": 704, 1107 | "taskStats": { 1108 | "Impasse": { 1109 | "points": 100, 1110 | "time": 1626118055 1111 | } 1112 | } 1113 | }, 1114 | { 1115 | "team": "discordgang", 1116 | "pos": 61, 1117 | "score": 100, 1118 | "id": 211, 1119 | "taskStats": { 1120 | "Impasse": { 1121 | "points": 100, 1122 | "time": 1626122594 1123 | } 1124 | } 1125 | }, 1126 | { 1127 | "team": "Nobody", 1128 | "pos": 62, 1129 | "score": 100, 1130 | "id": 733, 1131 | "taskStats": { 1132 | "Impasse": { 1133 | "points": 100, 1134 | "time": 1626122654 1135 | } 1136 | } 1137 | }, 1138 | { 1139 | "team": "absol", 1140 | "pos": 63, 1141 | "score": 100, 1142 | "id": 82, 1143 | "taskStats": { 1144 | "Impasse": { 1145 | "points": 100, 1146 | "time": 1626123782 1147 | } 1148 | } 1149 | }, 1150 | { 1151 | "team": "RONS", 1152 | "pos": 64, 1153 | "score": 100, 1154 | "id": 201, 1155 | "taskStats": { 1156 | "Impasse": { 1157 | "points": 100, 1158 | "time": 1626147342 1159 | } 1160 | } 1161 | }, 1162 | { 1163 | "team": "taidh", 1164 | "pos": 65, 1165 | "score": 100, 1166 | "id": 392, 1167 | "taskStats": { 1168 | "Impasse": { 1169 | "points": 100, 1170 | "time": 1626153092 1171 | } 1172 | } 1173 | }, 1174 | { 1175 | "team": "InfoSecIITR", 1176 | "pos": 66, 1177 | "score": 100, 1178 | "id": 673, 1179 | "taskStats": { 1180 | "Impasse": { 1181 | "points": 100, 1182 | "time": 1626177981 1183 | } 1184 | } 1185 | }, 1186 | { 1187 | "team": "hctawrevo", 1188 | "pos": 67, 1189 | "score": 100, 1190 | "id": 932, 1191 | "taskStats": { 1192 | "Impasse": { 1193 | "points": 100, 1194 | "time": 1626181959 1195 | } 1196 | } 1197 | }, 1198 | { 1199 | "team": "DROPSEC", 1200 | "pos": 68, 1201 | "score": 100, 1202 | "id": 942, 1203 | "taskStats": { 1204 | "Impasse": { 1205 | "points": 100, 1206 | "time": 1626184869 1207 | } 1208 | } 1209 | }, 1210 | { 1211 | "team": "dex", 1212 | "pos": 69, 1213 | "score": 100, 1214 | "id": 923, 1215 | "taskStats": { 1216 | "Impasse": { 1217 | "points": 100, 1218 | "time": 1626185010 1219 | } 1220 | } 1221 | }, 1222 | { 1223 | "team": "noob-atbash", 1224 | "pos": 70, 1225 | "score": 100, 1226 | "id": 547, 1227 | "taskStats": { 1228 | "Impasse": { 1229 | "points": 100, 1230 | "time": 1626190301 1231 | } 1232 | } 1233 | }, 1234 | { 1235 | "team": "legendsOfHell", 1236 | "pos": 71, 1237 | "score": 100, 1238 | "id": 138, 1239 | "taskStats": { 1240 | "Impasse": { 1241 | "points": 100, 1242 | "time": 1626203277 1243 | } 1244 | } 1245 | }, 1246 | { 1247 | "team": "Arch3r", 1248 | "pos": 72, 1249 | "score": 100, 1250 | "id": 250, 1251 | "taskStats": { 1252 | "Impasse": { 1253 | "points": 100, 1254 | "time": 1626205825 1255 | } 1256 | } 1257 | }, 1258 | { 1259 | "team": "YeoMin", 1260 | "pos": 73, 1261 | "score": 100, 1262 | "id": 960, 1263 | "taskStats": { 1264 | "Impasse": { 1265 | "points": 100, 1266 | "time": 1626206456 1267 | } 1268 | } 1269 | }, 1270 | { 1271 | "team": "DarkBoss", 1272 | "pos": 74, 1273 | "score": 100, 1274 | "id": 520, 1275 | "taskStats": { 1276 | "Impasse": { 1277 | "points": 100, 1278 | "time": 1626216068 1279 | } 1280 | } 1281 | }, 1282 | { 1283 | "team": "PwnPwn", 1284 | "pos": 75, 1285 | "score": 100, 1286 | "id": 43, 1287 | "taskStats": { 1288 | "Impasse": { 1289 | "points": 100, 1290 | "time": 1626220081 1291 | } 1292 | } 1293 | }, 1294 | { 1295 | "team": "teste", 1296 | "pos": 76, 1297 | "score": 100, 1298 | "id": 998, 1299 | "taskStats": { 1300 | "Impasse": { 1301 | "points": 100, 1302 | "time": 1626237517 1303 | } 1304 | } 1305 | }, 1306 | { 1307 | "team": "testeaaa", 1308 | "pos": 77, 1309 | "score": 100, 1310 | "id": 1008, 1311 | "taskStats": { 1312 | "Impasse": { 1313 | "points": 100, 1314 | "time": 1626237568 1315 | } 1316 | } 1317 | }, 1318 | { 1319 | "team": "DDLJ", 1320 | "pos": 78, 1321 | "score": 100, 1322 | "id": 33, 1323 | "taskStats": { 1324 | "Impasse": { 1325 | "points": 100, 1326 | "time": 1626253591 1327 | } 1328 | } 1329 | }, 1330 | { 1331 | "team": "STeam", 1332 | "pos": 79, 1333 | "score": 100, 1334 | "id": 807, 1335 | "taskStats": { 1336 | "Impasse": { 1337 | "points": 100, 1338 | "time": 1626263231 1339 | } 1340 | } 1341 | }, 1342 | { 1343 | "team": "ri5e", 1344 | "pos": 80, 1345 | "score": 100, 1346 | "id": 192, 1347 | "taskStats": { 1348 | "Impasse": { 1349 | "points": 100, 1350 | "time": 1626265892 1351 | } 1352 | } 1353 | }, 1354 | { 1355 | "team": "OLAN", 1356 | "pos": 81, 1357 | "score": 100, 1358 | "id": 868, 1359 | "taskStats": { 1360 | "Impasse": { 1361 | "points": 100, 1362 | "time": 1626275800 1363 | } 1364 | } 1365 | }, 1366 | { 1367 | "team": "ben", 1368 | "pos": 82, 1369 | "score": 100, 1370 | "id": 1063, 1371 | "taskStats": { 1372 | "Impasse": { 1373 | "points": 100, 1374 | "time": 1626289633 1375 | } 1376 | } 1377 | }, 1378 | { 1379 | "team": "TheSludges", 1380 | "pos": 83, 1381 | "score": 100, 1382 | "id": 940, 1383 | "taskStats": { 1384 | "Impasse": { 1385 | "points": 100, 1386 | "time": 1626291357 1387 | } 1388 | } 1389 | }, 1390 | { 1391 | "team": "DonnerPartySurvivors", 1392 | "pos": 84, 1393 | "score": 100, 1394 | "id": 1061, 1395 | "taskStats": { 1396 | "Impasse": { 1397 | "points": 100, 1398 | "time": 1626295222 1399 | } 1400 | } 1401 | }, 1402 | { 1403 | "team": "asdf1234", 1404 | "pos": 85, 1405 | "score": 100, 1406 | "id": 1071, 1407 | "taskStats": { 1408 | "Impasse": { 1409 | "points": 100, 1410 | "time": 1626315725 1411 | } 1412 | } 1413 | }, 1414 | { 1415 | "team": "hshui", 1416 | "pos": 86, 1417 | "score": 100, 1418 | "id": 1082, 1419 | "taskStats": { 1420 | "Impasse": { 1421 | "points": 100, 1422 | "time": 1626332958 1423 | } 1424 | } 1425 | }, 1426 | { 1427 | "team": "Team Info", 1428 | "pos": 87, 1429 | "score": 100, 1430 | "id": 1093, 1431 | "taskStats": { 1432 | "Impasse": { 1433 | "points": 100, 1434 | "time": 1626340808 1435 | } 1436 | } 1437 | }, 1438 | { 1439 | "team": "Team Akatsuki", 1440 | "pos": 88, 1441 | "score": 100, 1442 | "id": 1087, 1443 | "taskStats": { 1444 | "Impasse": { 1445 | "points": 100, 1446 | "time": 1626347214 1447 | } 1448 | } 1449 | } 1450 | ], 1451 | "date": 1626015600, 1452 | "name": "TyphoonCon CTF 2021" 1453 | } -------------------------------------------------------------------------------- /data/events/Valentine CTF 21'.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | "Needle In The Haystack", 4 | "Hidden Pages", 5 | "Where is the code?", 6 | "My Great Love", 7 | "Windows Reversing 101", 8 | "Go Go Go!", 9 | "Math Solver", 10 | "AutoWhat?", 11 | "Joke Shop", 12 | "Pickle Jar", 13 | "Phishing ", 14 | "MySpace Worm", 15 | "Anti-MITM", 16 | "Vulnerability Assessment", 17 | "Back to the Basics", 18 | "Flag Checker", 19 | "Rootkit 101", 20 | "Let's Dance" 21 | ], 22 | "standings": [ 23 | { 24 | "pos": 70, 25 | "team": "ByteForc3", 26 | "taskStats": { 27 | "Hidden Pages": null 28 | } 29 | }, 30 | { 31 | "pos": 8, 32 | "team": "fr334aks", 33 | "taskStats": { 34 | "Math Solver": null, 35 | "Joke Shop": null, 36 | "Needle In The Haystack": null, 37 | "Hidden Pages": null, 38 | "Phishing ": null, 39 | "My Great Love": null, 40 | "MySpace Worm": null, 41 | "Anti-MITM": null, 42 | "Vulnerability Assessment": null, 43 | "Go Go Go!": null, 44 | "Windows Reversing 101": null, 45 | "Back to the Basics": null 46 | } 47 | }, 48 | { 49 | "pos": 5, 50 | "team": "OyuSec", 51 | "taskStats": { 52 | "Needle In The Haystack": null, 53 | "MySpace Worm": null, 54 | "My Great Love": null, 55 | "Where is the code?": null, 56 | "Windows Reversing 101": null, 57 | "Back to the Basics": null, 58 | "Go Go Go!": null, 59 | "AutoWhat?": null, 60 | "Flag Checker": null, 61 | "Hidden Pages": null, 62 | "Math Solver": null, 63 | "Joke Shop": null 64 | } 65 | }, 66 | { 67 | "pos": 43, 68 | "team": "toor97", 69 | "taskStats": { 70 | "Hidden Pages": null, 71 | "Needle In The Haystack": null, 72 | "My Great Love": null 73 | } 74 | }, 75 | { 76 | "pos": 4, 77 | "team": "hack4chai", 78 | "taskStats": { 79 | "Needle In The Haystack": null, 80 | "My Great Love": null, 81 | "Phishing ": null, 82 | "Hidden Pages": null, 83 | "Windows Reversing 101": null, 84 | "Joke Shop": null, 85 | "Go Go Go!": null, 86 | "Pickle Jar": null, 87 | "Math Solver": null, 88 | "Back to the Basics": null, 89 | "MySpace Worm": null, 90 | "Anti-MITM": null, 91 | "Vulnerability Assessment": null, 92 | "AutoWhat?": null, 93 | "Flag Checker": null 94 | } 95 | }, 96 | { 97 | "pos": 3, 98 | "team": "zer0day", 99 | "taskStats": { 100 | "Needle In The Haystack": null, 101 | "Hidden Pages": null, 102 | "Math Solver": null, 103 | "Joke Shop": null, 104 | "Go Go Go!": null, 105 | "Windows Reversing 101": null, 106 | "Pickle Jar": null, 107 | "Vulnerability Assessment": null, 108 | "Anti-MITM": null, 109 | "MySpace Worm": null, 110 | "Phishing ": null, 111 | "Where is the code?": null, 112 | "Flag Checker": null, 113 | "Let's Dance": null 114 | } 115 | }, 116 | { 117 | "pos": 38, 118 | "team": "profdracula", 119 | "taskStats": { 120 | "Where is the code?": null, 121 | "Windows Reversing 101": null, 122 | "Needle In The Haystack": null, 123 | "Math Solver": null 124 | } 125 | }, 126 | { 127 | "pos": 65, 128 | "team": "n4s1R", 129 | "taskStats": { 130 | "My Great Love": null, 131 | "MySpace Worm": null, 132 | "Anti-MITM": null 133 | } 134 | }, 135 | { 136 | "pos": 26, 137 | "team": "hardcode", 138 | "taskStats": { 139 | "Math Solver": null, 140 | "MySpace Worm": null, 141 | "Needle In The Haystack": null, 142 | "Hidden Pages": null, 143 | "Go Go Go!": null 144 | } 145 | }, 146 | { 147 | "pos": 6, 148 | "team": "MM0X", 149 | "taskStats": { 150 | "My Great Love": null, 151 | "Hidden Pages": null, 152 | "Needle In The Haystack": null, 153 | "Math Solver": null, 154 | "Go Go Go!": null, 155 | "Where is the code?": null, 156 | "Phishing ": null, 157 | "MySpace Worm": null, 158 | "Back to the Basics": null, 159 | "Vulnerability Assessment": null, 160 | "Rootkit 101": null, 161 | "Anti-MITM": null 162 | } 163 | }, 164 | { 165 | "pos": 1, 166 | "team": "warlock_rootx", 167 | "taskStats": { 168 | "Needle In The Haystack": null, 169 | "Hidden Pages": null, 170 | "Where is the code?": null, 171 | "My Great Love": null, 172 | "Windows Reversing 101": null, 173 | "Go Go Go!": null, 174 | "Math Solver": null, 175 | "AutoWhat?": null, 176 | "Joke Shop": null, 177 | "Pickle Jar": null, 178 | "Phishing ": null, 179 | "MySpace Worm": null, 180 | "Anti-MITM": null, 181 | "Vulnerability Assessment": null, 182 | "Back to the Basics": null, 183 | "Flag Checker": null, 184 | "Rootkit 101": null 185 | } 186 | }, 187 | { 188 | "pos": 2, 189 | "team": "oltenxyz", 190 | "taskStats": { 191 | "Math Solver": null, 192 | "Joke Shop": null, 193 | "Pickle Jar": null, 194 | "Hidden Pages": null, 195 | "My Great Love": null, 196 | "Go Go Go!": null, 197 | "Needle In The Haystack": null, 198 | "Phishing ": null, 199 | "Where is the code?": null, 200 | "MySpace Worm": null, 201 | "Vulnerability Assessment": null, 202 | "Anti-MITM": null, 203 | "Rootkit 101": null, 204 | "Windows Reversing 101": null, 205 | "Back to the Basics": null, 206 | "AutoWhat?": null 207 | } 208 | }, 209 | { 210 | "pos": 7, 211 | "team": "vulnfreak", 212 | "taskStats": { 213 | "Needle In The Haystack": null, 214 | "Hidden Pages": null, 215 | "Math Solver": null, 216 | "My Great Love": null, 217 | "Phishing ": null, 218 | "Pickle Jar": null, 219 | "MySpace Worm": null, 220 | "Anti-MITM": null, 221 | "Joke Shop": null, 222 | "Windows Reversing 101": null, 223 | "Vulnerability Assessment": null 224 | } 225 | }, 226 | { 227 | "pos": 9, 228 | "team": "deshu", 229 | "taskStats": { 230 | "Math Solver": null, 231 | "Joke Shop": null, 232 | "Hidden Pages": null, 233 | "Needle In The Haystack": null, 234 | "Windows Reversing 101": null, 235 | "My Great Love": null, 236 | "Phishing ": null, 237 | "MySpace Worm": null, 238 | "Anti-MITM": null, 239 | "Vulnerability Assessment": null, 240 | "Pickle Jar": null 241 | } 242 | }, 243 | { 244 | "pos": 10, 245 | "team": "MZ_Nopes0x90", 246 | "taskStats": { 247 | "Go Go Go!": null, 248 | "Needle In The Haystack": null, 249 | "MySpace Worm": null, 250 | "Where is the code?": null, 251 | "My Great Love": null, 252 | "Back to the Basics": null, 253 | "Vulnerability Assessment": null, 254 | "Phishing ": null, 255 | "Windows Reversing 101": null, 256 | "Hidden Pages": null, 257 | "Rootkit 101": null 258 | } 259 | }, 260 | { 261 | "pos": 11, 262 | "team": "MrNef0", 263 | "taskStats": { 264 | "Phishing ": null, 265 | "My Great Love": null, 266 | "Joke Shop": null, 267 | "Hidden Pages": null, 268 | "Needle In The Haystack": null, 269 | "Math Solver": null, 270 | "MySpace Worm": null, 271 | "Anti-MITM": null, 272 | "Vulnerability Assessment": null, 273 | "Windows Reversing 101": null 274 | } 275 | }, 276 | { 277 | "pos": 12, 278 | "team": "Unknownamd", 279 | "taskStats": { 280 | "Phishing ": null, 281 | "My Great Love": null, 282 | "Hidden Pages": null, 283 | "Math Solver": null, 284 | "Joke Shop": null, 285 | "Needle In The Haystack": null, 286 | "MySpace Worm": null, 287 | "Vulnerability Assessment": null, 288 | "Anti-MITM": null 289 | } 290 | }, 291 | { 292 | "pos": 13, 293 | "team": "N4ijaSecForce", 294 | "taskStats": { 295 | "Hidden Pages": null, 296 | "My Great Love": null, 297 | "Needle In The Haystack": null, 298 | "Windows Reversing 101": null, 299 | "Phishing ": null, 300 | "Go Go Go!": null, 301 | "Vulnerability Assessment": null, 302 | "MySpace Worm": null, 303 | "Anti-MITM": null 304 | } 305 | }, 306 | { 307 | "pos": 14, 308 | "team": "Ycyber", 309 | "taskStats": { 310 | "My Great Love": null, 311 | "Needle In The Haystack": null, 312 | "Hidden Pages": null, 313 | "Phishing ": null, 314 | "MySpace Worm": null, 315 | "Anti-MITM": null, 316 | "Windows Reversing 101": null, 317 | "Vulnerability Assessment": null, 318 | "Math Solver": null 319 | } 320 | }, 321 | { 322 | "pos": 15, 323 | "team": "luck4o", 324 | "taskStats": { 325 | "Hidden Pages": null, 326 | "Math Solver": null, 327 | "Needle In The Haystack": null, 328 | "Phishing ": null, 329 | "My Great Love": null, 330 | "Joke Shop": null, 331 | "MySpace Worm": null 332 | } 333 | }, 334 | { 335 | "pos": 16, 336 | "team": "Icarus", 337 | "taskStats": { 338 | "Hidden Pages": null, 339 | "Needle In The Haystack": null, 340 | "Math Solver": null, 341 | "Phishing ": null, 342 | "My Great Love": null, 343 | "Joke Shop": null 344 | } 345 | }, 346 | { 347 | "pos": 17, 348 | "team": "CR1SS", 349 | "taskStats": { 350 | "Hidden Pages": null, 351 | "Needle In The Haystack": null, 352 | "Math Solver": null, 353 | "Phishing ": null, 354 | "My Great Love": null, 355 | "Joke Shop": null 356 | } 357 | }, 358 | { 359 | "pos": 18, 360 | "team": "boberoo", 361 | "taskStats": { 362 | "Math Solver": null, 363 | "Joke Shop": null, 364 | "Pickle Jar": null, 365 | "Needle In The Haystack": null 366 | } 367 | }, 368 | { 369 | "pos": 19, 370 | "team": "sn1per", 371 | "taskStats": { 372 | "MySpace Worm": null, 373 | "Anti-MITM": null, 374 | "My Great Love": null, 375 | "Vulnerability Assessment": null, 376 | "Math Solver": null, 377 | "Back to the Basics": null, 378 | "Needle In The Haystack": null, 379 | "Hidden Pages": null 380 | } 381 | }, 382 | { 383 | "pos": 20, 384 | "team": "HxNawaf", 385 | "taskStats": { 386 | "My Great Love": null, 387 | "Joke Shop": null, 388 | "Hidden Pages": null, 389 | "Needle In The Haystack": null, 390 | "MySpace Worm": null, 391 | "Math Solver": null 392 | } 393 | }, 394 | { 395 | "pos": 21, 396 | "team": "CyberKnight00", 397 | "taskStats": { 398 | "Math Solver": null, 399 | "My Great Love": null, 400 | "Needle In The Haystack": null, 401 | "Hidden Pages": null, 402 | "Joke Shop": null 403 | } 404 | }, 405 | { 406 | "pos": 22, 407 | "team": "UnicornLady", 408 | "taskStats": { 409 | "Pickle Jar": null, 410 | "Joke Shop": null, 411 | "MySpace Worm": null, 412 | "Anti-MITM": null, 413 | "Vulnerability Assessment": null 414 | } 415 | }, 416 | { 417 | "pos": 23, 418 | "team": "theHarvester", 419 | "taskStats": { 420 | "Hidden Pages": null, 421 | "Phishing ": null, 422 | "My Great Love": null, 423 | "Needle In The Haystack": null, 424 | "Anti-MITM": null, 425 | "MySpace Worm": null, 426 | "Vulnerability Assessment": null 427 | } 428 | }, 429 | { 430 | "pos": 24, 431 | "team": "Sancelisso", 432 | "taskStats": { 433 | "My Great Love": null, 434 | "Hidden Pages": null, 435 | "Needle In The Haystack": null, 436 | "Phishing ": null, 437 | "MySpace Worm": null, 438 | "Anti-MITM": null, 439 | "Math Solver": null 440 | } 441 | }, 442 | { 443 | "pos": 25, 444 | "team": "Ahmed8magdy", 445 | "taskStats": { 446 | "Hidden Pages": null, 447 | "Needle In The Haystack": null, 448 | "MySpace Worm": null, 449 | "Vulnerability Assessment": null, 450 | "Go Go Go!": null 451 | } 452 | }, 453 | { 454 | "pos": 27, 455 | "team": "meilz", 456 | "taskStats": { 457 | "Needle In The Haystack": null, 458 | "Joke Shop": null, 459 | "My Great Love": null, 460 | "Phishing ": null 461 | } 462 | }, 463 | { 464 | "pos": 28, 465 | "team": "Manikandan", 466 | "taskStats": { 467 | "Hidden Pages": null, 468 | "Needle In The Haystack": null, 469 | "MySpace Worm": null, 470 | "Anti-MITM": null, 471 | "Vulnerability Assessment": null, 472 | "My Great Love": null 473 | } 474 | }, 475 | { 476 | "pos": 29, 477 | "team": "Thomas J Mathew", 478 | "taskStats": { 479 | "My Great Love": null, 480 | "Hidden Pages": null, 481 | "MySpace Worm": null, 482 | "Anti-MITM": null, 483 | "Phishing ": null, 484 | "Math Solver": null, 485 | "Vulnerability Assessment": null 486 | } 487 | }, 488 | { 489 | "pos": 30, 490 | "team": "th3f0r31gn3r", 491 | "taskStats": { 492 | "Needle In The Haystack": null, 493 | "Hidden Pages": null, 494 | "MySpace Worm": null, 495 | "Anti-MITM": null, 496 | "Phishing ": null, 497 | "My Great Love": null 498 | } 499 | }, 500 | { 501 | "pos": 31, 502 | "team": "Gman_H4ck3r", 503 | "taskStats": { 504 | "Math Solver": null, 505 | "Phishing ": null, 506 | "MySpace Worm": null, 507 | "Anti-MITM": null, 508 | "Vulnerability Assessment": null, 509 | "Needle In The Haystack": null 510 | } 511 | }, 512 | { 513 | "pos": 32, 514 | "team": "MattG", 515 | "taskStats": { 516 | "Math Solver": null, 517 | "Needle In The Haystack": null, 518 | "My Great Love": null, 519 | "MySpace Worm": null, 520 | "Where is the code?": null 521 | } 522 | }, 523 | { 524 | "pos": 33, 525 | "team": "Isra_Mosad", 526 | "taskStats": { 527 | "Anti-MITM": null, 528 | "MySpace Worm": null, 529 | "Math Solver": null, 530 | "Let's Dance": null 531 | } 532 | }, 533 | { 534 | "pos": 34, 535 | "team": "Madaraxd", 536 | "taskStats": { 537 | "My Great Love": null, 538 | "Hidden Pages": null, 539 | "Needle In The Haystack": null, 540 | "Math Solver": null 541 | } 542 | }, 543 | { 544 | "pos": 35, 545 | "team": "lineconnect", 546 | "taskStats": { 547 | "My Great Love": null, 548 | "Math Solver": null, 549 | "Hidden Pages": null, 550 | "Needle In The Haystack": null 551 | } 552 | }, 553 | { 554 | "pos": 36, 555 | "team": "xElessaway", 556 | "taskStats": { 557 | "My Great Love": null, 558 | "Phishing ": null, 559 | "Needle In The Haystack": null, 560 | "Math Solver": null 561 | } 562 | }, 563 | { 564 | "pos": 37, 565 | "team": "realsung", 566 | "taskStats": { 567 | "Where is the code?": null, 568 | "Windows Reversing 101": null, 569 | "Go Go Go!": null, 570 | "Back to the Basics": null 571 | } 572 | }, 573 | { 574 | "pos": 39, 575 | "team": "hound", 576 | "taskStats": { 577 | "Hidden Pages": null, 578 | "Needle In The Haystack": null, 579 | "MySpace Worm": null, 580 | "Anti-MITM": null, 581 | "My Great Love": null 582 | } 583 | }, 584 | { 585 | "pos": 40, 586 | "team": "Cyr", 587 | "taskStats": { 588 | "Hidden Pages": null, 589 | "MySpace Worm": null, 590 | "Anti-MITM": null, 591 | "My Great Love": null, 592 | "Needle In The Haystack": null 593 | } 594 | }, 595 | { 596 | "pos": 41, 597 | "team": "haralali", 598 | "taskStats": { 599 | "Hidden Pages": null, 600 | "My Great Love": null, 601 | "MySpace Worm": null, 602 | "Anti-MITM": null, 603 | "Needle In The Haystack": null 604 | } 605 | }, 606 | { 607 | "pos": 42, 608 | "team": "3nc0d3dGuY", 609 | "taskStats": { 610 | "Hidden Pages": null, 611 | "My Great Love": null, 612 | "Needle In The Haystack": null 613 | } 614 | }, 615 | { 616 | "pos": 44, 617 | "team": "bullpup", 618 | "taskStats": { 619 | "Needle In The Haystack": null, 620 | "My Great Love": null, 621 | "Math Solver": null 622 | } 623 | }, 624 | { 625 | "pos": 45, 626 | "team": "a-z", 627 | "taskStats": { 628 | "Hidden Pages": null, 629 | "Needle In The Haystack": null, 630 | "MySpace Worm": null, 631 | "Anti-MITM": null 632 | } 633 | }, 634 | { 635 | "pos": 46, 636 | "team": "nssys", 637 | "taskStats": { 638 | "Hidden Pages": null, 639 | "Needle In The Haystack": null, 640 | "MySpace Worm": null, 641 | "Anti-MITM": null 642 | } 643 | }, 644 | { 645 | "pos": 47, 646 | "team": "Tyro🌹", 647 | "taskStats": { 648 | "Needle In The Haystack": null, 649 | "MySpace Worm": null, 650 | "Anti-MITM": null, 651 | "Vulnerability Assessment": null 652 | } 653 | }, 654 | { 655 | "pos": 48, 656 | "team": "Sins", 657 | "taskStats": { 658 | "Needle In The Haystack": null, 659 | "Where is the code?": null, 660 | "MySpace Worm": null 661 | } 662 | }, 663 | { 664 | "pos": 49, 665 | "team": "0xRamzi", 666 | "taskStats": { 667 | "Needle In The Haystack": null, 668 | "MySpace Worm": null, 669 | "Hidden Pages": null 670 | } 671 | }, 672 | { 673 | "pos": 50, 674 | "team": "MonzerKamal", 675 | "taskStats": { 676 | "Hidden Pages": null, 677 | "Needle In The Haystack": null 678 | } 679 | }, 680 | { 681 | "pos": 51, 682 | "team": "gk534n", 683 | "taskStats": { 684 | "Windows Reversing 101": null, 685 | "Needle In The Haystack": null 686 | } 687 | }, 688 | { 689 | "pos": 52, 690 | "team": "AusCryptor", 691 | "taskStats": { 692 | "Hidden Pages": null, 693 | "Needle In The Haystack": null 694 | } 695 | }, 696 | { 697 | "pos": 53, 698 | "team": "stas501", 699 | "taskStats": { 700 | "Hidden Pages": null, 701 | "Joke Shop": null 702 | } 703 | }, 704 | { 705 | "pos": 54, 706 | "team": "newebi", 707 | "taskStats": { 708 | "Where is the code?": null, 709 | "Go Go Go!": null 710 | } 711 | }, 712 | { 713 | "pos": 55, 714 | "team": "bit1", 715 | "taskStats": { 716 | "Phishing ": null, 717 | "Math Solver": null, 718 | "Hidden Pages": null 719 | } 720 | }, 721 | { 722 | "pos": 56, 723 | "team": "J37", 724 | "taskStats": { 725 | "MySpace Worm": null, 726 | "Anti-MITM": null, 727 | "Vulnerability Assessment": null, 728 | "Math Solver": null 729 | } 730 | }, 731 | { 732 | "pos": 57, 733 | "team": "karma", 734 | "taskStats": { 735 | "Needle In The Haystack": null, 736 | "MySpace Worm": null 737 | } 738 | }, 739 | { 740 | "pos": 58, 741 | "team": "ziodayne", 742 | "taskStats": { 743 | "Joke Shop": null 744 | } 745 | }, 746 | { 747 | "pos": 59, 748 | "team": "Sulaiman", 749 | "taskStats": { 750 | "Needle In The Haystack": null 751 | } 752 | }, 753 | { 754 | "pos": 60, 755 | "team": "noone...", 756 | "taskStats": { 757 | "My Great Love": null, 758 | "Phishing ": null 759 | } 760 | }, 761 | { 762 | "pos": 61, 763 | "team": "0d", 764 | "taskStats": { 765 | "Needle In The Haystack": null 766 | } 767 | }, 768 | { 769 | "pos": 62, 770 | "team": "cgg9rxsn", 771 | "taskStats": { 772 | "Phishing ": null, 773 | "My Great Love": null 774 | } 775 | }, 776 | { 777 | "pos": 63, 778 | "team": "MMarta33", 779 | "taskStats": { 780 | "MySpace Worm": null, 781 | "Anti-MITM": null, 782 | "Vulnerability Assessment": null 783 | } 784 | }, 785 | { 786 | "pos": 64, 787 | "team": "davinci", 788 | "taskStats": { 789 | "MySpace Worm": null, 790 | "Anti-MITM": null, 791 | "Vulnerability Assessment": null 792 | } 793 | }, 794 | { 795 | "pos": 66, 796 | "team": "Yosuf14", 797 | "taskStats": { 798 | "MySpace Worm": null, 799 | "Anti-MITM": null, 800 | "Math Solver": null 801 | } 802 | }, 803 | { 804 | "pos": 67, 805 | "team": "3m3s3c", 806 | "taskStats": { 807 | "Hidden Pages": null, 808 | "MySpace Worm": null, 809 | "Anti-MITM": null 810 | } 811 | }, 812 | { 813 | "pos": 68, 814 | "team": "Mitewarrior", 815 | "taskStats": { 816 | "MySpace Worm": null, 817 | "Anti-MITM": null, 818 | "Vulnerability Assessment": null 819 | } 820 | }, 821 | { 822 | "pos": 69, 823 | "team": "eatsmok", 824 | "taskStats": { 825 | "My Great Love": null 826 | } 827 | }, 828 | { 829 | "pos": 71, 830 | "team": "merankhairuddin", 831 | "taskStats": { 832 | "My Great Love": null 833 | } 834 | }, 835 | { 836 | "pos": 72, 837 | "team": "r3b0rn", 838 | "taskStats": { 839 | "My Great Love": null 840 | } 841 | }, 842 | { 843 | "pos": 73, 844 | "team": "Jeddy", 845 | "taskStats": { 846 | "My Great Love": null 847 | } 848 | }, 849 | { 850 | "pos": 74, 851 | "team": "exploit_punisher", 852 | "taskStats": { 853 | "Math Solver": null 854 | } 855 | }, 856 | { 857 | "pos": 75, 858 | "team": "dagon102", 859 | "taskStats": { 860 | "My Great Love": null 861 | } 862 | }, 863 | { 864 | "pos": 76, 865 | "team": "yss_xx", 866 | "taskStats": { 867 | "Hidden Pages": null 868 | } 869 | }, 870 | { 871 | "pos": 77, 872 | "team": "pratyushk403", 873 | "taskStats": { 874 | "Hidden Pages": null 875 | } 876 | }, 877 | { 878 | "pos": 78, 879 | "team": "fakejoker", 880 | "taskStats": { 881 | "Hidden Pages": null 882 | } 883 | }, 884 | { 885 | "pos": 79, 886 | "team": "faris", 887 | "taskStats": { 888 | "My Great Love": null 889 | } 890 | }, 891 | { 892 | "pos": 80, 893 | "team": "0xArab", 894 | "taskStats": { 895 | "Hidden Pages": null 896 | } 897 | }, 898 | { 899 | "pos": 81, 900 | "team": "def0cz", 901 | "taskStats": { 902 | "MySpace Worm": null, 903 | "Anti-MITM": null 904 | } 905 | }, 906 | { 907 | "pos": 82, 908 | "team": "Abusaffiya", 909 | "taskStats": { 910 | "MySpace Worm": null, 911 | "Anti-MITM": null 912 | } 913 | }, 914 | { 915 | "pos": 83, 916 | "team": "Zaid4350", 917 | "taskStats": { 918 | "MySpace Worm": null 919 | } 920 | }, 921 | { 922 | "pos": 84, 923 | "team": "Hani", 924 | "taskStats": { 925 | "MySpace Worm": null 926 | } 927 | }, 928 | { 929 | "pos": 85, 930 | "team": "Fanzi", 931 | "taskStats": { 932 | "MySpace Worm": null 933 | } 934 | }, 935 | { 936 | "pos": 86, 937 | "team": "Jonathan", 938 | "taskStats": { 939 | "MySpace Worm": null 940 | } 941 | } 942 | ], 943 | "name": "Valentine CTF 21'", 944 | "date": 1613228400 945 | } -------------------------------------------------------------------------------- /data/teams/alles.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ALLES!", 3 | "aliases": ["ALLES"], 4 | "country": "" 5 | } 6 | -------------------------------------------------------------------------------- /data/teams/kalmarunionen.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kalmarunionen", 3 | "aliases": ["Kalmarunionen", "KalmarUnionen"], 4 | "country": "DK" 5 | } 6 | -------------------------------------------------------------------------------- /data/teams/mslc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "More Smoked Leet Chicken", 3 | "aliases": ["MoreSmokedLeetChicken"], 4 | "country": "" 5 | } 6 | -------------------------------------------------------------------------------- /data/teams/superguesser.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Super Guesser", 3 | "aliases": ["Super Guessers"], 4 | "country": "" 5 | } 6 | -------------------------------------------------------------------------------- /data/teams/zer0pts.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zer0pts", 3 | "aliases": [], 4 | "country": "jp" 5 | } 6 | -------------------------------------------------------------------------------- /front/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .nuxt 3 | yarn-error.log 4 | dist 5 | -------------------------------------------------------------------------------- /front/assets/css/main.css: -------------------------------------------------------------------------------- 1 | *{ 2 | box-sizing: border-box; 3 | } 4 | html,body{ 5 | padding: 0; 6 | margin: 0; 7 | font-family: arial,sans-serif; 8 | height: 100%; 9 | } 10 | #__nuxt,#__layout{ 11 | height: 100%; 12 | } 13 | -------------------------------------------------------------------------------- /front/components/challengepanel.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 27 | 28 | 60 | -------------------------------------------------------------------------------- /front/components/date.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | -------------------------------------------------------------------------------- /front/components/ratecolor.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 36 | -------------------------------------------------------------------------------- /front/components/teamRow.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | 20 | 45 | 46 | -------------------------------------------------------------------------------- /front/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 20 | 21 | 62 | -------------------------------------------------------------------------------- /front/nuxt.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | components: true, 3 | head: { 4 | titleTemplate: 'CTF-Ratings' 5 | }, 6 | target: 'static', 7 | ssr: false, 8 | // generate: { 9 | // exclude: [ 10 | // /^\/team\/.+\// 11 | // ] 12 | // }, 13 | router: { 14 | base: '/ctf-ratings/' 15 | }, 16 | plugins: [ 17 | '@/plugins/vue-virtual-scroll-list.js', 18 | ], 19 | css: [ 20 | '@/assets/css/main.css', 21 | ], 22 | modules: [ 23 | ['nuxt-fontawesome', { 24 | component: 'fa', 25 | imports: [ 26 | //import whole set 27 | { 28 | set: '@fortawesome/free-solid-svg-icons', 29 | icons: ['fas'] 30 | }, 31 | ], 32 | }] 33 | ], 34 | } 35 | -------------------------------------------------------------------------------- /front/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@fortawesome/fontawesome-svg-core": "^1.2.36", 4 | "@fortawesome/free-solid-svg-icons": "^5.15.4", 5 | "@fortawesome/vue-fontawesome": "^2.0.2", 6 | "nuxt": "^2.15.3", 7 | "nuxt-fontawesome": "^0.4.0", 8 | "vue-virtual-scroll-list": "^2.3.2" 9 | }, 10 | "name": "CTF-ratings", 11 | "scripts": { 12 | "dev": "nuxt", 13 | "build": "nuxt build", 14 | "generate": "nuxt generate", 15 | "start": "nuxt start" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /front/pages/event/_name.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 70 | 71 | 77 | -------------------------------------------------------------------------------- /front/pages/events.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /front/pages/index.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 54 | 55 | 99 | -------------------------------------------------------------------------------- /front/pages/redirect.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | -------------------------------------------------------------------------------- /front/pages/team/_name.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 65 | -------------------------------------------------------------------------------- /front/pages/team/_name/_ctf.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 31 | 32 | 37 | -------------------------------------------------------------------------------- /front/plugins/vue-virtual-scroll-list.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VirtualList from 'vue-virtual-scroll-list' 3 | 4 | Vue.component('virtual-list', VirtualList); 5 | -------------------------------------------------------------------------------- /front/static/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /front/store/index.js: -------------------------------------------------------------------------------- 1 | import data from "../../ctf.json"; 2 | 3 | 4 | export const state = () => { 5 | const events = data["events"]; 6 | const teams = data["teams"]; 7 | 8 | return { 9 | events, teams 10 | }; 11 | } 12 | 13 | export const getters = { 14 | events(state) { return state.events }, 15 | teams(state) { return state.teams }, 16 | } 17 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/ctf-ratings/52aae558878af612142a51d3305b9cd6faa9cfec/lib/__init__.py -------------------------------------------------------------------------------- /lib/difficulty.py: -------------------------------------------------------------------------------- 1 | from sklearn.linear_model import LogisticRegression 2 | from typing import List 3 | 4 | def calc_difficulty(solve_team_perfs: List[float], unsolve_team_perfs: List[float])->float: 5 | """ 6 | 問題のdifficultyを推定する 7 | 問題のdifficultyがX = performance Xのチームが50%の確率でそれを解ける 8 | 中身はロジスティック回帰 9 | """ 10 | 11 | if len(solve_team_perfs) == 0: 12 | return 10000 13 | 14 | if len(unsolve_team_perfs) == 0: 15 | return int(min(solve_team_perfs)) 16 | 17 | lr = LogisticRegression() 18 | lr.fit([[x] for x in solve_team_perfs + unsolve_team_perfs], [1]*len(solve_team_perfs) + [0]*len(unsolve_team_perfs)) 19 | 20 | h = 10000 21 | l = -10000 22 | while abs(h - l) > 1: 23 | m = (h + l) // 2 24 | res = lr.predict_proba([[m]])[0][0] 25 | 26 | if res > 0.5: 27 | l = m 28 | else: 29 | h = m 30 | return int(max(l, min(solve_team_perfs))) 31 | 32 | 33 | -------------------------------------------------------------------------------- /lib/perf.py: -------------------------------------------------------------------------------- 1 | import math 2 | from typing import List 3 | 4 | INITIAL_PERF = 1200.0 5 | 6 | def avg_perf(perfs: List[float]) -> float: 7 | """ 8 | get average of past perfomances 9 | """ 10 | if len(perfs) == 0: 11 | perfs = [INITIAL_PERF] 12 | return sum([p*0.9**(i+1) for i, p in enumerate(reversed(perfs))]) / sum(0.9**(i+1) for i in range(len(perfs))) 13 | 14 | def calc_performance(team_perfs: List[List[float]]) -> List[float]: 15 | """ 16 | team_perfs: 参加したチームの過去のパフォーマンス。今回の順位に昇順にソートされている 17 | 各チームの過去のパフォーマンスは時刻に昇順になっている 18 | """ 19 | avg_perfs = [avg_perf(p) for p in team_perfs] 20 | def f(x: int) -> float: 21 | """ 22 | あるチームがi位のとき、 f(x) = i - 0.5 を満たすxがそのチームのパフォーマンス 23 | この関数はxの値に対して単調減少する 24 | """ 25 | perf = 0 26 | for a_perf in avg_perfs: 27 | perf += 1 / (1 + (6 ** ((x - a_perf) / 400))) 28 | return perf 29 | 30 | perfs = [] 31 | # i位のチームのパフォーマンスを二分探索で求める 32 | for i in range(len(team_perfs)): 33 | l, h = -10000, 10000 34 | while abs(h - l) > 1: 35 | m = (l + h) // 2 36 | perf = f(m) 37 | if perf < (i + 1) - 0.5: 38 | h = m 39 | else: 40 | l = m 41 | perfs.append(l) 42 | return perfs 43 | 44 | def calc_new_rating(past_perfs: List[float], perf: float) -> float: 45 | """ 46 | past_perfs: 過去のパフォーマンス 47 | perf: 今回のパフォーマンス 48 | returns: new rating 49 | """ 50 | def adjust(rating: float, n: int) -> float: 51 | """参加回数が少ないと正確に値が出ないので補正するらしい 52 | n: 参加回数 53 | https://github.com/kenkoooo/AtCoderProblems/blob/d4c125df495d4ebbbab507f024fccc5744768ad6/lambda-functions/time-estimator/rating.py#L25 54 | """ 55 | f_1 = 1.0 56 | f_inf = 1 / (19 ** 0.5) 57 | f_n = ((1 - 0.81 ** n) ** 0.5) / ((19 ** 0.5) * (1 - 0.9 ** n)) 58 | return rating - (f_n - f_inf) / (f_1 - f_inf) * 1200 59 | 60 | past_perfs = past_perfs[::-1] 61 | n = len(past_perfs) + 1 62 | exp_perf_sum = sum(2.0 ** (p / 800) * 0.9**(i+1) for i, p in enumerate([perf] + past_perfs)) 63 | rating = 800 * math.log2(exp_perf_sum / sum(0.9**(i+1) for i in range(n))) 64 | return adjust(rating, n) 65 | 66 | def calc_new_ahc_rating(past_perfs: List[float], perf: float) -> float: 67 | """ 68 | AHCに沿ってレーティングを求める (https://www.dropbox.com/s/ne358pdixfafppm/AHC_rating.pdf?dl=0) 69 | past_perfs: 過去のパフォーマンス 70 | perf: 今回のパフォーマンス 71 | returns: new rating 72 | """ 73 | R = 0.8271973364 74 | S = 724.4744301 75 | Q = sorted([p - S*math.log(j) for p in past_perfs + [perf] for j in range(1, 101)], reverse=True) 76 | numerator = sum([Q[i-1]*R**i for i in range(1, 101)]) 77 | denominator = sum([R**i for i in range(1, 101)]) 78 | r = numerator / denominator 79 | 80 | if r >= 400: 81 | return r 82 | else: 83 | return 400 / math.exp((400 - r) / 400.0) 84 | 85 | 86 | -------------------------------------------------------------------------------- /lib/scraper/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/ctf-ratings/52aae558878af612142a51d3305b9cd6faa9cfec/lib/scraper/__init__.py -------------------------------------------------------------------------------- /lib/scraper/angstromctf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from datetime import datetime 6 | from logging import getLogger, StreamHandler, Formatter 7 | from tqdm import tqdm 8 | from http.cookies import SimpleCookie 9 | 10 | logger = getLogger(__name__) 11 | handler = StreamHandler() 12 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 13 | logger.addHandler(handler) 14 | 15 | class AngstromCTFScraper(): 16 | def __init__(self, url, **kwargs): 17 | self.url = url 18 | cookies = SimpleCookie() 19 | if "cookies" in kwargs and kwargs["cookies"]: 20 | cookies.load(kwargs["cookies"]) 21 | 22 | self.cookiejar = requests.cookies.RequestsCookieJar() 23 | self.cookiejar.update(cookies) 24 | 25 | def _get(self, path): 26 | s = requests.Session() 27 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 28 | s.mount("http://", HTTPAdapter(max_retries=retries)) 29 | s.mount("https://", HTTPAdapter(max_retries=retries)) 30 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 31 | 32 | def _teams(self): 33 | r = self._get("teams?frozen=1") 34 | r.raise_for_status() 35 | data = r.json() 36 | 37 | teams = [{ 38 | "id": team["id"], 39 | "team": team["name"], 40 | "pos": 0, 41 | "score": team["score"], 42 | "lastSolve": int( 43 | datetime.strptime( 44 | team["lastSolve"].split(".")[0], 45 | "%Y-%m-%dT%H:%M:%S" 46 | ).timestamp() 47 | ), 48 | "taskStats": {}, 49 | } for team in data if team["score"] > 0 and "lastSolve" in team] 50 | teams = sorted(teams, key=lambda x: (x["score"], -x["lastSolve"]), reverse=True) 51 | for i in range(len(teams)): 52 | teams[i]["pos"] = i + 1 53 | 54 | return teams 55 | 56 | def _team_solves(self, team_id): 57 | r = self._get("teams/{}".format(team_id)) 58 | r.raise_for_status() 59 | data = r.json() 60 | stats = {} 61 | for stat in data["solves"]: 62 | stats[stat["challenge"]["title"]] = { 63 | "points": stat["challenge"]["value"], 64 | "time": int(datetime.strptime( 65 | stat["time"].split(".")[0], 66 | "%Y-%m-%dT%H:%M:%S" 67 | ).timestamp()), 68 | } 69 | return stats 70 | 71 | def _tasks(self): 72 | r = self._get("challenges") 73 | r.raise_for_status() 74 | data = r.json() 75 | return [task["title"] for task in data] 76 | 77 | def scoreboard(self): 78 | logger.warning("getting scoreboard...") 79 | teams = self._teams() 80 | logger.warning("done") 81 | 82 | logger.warning("getting tasks...") 83 | tasks = self._tasks() 84 | logger.warning("done") 85 | 86 | logger.warning("getting teams...") 87 | standings = [] 88 | for team in tqdm(teams): 89 | taskStats = self._team_solves(team["id"]) 90 | standings.append({ 91 | "team": team["team"], 92 | "pos": team["pos"], 93 | "score": team["score"], 94 | "id": team["id"], 95 | "taskStats": taskStats, 96 | }) 97 | logger.warning("done") 98 | return {"tasks": list(tasks), "standings": standings} 99 | -------------------------------------------------------------------------------- /lib/scraper/asisctf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from logging import getLogger, StreamHandler, Formatter 6 | from http.cookies import SimpleCookie 7 | from bs4 import BeautifulSoup 8 | from tqdm import tqdm 9 | 10 | logger = getLogger(__name__) 11 | handler = StreamHandler() 12 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 13 | logger.addHandler(handler) 14 | 15 | class AsisCTFScraper(): 16 | def __init__(self, url, **kwargs): 17 | self.url = url 18 | 19 | cookies = SimpleCookie() 20 | if "cookies" in kwargs and kwargs["cookies"]: 21 | cookies.load(kwargs["cookies"]) 22 | 23 | self.cookiejar = requests.cookies.RequestsCookieJar() 24 | self.cookiejar.update(cookies) 25 | 26 | def _get(self, path): 27 | s = requests.Session() 28 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 29 | s.mount("http://", HTTPAdapter(max_retries=retries)) 30 | s.mount("https://", HTTPAdapter(max_retries=retries)) 31 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 32 | 33 | def scoreboard(self): 34 | r = self._get("/scoreboard") 35 | r.raise_for_status() 36 | soup = BeautifulSoup(r.text, "html.parser") 37 | 38 | # parse thead 39 | tasks = soup.select("thead tr th")[4:] # skip #, Team, Points, Country 40 | tasks = [t.string.strip() for t in tasks] 41 | 42 | # parse tbody 43 | standings = [] 44 | rows = soup.select("tbody tr") 45 | for row in tqdm(rows): 46 | heads = row.select("th") 47 | data = row.select("td") 48 | 49 | pos = int(heads[0].text.strip()) 50 | team = data[0].text.strip() 51 | score = int(data[1].text.strip()) 52 | 53 | solves = solves = row.select(".chall") 54 | solves = [len(solve.select("svg")) > 0 for solve in solves] 55 | assert len(tasks) == len(solves) 56 | taskStats = {tasks[i]: None for i in range(len(tasks)) if solves[i]} 57 | 58 | standings.append({ 59 | "team": team, 60 | "pos": pos, 61 | "score": score, 62 | "taskStats": taskStats, 63 | }) 64 | return {"tasks": tasks, "standings": standings} 65 | -------------------------------------------------------------------------------- /lib/scraper/bcactf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from bs4 import BeautifulSoup 6 | from logging import getLogger, StreamHandler, Formatter 7 | from http.cookies import SimpleCookie 8 | from tqdm import tqdm 9 | import dateparser 10 | 11 | logger = getLogger(__name__) 12 | handler = StreamHandler() 13 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 14 | logger.addHandler(handler) 15 | 16 | class BCACTFScraper(): 17 | def __init__(self, url, **kwargs): 18 | self.url = url 19 | cookies = SimpleCookie() 20 | if "cookies" in kwargs: 21 | cookies.load(kwargs["cookies"]) 22 | 23 | self.cookiejar = requests.cookies.RequestsCookieJar() 24 | self.cookiejar.update(cookies) 25 | 26 | def _get(self, path): 27 | s = requests.Session() 28 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 29 | s.mount("http://", HTTPAdapter(max_retries=retries)) 30 | s.mount("https://", HTTPAdapter(max_retries=retries)) 31 | return s.get(urljoin(self.url, path), cookies=self.cookiejar, verify=False) 32 | 33 | def _tasks(self): 34 | r = self._get("/challenges") 35 | r.raise_for_status() 36 | soup = BeautifulSoup(r.text, "html.parser") 37 | tasknames = soup.select(".challenge-group h3") 38 | 39 | return [t.text.strip() for t in tasknames] 40 | 41 | def _team(self, path): 42 | r = self._get(path) 43 | r.raise_for_status() 44 | soup = BeautifulSoup(r.text, "html.parser") 45 | rows = soup.select("#solves tr") 46 | 47 | stats = {} 48 | for row in rows: 49 | data = row.select("td") 50 | task = data[0].text.strip() 51 | score = int(data[1].text.strip()) 52 | solved_at = int(dateparser.parse(data[3].find("abbr")["title"]).timestamp()) 53 | stats[task] = { 54 | "points": score, 55 | "time": solved_at, 56 | } 57 | return stats 58 | 59 | def _teams(self): 60 | logger.warning("getting scoreboard...") 61 | r = self._get("/scoreboard") 62 | r.raise_for_status() 63 | 64 | soup = BeautifulSoup(r.text, "html.parser") 65 | rows = soup.select("#teams tr") 66 | teams = [] 67 | for row in tqdm(rows): 68 | data = row.select("td") 69 | pos = int(data[0].text.strip()) 70 | team = data[1].text.strip() 71 | score = int(data[3].text.strip()) 72 | if score <= 0: 73 | continue 74 | teams.append({ 75 | "team": team, 76 | "pos": pos, 77 | "score": score, 78 | "taskStats": self._team(data[1].find("a")["href"]), 79 | }) 80 | return teams 81 | 82 | def scoreboard(self): 83 | standings = self._teams() 84 | tasks = self._tasks() 85 | 86 | return {"standings": standings, "tasks": tasks} 87 | -------------------------------------------------------------------------------- /lib/scraper/bsidessf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib.parse import urljoin 3 | import json 4 | from datetime import datetime 5 | 6 | class BSidesSFScraper(): 7 | def __init__(self, url, **kwargs): 8 | self.url = url 9 | 10 | def _scoreboard(self): 11 | r = requests.get(urljoin(self.url, "/api/scoreboard")) 12 | r.raise_for_status() 13 | ranking = json.loads(r.text.split("\n")[1])["scoreboard"] 14 | board = [] 15 | for team in ranking: 16 | if team["score"] > 0: 17 | board.append({ 18 | "pos": team["position"], 19 | "team": team["name"], 20 | "score": team["score"] 21 | }) 22 | return board 23 | 24 | def _tasks(self): 25 | r = requests.get(urljoin(self.url, "/api/challenges")) 26 | r.raise_for_status() 27 | challenges = json.loads(r.text.split("\n")[1])["challenges"] 28 | tasks = [] 29 | taskStats = {} 30 | for challenge in challenges: 31 | tasks.append(challenge["name"]) 32 | for answer in challenge["answers"]: 33 | solver = answer["team"]["name"] 34 | if solver not in taskStats: 35 | taskStats[solver] = {} 36 | taskStats[solver][ challenge["name"] ] = {"points": challenge["current_points"], "time": int(datetime.strptime(answer["timestamp"], "%a, %d %b %Y %H:%M:%S -0000").timestamp())} 37 | return tasks, taskStats 38 | 39 | def scoreboard(self): 40 | board = self._scoreboard() 41 | tasks, taskStats = self._tasks() 42 | for i in range(len(board)): 43 | if board[i]["team"] in taskStats: 44 | board[i]["taskStats"] = taskStats[ board[i]["team"] ] 45 | else: 46 | board[i]["taskStats"] = {} 47 | return {"tasks": tasks, "standings": board} 48 | -------------------------------------------------------------------------------- /lib/scraper/ctfd.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from datetime import datetime 6 | from logging import getLogger, StreamHandler, Formatter 7 | from tqdm import tqdm 8 | from http.cookies import SimpleCookie 9 | 10 | logger = getLogger(__name__) 11 | handler = StreamHandler() 12 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 13 | logger.addHandler(handler) 14 | 15 | class CTFdScraper(): 16 | def __init__(self, url, **kwargs): 17 | self.url = url 18 | 19 | cookies = SimpleCookie() 20 | if "cookies" in kwargs and kwargs["cookies"]: 21 | cookies.load(kwargs["cookies"]) 22 | 23 | self.cookiejar = requests.cookies.RequestsCookieJar() 24 | self.cookiejar.update(cookies) 25 | 26 | self.mode = 'teams' 27 | if 'mode' in kwargs: 28 | self.mode = kwargs["mode"] # type: str 29 | 30 | self.without_tasks = False 31 | if kwargs.get('without_tasks', False): 32 | self.without_tasks = True 33 | 34 | def _get(self, path): 35 | s = requests.Session() 36 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 37 | s.mount("http://", HTTPAdapter(max_retries=retries)) 38 | s.mount("https://", HTTPAdapter(max_retries=retries)) 39 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 40 | 41 | def _team_solves(self, team_id): 42 | r = self._get("/api/v1/{}/{}/solves".format(self.mode, team_id)) 43 | r.raise_for_status() 44 | data = r.json()["data"] 45 | stats = {} 46 | for stat in data: 47 | stats[stat["challenge"]["name"]] = { 48 | "points": stat["challenge"]["value"], 49 | "time": int(datetime.strptime( 50 | stat["date"], 51 | "%Y-%m-%dT%H:%M:%S%z" 52 | ).timestamp()), 53 | } 54 | return stats 55 | 56 | def _tasks(self): 57 | if self.without_tasks: 58 | return [] 59 | logger.warning("getting tasks...") 60 | r = self._get("/api/v1/challenges") 61 | r.raise_for_status() 62 | data = r.json()["data"] 63 | logger.warning("done") 64 | return data 65 | 66 | def scoreboard(self): 67 | logger.warning("getting scoreboard...") 68 | r = self._get("/api/v1/scoreboard") 69 | r.raise_for_status() 70 | data = r.json()["data"] 71 | logger.warning("done") 72 | 73 | tasks = self._tasks() 74 | taskNames = set([task["name"] for task in tasks]) 75 | standings = [] 76 | for team in tqdm(data): 77 | taskStats = self._team_solves(team["account_id"]) 78 | standings.append({ 79 | "team": team["name"], 80 | "pos": team["pos"], 81 | "score": team["score"], 82 | "id": team["account_id"], 83 | "taskStats": taskStats, 84 | }) 85 | taskNames.update(taskStats.keys()) 86 | return {"tasks": list(taskNames), "standings": standings, "taskinfo": { 87 | task["name"]:{ 88 | "category": task["category"], 89 | "tags": task["tags"], 90 | } 91 | for task in tasks 92 | }} 93 | -------------------------------------------------------------------------------- /lib/scraper/ctfd_legacy.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from datetime import datetime 6 | from bs4 import BeautifulSoup 7 | import re 8 | import time 9 | from logging import getLogger, StreamHandler, Formatter 10 | from http.cookies import SimpleCookie 11 | from tqdm import tqdm 12 | 13 | logger = getLogger(__name__) 14 | handler = StreamHandler() 15 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 16 | logger.addHandler(handler) 17 | 18 | class LegacyCTFdScraper(): 19 | def __init__(self, url, **kwargs): 20 | self.url = url 21 | 22 | cookies = SimpleCookie() 23 | if "cookies" in kwargs and kwargs["cookies"]: 24 | cookies.load(kwargs["cookies"]) 25 | 26 | self.cookiejar = requests.cookies.RequestsCookieJar() 27 | self.cookiejar.update(cookies) 28 | 29 | self.mode = 'teams' 30 | if 'mode' in kwargs: 31 | self.mode = kwargs["mode"] # type: str 32 | 33 | def _get(self, path): 34 | s = requests.Session() 35 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 36 | s.mount("http://", HTTPAdapter(max_retries=retries)) 37 | s.mount("https://", HTTPAdapter(max_retries=retries)) 38 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 39 | 40 | def _teams(self): 41 | logger.warning("[+] get scoreboard...") 42 | r = self._get("/scoreboard") 43 | r.raise_for_status() 44 | soup = BeautifulSoup(r.text, "html.parser") 45 | 46 | hdr = soup.select("#scoreboard thead th, #scoreboard thead td") 47 | if not hdr: 48 | hdr = soup.select("thead th, thead td") 49 | 50 | for i, th in enumerate(hdr): 51 | if re.match(r"^(score|value)$", th.text, re.IGNORECASE): 52 | score_index = i 53 | break 54 | else: 55 | raise ValueError("[-] failed to find score index") 56 | 57 | trs = soup.select("#scoreboard tbody tr") 58 | teams = [] 59 | for tr in trs: 60 | id = tr.find("a")["href"].split("/")[-1] 61 | name = tr.find("a").text.strip() 62 | score = int(tr.select("td, th")[score_index].text) 63 | teams.append({"id": id, "team": name, "pos": len(teams) + 1, "score": score, "taskStats": {}}) 64 | logger.warning("[+] done") 65 | return teams 66 | 67 | def _team_solves(self, team_id): 68 | r = self._get("/{}/{}".format(self.mode, team_id)) 69 | r.raise_for_status() 70 | soup = BeautifulSoup(r.text, "html.parser") 71 | trs = soup.select("table tbody tr") 72 | tasks = {} 73 | for tr in trs: 74 | if len(tr.find_all("td")) != 4: 75 | continue 76 | 77 | name = tr.find("a").text.strip() 78 | score = tr.find_all("td")[2].text 79 | datestr = tr.select("span[data-time]")[0]["data-time"].strip() 80 | datestr = re.sub(r"\.[0-9]+", "", datestr) 81 | time = datetime.strptime(datestr, "%Y-%m-%dT%H:%M:%SZ") 82 | tasks[name] = {"points": score, "time": int(time.timestamp())} 83 | return tasks 84 | 85 | def _teams_tasks(self): 86 | """ 87 | 問題のIDはstrで管理する 88 | """ 89 | teams = self._teams() 90 | tasks = set() 91 | 92 | for i in tqdm(range(len(teams))): 93 | if i % 10 == 9: 94 | time.sleep(0.5) 95 | 96 | solves = self._team_solves(teams[i]["id"]) 97 | tasks.update(solves.keys()) 98 | teams[i]["taskStats"] = solves 99 | 100 | return teams, list(tasks) 101 | 102 | def scoreboard(self): 103 | board, tasks = self._teams_tasks() 104 | return {"tasks": tasks, "standings": board} 105 | -------------------------------------------------------------------------------- /lib/scraper/ctfx.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from bs4 import BeautifulSoup 6 | from logging import getLogger, StreamHandler, Formatter 7 | from http.cookies import SimpleCookie 8 | 9 | logger = getLogger(__name__) 10 | handler = StreamHandler() 11 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 12 | logger.addHandler(handler) 13 | 14 | class CTFxScraper(): 15 | def __init__(self, url, **kwargs): 16 | self.url = url 17 | cookies = SimpleCookie() 18 | if "cookies" in kwargs: 19 | cookies.load(kwargs["cookies"]) 20 | 21 | if "session" in kwargs: 22 | cookies["login_tokens"] = kwargs["session"] 23 | 24 | self.cookiejar = requests.cookies.RequestsCookieJar() 25 | self.cookiejar.update(cookies) 26 | 27 | def _get(self, path): 28 | s = requests.Session() 29 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 30 | s.mount("http://", HTTPAdapter(max_retries=retries)) 31 | s.mount("https://", HTTPAdapter(max_retries=retries)) 32 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 33 | 34 | def _categories(self): 35 | logger.warning("getting categories...") 36 | r = self._get("/challenges") 37 | r.raise_for_status() 38 | soup = BeautifulSoup(r.text, "html.parser") 39 | categories = soup.select("#categories-menu a") 40 | logger.warning("done") 41 | return [cat["href"] for cat in categories] 42 | 43 | def _category_task_ids(self, path): 44 | logger.warning("getting {}".format(path)) 45 | r = self._get(path) 46 | r.raise_for_status() 47 | soup = BeautifulSoup(r.text, "html.parser") 48 | cards = soup.select(".ctfx-card-head") 49 | logger.warning("done") 50 | return [card.find("a")["href"] for card in cards] 51 | 52 | def _task(self, path): 53 | logger.warning("getting {}".format(path)) 54 | r = self._get(path) 55 | r.raise_for_status() 56 | soup = BeautifulSoup(r.text, "html.parser") 57 | taskname = soup.select_one(".typewriter").text.strip() 58 | trs = soup.select(".challenge-table tbody tr") 59 | teams = [] 60 | for tr in trs: 61 | teams.append(tr.select_one(".team-name").text) 62 | logger.warning("done") 63 | return taskname, teams 64 | 65 | def scoreboard(self): 66 | logger.warning("getting scoreboard...") 67 | r = self._get("/json?view=scoreboard") 68 | r.raise_for_status() 69 | standings = [t | {"taskStats": {}} for t in r.json()["standings"] if t["score"] > 0] 70 | logger.warning("done") 71 | 72 | task_ids = [] 73 | categories = self._categories() 74 | for category in categories: 75 | task_ids.extend(self._category_task_ids(category)) 76 | 77 | tasks = [] 78 | for task_id in task_ids: 79 | taskname, teams = self._task(task_id) 80 | tasks.append(taskname) 81 | for t in teams: 82 | for i in range(len(standings)): 83 | if standings[i]["team"] == t: 84 | standings[i]["taskStats"][taskname] = None 85 | 86 | return {"standings": standings, "tasks": tasks} 87 | -------------------------------------------------------------------------------- /lib/scraper/d3ctf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | import json 6 | from datetime import datetime 7 | 8 | class D3CTFScraper(): 9 | def __init__(self, url, **kwargs): 10 | self.url = url 11 | self.session = kwargs["session"] 12 | self.token = kwargs["token"] 13 | 14 | def _get(self, path): 15 | s = requests.Session() 16 | retries = Retry(backoff_factor=5, status_forcelist=[500, 501, 502, 503, 504]) 17 | s.mount("http://", HTTPAdapter(max_retries=retries)) 18 | s.mount("https://", HTTPAdapter(max_retries=retries)) 19 | return s.get(urljoin(self.url, path), cookies={'laravel_session': self.session}, headers={'Authorization': "Bearer {}".format(self.token)}) 20 | 21 | def _scoreboard(self): 22 | page = 1 23 | teams = [] 24 | while True: 25 | r = self._get("/API/Team/ranking?language=en&page={}&withCount=false".format(page)) 26 | r.raise_for_status() 27 | data = r.json()["data"] 28 | if len(data["ranking"]) == 0: 29 | break 30 | 31 | for team in data["ranking"]: 32 | teams.append({ 33 | "pos": len(teams) + 1, 34 | "team": team["team_name"], 35 | "score": team["dynamic_total_score"] 36 | }) 37 | 38 | page += 1 39 | 40 | removeindex = [] 41 | for i in range(len(teams)): 42 | if teams[i]["score"] == 0: 43 | removeindex.append(i) 44 | for i in removeindex[::-1]: 45 | del teams[i] 46 | 47 | return teams 48 | 49 | def _tasks(self): 50 | r = self._get("/API/Challenge/list?language=en") 51 | r.raise_for_status() 52 | data = r.json()["data"] 53 | challenges = data["challenges"] 54 | 55 | tasks = [] 56 | taskStats = {} 57 | for cat in challenges.values(): 58 | for cat2 in cat.values(): 59 | for challenge in cat2: 60 | tasks.append(challenge["title"]) 61 | r2 = self._get("/API/Challenge/solvedTeams?language=en&challengeId={}".format(challenge["challenge_id"])) 62 | r2.raise_for_status() 63 | solved = r2.json()["data"] 64 | for solve in solved: 65 | solver = solve["teamName"] 66 | if solver not in taskStats: 67 | taskStats[solver] = {} 68 | taskStats[solver][challenge["title"]] = {"points": challenge["nowScore"], "time": int(datetime.strptime(solve["solvedAt"], "%Y-%m-%dT%H:%M:%S+00:00").timestamp())} 69 | return tasks, taskStats 70 | 71 | def scoreboard(self): 72 | board = self._scoreboard() 73 | tasks, taskStats = self._tasks() 74 | for i in range(len(board)): 75 | if board[i]["team"] in taskStats: 76 | board[i]["taskStats"] = taskStats[ board[i]["team"] ] 77 | else: 78 | board[i]["taskStats"] = {} 79 | return {"tasks": tasks, "standings": board} 80 | -------------------------------------------------------------------------------- /lib/scraper/defcon.py: -------------------------------------------------------------------------------- 1 | import math 2 | import requests 3 | from urllib3.util.retry import Retry 4 | from requests.adapters import HTTPAdapter 5 | from urllib.parse import urljoin 6 | from logging import getLogger, StreamHandler, Formatter 7 | from http.cookies import SimpleCookie 8 | 9 | logger = getLogger(__name__) 10 | handler = StreamHandler() 11 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 12 | logger.addHandler(handler) 13 | 14 | class DEFCONScraper(): 15 | def __init__(self, url, **kwargs): 16 | self.url = url 17 | 18 | cookies = SimpleCookie() 19 | if "cookies" in kwargs and kwargs["cookies"]: 20 | cookies.load(kwargs["cookies"]) 21 | 22 | self.cookiejar = requests.cookies.RequestsCookieJar() 23 | self.cookiejar.update(cookies) 24 | 25 | def _get(self, path): 26 | s = requests.Session() 27 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 28 | s.mount("http://", HTTPAdapter(max_retries=retries)) 29 | s.mount("https://", HTTPAdapter(max_retries=retries)) 30 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 31 | 32 | def _tasks(self): 33 | r = self._get("/challenges.json") 34 | r.raise_for_status() 35 | return [task[0] for task in r.json()['message']['open']] 36 | 37 | def _solves(self): 38 | r = self._get("/challenges.json") 39 | r.raise_for_status() 40 | return [{ 41 | 'task': solve[0], 42 | 'team': solve[1], 43 | 'time': int(float(solve[2])), 44 | } for solve in r.json()['message']['solves']] 45 | 46 | def _taskPoint(self, solves: int) -> int: 47 | if solves < 2: 48 | return 500 49 | return int(100 + 400 / (1 + 0.08 * solves * math.log(solves))) 50 | 51 | def scoreboard(self): 52 | tasks = self._tasks() 53 | teams = {} 54 | solveCount = {task:0 for task in tasks} 55 | 56 | for solve in self._solves(): 57 | if solve["team"] not in teams: 58 | teams[solve["team"]] = { 59 | "team": solve["team"], 60 | "pos": 0, 61 | "score": 0, 62 | "taskStats": {}, 63 | } 64 | teams[solve["team"]]["taskStats"][solve["task"]] = { 65 | "time": solve["time"] 66 | } 67 | solveCount[solve["task"]] += 1 68 | 69 | taskPoints = { 70 | task: self._taskPoint(solveCount[task]) 71 | for task in tasks 72 | } 73 | 74 | teamList = list(teams.values()) 75 | for i in range(len(teamList)): 76 | teamList[i]["score"] = sum(taskPoints[task] for task in teamList[i]["taskStats"].keys()) 77 | 78 | teamList = sorted(teamList, key=lambda x: (x["score"], -max(v["time"] for v in x["taskStats"].values()) ), reverse=True) 79 | for i in range(len(teamList)): 80 | teamList[i]["pos"] = i+1 81 | 82 | return {"tasks": tasks, "standings": teamList} 83 | -------------------------------------------------------------------------------- /lib/scraper/hacklu.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from logging import getLogger, StreamHandler, Formatter 6 | from http.cookies import SimpleCookie 7 | from bs4 import BeautifulSoup 8 | from tqdm import tqdm 9 | import re 10 | 11 | logger = getLogger(__name__) 12 | handler = StreamHandler() 13 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 14 | logger.addHandler(handler) 15 | 16 | class HackluScraper(): 17 | def __init__(self, url, **kwargs): 18 | self.url = url 19 | 20 | cookies = SimpleCookie() 21 | if "cookies" in kwargs and kwargs["cookies"]: 22 | cookies.load(kwargs["cookies"]) 23 | 24 | self.cookiejar = requests.cookies.RequestsCookieJar() 25 | self.cookiejar.update(cookies) 26 | 27 | def _get(self, path): 28 | s = requests.Session() 29 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 30 | s.mount("http://", HTTPAdapter(max_retries=retries)) 31 | s.mount("https://", HTTPAdapter(max_retries=retries)) 32 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 33 | 34 | def _tasks(self): 35 | r = self._get("/challenges") 36 | r.raise_for_status() 37 | 38 | soup = BeautifulSoup(r.text, "html.parser") 39 | rows = soup.select("tbody tr") 40 | tasks = {} 41 | for row in rows: 42 | data = row.select("td") 43 | tasks[data[0].text.strip()] = { 44 | "category": data[1].text.strip(), 45 | "tags": [], 46 | } 47 | return tasks 48 | 49 | def _team_solves(self, team_url): 50 | r = self._get(team_url[len(self.url):]) 51 | r.raise_for_status() 52 | 53 | soup = BeautifulSoup(r.text, "html.parser") 54 | rows = soup.select("tbody tr") 55 | solved_tasks = {} 56 | for row in rows: 57 | data = row.select("td") 58 | solved_tasks[data[0].text.strip()] = None 59 | return solved_tasks 60 | 61 | def scoreboard(self): 62 | r = self._get("/scoreboard") 63 | r.raise_for_status() 64 | soup = BeautifulSoup(r.text, "html.parser") 65 | 66 | tasks = self._tasks() 67 | 68 | # parse tbody 69 | standings = [] 70 | team_urls = [] 71 | rows = soup.select("tbody tr") 72 | for row in tqdm(rows): 73 | data = row.select("td") 74 | 75 | pos = int(data[0].text.strip()) 76 | team = data[1].text.strip() 77 | score = int(re.findall(r"\d+", data[2].text.strip())[0]) 78 | standings.append({ 79 | "team": team, 80 | "pos": pos, 81 | "score": score, 82 | "taskStats": {}, 83 | }) 84 | team_url = data[1].select_one("a")["href"] 85 | team_urls.append(team_url) 86 | 87 | for i in tqdm(range(len(team_urls))): 88 | solved_tasks = self._team_solves(team_urls[i]) 89 | standings[i]["taskStats"] = solved_tasks 90 | 91 | return {"tasks": list(tasks.keys()), "standings": standings, "taskinfo": tasks} 92 | -------------------------------------------------------------------------------- /lib/scraper/imaginaryctf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from logging import getLogger, StreamHandler, Formatter 6 | from http.cookies import SimpleCookie 7 | from bs4 import BeautifulSoup 8 | from tqdm import tqdm 9 | 10 | logger = getLogger(__name__) 11 | handler = StreamHandler() 12 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 13 | logger.addHandler(handler) 14 | 15 | class ImaginaryCTFScraper(): 16 | def __init__(self, url, **kwargs): 17 | self.url = url 18 | 19 | cookies = SimpleCookie() 20 | if "cookies" in kwargs and kwargs["cookies"]: 21 | cookies.load(kwargs["cookies"]) 22 | 23 | self.cookiejar = requests.cookies.RequestsCookieJar() 24 | self.cookiejar.update(cookies) 25 | 26 | def _get(self, path): 27 | s = requests.Session() 28 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 29 | s.mount("http://", HTTPAdapter(max_retries=retries)) 30 | s.mount("https://", HTTPAdapter(max_retries=retries)) 31 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 32 | 33 | def _team_solved(self, link): 34 | r = self._get(link) 35 | r.raise_for_status() 36 | soup = BeautifulSoup(r.text, "html.parser") 37 | 38 | rows = soup.select("tbody tr") 39 | tasks = {} 40 | for row in rows: 41 | tasks[row.select("td")[0].text.strip()] = None 42 | return tasks 43 | 44 | def scoreboard(self): 45 | r = self._get("/Leaderboard") 46 | r.raise_for_status() 47 | soup = BeautifulSoup(r.text, "html.parser") 48 | 49 | # parse tbody 50 | tasks = set() 51 | standings = [] 52 | rows = soup.select("tbody tr") 53 | for row in tqdm(rows): 54 | data = row.select("td") 55 | 56 | pos = int(data[0].text.strip()) 57 | score = int(data[2].text.strip()) 58 | 59 | team = row.select_one("a") 60 | teamname = team.text.strip() 61 | team_solved = self._team_solved(team["href"]) 62 | tasks.update(list(team_solved.keys())) 63 | 64 | standings.append({ 65 | "team": teamname, 66 | "pos": pos, 67 | "score": score, 68 | "taskStats": team_solved, 69 | }) 70 | return {"tasks": list(tasks), "standings": standings} 71 | -------------------------------------------------------------------------------- /lib/scraper/midnightsun.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from bs4 import BeautifulSoup 6 | from logging import getLogger, StreamHandler, Formatter 7 | from http.cookies import SimpleCookie 8 | 9 | logger = getLogger(__name__) 10 | handler = StreamHandler() 11 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 12 | logger.addHandler(handler) 13 | 14 | class MidnightsunScraper(): 15 | def __init__(self, url, **kwargs): 16 | self.url = url 17 | cookies = SimpleCookie() 18 | if "cookies" in kwargs and kwargs["cookies"]: 19 | cookies.load(kwargs["cookies"]) 20 | 21 | self.cookiejar = requests.cookies.RequestsCookieJar() 22 | self.cookiejar.update(cookies) 23 | 24 | def _get(self, path): 25 | s = requests.Session() 26 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 27 | s.mount("http://", HTTPAdapter(max_retries=retries)) 28 | s.mount("https://", HTTPAdapter(max_retries=retries)) 29 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 30 | 31 | def scoreboard(self): 32 | logger.warning("getting scoreboard...") 33 | r = self._get("/dashboard/scoreboard") 34 | r.raise_for_status() 35 | logger.warning("done") 36 | 37 | tasks = [] 38 | soup = BeautifulSoup(r.text, "html.parser") 39 | heads = soup.select("table.ctf-scoreboard thead th") 40 | for head in heads[4:]: 41 | tasks.append(head.text.strip()) 42 | 43 | standings = [] 44 | solves = soup.select("table.ctf-scoreboard tbody tr") 45 | for solve in solves: 46 | datas = solve.select("td") 47 | pos = int(datas[0].text.strip()) 48 | team = datas[1].text.strip() 49 | score = int(datas[2].text.strip()) 50 | taskStats = {} 51 | 52 | for i, taskStat in enumerate(datas[4:]): 53 | if taskStat.text.strip() != "": 54 | taskStats[tasks[i]] = None 55 | standings.append({ 56 | "pos": pos, 57 | "team": team, 58 | "score": score, 59 | "taskStats": taskStats, 60 | }) 61 | 62 | return {"standings": standings, "tasks": tasks} 63 | -------------------------------------------------------------------------------- /lib/scraper/n1ctf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib.parse import urljoin 3 | from urllib3.util.retry import Retry 4 | from requests.adapters import HTTPAdapter 5 | from http.cookies import SimpleCookie 6 | 7 | class N1CTFScraper(): 8 | def __init__(self, url, **kwargs): 9 | self.url = url 10 | 11 | cookies = SimpleCookie() 12 | if "cookies" in kwargs and kwargs["cookies"]: 13 | cookies.load(kwargs["cookies"]) 14 | 15 | self.cookiejar = requests.cookies.RequestsCookieJar() 16 | self.cookiejar.update(cookies) 17 | self.token = kwargs["token"] # type: str 18 | 19 | def _get(self, path, **kwargs): 20 | s = requests.Session() 21 | s.verify = False 22 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 23 | s.mount("http://", HTTPAdapter(max_retries=retries)) 24 | s.mount("https://", HTTPAdapter(max_retries=retries)) 25 | return s.get(urljoin(self.url, path), cookies=self.cookiejar, headers={"Authorization": "Bearer {}".format(self.token)}, **kwargs) 26 | 27 | def _scoreboard(self): 28 | page = 1 29 | teams = [] 30 | while True: 31 | r = self._get("/api/scoreboard", params={"page": page}) 32 | r.raise_for_status() 33 | data = r.json() 34 | challs = {chall["id"]:chall["title"] for chall in data["challs"] } 35 | for _, team in data["teams"].items(): 36 | teams.append({ 37 | "team": team["name"], 38 | "pos": team["rank"], 39 | "score": team["totalScore"], 40 | "id": team["id"], 41 | "taskStats": {challs[cid]:None for cid in team["solveds"] } 42 | }) 43 | total = data["total"] 44 | print("[+] {}/{}".format(len(teams), total)) 45 | if len(teams) >= total: 46 | break 47 | 48 | page += 1 49 | return teams 50 | 51 | def _tasks(self): 52 | r = self._get("/api/challenges") 53 | r.raise_for_status() 54 | data = r.json() 55 | return data["challs"] # {id: x, title: "y", class: "z"} 56 | 57 | def scoreboard(self): 58 | tasks = self._tasks() 59 | teams = self._scoreboard() 60 | taskinfo = { 61 | task["title"]:{ 62 | "category": task["class"], 63 | "tags": [], 64 | } 65 | for task in tasks 66 | } 67 | 68 | return {"tasks": [t["title"] for t in tasks], "standings": teams, "taskinfo": taskinfo} 69 | -------------------------------------------------------------------------------- /lib/scraper/p4.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from bs4 import BeautifulSoup 6 | from logging import getLogger, StreamHandler, Formatter 7 | from http.cookies import SimpleCookie 8 | 9 | logger = getLogger(__name__) 10 | handler = StreamHandler() 11 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 12 | logger.addHandler(handler) 13 | 14 | class p4CTFScraper(): 15 | def __init__(self, url, **kwargs): 16 | self.url = url 17 | cookies = SimpleCookie() 18 | if "cookies" in kwargs and kwargs["cookies"]: 19 | cookies.load(kwargs["cookies"]) 20 | 21 | self.cookiejar = requests.cookies.RequestsCookieJar() 22 | self.cookiejar.update(cookies) 23 | 24 | def _get(self, path): 25 | s = requests.Session() 26 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 27 | s.mount("http://", HTTPAdapter(max_retries=retries)) 28 | s.mount("https://", HTTPAdapter(max_retries=retries)) 29 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 30 | 31 | def scoreboard(self): 32 | r = self._get("/scoreboard") 33 | r.raise_for_status() 34 | soup = BeautifulSoup(r.text, "html.parser") 35 | 36 | tasks = [task.text.strip() for task in soup.select(".header-task")] 37 | trs = soup.select("table tbody tr") 38 | 39 | teams = [] 40 | for tr in trs: 41 | teams.append({ 42 | "pos": int(tr.select_one(".column-index").text.strip().rstrip(".")), 43 | "team": tr.select_one(".column-nick").select("span")[1].text.strip(), 44 | "score": int(tr.select_one(".column-total").text.strip()), 45 | "taskStats": {task["data-task"]:{ 46 | "time": int(task["data-solved_at"]), 47 | }for task in tr.select(".column-solve")}, 48 | }) 49 | 50 | return {"standings": teams, "tasks": tasks} 51 | -------------------------------------------------------------------------------- /lib/scraper/plaidctf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from logging import getLogger, StreamHandler, Formatter 6 | from http.cookies import SimpleCookie 7 | 8 | logger = getLogger(__name__) 9 | handler = StreamHandler() 10 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 11 | logger.addHandler(handler) 12 | 13 | class PlaidCTFScraper(): 14 | def __init__(self, url, **kwargs): 15 | self.url = url 16 | 17 | cookies = SimpleCookie() 18 | if "cookies" in kwargs and kwargs["cookies"]: 19 | cookies.load(kwargs["cookies"]) 20 | 21 | self.cookiejar = requests.cookies.RequestsCookieJar() 22 | self.cookiejar.update(cookies) 23 | 24 | def _get(self, path): 25 | s = requests.Session() 26 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 27 | s.mount("http://", HTTPAdapter(max_retries=retries)) 28 | s.mount("https://", HTTPAdapter(max_retries=retries)) 29 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 30 | 31 | def _tasks(self): 32 | r = self._get("/api/challenge") 33 | r.raise_for_status() 34 | data = r.json()["challenges"] 35 | 36 | tasks = {} 37 | for task in data: 38 | for i, flag in enumerate(task["flags"]): 39 | tasks[flag["id"]] = "{} - {}".format(task["metadata"]["title"], i + 1) 40 | return tasks 41 | 42 | def _standings(self): 43 | r = self._get("/api/scoreboard") 44 | r.raise_for_status() 45 | data = r.json()["teams"] 46 | return [{ 47 | "team": t["name"], 48 | "pos": t["rank"], 49 | "score": t["score"], 50 | "solves": [solve["flagId"] for solve in t["solves"]], 51 | }for t in data] 52 | 53 | def scoreboard(self): 54 | tasks = self._tasks() 55 | standings = self._standings() 56 | for i in range(len(standings)): 57 | standings[i]["taskStats"] = {tasks[flagID]: None for flagID in standings[i]["solves"]} 58 | del standings[i]["solves"] 59 | return {"tasks": list(tasks.values()), "standings": standings} 60 | -------------------------------------------------------------------------------- /lib/scraper/rctf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib.parse import urljoin 3 | from urllib3.util.retry import Retry 4 | from requests.adapters import HTTPAdapter 5 | from http.cookies import SimpleCookie 6 | from tqdm import tqdm 7 | 8 | class RCTFScraper(): 9 | def __init__(self, url, **kwargs): 10 | self.url = url 11 | 12 | cookies = SimpleCookie() 13 | if "cookies" in kwargs and kwargs["cookies"]: 14 | cookies.load(kwargs["cookies"]) 15 | 16 | self.cookiejar = requests.cookies.RequestsCookieJar() 17 | self.cookiejar.update(cookies) 18 | self.token = kwargs["token"] # type: str 19 | 20 | def _get(self, path, **kwargs): 21 | s = requests.Session() 22 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 23 | s.mount("http://", HTTPAdapter(max_retries=retries)) 24 | s.mount("https://", HTTPAdapter(max_retries=retries)) 25 | return s.get(urljoin(self.url, path), cookies=self.cookiejar, headers={"Authorization": "Bearer {}".format(self.token)}, **kwargs) 26 | 27 | def _scoreboard(self): 28 | total = 0 29 | cur_rows = [] 30 | while True: 31 | r = self._get("/api/v1/leaderboard/now", params={"limit": 100, "offset": len(cur_rows)}) 32 | r.raise_for_status() 33 | data = r.json()["data"] 34 | total = data["total"] 35 | cur_rows.extend(data["leaderboard"]) 36 | print("[+] {}/{}".format(len(cur_rows), total)) 37 | if len(cur_rows) >= total: 38 | break 39 | return [{ 40 | "pos": i+1, 41 | "team": row["name"], 42 | "score": row["score"], 43 | "id": row["id"], 44 | } for i, row in enumerate(cur_rows)] 45 | 46 | def _team_tasks(self, team_id: str): 47 | r = self._get("/api/v1/users/{}".format(team_id)) 48 | r.raise_for_status() 49 | data = r.json()["data"] 50 | return {s["name"]:{ 51 | "points": s["points"], 52 | "time": s["createdAt"], 53 | } for s in data["solves"]} 54 | 55 | def _tasks(self): 56 | r = self._get("/api/v1/challs") 57 | r.raise_for_status() 58 | data = r.json()["data"] 59 | return [d["name"] for d in data] 60 | 61 | def scoreboard(self): 62 | tasks = self._tasks() 63 | teams = self._scoreboard() 64 | for i in tqdm(range(len(teams))): 65 | teams[i]["taskStats"] = self._team_tasks(teams[i]["id"]) 66 | 67 | return {"tasks": tasks, "standings": teams} 68 | -------------------------------------------------------------------------------- /lib/scraper/tctf.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from bs4 import BeautifulSoup 6 | from logging import getLogger, StreamHandler, Formatter 7 | from http.cookies import SimpleCookie 8 | 9 | logger = getLogger(__name__) 10 | handler = StreamHandler() 11 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 12 | logger.addHandler(handler) 13 | 14 | class TCTFScraper(): 15 | def __init__(self, url, **kwargs): 16 | self.url = url 17 | cookies = SimpleCookie() 18 | if "cookies" in kwargs and kwargs["cookies"]: 19 | cookies.load(kwargs["cookies"]) 20 | 21 | self.cookiejar = requests.cookies.RequestsCookieJar() 22 | self.cookiejar.update(cookies) 23 | 24 | def _get(self, path): 25 | s = requests.Session() 26 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 27 | s.mount("http://", HTTPAdapter(max_retries=retries)) 28 | s.mount("https://", HTTPAdapter(max_retries=retries)) 29 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 30 | 31 | def scoreboard(self): 32 | r = self._get("/data/scoreboard.json") 33 | data = r.json() 34 | 35 | problem_id = {} 36 | for p in data["problems"]: 37 | problem_id[p["id"]] = p["title"] 38 | 39 | teams = [] 40 | for t in data["teams"]: 41 | teams.append({ 42 | "pos": t["rank"], 43 | "team": t["username"], 44 | "score": t["score"], 45 | "taskStats": {problem_id[p_id]:None for p_id in t["solved"]}, 46 | }) 47 | 48 | return {"standings": teams, "tasks": list(problem_id.values())} 49 | -------------------------------------------------------------------------------- /lib/scraper/the3000.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib3.util.retry import Retry 3 | from requests.adapters import HTTPAdapter 4 | from urllib.parse import urljoin 5 | from bs4 import BeautifulSoup 6 | from logging import getLogger, StreamHandler, Formatter 7 | from http.cookies import SimpleCookie 8 | 9 | logger = getLogger(__name__) 10 | handler = StreamHandler() 11 | handler.setFormatter(Formatter('%(asctime)-15s %(message)s')) 12 | logger.addHandler(handler) 13 | 14 | class The3000CTFScraper(): 15 | def __init__(self, url, **kwargs): 16 | self.url = url 17 | cookies = SimpleCookie() 18 | if "cookies" in kwargs and kwargs["cookies"]: 19 | cookies.load(kwargs["cookies"]) 20 | 21 | self.cookiejar = requests.cookies.RequestsCookieJar() 22 | self.cookiejar.update(cookies) 23 | 24 | def _get(self, path): 25 | s = requests.Session() 26 | retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 501, 502, 503, 504]) 27 | s.mount("http://", HTTPAdapter(max_retries=retries)) 28 | s.mount("https://", HTTPAdapter(max_retries=retries)) 29 | return s.get(urljoin(self.url, path), cookies=self.cookiejar) 30 | 31 | 32 | def _tasks(self): 33 | r = self._get("/challenges") 34 | r.raise_for_status() 35 | soup = BeautifulSoup(r.text, "html.parser") 36 | return [task.text.strip() for task in soup.select(".list-group-item-text")] 37 | 38 | 39 | def scoreboard(self): 40 | tasks = self._tasks() 41 | r = self._get("/rankingpp") 42 | r.raise_for_status() 43 | soup = BeautifulSoup(r.text, "html.parser") 44 | trs = soup.select("table tbody tr") 45 | 46 | teams = [] 47 | for tr in trs: 48 | tds = tr.find_all("td") 49 | teams.append({ 50 | "pos": int(tds[0].text.strip()), 51 | "team": tds[2].text.strip(), 52 | "score": int(tds[3].text.strip()), 53 | "taskStats": {task["title"]:None for task in tr.select("i.las")}, 54 | }) 55 | 56 | return {"standings": teams, "tasks": tasks} 57 | -------------------------------------------------------------------------------- /lib/types.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict 2 | from lib.perf import avg_perf 3 | 4 | class History(): 5 | def __init__(self, event: str, rank: int, perf: float, new_rating: float, tasks: List[str], ahc_rating: float): 6 | self.event = event 7 | self.rank = rank 8 | self.perf = perf 9 | self.new_rating = new_rating 10 | self.tasks = tasks 11 | self.ahc_rating = ahc_rating 12 | 13 | def toJSON(self)->Dict: 14 | return {"event": self.event, "rank": self.rank, "perf": self.perf, "rating": self.new_rating, "tasks": self.tasks, "ahc_rating": self.ahc_rating} 15 | 16 | 17 | class Team(): 18 | def __init__(self, name: str, country: str): 19 | self.name = name 20 | self.country = country 21 | self.history: List[History] = [] 22 | 23 | def past_perfs(self)->List[float]: 24 | return [h.perf for h in self.history] 25 | 26 | def aperf(self)->float: 27 | return avg_perf(self.past_perfs()) 28 | 29 | def toJSON(self)->Dict: 30 | return { 31 | "name": self.name, 32 | "country": self.country, 33 | "history": [h.toJSON() for h in self.history], 34 | "rating": self.history[-1].new_rating 35 | } 36 | 37 | class Event(): 38 | def __init__(self, name: str, date: int, tasks: Dict[str,float]): 39 | self.name = name 40 | self.date = date 41 | self.tasks = tasks 42 | 43 | def toJSON(self)->Dict: 44 | return self.__dict__ 45 | 46 | 47 | -------------------------------------------------------------------------------- /makedb.py: -------------------------------------------------------------------------------- 1 | import json 2 | from lib.perf import calc_performance, calc_new_rating, calc_new_ahc_rating 3 | from lib.difficulty import calc_difficulty 4 | from lib.types import Team, History, Event 5 | from pathlib import Path 6 | 7 | def jsonEncoder(x): 8 | try: 9 | return x.toJSON() 10 | except: 11 | return x.__dict__ 12 | 13 | ts = [] 14 | for p in Path("./data/teams/").glob("*.json"): 15 | with open(p) as f: 16 | ts.append( json.load(f) ) 17 | 18 | team_index = {} 19 | for i, t in enumerate(ts): 20 | for name in [t["name"]] + t["aliases"]: 21 | if name in team_index: 22 | raise ValueError("name [{}] is duplicated".format(name)) 23 | team_index[name] = i 24 | teams = [Team(t["name"], t["country"]) for t in ts] 25 | 26 | 27 | es = [] 28 | for p in Path("./data/events/").glob("*.json"): 29 | with open(p) as f: 30 | es.append( json.load(f) ) 31 | es = sorted(es, key=lambda e: e["date"]) 32 | 33 | events = [] 34 | for e in es: 35 | print("[+]", "calculating about {}".format(e["name"])) 36 | 37 | e["standings"] = sorted(e["standings"], key=lambda t: t["pos"]) # sort teams by pos 38 | 39 | # get past performances of teams 40 | team_perfs = [] 41 | indices = [] 42 | for t in e["standings"]: 43 | if t["team"] not in team_index: 44 | teams.append(Team(t["team"], "")) 45 | team_index[ t["team"] ] = len(teams) - 1 46 | 47 | index = team_index[ t["team"] ] 48 | team_perfs.append(teams[index].past_perfs()) 49 | 50 | # calc performance 51 | perfs = calc_performance(team_perfs) 52 | 53 | # calc rating and save 54 | for i in range(len(perfs)): 55 | t = e["standings"][i] 56 | index = team_index[ t["team"] ] 57 | rating = calc_new_rating(team_perfs[i], perfs[i]) 58 | ahc_rating = calc_new_ahc_rating(team_perfs[i], perfs[i]) 59 | teams[index].history.append(History( 60 | e["name"], 61 | i+1, 62 | perfs[i], 63 | rating, 64 | list(t["taskStats"].keys()), 65 | ahc_rating, 66 | )) 67 | 68 | # calc challenge difficulties 69 | tasks = [] 70 | for task in e["tasks"]: 71 | solve_teams = [e["standings"][i]["team"] for i in range(len(e["standings"])) if task in e["standings"][i]["taskStats"]] 72 | solve_team_perfs = [teams[team_index[t]].aperf() for t in solve_teams] 73 | unsolve_team_perfs = [e["standings"][i]["team"] for i in range(len(e["standings"])) if task not in e["standings"][i]["taskStats"]] 74 | unsolve_team_perfs = [teams[team_index[t]].aperf() for t in unsolve_team_perfs] 75 | 76 | diff = calc_difficulty(solve_team_perfs, unsolve_team_perfs) 77 | tasks.append({"name": task, "difficulty": diff}) 78 | 79 | # save event 80 | events.append(Event(e["name"], e["date"], {t["name"]:t["difficulty"] for t in tasks})) 81 | 82 | teams = [t for t in teams if len(t.history) > 0] 83 | teams = sorted(teams, key=lambda x: x.history[-1].new_rating, reverse=True) 84 | with open("ctf.json", "w") as f: 85 | json.dump({ 86 | "teams": teams, 87 | "events": events, 88 | }, f, default=jsonEncoder, ensure_ascii=False) 89 | 90 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "ctf-ratings" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["theoremoon "] 6 | license = "Apache 2.0" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.9" 10 | requests = "^2.25.1" 11 | scikit-learn = "^0.24.1" 12 | beautifulsoup4 = "^4.9.3" 13 | tqdm = "^4.59.0" 14 | pylint = "^2.8.2" 15 | dateparser = "^1.0.0" 16 | 17 | [tool.poetry.dev-dependencies] 18 | 19 | [build-system] 20 | requires = ["poetry-core>=1.0.0"] 21 | build-backend = "poetry.core.masonry.api" 22 | -------------------------------------------------------------------------------- /script.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | import json 4 | from datetime import datetime 5 | 6 | from lib.scraper.bsidessf import BSidesSFScraper 7 | from lib.scraper.d3ctf import D3CTFScraper 8 | from lib.scraper.ctfd_legacy import LegacyCTFdScraper 9 | from lib.scraper.ctfd import CTFdScraper 10 | from lib.scraper.ctfx import CTFxScraper 11 | from lib.scraper.angstromctf import AngstromCTFScraper 12 | from lib.scraper.midnightsun import MidnightsunScraper 13 | from lib.scraper.plaidctf import PlaidCTFScraper 14 | from lib.scraper.asisctf import AsisCTFScraper 15 | from lib.scraper.defcon import DEFCONScraper 16 | from lib.scraper.the3000 import The3000CTFScraper 17 | from lib.scraper.p4 import p4CTFScraper 18 | from lib.scraper.bcactf import BCACTFScraper 19 | from lib.scraper.rctf import RCTFScraper 20 | from lib.scraper.tctf import TCTFScraper 21 | from lib.scraper.imaginaryctf import ImaginaryCTFScraper 22 | from lib.scraper.hacklu import HackluScraper 23 | from lib.scraper.n1ctf import N1CTFScraper 24 | 25 | PLATFORMS = {"bsidessf": BSidesSFScraper, "d3ctf": D3CTFScraper, "ctfd-legacy": LegacyCTFdScraper, "ctfd": CTFdScraper, "ctfx": CTFxScraper, "angstrom": AngstromCTFScraper, "midnightsun": MidnightsunScraper, "plaidctf": PlaidCTFScraper, "asis": AsisCTFScraper, "defcon": DEFCONScraper, "3kctf": The3000CTFScraper, "p4": p4CTFScraper, "bcactf": BCACTFScraper, "rctf": RCTFScraper, "tctf": TCTFScraper, "imaginaryctf": ImaginaryCTFScraper, "hacklu": HackluScraper, "n1ctf": N1CTFScraper} 26 | 27 | def main(): 28 | parser = argparse.ArgumentParser() 29 | parser.add_argument("name") 30 | parser.add_argument("date") 31 | parser.add_argument("url") 32 | parser.add_argument("--platform", default="ctfd") 33 | parser.add_argument("--session") 34 | parser.add_argument("--cookies") 35 | parser.add_argument("--token") 36 | parser.add_argument("--mode", default="teams") 37 | parser.add_argument("--without-tasks", action='store_true') 38 | 39 | args = parser.parse_args() 40 | if args.platform not in PLATFORMS: 41 | print("Currently supported platforms are: {}".format(PLATFORMS.keys()), file=sys.stderr) 42 | quit(1) 43 | 44 | scraper = PLATFORMS[args.platform](**vars(args)) 45 | data = scraper.scoreboard() 46 | data["date"] = int(datetime.strptime(args.date, "%Y-%m-%d").timestamp()) 47 | data["name"] = args.name 48 | 49 | with open("./data/events/{}.json".format(args.name.replace("/", "-")), "w") as f: 50 | json.dump(data, f, indent=2, ensure_ascii=False) 51 | 52 | 53 | if __name__ == "__main__": 54 | main() 55 | --------------------------------------------------------------------------------