Skip to content

Instantly share code, notes, and snippets.

@mnixry
Created October 30, 2023 06:56
Show Gist options
  • Save mnixry/fa514f408c975071ec375dcc2df1ce44 to your computer and use it in GitHub Desktop.
Save mnixry/fa514f408c975071ec375dcc2df1ce44 to your computer and use it in GitHub Desktop.
Pure Python implementation for HashCash proof-of work, friendly for CTF.
from typing import Optional
import re
from pwn import *
def mint(
resource: str,
bits: int = 20,
now: Optional[float] = None,
ext: str = "",
salt_length: int = 8,
stamp_seconds: bool = False,
):
from secrets import token_urlsafe
import hashlib
from time import strftime, localtime, time
from itertools import count
def _mint(challenge: str, bits: int) -> str: # type: ignore
counter = 0
hex_zeros = "0" * (bits // 4)
remain_zeros = {0: 0b0000, 1: 0b0111, 2: 0b0011, 3: 0b0001}.get(bits % 4, 0)
counter_hex = "0"
for counter in count():
counter_hex = f"{counter:x}"
hash = hashlib.sha1(f"{challenge}{counter_hex}".encode()).hexdigest()
if not hash.startswith(hex_zeros):
continue
if not remain_zeros:
break
if int(hash[bits // 4], 16) <= remain_zeros:
break
return counter_hex
ver = "1"
now = now or time()
if stamp_seconds:
ts = strftime("%y%m%d%H%M%S", localtime(now))
else:
ts = strftime("%y%m%d", localtime(now))
challenge = "%s:" * 6 % (ver, bits, ts, resource, ext, token_urlsafe(salt_length))
return challenge + _mint(challenge, bits)
HASHCASH_RE = re.compile(r"`hashcash -mb(\d+) (\S+)`")
r = remote("120.46.65.156", 32106)
matched = None
while matched is None:
line = r.recvline().decode()
print(line)
matched = HASHCASH_RE.search(line)
pow_bits, pow_resource = matched.groups()
mint_result = mint(pow_resource, bits=int(pow_bits))
r.sendline(mint_result.encode())
r.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment