From a09dc4b00893af5e67cc994629789234d50f9a7e Mon Sep 17 00:00:00 2001 From: six <51x@keemail.me> Date: Thu, 25 Aug 2022 18:13:05 +0200 Subject: [PATCH] Scoreboard by Robin Jadoul and address fix --- README.md | 4 +- challenges/vol9_rnd1/Day0/README.md | 4 +- scoreboard/game_abi.json | 1 + scoreboard/scoreboard.py | 74 +++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 scoreboard/game_abi.json create mode 100644 scoreboard/scoreboard.py diff --git a/README.md b/README.md index 5404e7e..9af808d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The story of CCTF: From crypto hackers' vision to the biggest web3 hacking compe **Finish date**: 2022 August 26., 16:00, Singapore Time - UTC/GMT +8 -**Global location link**: Flags are to be submitted to the CCTF smart contract! +**Global location link**: TBA (flags are to be submitted to the CCTF smart contract) **Physical location**: HiTB Conference, InterContinental Singapore, 80 Middle Rd, Singapore 188966 @@ -29,4 +29,4 @@ The story of CCTF: From crypto hackers' vision to the biggest web3 hacking compe ## Vol9. Round 2. information - TBA -Target date: Q4 2022 \ No newline at end of file +Target date: Q4 2022 diff --git a/challenges/vol9_rnd1/Day0/README.md b/challenges/vol9_rnd1/Day0/README.md index d3954dd..cbe684f 100644 --- a/challenges/vol9_rnd1/Day0/README.md +++ b/challenges/vol9_rnd1/Day0/README.md @@ -1,7 +1,7 @@ ## CCTF vol9 Info Max points = 4096 -Registration => https://polygonscan.com/address/0x5c9d7d00880a6dda6fc0a27ea682f513eab8045a#writeContract +Registration => https://polygonscan.com/address/0x36a1424da63a50627863d8f65c0669da7347814a How to and rules => https://cryptoctf.org/2022/08/22/decentralized-ctf/ @@ -9,8 +9,6 @@ If you have not found a private key, but a standard string, use one of this API: http://209.250.246.26:6789/get?flag=CCTF{test} fyord7wc4lzrgp4g4v2z7nhftoymolmmhmuixgkmnvo6f2bvlqdtjjid.onion - - Start date, Day 0: 2022 August 25, 10:00, Singapore Time - UTC/GMT +8 Release of Day 1 challenges: Start date: 2022 August 26, 10:00, Singapore Time - UTC/GMT +8 diff --git a/scoreboard/game_abi.json b/scoreboard/game_abi.json new file mode 100644 index 0000000..b1ad204 --- /dev/null +++ b/scoreboard/game_abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"_volMaxPoints","type":"uint256"},{"internalType":"uint256","name":"_powDiff","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"CCTFStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"flagId","type":"uint256"},{"indexed":false,"internalType":"address","name":"flagSigner","type":"address"}],"name":"FlagAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"flagId","type":"uint256"}],"name":"FlagRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"flagId","type":"uint256"},{"indexed":true,"internalType":"address","name":"solver","type":"address"}],"name":"FlagSolved","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_message","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"_submitFor","type":"uint256"}],"name":"SubmitFlag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"flags","outputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bool","name":"onlyFirstSolver","type":"bool"},{"internalType":"uint256","name":"points","type":"uint256"},{"internalType":"string","name":"skill_name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"getPlayerPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"getPlayerStatus","outputs":[{"internalType":"enum CCTF9.PlayerStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSuccessfulSubmissionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"players","outputs":[{"internalType":"enum CCTF9.PlayerStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"points","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"powDiff","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_ethSignedMessageHash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"recoverSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"_RTFM","type":"string"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_started","type":"bool"}],"name":"setCCTFStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_flagId","type":"uint256"},{"internalType":"address","name":"_flagSigner","type":"address"},{"internalType":"bool","name":"_onlyFirstSolver","type":"bool"},{"internalType":"uint256","name":"_points","type":"uint256"},{"internalType":"string","name":"_skill","type":"string"}],"name":"setFlag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"enum CCTF9.PlayerStatus","name":"status","type":"uint8"}],"name":"setPlayerStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_powDiff","type":"uint256"}],"name":"setPowDiff","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"splitSignature","outputs":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"started","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"submission_success_count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"volMaxPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"volStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] diff --git a/scoreboard/scoreboard.py b/scoreboard/scoreboard.py new file mode 100644 index 0000000..db6e5d0 --- /dev/null +++ b/scoreboard/scoreboard.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + +# This scoreboard is a community contribution by Robin Jadoul. Thank you! + +import collections, pickle +import rich.console, rich.table +from pwn import * +from web3 import Web3, HTTPProvider +from web3.middleware import geth_poa_middleware +import eth_account, eth_abi +import pprint, time, json, shutil, os +import requests + +web3 = Web3(HTTPProvider("https://polygon-rpc.com/")) +web3.middleware_onion.inject(geth_poa_middleware, layer=0) + +GAME_CONTRACT = "0x36A1424DA63a50627863d8f65C0669da7347814A" +GAME = web3.eth.contract(GAME_CONTRACT, abi=json.load(open("game_abi.json"))) + +known_addresses = { + #"address": "username", # Fill it if you want to see the names +} + +############################################################# + +BLOCK_START = 32265959 +BLOCK_END = web3.eth.block_number +BLOCK_RANGE = 10000 +if os.path.exists("scoreboard.pkl"): + with open("scoreboard.pkl", "rb") as f: + seenEvents = pickle.load(f) +else: + seenEvents = {} + +def iterEvents(ev): + name = ev.event_name + known, start = seenEvents.get(name, ([], BLOCK_START)) + + yield from known + for i in range(start, BLOCK_END + 1, BLOCK_RANGE): + res = ev.getLogs(fromBlock=hex(i), toBlock=hex(i + BLOCK_RANGE)) + known += list(res) + yield from res + + seenEvents[name] = (known, BLOCK_END) + with open("scoreboard.pkl", "wb") as f: + pickle.dump(seenEvents, f) + +def main(): + con = rich.console.Console() + + allchals = [] + solves = collections.defaultdict(lambda: collections.defaultdict(lambda: False)) + + for chal in iterEvents(GAME.events.FlagAdded): + chal = (chal["args"]["flagId"], GAME.caller.flags(chal["args"]["flagId"])[3]) + allchals.append(chal) + + for solve in iterEvents(GAME.events.FlagSolved): + solver, chal = solve["args"]["solver"], solve["args"]["flagId"] + solves[solver][chal] = True + + board = [(solver if solver not in known_addresses else f"[bold cyan]{known_addresses[solver]}", str(GAME.caller.getPlayerPoints(solver))) + tuple(["[bold red]:x:", "[bold green]:heavy_check_mark:"][solved[c[0]]] for c in allchals) for solver, solved in solves.items()] + + allchals.sort() + board.sort(key = lambda e: (int(e[1]), e[0]), reverse=True) + + tab = rich.table.Table("Rank", "User", "Score", *[c[1] for c in allchals], title="Scoreboard") + for i, b in enumerate(board, 1): + tab.add_row(str(i), *b) + con.print(tab) + +if __name__ == "__main__": + main()